oleaut32: Implement ICreateTypeInfo2::SetVarDocString().
[wine] / dlls / oleaut32 / typelib.c
1 /*
2  *      TYPELIB
3  *
4  *      Copyright 1997  Marcus Meissner
5  *                    1999  Rein Klazes
6  *                    2000  Francois Jacques
7  *                    2001  Huw D M Davies for CodeWeavers
8  *                    2005  Robert Shearman, for CodeWeavers
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23  *
24  * --------------------------------------------------------------------------------------
25  * Known problems (2000, Francois Jacques)
26  *
27  * - Tested using OLEVIEW (Platform SDK tool) only.
28  *
29  * - dual interface dispinterfaces. vtable-interface ITypeInfo instances are
30  *   creating by doing a straight copy of the dispinterface instance and just changing
31  *   its typekind. Pointed structures aren't copied - only the address of the pointers.
32  *
33  * - locale stuff is partially implemented but hasn't been tested.
34  *
35  * - typelib file is still read in its entirety, but it is released now.
36  *
37  * --------------------------------------------------------------------------------------
38  *  Known problems left from previous implementation (1999, Rein Klazes) :
39  *
40  * -. Data structures are straightforward, but slow for look-ups.
41  * -. (related) nothing is hashed
42  * -. Most error return values are just guessed not checked with windows
43  *      behaviour.
44  * -. lousy fatal error handling
45  *
46  */
47
48 #include "config.h"
49 #include "wine/port.h"
50
51 #include <stdlib.h>
52 #include <string.h>
53 #include <stdarg.h>
54 #include <stdio.h>
55 #include <ctype.h>
56
57 #define COBJMACROS
58 #define NONAMELESSUNION
59 #define NONAMELESSSTRUCT
60
61 #include "winerror.h"
62 #include "windef.h"
63 #include "winbase.h"
64 #include "winnls.h"
65 #include "winreg.h"
66 #include "winuser.h"
67 #include "lzexpand.h"
68
69 #include "wine/unicode.h"
70 #include "objbase.h"
71 #include "typelib.h"
72 #include "wine/debug.h"
73 #include "variant.h"
74 #include "wine/list.h"
75
76 WINE_DEFAULT_DEBUG_CHANNEL(ole);
77 WINE_DECLARE_DEBUG_CHANNEL(typelib);
78
79 typedef struct
80 {
81     WORD     offset;
82     WORD     length;
83     WORD     flags;
84     WORD     id;
85     WORD     handle;
86     WORD     usage;
87 } NE_NAMEINFO;
88
89 typedef struct
90 {
91     WORD        type_id;   /* Type identifier */
92     WORD        count;     /* Number of resources of this type */
93     DWORD       resloader; /* SetResourceHandler() */
94     /*
95      * Name info array.
96      */
97 } NE_TYPEINFO;
98
99 static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt);
100 static HRESULT TLB_AllocAndInitVarDesc(const VARDESC *src, VARDESC **dest_ptr);
101
102 /****************************************************************************
103  *              FromLExxx
104  *
105  * Takes p_iVal (which is in little endian) and returns it
106  *   in the host machine's byte order.
107  */
108 #ifdef WORDS_BIGENDIAN
109 static WORD FromLEWord(WORD p_iVal)
110 {
111   return (((p_iVal & 0x00FF) << 8) |
112           ((p_iVal & 0xFF00) >> 8));
113 }
114
115
116 static DWORD FromLEDWord(DWORD p_iVal)
117 {
118   return (((p_iVal & 0x000000FF) << 24) |
119           ((p_iVal & 0x0000FF00) <<  8) |
120           ((p_iVal & 0x00FF0000) >>  8) |
121           ((p_iVal & 0xFF000000) >> 24));
122 }
123 #else
124 #define FromLEWord(X)  (X)
125 #define FromLEDWord(X) (X)
126 #endif
127
128 #define DISPATCH_HREF_OFFSET 0x01000000
129 #define DISPATCH_HREF_MASK   0xff000000
130
131 /****************************************************************************
132  *              FromLExxx
133  *
134  * Fix byte order in any structure if necessary
135  */
136 #ifdef WORDS_BIGENDIAN
137 static void FromLEWords(void *p_Val, int p_iSize)
138 {
139   WORD *Val = p_Val;
140
141   p_iSize /= sizeof(WORD);
142
143   while (p_iSize) {
144     *Val = FromLEWord(*Val);
145     Val++;
146     p_iSize--;
147   }
148 }
149
150
151 static void FromLEDWords(void *p_Val, int p_iSize)
152 {
153   DWORD *Val = p_Val;
154
155   p_iSize /= sizeof(DWORD);
156
157   while (p_iSize) {
158     *Val = FromLEDWord(*Val);
159     Val++;
160     p_iSize--;
161   }
162 }
163 #else
164 #define FromLEWords(X,Y) /*nothing*/
165 #define FromLEDWords(X,Y) /*nothing*/
166 #endif
167
168 /*
169  * Find a typelib key which matches a requested maj.min version.
170  */
171 static BOOL find_typelib_key( REFGUID guid, WORD *wMaj, WORD *wMin )
172 {
173     static const WCHAR typelibW[] = {'T','y','p','e','l','i','b','\\',0};
174     WCHAR buffer[60];
175     char key_name[16];
176     DWORD len, i;
177     INT best_maj = -1, best_min = -1;
178     HKEY hkey;
179
180     memcpy( buffer, typelibW, sizeof(typelibW) );
181     StringFromGUID2( guid, buffer + strlenW(buffer), 40 );
182
183     if (RegOpenKeyExW( HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hkey ) != ERROR_SUCCESS)
184         return FALSE;
185
186     len = sizeof(key_name);
187     i = 0;
188     while (RegEnumKeyExA(hkey, i++, key_name, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
189     {
190         INT v_maj, v_min;
191
192         if (sscanf(key_name, "%x.%x", &v_maj, &v_min) == 2)
193         {
194             TRACE("found %s: %x.%x\n", debugstr_w(buffer), v_maj, v_min);
195
196             if (*wMaj == 0xffff && *wMin == 0xffff)
197             {
198                 if (v_maj > best_maj) best_maj = v_maj;
199                 if (v_min > best_min) best_min = v_min;
200             }
201             else if (*wMaj == v_maj)
202             {
203                 best_maj = v_maj;
204
205                 if (*wMin == v_min)
206                 {
207                     best_min = v_min;
208                     break; /* exact match */
209                 }
210                 if (*wMin != 0xffff && v_min > best_min) best_min = v_min;
211             }
212         }
213         len = sizeof(key_name);
214     }
215     RegCloseKey( hkey );
216
217     TRACE("found best_maj %d, best_min %d\n", best_maj, best_min);
218
219     if (*wMaj == 0xffff && *wMin == 0xffff)
220     {
221         if (best_maj >= 0 && best_min >= 0)
222         {
223             *wMaj = best_maj;
224             *wMin = best_min;
225             return TRUE;
226         }
227     }
228
229     if (*wMaj == best_maj && best_min >= 0)
230     {
231         *wMin = best_min;
232         return TRUE;
233     }
234     return FALSE;
235 }
236
237 /* get the path of a typelib key, in the form "Typelib\\<guid>\\<maj>.<min>" */
238 /* buffer must be at least 60 characters long */
239 static WCHAR *get_typelib_key( REFGUID guid, WORD wMaj, WORD wMin, WCHAR *buffer )
240 {
241     static const WCHAR TypelibW[] = {'T','y','p','e','l','i','b','\\',0};
242     static const WCHAR VersionFormatW[] = {'\\','%','x','.','%','x',0};
243
244     memcpy( buffer, TypelibW, sizeof(TypelibW) );
245     StringFromGUID2( guid, buffer + strlenW(buffer), 40 );
246     sprintfW( buffer + strlenW(buffer), VersionFormatW, wMaj, wMin );
247     return buffer;
248 }
249
250 /* get the path of an interface key, in the form "Interface\\<guid>" */
251 /* buffer must be at least 50 characters long */
252 static WCHAR *get_interface_key( REFGUID guid, WCHAR *buffer )
253 {
254     static const WCHAR InterfaceW[] = {'I','n','t','e','r','f','a','c','e','\\',0};
255
256     memcpy( buffer, InterfaceW, sizeof(InterfaceW) );
257     StringFromGUID2( guid, buffer + strlenW(buffer), 40 );
258     return buffer;
259 }
260
261 /* get the lcid subkey for a typelib, in the form "<lcid>\\<syskind>" */
262 /* buffer must be at least 16 characters long */
263 static WCHAR *get_lcid_subkey( LCID lcid, SYSKIND syskind, WCHAR *buffer )
264 {
265     static const WCHAR LcidFormatW[] = {'%','l','x','\\',0};
266     static const WCHAR win16W[] = {'w','i','n','1','6',0};
267     static const WCHAR win32W[] = {'w','i','n','3','2',0};
268     static const WCHAR win64W[] = {'w','i','n','6','4',0};
269
270     sprintfW( buffer, LcidFormatW, lcid );
271     switch(syskind)
272     {
273     case SYS_WIN16: strcatW( buffer, win16W ); break;
274     case SYS_WIN32: strcatW( buffer, win32W ); break;
275     case SYS_WIN64: strcatW( buffer, win64W ); break;
276     default:
277         TRACE("Typelib is for unsupported syskind %i\n", syskind);
278         return NULL;
279     }
280     return buffer;
281 }
282
283 static HRESULT TLB_ReadTypeLib(LPCWSTR pszFileName, LPWSTR pszPath, UINT cchPath, ITypeLib2 **ppTypeLib);
284
285
286 /* Get the path to a registered type library. Helper for QueryPathOfRegTypeLib. */
287 static HRESULT query_typelib_path( REFGUID guid, WORD wMaj, WORD wMin,
288                                    SYSKIND syskind, LCID lcid, LPBSTR path )
289 {
290     HRESULT hr = TYPE_E_LIBNOTREGISTERED;
291     LCID myLCID = lcid;
292     HKEY hkey;
293     WCHAR buffer[60];
294     WCHAR Path[MAX_PATH];
295     LONG res;
296
297     TRACE_(typelib)("(%s, %x.%x, 0x%x, %p)\n", debugstr_guid(guid), wMaj, wMin, lcid, path);
298
299     if (!find_typelib_key( guid, &wMaj, &wMin )) return TYPE_E_LIBNOTREGISTERED;
300     get_typelib_key( guid, wMaj, wMin, buffer );
301
302     res = RegOpenKeyExW( HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hkey );
303     if (res == ERROR_FILE_NOT_FOUND)
304     {
305         TRACE_(typelib)("%s not found\n", debugstr_w(buffer));
306         return TYPE_E_LIBNOTREGISTERED;
307     }
308     else if (res != ERROR_SUCCESS)
309     {
310         TRACE_(typelib)("failed to open %s for read access\n", debugstr_w(buffer));
311         return TYPE_E_REGISTRYACCESS;
312     }
313
314     while (hr != S_OK)
315     {
316         LONG dwPathLen = sizeof(Path);
317
318         get_lcid_subkey( myLCID, syskind, buffer );
319
320         if (RegQueryValueW(hkey, buffer, Path, &dwPathLen))
321         {
322             if (!lcid)
323                 break;
324             else if (myLCID == lcid)
325             {
326                 /* try with sub-langid */
327                 myLCID = SUBLANGID(lcid);
328             }
329             else if ((myLCID == SUBLANGID(lcid)) && myLCID)
330             {
331                 /* try with system langid */
332                 myLCID = 0;
333             }
334             else
335             {
336                 break;
337             }
338         }
339         else
340         {
341             *path = SysAllocString( Path );
342             hr = S_OK;
343         }
344     }
345     RegCloseKey( hkey );
346     TRACE_(typelib)("-- 0x%08x\n", hr);
347     return hr;
348 }
349
350 /****************************************************************************
351  *              QueryPathOfRegTypeLib   [OLEAUT32.164]
352  *
353  * Gets the path to a registered type library.
354  *
355  * PARAMS
356  *  guid [I] referenced guid
357  *  wMaj [I] major version
358  *  wMin [I] minor version
359  *  lcid [I] locale id
360  *  path [O] path of typelib
361  *
362  * RETURNS
363  *  Success: S_OK.
364  *  Failure: If the type library is not registered then TYPE_E_LIBNOTREGISTERED
365  *  or TYPE_E_REGISTRYACCESS if the type library registration key couldn't be
366  *  opened.
367  */
368 HRESULT WINAPI QueryPathOfRegTypeLib( REFGUID guid, WORD wMaj, WORD wMin, LCID lcid, LPBSTR path )
369 {
370 #ifdef _WIN64
371     HRESULT hres = query_typelib_path( guid, wMaj, wMin, SYS_WIN64, lcid, path );
372     if(SUCCEEDED(hres))
373         return hres;
374 #endif
375     return query_typelib_path( guid, wMaj, wMin, SYS_WIN32, lcid, path );
376 }
377
378 /******************************************************************************
379  * CreateTypeLib [OLEAUT32.160]  creates a typelib
380  *
381  * RETURNS
382  *    Success: S_OK
383  *    Failure: Status
384  */
385 HRESULT WINAPI CreateTypeLib(
386         SYSKIND syskind, LPCOLESTR szFile, ICreateTypeLib** ppctlib
387 ) {
388     FIXME("(%d,%s,%p), stub!\n",syskind,debugstr_w(szFile),ppctlib);
389     return E_FAIL;
390 }
391
392 /******************************************************************************
393  *              LoadTypeLib     [OLEAUT32.161]
394  *
395  * Loads a type library
396  *
397  * PARAMS
398  *  szFile [I] Name of file to load from.
399  *  pptLib [O] Pointer that receives ITypeLib object on success.
400  *
401  * RETURNS
402  *    Success: S_OK
403  *    Failure: Status
404  *
405  * SEE
406  *  LoadTypeLibEx, LoadRegTypeLib, CreateTypeLib.
407  */
408 HRESULT WINAPI LoadTypeLib(const OLECHAR *szFile, ITypeLib * *pptLib)
409 {
410     TRACE("(%s,%p)\n",debugstr_w(szFile), pptLib);
411     return LoadTypeLibEx(szFile, REGKIND_DEFAULT, pptLib);
412 }
413
414 /******************************************************************************
415  *              LoadTypeLibEx   [OLEAUT32.183]
416  *
417  * Loads and optionally registers a type library
418  *
419  * RETURNS
420  *    Success: S_OK
421  *    Failure: Status
422  */
423 HRESULT WINAPI LoadTypeLibEx(
424     LPCOLESTR szFile,  /* [in] Name of file to load from */
425     REGKIND  regkind,  /* [in] Specify kind of registration */
426     ITypeLib **pptLib) /* [out] Pointer to pointer to loaded type library */
427 {
428     WCHAR szPath[MAX_PATH+1];
429     HRESULT res;
430
431     TRACE("(%s,%d,%p)\n",debugstr_w(szFile), regkind, pptLib);
432
433     *pptLib = NULL;
434
435     res = TLB_ReadTypeLib(szFile, szPath, MAX_PATH + 1, (ITypeLib2**)pptLib);
436
437     if (SUCCEEDED(res))
438         switch(regkind)
439         {
440             case REGKIND_DEFAULT:
441                 /* don't register typelibs supplied with full path. Experimentation confirms the following */
442                 if (((szFile[0] == '\\') && (szFile[1] == '\\')) ||
443                     (szFile[0] && (szFile[1] == ':'))) break;
444                 /* else fall-through */
445
446             case REGKIND_REGISTER:
447                 if (FAILED(res = RegisterTypeLib(*pptLib, szPath, NULL)))
448                 {
449                     IUnknown_Release(*pptLib);
450                     *pptLib = 0;
451                 }
452                 break;
453             case REGKIND_NONE:
454                 break;
455         }
456
457     TRACE(" returns %08x\n",res);
458     return res;
459 }
460
461 /******************************************************************************
462  *              LoadRegTypeLib  [OLEAUT32.162]
463  *
464  * Loads a registered type library.
465  *
466  * PARAMS
467  *  rguid     [I] GUID of the registered type library.
468  *  wVerMajor [I] major version.
469  *  wVerMinor [I] minor version.
470  *  lcid      [I] locale ID.
471  *  ppTLib    [O] pointer that receives an ITypeLib object on success.
472  *
473  * RETURNS
474  *  Success: S_OK.
475  *  Failure: Any HRESULT code returned from QueryPathOfRegTypeLib or
476  *  LoadTypeLib.
477  */
478 HRESULT WINAPI LoadRegTypeLib(
479         REFGUID rguid,
480         WORD wVerMajor,
481         WORD wVerMinor,
482         LCID lcid,
483         ITypeLib **ppTLib)
484 {
485     BSTR bstr=NULL;
486     HRESULT res;
487
488     *ppTLib = NULL;
489
490     res = QueryPathOfRegTypeLib( rguid, wVerMajor, wVerMinor, lcid, &bstr);
491
492     if(SUCCEEDED(res))
493     {
494         res= LoadTypeLib(bstr, ppTLib);
495         SysFreeString(bstr);
496     }
497
498     TRACE("(IID: %s) load %s (%p)\n",debugstr_guid(rguid), SUCCEEDED(res)? "SUCCESS":"FAILED", *ppTLib);
499
500     return res;
501 }
502
503
504 /* some string constants shared between RegisterTypeLib and UnRegisterTypeLib */
505 static const WCHAR TypeLibW[] = {'T','y','p','e','L','i','b',0};
506 static const WCHAR FLAGSW[] = {'F','L','A','G','S',0};
507 static const WCHAR HELPDIRW[] = {'H','E','L','P','D','I','R',0};
508 static const WCHAR ProxyStubClsidW[] = {'P','r','o','x','y','S','t','u','b','C','l','s','i','d',0};
509 static const WCHAR ProxyStubClsid32W[] = {'P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
510
511 /******************************************************************************
512  *              RegisterTypeLib [OLEAUT32.163]
513  * Adds information about a type library to the System Registry
514  * NOTES
515  *    Docs: ITypeLib FAR * ptlib
516  *    Docs: OLECHAR FAR* szFullPath
517  *    Docs: OLECHAR FAR* szHelpDir
518  *
519  * RETURNS
520  *    Success: S_OK
521  *    Failure: Status
522  */
523 HRESULT WINAPI RegisterTypeLib(
524      ITypeLib * ptlib,     /* [in] Pointer to the library*/
525      OLECHAR * szFullPath, /* [in] full Path of the library*/
526      OLECHAR * szHelpDir)  /* [in] dir to the helpfile for the library,
527                                                          may be NULL*/
528 {
529     static const WCHAR PSOA[] = {'{','0','0','0','2','0','4','2','4','-',
530                                  '0','0','0','0','-','0','0','0','0','-','C','0','0','0','-',
531                                  '0','0','0','0','0','0','0','0','0','0','4','6','}',0};
532     HRESULT res;
533     TLIBATTR *attr;
534     WCHAR keyName[60];
535     WCHAR tmp[16];
536     HKEY key, subKey;
537     UINT types, tidx;
538     TYPEKIND kind;
539     DWORD disposition;
540
541     if (ptlib == NULL || szFullPath == NULL)
542         return E_INVALIDARG;
543
544     if (FAILED(ITypeLib_GetLibAttr(ptlib, &attr)))
545         return E_FAIL;
546
547 #ifdef _WIN64
548     if (attr->syskind != SYS_WIN64) return TYPE_E_BADMODULEKIND;
549 #else
550     if (attr->syskind != SYS_WIN32 && attr->syskind != SYS_WIN16) return TYPE_E_BADMODULEKIND;
551 #endif
552
553     get_typelib_key( &attr->guid, attr->wMajorVerNum, attr->wMinorVerNum, keyName );
554
555     res = S_OK;
556     if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0,
557         KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS)
558     {
559         LPOLESTR doc;
560
561         /* Set the human-readable name of the typelib */
562         if (FAILED(ITypeLib_GetDocumentation(ptlib, -1, NULL, &doc, NULL, NULL)))
563             res = E_FAIL;
564         else if (doc)
565         {
566             if (RegSetValueExW(key, NULL, 0, REG_SZ,
567                 (BYTE *)doc, (lstrlenW(doc)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS)
568                 res = E_FAIL;
569
570             SysFreeString(doc);
571         }
572
573         /* Make up the name of the typelib path subkey */
574         if (!get_lcid_subkey( attr->lcid, attr->syskind, tmp )) res = E_FAIL;
575
576         /* Create the typelib path subkey */
577         if (res == S_OK && RegCreateKeyExW(key, tmp, 0, NULL, 0,
578             KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
579         {
580             if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
581                 (BYTE *)szFullPath, (lstrlenW(szFullPath)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS)
582                 res = E_FAIL;
583
584             RegCloseKey(subKey);
585         }
586         else
587             res = E_FAIL;
588
589         /* Create the flags subkey */
590         if (res == S_OK && RegCreateKeyExW(key, FLAGSW, 0, NULL, 0,
591             KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
592         {
593             /* FIXME: is %u correct? */
594             static const WCHAR formatW[] = {'%','u',0};
595             WCHAR buf[20];
596             sprintfW(buf, formatW, attr->wLibFlags);
597             if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
598                                (BYTE *)buf, (strlenW(buf) + 1)*sizeof(WCHAR) ) != ERROR_SUCCESS)
599                 res = E_FAIL;
600
601             RegCloseKey(subKey);
602         }
603         else
604             res = E_FAIL;
605
606         /* create the helpdir subkey */
607         if (res == S_OK && RegCreateKeyExW(key, HELPDIRW, 0, NULL, 0,
608             KEY_WRITE, NULL, &subKey, &disposition) == ERROR_SUCCESS)
609         {
610             BOOL freeHelpDir = FALSE;
611             OLECHAR* pIndexStr;
612
613             /* if we created a new key, and helpDir was null, set the helpdir
614                to the directory which contains the typelib. However,
615                if we just opened an existing key, we leave the helpdir alone */
616             if ((disposition == REG_CREATED_NEW_KEY) && (szHelpDir == NULL)) {
617                 szHelpDir = SysAllocString(szFullPath);
618                 pIndexStr = strrchrW(szHelpDir, '\\');
619                 if (pIndexStr) {
620                     *pIndexStr = 0;
621                 }
622                 freeHelpDir = TRUE;
623             }
624
625             /* if we have an szHelpDir, set it! */
626             if (szHelpDir != NULL) {
627                 if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
628                     (BYTE *)szHelpDir, (lstrlenW(szHelpDir)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS) {
629                     res = E_FAIL;
630                 }
631             }
632
633             /* tidy up */
634             if (freeHelpDir) SysFreeString(szHelpDir);
635             RegCloseKey(subKey);
636
637         } else {
638             res = E_FAIL;
639         }
640
641         RegCloseKey(key);
642     }
643     else
644         res = E_FAIL;
645
646     /* register OLE Automation-compatible interfaces for this typelib */
647     types = ITypeLib_GetTypeInfoCount(ptlib);
648     for (tidx=0; tidx<types; tidx++) {
649         if (SUCCEEDED(ITypeLib_GetTypeInfoType(ptlib, tidx, &kind))) {
650             LPOLESTR name = NULL;
651             ITypeInfo *tinfo = NULL;
652
653             ITypeLib_GetDocumentation(ptlib, tidx, &name, NULL, NULL, NULL);
654
655             switch (kind) {
656             case TKIND_INTERFACE:
657                 TRACE_(typelib)("%d: interface %s\n", tidx, debugstr_w(name));
658                 ITypeLib_GetTypeInfo(ptlib, tidx, &tinfo);
659                 break;
660
661             case TKIND_DISPATCH:
662                 TRACE_(typelib)("%d: dispinterface %s\n", tidx, debugstr_w(name));
663                 ITypeLib_GetTypeInfo(ptlib, tidx, &tinfo);
664                 break;
665
666             default:
667                 TRACE_(typelib)("%d: %s\n", tidx, debugstr_w(name));
668                 break;
669             }
670
671             if (tinfo) {
672                 TYPEATTR *tattr = NULL;
673                 ITypeInfo_GetTypeAttr(tinfo, &tattr);
674
675                 if (tattr) {
676                     TRACE_(typelib)("guid=%s, flags=%04x (",
677                                     debugstr_guid(&tattr->guid),
678                                     tattr->wTypeFlags);
679
680                     if (TRACE_ON(typelib)) {
681 #define XX(x) if (TYPEFLAG_##x & tattr->wTypeFlags) MESSAGE(#x"|");
682                         XX(FAPPOBJECT);
683                         XX(FCANCREATE);
684                         XX(FLICENSED);
685                         XX(FPREDECLID);
686                         XX(FHIDDEN);
687                         XX(FCONTROL);
688                         XX(FDUAL);
689                         XX(FNONEXTENSIBLE);
690                         XX(FOLEAUTOMATION);
691                         XX(FRESTRICTED);
692                         XX(FAGGREGATABLE);
693                         XX(FREPLACEABLE);
694                         XX(FDISPATCHABLE);
695                         XX(FREVERSEBIND);
696                         XX(FPROXY);
697 #undef XX
698                         MESSAGE("\n");
699                     }
700
701                     /* Register all dispinterfaces (which includes dual interfaces) and
702                        oleautomation interfaces */
703                     if ((kind == TKIND_INTERFACE && (tattr->wTypeFlags & TYPEFLAG_FOLEAUTOMATION)) ||
704                         kind == TKIND_DISPATCH)
705                     {
706                         /* register interface<->typelib coupling */
707                         get_interface_key( &tattr->guid, keyName );
708                         if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0,
709                                             KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS)
710                         {
711                             if (name)
712                                 RegSetValueExW(key, NULL, 0, REG_SZ,
713                                                (BYTE *)name, (strlenW(name)+1) * sizeof(OLECHAR));
714
715                             if (RegCreateKeyExW(key, ProxyStubClsidW, 0, NULL, 0,
716                                 KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) {
717                                 RegSetValueExW(subKey, NULL, 0, REG_SZ,
718                                                (const BYTE *)PSOA, sizeof PSOA);
719                                 RegCloseKey(subKey);
720                             }
721
722                             if (RegCreateKeyExW(key, ProxyStubClsid32W, 0, NULL, 0,
723                                 KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) {
724                                 RegSetValueExW(subKey, NULL, 0, REG_SZ,
725                                                (const BYTE *)PSOA, sizeof PSOA);
726                                 RegCloseKey(subKey);
727                             }
728
729                             if (RegCreateKeyExW(key, TypeLibW, 0, NULL, 0,
730                                 KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
731                             {
732                                 WCHAR buffer[40];
733                                 static const WCHAR fmtver[] = {'%','x','.','%','x',0 };
734                                 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
735
736                                 StringFromGUID2(&attr->guid, buffer, 40);
737                                 RegSetValueExW(subKey, NULL, 0, REG_SZ,
738                                                (BYTE *)buffer, (strlenW(buffer)+1) * sizeof(WCHAR));
739                                 sprintfW(buffer, fmtver, attr->wMajorVerNum, attr->wMinorVerNum);
740                                 RegSetValueExW(subKey, VersionW, 0, REG_SZ,
741                                                (BYTE*)buffer, (strlenW(buffer)+1) * sizeof(WCHAR));
742                                 RegCloseKey(subKey);
743                             }
744
745                             RegCloseKey(key);
746                         }
747                     }
748
749                     ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
750                 }
751
752                 ITypeInfo_Release(tinfo);
753             }
754
755             SysFreeString(name);
756         }
757     }
758
759     ITypeLib_ReleaseTLibAttr(ptlib, attr);
760
761     return res;
762 }
763
764
765 /******************************************************************************
766  *      UnRegisterTypeLib       [OLEAUT32.186]
767  * Removes information about a type library from the System Registry
768  * NOTES
769  *
770  * RETURNS
771  *    Success: S_OK
772  *    Failure: Status
773  */
774 HRESULT WINAPI UnRegisterTypeLib(
775     REFGUID libid,      /* [in] Guid of the library */
776         WORD wVerMajor, /* [in] major version */
777         WORD wVerMinor, /* [in] minor version */
778         LCID lcid,      /* [in] locale id */
779         SYSKIND syskind)
780 {
781     BSTR tlibPath = NULL;
782     DWORD tmpLength;
783     WCHAR keyName[60];
784     WCHAR subKeyName[50];
785     int result = S_OK;
786     DWORD i = 0;
787     BOOL deleteOtherStuff;
788     HKEY key = NULL;
789     HKEY subKey = NULL;
790     TYPEATTR* typeAttr = NULL;
791     TYPEKIND kind;
792     ITypeInfo* typeInfo = NULL;
793     ITypeLib* typeLib = NULL;
794     int numTypes;
795
796     TRACE("(IID: %s)\n",debugstr_guid(libid));
797
798     /* Create the path to the key */
799     get_typelib_key( libid, wVerMajor, wVerMinor, keyName );
800
801     if (syskind != SYS_WIN16 && syskind != SYS_WIN32 && syskind != SYS_WIN64)
802     {
803         TRACE("Unsupported syskind %i\n", syskind);
804         result = E_INVALIDARG;
805         goto end;
806     }
807
808     /* get the path to the typelib on disk */
809     if (query_typelib_path(libid, wVerMajor, wVerMinor, syskind, lcid, &tlibPath) != S_OK) {
810         result = E_INVALIDARG;
811         goto end;
812     }
813
814     /* Try and open the key to the type library. */
815     if (RegOpenKeyExW(HKEY_CLASSES_ROOT, keyName, 0, KEY_READ | KEY_WRITE, &key) != ERROR_SUCCESS) {
816         result = E_INVALIDARG;
817         goto end;
818     }
819
820     /* Try and load the type library */
821     if (LoadTypeLibEx(tlibPath, REGKIND_NONE, &typeLib)) {
822         result = TYPE_E_INVALIDSTATE;
823         goto end;
824     }
825
826     /* remove any types registered with this typelib */
827     numTypes = ITypeLib_GetTypeInfoCount(typeLib);
828     for (i=0; i<numTypes; i++) {
829         /* get the kind of type */
830         if (ITypeLib_GetTypeInfoType(typeLib, i, &kind) != S_OK) {
831             goto enddeleteloop;
832         }
833
834         /* skip non-interfaces, and get type info for the type */
835         if ((kind != TKIND_INTERFACE) && (kind != TKIND_DISPATCH)) {
836             goto enddeleteloop;
837         }
838         if (ITypeLib_GetTypeInfo(typeLib, i, &typeInfo) != S_OK) {
839             goto enddeleteloop;
840         }
841         if (ITypeInfo_GetTypeAttr(typeInfo, &typeAttr) != S_OK) {
842             goto enddeleteloop;
843         }
844
845         if ((kind == TKIND_INTERFACE && (typeAttr->wTypeFlags & TYPEFLAG_FOLEAUTOMATION)) ||
846             kind == TKIND_DISPATCH)
847         {
848             /* the path to the type */
849             get_interface_key( &typeAttr->guid, subKeyName );
850
851             /* Delete its bits */
852             if (RegOpenKeyExW(HKEY_CLASSES_ROOT, subKeyName, 0, KEY_WRITE, &subKey) != ERROR_SUCCESS)
853                 goto enddeleteloop;
854
855             RegDeleteKeyW(subKey, ProxyStubClsidW);
856             RegDeleteKeyW(subKey, ProxyStubClsid32W);
857             RegDeleteKeyW(subKey, TypeLibW);
858             RegCloseKey(subKey);
859             subKey = NULL;
860             RegDeleteKeyW(HKEY_CLASSES_ROOT, subKeyName);
861         }
862
863 enddeleteloop:
864         if (typeAttr) ITypeInfo_ReleaseTypeAttr(typeInfo, typeAttr);
865         typeAttr = NULL;
866         if (typeInfo) ITypeInfo_Release(typeInfo);
867         typeInfo = NULL;
868     }
869
870     /* Now, delete the type library path subkey */
871     get_lcid_subkey( lcid, syskind, subKeyName );
872     RegDeleteKeyW(key, subKeyName);
873     *strrchrW( subKeyName, '\\' ) = 0;  /* remove last path component */
874     RegDeleteKeyW(key, subKeyName);
875
876     /* check if there is anything besides the FLAGS/HELPDIR keys.
877        If there is, we don't delete them */
878     tmpLength = sizeof(subKeyName)/sizeof(WCHAR);
879     deleteOtherStuff = TRUE;
880     i = 0;
881     while(RegEnumKeyExW(key, i++, subKeyName, &tmpLength, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
882         tmpLength = sizeof(subKeyName)/sizeof(WCHAR);
883
884         /* if its not FLAGS or HELPDIR, then we must keep the rest of the key */
885         if (!strcmpW(subKeyName, FLAGSW)) continue;
886         if (!strcmpW(subKeyName, HELPDIRW)) continue;
887         deleteOtherStuff = FALSE;
888         break;
889     }
890
891     /* only delete the other parts of the key if we're absolutely sure */
892     if (deleteOtherStuff) {
893         RegDeleteKeyW(key, FLAGSW);
894         RegDeleteKeyW(key, HELPDIRW);
895         RegCloseKey(key);
896         key = NULL;
897
898         RegDeleteKeyW(HKEY_CLASSES_ROOT, keyName);
899         *strrchrW( keyName, '\\' ) = 0;  /* remove last path component */
900         RegDeleteKeyW(HKEY_CLASSES_ROOT, keyName);
901     }
902
903 end:
904     SysFreeString(tlibPath);
905     if (typeLib) ITypeLib_Release(typeLib);
906     if (subKey) RegCloseKey(subKey);
907     if (key) RegCloseKey(key);
908     return result;
909 }
910
911 /******************************************************************************
912  *              RegisterTypeLibForUser  [OLEAUT32.442]
913  * Adds information about a type library to the user registry
914  * NOTES
915  *    Docs: ITypeLib FAR * ptlib
916  *    Docs: OLECHAR FAR* szFullPath
917  *    Docs: OLECHAR FAR* szHelpDir
918  *
919  * RETURNS
920  *    Success: S_OK
921  *    Failure: Status
922  */
923 HRESULT WINAPI RegisterTypeLibForUser(
924      ITypeLib * ptlib,     /* [in] Pointer to the library*/
925      OLECHAR * szFullPath, /* [in] full Path of the library*/
926      OLECHAR * szHelpDir)  /* [in] dir to the helpfile for the library,
927                                                          may be NULL*/
928 {
929     FIXME("(%p, %s, %s) registering the typelib system-wide\n", ptlib,
930           debugstr_w(szFullPath), debugstr_w(szHelpDir));
931     return RegisterTypeLib(ptlib, szFullPath, szHelpDir);
932 }
933
934 /******************************************************************************
935  *      UnRegisterTypeLibForUser        [OLEAUT32.443]
936  * Removes information about a type library from the user registry
937  *
938  * RETURNS
939  *    Success: S_OK
940  *    Failure: Status
941  */
942 HRESULT WINAPI UnRegisterTypeLibForUser(
943     REFGUID libid,      /* [in] GUID of the library */
944     WORD wVerMajor,     /* [in] major version */
945     WORD wVerMinor,     /* [in] minor version */
946     LCID lcid,  /* [in] locale id */
947     SYSKIND syskind)
948 {
949     FIXME("(%s, %u, %u, %u, %u) unregistering the typelib system-wide\n",
950           debugstr_guid(libid), wVerMajor, wVerMinor, lcid, syskind);
951     return UnRegisterTypeLib(libid, wVerMajor, wVerMinor, lcid, syskind);
952 }
953
954 /*======================= ITypeLib implementation =======================*/
955
956 typedef struct tagTLBCustData
957 {
958     GUID guid;
959     VARIANT data;
960     struct tagTLBCustData* next;
961 } TLBCustData;
962
963 /* data structure for import typelibs */
964 typedef struct tagTLBImpLib
965 {
966     int offset;                 /* offset in the file (MSFT)
967                                    offset in nametable (SLTG)
968                                    just used to identify library while reading
969                                    data from file */
970     GUID guid;                  /* libid */
971     BSTR name;                  /* name */
972
973     LCID lcid;                  /* lcid of imported typelib */
974
975     WORD wVersionMajor;         /* major version number */
976     WORD wVersionMinor;         /* minor version number */
977
978     struct tagITypeLibImpl *pImpTypeLib; /* pointer to loaded typelib, or
979                                             NULL if not yet loaded */
980     struct tagTLBImpLib * next;
981 } TLBImpLib;
982
983 /* internal ITypeLib data */
984 typedef struct tagITypeLibImpl
985 {
986     const ITypeLib2Vtbl *lpVtbl;
987     const ITypeCompVtbl *lpVtblTypeComp;
988     LONG ref;
989     TLIBATTR LibAttr;            /* guid,lcid,syskind,version,flags */
990     LCID lcid;
991
992     /* strings can be stored in tlb as multibyte strings BUT they are *always*
993      * exported to the application as a UNICODE string.
994      */
995     BSTR Name;
996     BSTR DocString;
997     BSTR HelpFile;
998     BSTR HelpStringDll;
999     DWORD dwHelpContext;
1000     int TypeInfoCount;          /* nr of typeinfo's in librarry */
1001     struct tagITypeInfoImpl *pTypeInfo;   /* linked list of type info data */
1002     int ctCustData;             /* number of items in cust data list */
1003     TLBCustData * pCustData;    /* linked list to cust data */
1004     TLBImpLib   * pImpLibs;     /* linked list to all imported typelibs */
1005     int ctTypeDesc;             /* number of items in type desc array */
1006     TYPEDESC * pTypeDesc;       /* array of TypeDescriptions found in the
1007                                    library. Only used while reading MSFT
1008                                    typelibs */
1009     struct list ref_list;       /* list of ref types in this typelib */
1010     HREFTYPE dispatch_href;     /* reference to IDispatch, -1 if unused */
1011
1012
1013     /* typelibs are cached, keyed by path and index, so store the linked list info within them */
1014     struct tagITypeLibImpl *next, *prev;
1015     WCHAR *path;
1016     INT index;
1017 } ITypeLibImpl;
1018
1019 static const ITypeLib2Vtbl tlbvt;
1020 static const ITypeCompVtbl tlbtcvt;
1021
1022 static inline ITypeLibImpl *impl_from_ITypeComp( ITypeComp *iface )
1023 {
1024     return (ITypeLibImpl *)((char*)iface - FIELD_OFFSET(ITypeLibImpl, lpVtblTypeComp));
1025 }
1026
1027 /* ITypeLib methods */
1028 static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength);
1029 static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength);
1030
1031 /*======================= ITypeInfo implementation =======================*/
1032
1033 /* data for referenced types */
1034 typedef struct tagTLBRefType
1035 {
1036     INT index;              /* Type index for internal ref or for external ref
1037                                it the format is SLTG.  -2 indicates to
1038                                use guid */
1039
1040     GUID guid;              /* guid of the referenced type */
1041                             /* if index == TLB_REF_USE_GUID */
1042
1043     HREFTYPE reference;     /* The href of this ref */
1044     TLBImpLib *pImpTLInfo;  /* If ref is external ptr to library data
1045                                TLB_REF_INTERNAL for internal refs
1046                                TLB_REF_NOT_FOUND for broken refs */
1047
1048     struct list entry;
1049 } TLBRefType;
1050
1051 #define TLB_REF_USE_GUID -2
1052
1053 #define TLB_REF_INTERNAL (void*)-2
1054 #define TLB_REF_NOT_FOUND (void*)-1
1055
1056 /* internal Parameter data */
1057 typedef struct tagTLBParDesc
1058 {
1059     BSTR Name;
1060     int ctCustData;
1061     TLBCustData * pCustData;        /* linked list to cust data */
1062 } TLBParDesc;
1063
1064 /* internal Function data */
1065 typedef struct tagTLBFuncDesc
1066 {
1067     FUNCDESC funcdesc;      /* lots of info on the function and its attributes. */
1068     BSTR Name;             /* the name of this function */
1069     TLBParDesc *pParamDesc; /* array with param names and custom data */
1070     int helpcontext;
1071     int HelpStringContext;
1072     BSTR HelpString;
1073     BSTR Entry;            /* if IS_INTRESOURCE true, it's numeric; if -1 it isn't present */
1074     int ctCustData;
1075     TLBCustData * pCustData;        /* linked list to cust data; */
1076     struct tagTLBFuncDesc * next;
1077 } TLBFuncDesc;
1078
1079 /* internal Variable data */
1080 typedef struct tagTLBVarDesc
1081 {
1082     VARDESC vardesc;        /* lots of info on the variable and its attributes. */
1083     BSTR Name;             /* the name of this variable */
1084     int HelpContext;
1085     int HelpStringContext;  /* FIXME: where? */
1086     BSTR HelpString;
1087     int ctCustData;
1088     TLBCustData * pCustData;/* linked list to cust data; */
1089     struct tagTLBVarDesc * next;
1090 } TLBVarDesc;
1091
1092 /* internal implemented interface data */
1093 typedef struct tagTLBImplType
1094 {
1095     HREFTYPE hRef;          /* hRef of interface */
1096     int implflags;          /* IMPLFLAG_*s */
1097     int ctCustData;
1098     TLBCustData * pCustData;/* linked list to custom data; */
1099     struct tagTLBImplType *next;
1100 } TLBImplType;
1101
1102 /* internal TypeInfo data */
1103 typedef struct tagITypeInfoImpl
1104 {
1105     const ITypeInfo2Vtbl *lpVtbl;
1106     const ITypeCompVtbl  *lpVtblTypeComp;
1107     LONG ref;
1108     BOOL not_attached_to_typelib;
1109     TYPEATTR TypeAttr ;         /* _lots_ of type information. */
1110     ITypeLibImpl * pTypeLib;        /* back pointer to typelib */
1111     int index;                  /* index in this typelib; */
1112     HREFTYPE hreftype;          /* hreftype for app object binding */
1113     /* type libs seem to store the doc strings in ascii
1114      * so why should we do it in unicode?
1115      */
1116     BSTR Name;
1117     BSTR DocString;
1118     BSTR DllName;
1119     DWORD dwHelpContext;
1120     DWORD dwHelpStringContext;
1121
1122     /* functions  */
1123     TLBFuncDesc * funclist;     /* linked list with function descriptions */
1124
1125     /* variables  */
1126     TLBVarDesc * varlist;       /* linked list with variable descriptions */
1127
1128     /* Implemented Interfaces  */
1129     TLBImplType * impltypelist;
1130
1131     int ctCustData;
1132     TLBCustData * pCustData;        /* linked list to cust data; */
1133     struct tagITypeInfoImpl * next;
1134 } ITypeInfoImpl;
1135
1136 static inline ITypeInfoImpl *info_impl_from_ITypeComp( ITypeComp *iface )
1137 {
1138     return (ITypeInfoImpl *)((char*)iface - FIELD_OFFSET(ITypeInfoImpl, lpVtblTypeComp));
1139 }
1140
1141 static const ITypeInfo2Vtbl tinfvt;
1142 static const ITypeCompVtbl  tcompvt;
1143
1144 static ITypeInfo2 * ITypeInfo_Constructor(void);
1145 static void ITypeInfo_fnDestroy(ITypeInfoImpl *This);
1146
1147 typedef struct tagTLBContext
1148 {
1149         unsigned int oStart;  /* start of TLB in file */
1150         unsigned int pos;     /* current pos */
1151         unsigned int length;  /* total length */
1152         void *mapping;        /* memory mapping */
1153         MSFT_SegDir * pTblDir;
1154         ITypeLibImpl* pLibInfo;
1155 } TLBContext;
1156
1157
1158 static void MSFT_DoRefType(TLBContext *pcx, ITypeLibImpl *pTL, int offset);
1159
1160 /*
1161  debug
1162 */
1163 static void dump_TypeDesc(const TYPEDESC *pTD,char *szVarType) {
1164     if (pTD->vt & VT_RESERVED)
1165         szVarType += strlen(strcpy(szVarType, "reserved | "));
1166     if (pTD->vt & VT_BYREF)
1167         szVarType += strlen(strcpy(szVarType, "ref to "));
1168     if (pTD->vt & VT_ARRAY)
1169         szVarType += strlen(strcpy(szVarType, "array of "));
1170     if (pTD->vt & VT_VECTOR)
1171         szVarType += strlen(strcpy(szVarType, "vector of "));
1172     switch(pTD->vt & VT_TYPEMASK) {
1173     case VT_UI1: sprintf(szVarType, "VT_UI1"); break;
1174     case VT_I2: sprintf(szVarType, "VT_I2"); break;
1175     case VT_I4: sprintf(szVarType, "VT_I4"); break;
1176     case VT_R4: sprintf(szVarType, "VT_R4"); break;
1177     case VT_R8: sprintf(szVarType, "VT_R8"); break;
1178     case VT_BOOL: sprintf(szVarType, "VT_BOOL"); break;
1179     case VT_ERROR: sprintf(szVarType, "VT_ERROR"); break;
1180     case VT_CY: sprintf(szVarType, "VT_CY"); break;
1181     case VT_DATE: sprintf(szVarType, "VT_DATE"); break;
1182     case VT_BSTR: sprintf(szVarType, "VT_BSTR"); break;
1183     case VT_UNKNOWN: sprintf(szVarType, "VT_UNKNOWN"); break;
1184     case VT_DISPATCH: sprintf(szVarType, "VT_DISPATCH"); break;
1185     case VT_I1: sprintf(szVarType, "VT_I1"); break;
1186     case VT_UI2: sprintf(szVarType, "VT_UI2"); break;
1187     case VT_UI4: sprintf(szVarType, "VT_UI4"); break;
1188     case VT_INT: sprintf(szVarType, "VT_INT"); break;
1189     case VT_UINT: sprintf(szVarType, "VT_UINT"); break;
1190     case VT_VARIANT: sprintf(szVarType, "VT_VARIANT"); break;
1191     case VT_VOID: sprintf(szVarType, "VT_VOID"); break;
1192     case VT_HRESULT: sprintf(szVarType, "VT_HRESULT"); break;
1193     case VT_USERDEFINED: sprintf(szVarType, "VT_USERDEFINED ref = %x",
1194                                  pTD->u.hreftype); break;
1195     case VT_LPSTR: sprintf(szVarType, "VT_LPSTR"); break;
1196     case VT_LPWSTR: sprintf(szVarType, "VT_LPWSTR"); break;
1197     case VT_PTR: sprintf(szVarType, "ptr to ");
1198       dump_TypeDesc(pTD->u.lptdesc, szVarType + 7);
1199       break;
1200     case VT_SAFEARRAY: sprintf(szVarType, "safearray of ");
1201       dump_TypeDesc(pTD->u.lptdesc, szVarType + 13);
1202       break;
1203     case VT_CARRAY: sprintf(szVarType, "%d dim array of ",
1204                             pTD->u.lpadesc->cDims); /* FIXME print out sizes */
1205       dump_TypeDesc(&pTD->u.lpadesc->tdescElem, szVarType + strlen(szVarType));
1206       break;
1207
1208     default: sprintf(szVarType, "unknown(%d)", pTD->vt & VT_TYPEMASK); break;
1209     }
1210 }
1211
1212 static void dump_ELEMDESC(const ELEMDESC *edesc) {
1213   char buf[200];
1214   USHORT flags = edesc->u.paramdesc.wParamFlags;
1215   dump_TypeDesc(&edesc->tdesc,buf);
1216   MESSAGE("\t\ttdesc.vartype %d (%s)\n",edesc->tdesc.vt,buf);
1217   MESSAGE("\t\tu.paramdesc.wParamFlags");
1218   if (!flags) MESSAGE(" PARAMFLAGS_NONE");
1219   if (flags & PARAMFLAG_FIN) MESSAGE(" PARAMFLAG_FIN");
1220   if (flags & PARAMFLAG_FOUT) MESSAGE(" PARAMFLAG_FOUT");
1221   if (flags & PARAMFLAG_FLCID) MESSAGE(" PARAMFLAG_FLCID");
1222   if (flags & PARAMFLAG_FRETVAL) MESSAGE(" PARAMFLAG_FRETVAL");
1223   if (flags & PARAMFLAG_FOPT) MESSAGE(" PARAMFLAG_FOPT");
1224   if (flags & PARAMFLAG_FHASDEFAULT) MESSAGE(" PARAMFLAG_FHASDEFAULT");
1225   if (flags & PARAMFLAG_FHASCUSTDATA) MESSAGE(" PARAMFLAG_FHASCUSTDATA");
1226   MESSAGE("\n\t\tu.paramdesc.lpex %p\n",edesc->u.paramdesc.pparamdescex);
1227 }
1228 static void dump_FUNCDESC(const FUNCDESC *funcdesc) {
1229   int i;
1230   MESSAGE("memid is %08x\n",funcdesc->memid);
1231   for (i=0;i<funcdesc->cParams;i++) {
1232       MESSAGE("Param %d:\n",i);
1233       dump_ELEMDESC(funcdesc->lprgelemdescParam+i);
1234   }
1235   MESSAGE("\tfunckind: %d (",funcdesc->funckind);
1236   switch (funcdesc->funckind) {
1237   case FUNC_VIRTUAL: MESSAGE("virtual");break;
1238   case FUNC_PUREVIRTUAL: MESSAGE("pure virtual");break;
1239   case FUNC_NONVIRTUAL: MESSAGE("nonvirtual");break;
1240   case FUNC_STATIC: MESSAGE("static");break;
1241   case FUNC_DISPATCH: MESSAGE("dispatch");break;
1242   default: MESSAGE("unknown");break;
1243   }
1244   MESSAGE(")\n\tinvkind: %d (",funcdesc->invkind);
1245   switch (funcdesc->invkind) {
1246   case INVOKE_FUNC: MESSAGE("func");break;
1247   case INVOKE_PROPERTYGET: MESSAGE("property get");break;
1248   case INVOKE_PROPERTYPUT: MESSAGE("property put");break;
1249   case INVOKE_PROPERTYPUTREF: MESSAGE("property put ref");break;
1250   }
1251   MESSAGE(")\n\tcallconv: %d (",funcdesc->callconv);
1252   switch (funcdesc->callconv) {
1253   case CC_CDECL: MESSAGE("cdecl");break;
1254   case CC_PASCAL: MESSAGE("pascal");break;
1255   case CC_STDCALL: MESSAGE("stdcall");break;
1256   case CC_SYSCALL: MESSAGE("syscall");break;
1257   default:break;
1258   }
1259   MESSAGE(")\n\toVft: %d\n", funcdesc->oVft);
1260   MESSAGE("\tcParamsOpt: %d\n", funcdesc->cParamsOpt);
1261   MESSAGE("\twFlags: %x\n", funcdesc->wFuncFlags);
1262
1263   MESSAGE("\telemdescFunc (return value type):\n");
1264   dump_ELEMDESC(&funcdesc->elemdescFunc);
1265 }
1266
1267 static const char * const typekind_desc[] =
1268 {
1269         "TKIND_ENUM",
1270         "TKIND_RECORD",
1271         "TKIND_MODULE",
1272         "TKIND_INTERFACE",
1273         "TKIND_DISPATCH",
1274         "TKIND_COCLASS",
1275         "TKIND_ALIAS",
1276         "TKIND_UNION",
1277         "TKIND_MAX"
1278 };
1279
1280 static void dump_TLBFuncDescOne(const TLBFuncDesc * pfd)
1281 {
1282   int i;
1283   MESSAGE("%s(%u)\n", debugstr_w(pfd->Name), pfd->funcdesc.cParams);
1284   for (i=0;i<pfd->funcdesc.cParams;i++)
1285       MESSAGE("\tparm%d: %s\n",i,debugstr_w(pfd->pParamDesc[i].Name));
1286
1287
1288   dump_FUNCDESC(&(pfd->funcdesc));
1289
1290   MESSAGE("\thelpstring: %s\n", debugstr_w(pfd->HelpString));
1291   MESSAGE("\tentry: %s\n", (pfd->Entry == (void *)-1) ? "invalid" : debugstr_w(pfd->Entry));
1292 }
1293 static void dump_TLBFuncDesc(const TLBFuncDesc * pfd)
1294 {
1295         while (pfd)
1296         {
1297           dump_TLBFuncDescOne(pfd);
1298           pfd = pfd->next;
1299         };
1300 }
1301 static void dump_TLBVarDesc(const TLBVarDesc * pvd)
1302 {
1303         while (pvd)
1304         {
1305           TRACE_(typelib)("%s\n", debugstr_w(pvd->Name));
1306           pvd = pvd->next;
1307         };
1308 }
1309
1310 static void dump_TLBImpLib(const TLBImpLib *import)
1311 {
1312     TRACE_(typelib)("%s %s\n", debugstr_guid(&(import->guid)),
1313                     debugstr_w(import->name));
1314     TRACE_(typelib)("v%d.%d lcid=%x offset=%x\n", import->wVersionMajor,
1315                     import->wVersionMinor, import->lcid, import->offset);
1316 }
1317
1318 static void dump_TLBRefType(const ITypeLibImpl *pTL)
1319 {
1320     TLBRefType *ref;
1321
1322     LIST_FOR_EACH_ENTRY(ref, &pTL->ref_list, TLBRefType, entry)
1323     {
1324         TRACE_(typelib)("href:0x%08x\n", ref->reference);
1325         if(ref->index == -1)
1326             TRACE_(typelib)("%s\n", debugstr_guid(&(ref->guid)));
1327         else
1328             TRACE_(typelib)("type no: %d\n", ref->index);
1329
1330         if(ref->pImpTLInfo != TLB_REF_INTERNAL && ref->pImpTLInfo != TLB_REF_NOT_FOUND)
1331         {
1332             TRACE_(typelib)("in lib\n");
1333             dump_TLBImpLib(ref->pImpTLInfo);
1334         }
1335     }
1336 }
1337
1338 static void dump_TLBImplType(const TLBImplType * impl)
1339 {
1340     while (impl) {
1341         TRACE_(typelib)(
1342                 "implementing/inheriting interface hRef = %x implflags %x\n",
1343                 impl->hRef, impl->implflags);
1344         impl = impl->next;
1345     }
1346 }
1347
1348 static void dump_Variant(const VARIANT * pvar)
1349 {
1350     SYSTEMTIME st;
1351
1352     TRACE("%p->{%s%s", pvar, debugstr_VT(pvar), debugstr_VF(pvar));
1353
1354     if (pvar)
1355     {
1356       if (V_ISBYREF(pvar) || V_TYPE(pvar) == VT_UNKNOWN ||
1357           V_TYPE(pvar) == VT_DISPATCH || V_TYPE(pvar) == VT_RECORD)
1358       {
1359         TRACE(",%p", V_BYREF(pvar));
1360       }
1361       else if (V_ISARRAY(pvar) || V_ISVECTOR(pvar))
1362       {
1363         TRACE(",%p", V_ARRAY(pvar));
1364       }
1365       else switch (V_TYPE(pvar))
1366       {
1367       case VT_I1:   TRACE(",%d", V_I1(pvar)); break;
1368       case VT_UI1:  TRACE(",%d", V_UI1(pvar)); break;
1369       case VT_I2:   TRACE(",%d", V_I2(pvar)); break;
1370       case VT_UI2:  TRACE(",%d", V_UI2(pvar)); break;
1371       case VT_INT:
1372       case VT_I4:   TRACE(",%d", V_I4(pvar)); break;
1373       case VT_UINT:
1374       case VT_UI4:  TRACE(",%d", V_UI4(pvar)); break;
1375       case VT_I8:   TRACE(",0x%08x,0x%08x", (ULONG)(V_I8(pvar) >> 32),
1376                           (ULONG)(V_I8(pvar) & 0xffffffff)); break;
1377       case VT_UI8:  TRACE(",0x%08x,0x%08x", (ULONG)(V_UI8(pvar) >> 32),
1378                           (ULONG)(V_UI8(pvar) & 0xffffffff)); break;
1379       case VT_R4:   TRACE(",%3.3e", V_R4(pvar)); break;
1380       case VT_R8:   TRACE(",%3.3e", V_R8(pvar)); break;
1381       case VT_BOOL: TRACE(",%s", V_BOOL(pvar) ? "TRUE" : "FALSE"); break;
1382       case VT_BSTR: TRACE(",%s", debugstr_w(V_BSTR(pvar))); break;
1383       case VT_CY:   TRACE(",0x%08x,0x%08x", V_CY(pvar).s.Hi,
1384                            V_CY(pvar).s.Lo); break;
1385       case VT_DATE:
1386         if(!VariantTimeToSystemTime(V_DATE(pvar), &st))
1387           TRACE(",<invalid>");
1388         else
1389           TRACE(",%04d/%02d/%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay,
1390                 st.wHour, st.wMinute, st.wSecond);
1391         break;
1392       case VT_ERROR:
1393       case VT_VOID:
1394       case VT_USERDEFINED:
1395       case VT_EMPTY:
1396       case VT_NULL:  break;
1397       default:       TRACE(",?"); break;
1398       }
1399     }
1400     TRACE("}\n");
1401 }
1402
1403 static void dump_DispParms(const DISPPARAMS * pdp)
1404 {
1405     unsigned int index;
1406
1407     TRACE("args=%u named args=%u\n", pdp->cArgs, pdp->cNamedArgs);
1408
1409     if (pdp->cNamedArgs && pdp->rgdispidNamedArgs)
1410     {
1411         TRACE("named args:\n");
1412         for (index = 0; index < pdp->cNamedArgs; index++)
1413             TRACE( "\t0x%x\n", pdp->rgdispidNamedArgs[index] );
1414     }
1415
1416     if (pdp->cArgs && pdp->rgvarg)
1417     {
1418         TRACE("args:\n");
1419         for (index = 0; index < pdp->cArgs; index++)
1420             dump_Variant( &pdp->rgvarg[index] );
1421     }
1422 }
1423
1424 static void dump_TypeInfo(const ITypeInfoImpl * pty)
1425 {
1426     TRACE("%p ref=%u\n", pty, pty->ref);
1427     TRACE("%s %s\n", debugstr_w(pty->Name), debugstr_w(pty->DocString));
1428     TRACE("attr:%s\n", debugstr_guid(&(pty->TypeAttr.guid)));
1429     TRACE("kind:%s\n", typekind_desc[pty->TypeAttr.typekind]);
1430     TRACE("fct:%u var:%u impl:%u\n",
1431       pty->TypeAttr.cFuncs, pty->TypeAttr.cVars, pty->TypeAttr.cImplTypes);
1432     TRACE("wTypeFlags: 0x%04x\n", pty->TypeAttr.wTypeFlags);
1433     TRACE("parent tlb:%p index in TLB:%u\n",pty->pTypeLib, pty->index);
1434     if (pty->TypeAttr.typekind == TKIND_MODULE) TRACE("dllname:%s\n", debugstr_w(pty->DllName));
1435     if (TRACE_ON(ole))
1436         dump_TLBFuncDesc(pty->funclist);
1437     dump_TLBVarDesc(pty->varlist);
1438     dump_TLBImplType(pty->impltypelist);
1439 }
1440
1441 static void dump_VARDESC(const VARDESC *v)
1442 {
1443     MESSAGE("memid %d\n",v->memid);
1444     MESSAGE("lpstrSchema %s\n",debugstr_w(v->lpstrSchema));
1445     MESSAGE("oInst %d\n",v->u.oInst);
1446     dump_ELEMDESC(&(v->elemdescVar));
1447     MESSAGE("wVarFlags %x\n",v->wVarFlags);
1448     MESSAGE("varkind %d\n",v->varkind);
1449 }
1450
1451 static TYPEDESC stndTypeDesc[VT_LPWSTR+1]=
1452 {
1453     /* VT_LPWSTR is largest type that */
1454     /* may appear in type description*/
1455     {{0}, 0},{{0}, 1},{{0}, 2},{{0}, 3},{{0}, 4},
1456     {{0}, 5},{{0}, 6},{{0}, 7},{{0}, 8},{{0}, 9},
1457     {{0},10},{{0},11},{{0},12},{{0},13},{{0},14},
1458     {{0},15},{{0},16},{{0},17},{{0},18},{{0},19},
1459     {{0},20},{{0},21},{{0},22},{{0},23},{{0},24},
1460     {{0},25},{{0},26},{{0},27},{{0},28},{{0},29},
1461     {{0},30},{{0},31}
1462 };
1463
1464 static void TLB_abort(void)
1465 {
1466     DebugBreak();
1467 }
1468
1469 static void * TLB_Alloc(unsigned size) __WINE_ALLOC_SIZE(1);
1470 static void * TLB_Alloc(unsigned size)
1471 {
1472     void * ret;
1473     if((ret=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size))==NULL){
1474         /* FIXME */
1475         ERR("cannot allocate memory\n");
1476     }
1477     return ret;
1478 }
1479
1480 static void TLB_Free(void * ptr)
1481 {
1482     HeapFree(GetProcessHeap(), 0, ptr);
1483 }
1484
1485 /* returns the size required for a deep copy of a typedesc into a
1486  * flat buffer */
1487 static SIZE_T TLB_SizeTypeDesc( const TYPEDESC *tdesc, BOOL alloc_initial_space )
1488 {
1489     SIZE_T size = 0;
1490
1491     if (alloc_initial_space)
1492         size += sizeof(TYPEDESC);
1493
1494     switch (tdesc->vt)
1495     {
1496     case VT_PTR:
1497     case VT_SAFEARRAY:
1498         size += TLB_SizeTypeDesc(tdesc->u.lptdesc, TRUE);
1499         break;
1500     case VT_CARRAY:
1501         size += FIELD_OFFSET(ARRAYDESC, rgbounds[tdesc->u.lpadesc->cDims]);
1502         size += TLB_SizeTypeDesc(&tdesc->u.lpadesc->tdescElem, FALSE);
1503         break;
1504     }
1505     return size;
1506 }
1507
1508 /* deep copy a typedesc into a flat buffer */
1509 static void *TLB_CopyTypeDesc( TYPEDESC *dest, const TYPEDESC *src, void *buffer )
1510 {
1511     if (!dest)
1512     {
1513         dest = buffer;
1514         buffer = (char *)buffer + sizeof(TYPEDESC);
1515     }
1516
1517     *dest = *src;
1518
1519     switch (src->vt)
1520     {
1521     case VT_PTR:
1522     case VT_SAFEARRAY:
1523         dest->u.lptdesc = buffer;
1524         buffer = TLB_CopyTypeDesc(NULL, src->u.lptdesc, buffer);
1525         break;
1526     case VT_CARRAY:
1527         dest->u.lpadesc = buffer;
1528         memcpy(dest->u.lpadesc, src->u.lpadesc, FIELD_OFFSET(ARRAYDESC, rgbounds[src->u.lpadesc->cDims]));
1529         buffer = (char *)buffer + FIELD_OFFSET(ARRAYDESC, rgbounds[src->u.lpadesc->cDims]);
1530         buffer = TLB_CopyTypeDesc(&dest->u.lpadesc->tdescElem, &src->u.lpadesc->tdescElem, buffer);
1531         break;
1532     }
1533     return buffer;
1534 }
1535
1536 /* free custom data allocated by MSFT_CustData */
1537 static inline void TLB_FreeCustData(TLBCustData *pCustData)
1538 {
1539     TLBCustData *pCustDataNext;
1540     for (; pCustData; pCustData = pCustDataNext)
1541     {
1542         VariantClear(&pCustData->data);
1543
1544         pCustDataNext = pCustData->next;
1545         TLB_Free(pCustData);
1546     }
1547 }
1548
1549 static BSTR TLB_MultiByteToBSTR(const char *ptr)
1550 {
1551     DWORD len;
1552     BSTR ret;
1553
1554     len = MultiByteToWideChar(CP_ACP, 0, ptr, -1, NULL, 0);
1555     ret = SysAllocStringLen(NULL, len - 1);
1556     if (!ret) return ret;
1557     MultiByteToWideChar(CP_ACP, 0, ptr, -1, ret, len);
1558     return ret;
1559 }
1560
1561 /**********************************************************************
1562  *
1563  *  Functions for reading MSFT typelibs (those created by CreateTypeLib2)
1564  */
1565 static inline unsigned int MSFT_Tell(const TLBContext *pcx)
1566 {
1567     return pcx->pos;
1568 }
1569
1570 static inline void MSFT_Seek(TLBContext *pcx, LONG where)
1571 {
1572     if (where != DO_NOT_SEEK)
1573     {
1574         where += pcx->oStart;
1575         if (where > pcx->length)
1576         {
1577             /* FIXME */
1578             ERR("seek beyond end (%d/%d)\n", where, pcx->length );
1579             TLB_abort();
1580         }
1581         pcx->pos = where;
1582     }
1583 }
1584
1585 /* read function */
1586 static DWORD MSFT_Read(void *buffer,  DWORD count, TLBContext *pcx, LONG where )
1587 {
1588     TRACE_(typelib)("pos=0x%08x len=0x%08x 0x%08x 0x%08x 0x%08x\n",
1589        pcx->pos, count, pcx->oStart, pcx->length, where);
1590
1591     MSFT_Seek(pcx, where);
1592     if (pcx->pos + count > pcx->length) count = pcx->length - pcx->pos;
1593     memcpy( buffer, (char *)pcx->mapping + pcx->pos, count );
1594     pcx->pos += count;
1595     return count;
1596 }
1597
1598 static DWORD MSFT_ReadLEDWords(void *buffer,  DWORD count, TLBContext *pcx,
1599                                LONG where )
1600 {
1601   DWORD ret;
1602
1603   ret = MSFT_Read(buffer, count, pcx, where);
1604   FromLEDWords(buffer, ret);
1605
1606   return ret;
1607 }
1608
1609 static DWORD MSFT_ReadLEWords(void *buffer,  DWORD count, TLBContext *pcx,
1610                               LONG where )
1611 {
1612   DWORD ret;
1613
1614   ret = MSFT_Read(buffer, count, pcx, where);
1615   FromLEWords(buffer, ret);
1616
1617   return ret;
1618 }
1619
1620 static void MSFT_ReadGuid( GUID *pGuid, int offset, TLBContext *pcx)
1621 {
1622     if(offset<0 || pcx->pTblDir->pGuidTab.offset <0){
1623         memset(pGuid,0, sizeof(GUID));
1624         return;
1625     }
1626     MSFT_Read(pGuid, sizeof(GUID), pcx, pcx->pTblDir->pGuidTab.offset+offset );
1627     pGuid->Data1 = FromLEDWord(pGuid->Data1);
1628     pGuid->Data2 = FromLEWord(pGuid->Data2);
1629     pGuid->Data3 = FromLEWord(pGuid->Data3);
1630     TRACE_(typelib)("%s\n", debugstr_guid(pGuid));
1631 }
1632
1633 static HREFTYPE MSFT_ReadHreftype( TLBContext *pcx, int offset )
1634 {
1635     MSFT_NameIntro niName;
1636
1637     if (offset < 0)
1638     {
1639         ERR_(typelib)("bad offset %d\n", offset);
1640         return -1;
1641     }
1642
1643     MSFT_ReadLEDWords(&niName, sizeof(niName), pcx,
1644                       pcx->pTblDir->pNametab.offset+offset);
1645
1646     return niName.hreftype;
1647 }
1648
1649 static BSTR MSFT_ReadName( TLBContext *pcx, int offset)
1650 {
1651     char * name;
1652     MSFT_NameIntro niName;
1653     int lengthInChars;
1654     BSTR bstrName = NULL;
1655
1656     if (offset < 0)
1657     {
1658         ERR_(typelib)("bad offset %d\n", offset);
1659         return NULL;
1660     }
1661     MSFT_ReadLEDWords(&niName, sizeof(niName), pcx,
1662                       pcx->pTblDir->pNametab.offset+offset);
1663     niName.namelen &= 0xFF; /* FIXME: correct ? */
1664     name=TLB_Alloc((niName.namelen & 0xff) +1);
1665     MSFT_Read(name, (niName.namelen & 0xff), pcx, DO_NOT_SEEK);
1666     name[niName.namelen & 0xff]='\0';
1667
1668     lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
1669                                         name, -1, NULL, 0);
1670
1671     /* no invalid characters in string */
1672     if (lengthInChars)
1673     {
1674         bstrName = SysAllocStringByteLen(NULL, lengthInChars * sizeof(WCHAR));
1675
1676         /* don't check for invalid character since this has been done previously */
1677         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name, -1, bstrName, lengthInChars);
1678     }
1679     TLB_Free(name);
1680
1681     TRACE_(typelib)("%s %d\n", debugstr_w(bstrName), lengthInChars);
1682     return bstrName;
1683 }
1684
1685 static BSTR MSFT_ReadString( TLBContext *pcx, int offset)
1686 {
1687     char * string;
1688     INT16 length;
1689     int lengthInChars;
1690     BSTR bstr = NULL;
1691
1692     if(offset<0) return NULL;
1693     MSFT_ReadLEWords(&length, sizeof(INT16), pcx, pcx->pTblDir->pStringtab.offset+offset);
1694     if(length <= 0) return 0;
1695     string=TLB_Alloc(length +1);
1696     MSFT_Read(string, length, pcx, DO_NOT_SEEK);
1697     string[length]='\0';
1698
1699     lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
1700                                         string, -1, NULL, 0);
1701
1702     /* no invalid characters in string */
1703     if (lengthInChars)
1704     {
1705         bstr = SysAllocStringByteLen(NULL, lengthInChars * sizeof(WCHAR));
1706
1707         /* don't check for invalid character since this has been done previously */
1708         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, string, -1, bstr, lengthInChars);
1709     }
1710     TLB_Free(string);
1711
1712     TRACE_(typelib)("%s %d\n", debugstr_w(bstr), lengthInChars);
1713     return bstr;
1714 }
1715 /*
1716  * read a value and fill a VARIANT structure
1717  */
1718 static void MSFT_ReadValue( VARIANT * pVar, int offset, TLBContext *pcx )
1719 {
1720     int size;
1721
1722     TRACE_(typelib)("\n");
1723
1724     if(offset <0) { /* data are packed in here */
1725         V_VT(pVar) = (offset & 0x7c000000 )>> 26;
1726         V_I4(pVar) = offset & 0x3ffffff;
1727         return;
1728     }
1729     MSFT_ReadLEWords(&(V_VT(pVar)), sizeof(VARTYPE), pcx,
1730                      pcx->pTblDir->pCustData.offset + offset );
1731     TRACE_(typelib)("Vartype = %x\n", V_VT(pVar));
1732     switch (V_VT(pVar)){
1733         case VT_EMPTY:  /* FIXME: is this right? */
1734         case VT_NULL:   /* FIXME: is this right? */
1735         case VT_I2  :   /* this should not happen */
1736         case VT_I4  :
1737         case VT_R4  :
1738         case VT_ERROR   :
1739         case VT_BOOL    :
1740         case VT_I1  :
1741         case VT_UI1 :
1742         case VT_UI2 :
1743         case VT_UI4 :
1744         case VT_INT :
1745         case VT_UINT    :
1746         case VT_VOID    : /* FIXME: is this right? */
1747         case VT_HRESULT :
1748             size=4; break;
1749         case VT_R8  :
1750         case VT_CY  :
1751         case VT_DATE    :
1752         case VT_I8  :
1753         case VT_UI8 :
1754         case VT_DECIMAL :  /* FIXME: is this right? */
1755         case VT_FILETIME :
1756             size=8;break;
1757             /* pointer types with known behaviour */
1758         case VT_BSTR    :{
1759             char * ptr;
1760             MSFT_ReadLEDWords(&size, sizeof(INT), pcx, DO_NOT_SEEK );
1761             if(size < 0) {
1762                 char next;
1763                 DWORD origPos = MSFT_Tell(pcx), nullPos;
1764
1765                 do {
1766                     MSFT_Read(&next, 1, pcx, DO_NOT_SEEK);
1767                 } while (next);
1768                 nullPos = MSFT_Tell(pcx);
1769                 size = nullPos - origPos;
1770                 MSFT_Seek(pcx, origPos);
1771             }
1772             ptr=TLB_Alloc(size);/* allocate temp buffer */
1773             MSFT_Read(ptr, size, pcx, DO_NOT_SEEK);/* read string (ANSI) */
1774             V_BSTR(pVar)=SysAllocStringLen(NULL,size);
1775             /* FIXME: do we need a AtoW conversion here? */
1776             V_UNION(pVar, bstrVal[size])='\0';
1777             while(size--) V_UNION(pVar, bstrVal[size])=ptr[size];
1778             TLB_Free(ptr);
1779         }
1780         size=-4; break;
1781     /* FIXME: this will not work AT ALL when the variant contains a pointer */
1782         case VT_DISPATCH :
1783         case VT_VARIANT :
1784         case VT_UNKNOWN :
1785         case VT_PTR :
1786         case VT_SAFEARRAY :
1787         case VT_CARRAY  :
1788         case VT_USERDEFINED :
1789         case VT_LPSTR   :
1790         case VT_LPWSTR  :
1791         case VT_BLOB    :
1792         case VT_STREAM  :
1793         case VT_STORAGE :
1794         case VT_STREAMED_OBJECT :
1795         case VT_STORED_OBJECT   :
1796         case VT_BLOB_OBJECT :
1797         case VT_CF  :
1798         case VT_CLSID   :
1799         default:
1800             size=0;
1801             FIXME("VARTYPE %d is not supported, setting pointer to NULL\n",
1802                 V_VT(pVar));
1803     }
1804
1805     if(size>0) /* (big|small) endian correct? */
1806         MSFT_Read(&(V_I2(pVar)), size, pcx, DO_NOT_SEEK );
1807     return;
1808 }
1809 /*
1810  * create a linked list with custom data
1811  */
1812 static int MSFT_CustData( TLBContext *pcx, int offset, TLBCustData** ppCustData )
1813 {
1814     MSFT_CDGuid entry;
1815     TLBCustData* pNew;
1816     int count=0;
1817
1818     TRACE_(typelib)("\n");
1819
1820     while(offset >=0){
1821         count++;
1822         pNew=TLB_Alloc(sizeof(TLBCustData));
1823         MSFT_ReadLEDWords(&entry, sizeof(entry), pcx, pcx->pTblDir->pCDGuids.offset+offset);
1824         MSFT_ReadGuid(&(pNew->guid), entry.GuidOffset , pcx);
1825         MSFT_ReadValue(&(pNew->data), entry.DataOffset, pcx);
1826         /* add new custom data at head of the list */
1827         pNew->next=*ppCustData;
1828         *ppCustData=pNew;
1829         offset = entry.next;
1830     }
1831     return count;
1832 }
1833
1834 static void MSFT_GetTdesc(TLBContext *pcx, INT type, TYPEDESC *pTd,
1835                           ITypeInfoImpl *pTI)
1836 {
1837     if(type <0)
1838         pTd->vt=type & VT_TYPEMASK;
1839     else
1840         *pTd=pcx->pLibInfo->pTypeDesc[type/(2*sizeof(INT))];
1841
1842     if(pTd->vt == VT_USERDEFINED)
1843       MSFT_DoRefType(pcx, pTI->pTypeLib, pTd->u.hreftype);
1844
1845     TRACE_(typelib)("vt type = %X\n", pTd->vt);
1846 }
1847
1848 static void MSFT_ResolveReferencedTypes(TLBContext *pcx, ITypeInfoImpl *pTI, TYPEDESC *lpTypeDesc)
1849 {
1850     /* resolve referenced type if any */
1851     while (lpTypeDesc)
1852     {
1853         switch (lpTypeDesc->vt)
1854         {
1855         case VT_PTR:
1856             lpTypeDesc = lpTypeDesc->u.lptdesc;
1857             break;
1858
1859         case VT_CARRAY:
1860             lpTypeDesc = & (lpTypeDesc->u.lpadesc->tdescElem);
1861             break;
1862
1863         case VT_USERDEFINED:
1864             MSFT_DoRefType(pcx, pTI->pTypeLib,
1865                            lpTypeDesc->u.hreftype);
1866
1867             lpTypeDesc = NULL;
1868             break;
1869
1870         default:
1871             lpTypeDesc = NULL;
1872         }
1873     }
1874 }
1875
1876 static void
1877 MSFT_DoFuncs(TLBContext*     pcx,
1878             ITypeInfoImpl*  pTI,
1879             int             cFuncs,
1880             int             cVars,
1881             int             offset,
1882             TLBFuncDesc**   pptfd)
1883 {
1884     /*
1885      * member information is stored in a data structure at offset
1886      * indicated by the memoffset field of the typeinfo structure
1887      * There are several distinctive parts.
1888      * The first part starts with a field that holds the total length
1889      * of this (first) part excluding this field. Then follow the records,
1890      * for each member there is one record.
1891      *
1892      * The first entry is always the length of the record (including this
1893      * length word).
1894      * The rest of the record depends on the type of the member. If there is
1895      * a field indicating the member type (function, variable, interface, etc)
1896      * I have not found it yet. At this time we depend on the information
1897      * in the type info and the usual order how things are stored.
1898      *
1899      * Second follows an array sized nrMEM*sizeof(INT) with a member id
1900      * for each member;
1901      *
1902      * Third is an equal sized array with file offsets to the name entry
1903      * of each member.
1904      *
1905      * The fourth and last (?) part is an array with offsets to the records
1906      * in the first part of this file segment.
1907      */
1908
1909     int infolen, nameoffset, reclength, i;
1910     int recoffset = offset + sizeof(INT);
1911
1912     char *recbuf = HeapAlloc(GetProcessHeap(), 0, 0xffff);
1913     MSFT_FuncRecord *pFuncRec = (MSFT_FuncRecord*)recbuf;
1914     TLBFuncDesc *ptfd_prev = NULL;
1915
1916     TRACE_(typelib)("\n");
1917
1918     MSFT_ReadLEDWords(&infolen, sizeof(INT), pcx, offset);
1919
1920     for ( i = 0; i < cFuncs ; i++ )
1921     {
1922         int optional;
1923
1924         *pptfd = TLB_Alloc(sizeof(TLBFuncDesc));
1925
1926         /* name, eventually add to a hash table */
1927         MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx,
1928                           offset + infolen + (cFuncs + cVars + i + 1) * sizeof(INT));
1929
1930         /* nameoffset is sometimes -1 on the second half of a propget/propput
1931          * pair of functions */
1932         if ((nameoffset == -1) && (i > 0))
1933             (*pptfd)->Name = SysAllocString(ptfd_prev->Name);
1934         else
1935             (*pptfd)->Name = MSFT_ReadName(pcx, nameoffset);
1936
1937         /* read the function information record */
1938         MSFT_ReadLEDWords(&reclength, sizeof(pFuncRec->Info), pcx, recoffset);
1939
1940         reclength &= 0xffff;
1941
1942         MSFT_ReadLEDWords(&pFuncRec->DataType, reclength - FIELD_OFFSET(MSFT_FuncRecord, DataType), pcx, DO_NOT_SEEK);
1943
1944         /* size without argument data */
1945         optional = reclength - pFuncRec->nrargs*sizeof(MSFT_ParameterInfo);
1946
1947         if (optional > FIELD_OFFSET(MSFT_FuncRecord, HelpContext))
1948             (*pptfd)->helpcontext = pFuncRec->HelpContext;
1949
1950         if (optional > FIELD_OFFSET(MSFT_FuncRecord, oHelpString))
1951             (*pptfd)->HelpString = MSFT_ReadString(pcx, pFuncRec->oHelpString);
1952
1953         if (optional > FIELD_OFFSET(MSFT_FuncRecord, oEntry))
1954         {
1955             if (pFuncRec->FKCCIC & 0x2000 )
1956             {
1957                 if (!IS_INTRESOURCE(pFuncRec->oEntry))
1958                     ERR("ordinal 0x%08x invalid, IS_INTRESOURCE is false\n", pFuncRec->oEntry);
1959                 (*pptfd)->Entry = (BSTR)(DWORD_PTR)LOWORD(pFuncRec->oEntry);
1960             }
1961             else
1962                 (*pptfd)->Entry = MSFT_ReadString(pcx, pFuncRec->oEntry);
1963         }
1964         else
1965             (*pptfd)->Entry = (BSTR)-1;
1966
1967         if (optional > FIELD_OFFSET(MSFT_FuncRecord, HelpStringContext))
1968             (*pptfd)->HelpStringContext = pFuncRec->HelpStringContext;
1969
1970         if (optional > FIELD_OFFSET(MSFT_FuncRecord, oCustData) && pFuncRec->FKCCIC & 0x80)
1971             MSFT_CustData(pcx, pFuncRec->oCustData, &(*pptfd)->pCustData);
1972
1973         /* fill the FuncDesc Structure */
1974         MSFT_ReadLEDWords( & (*pptfd)->funcdesc.memid, sizeof(INT), pcx,
1975                            offset + infolen + ( i + 1) * sizeof(INT));
1976
1977         (*pptfd)->funcdesc.funckind   =  (pFuncRec->FKCCIC)      & 0x7;
1978         (*pptfd)->funcdesc.invkind    =  (pFuncRec->FKCCIC) >> 3 & 0xF;
1979         (*pptfd)->funcdesc.callconv   =  (pFuncRec->FKCCIC) >> 8 & 0xF;
1980         (*pptfd)->funcdesc.cParams    =   pFuncRec->nrargs  ;
1981         (*pptfd)->funcdesc.cParamsOpt =   pFuncRec->nroargs ;
1982         (*pptfd)->funcdesc.oVft       =   pFuncRec->VtableOffset;
1983         (*pptfd)->funcdesc.wFuncFlags =   LOWORD(pFuncRec->Flags) ;
1984
1985         MSFT_GetTdesc(pcx,
1986                       pFuncRec->DataType,
1987                       &(*pptfd)->funcdesc.elemdescFunc.tdesc,
1988                       pTI);
1989         MSFT_ResolveReferencedTypes(pcx, pTI, &(*pptfd)->funcdesc.elemdescFunc.tdesc);
1990
1991         /* do the parameters/arguments */
1992         if(pFuncRec->nrargs)
1993         {
1994             int j = 0;
1995             MSFT_ParameterInfo paraminfo;
1996
1997             (*pptfd)->funcdesc.lprgelemdescParam =
1998                 TLB_Alloc(pFuncRec->nrargs * sizeof(ELEMDESC));
1999
2000             (*pptfd)->pParamDesc =
2001                 TLB_Alloc(pFuncRec->nrargs * sizeof(TLBParDesc));
2002
2003             MSFT_ReadLEDWords(&paraminfo, sizeof(paraminfo), pcx,
2004                               recoffset + reclength - pFuncRec->nrargs * sizeof(MSFT_ParameterInfo));
2005
2006             for ( j = 0 ; j < pFuncRec->nrargs ; j++ )
2007             {
2008                 ELEMDESC *elemdesc = &(*pptfd)->funcdesc.lprgelemdescParam[j];
2009
2010                 MSFT_GetTdesc(pcx,
2011                               paraminfo.DataType,
2012                               &elemdesc->tdesc,
2013                               pTI);
2014
2015                 elemdesc->u.paramdesc.wParamFlags = paraminfo.Flags;
2016
2017                 /* name */
2018                 if (paraminfo.oName == -1)
2019                     /* this occurs for [propput] or [propget] methods, so
2020                      * we should just set the name of the parameter to the
2021                      * name of the method. */
2022                     (*pptfd)->pParamDesc[j].Name = SysAllocString((*pptfd)->Name);
2023                 else
2024                     (*pptfd)->pParamDesc[j].Name =
2025                         MSFT_ReadName( pcx, paraminfo.oName );
2026                 TRACE_(typelib)("param[%d] = %s\n", j, debugstr_w((*pptfd)->pParamDesc[j].Name));
2027
2028                 MSFT_ResolveReferencedTypes(pcx, pTI, &elemdesc->tdesc);
2029
2030                 /* default value */
2031                 if ( (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) &&
2032                      (pFuncRec->FKCCIC & 0x1000) )
2033                 {
2034                     INT* pInt = (INT *)((char *)pFuncRec +
2035                                    reclength -
2036                                    (pFuncRec->nrargs * 4) * sizeof(INT) );
2037
2038                     PARAMDESC* pParamDesc = &elemdesc->u.paramdesc;
2039
2040                     pParamDesc->pparamdescex = TLB_Alloc(sizeof(PARAMDESCEX));
2041                     pParamDesc->pparamdescex->cBytes = sizeof(PARAMDESCEX);
2042
2043                     MSFT_ReadValue(&(pParamDesc->pparamdescex->varDefaultValue),
2044                         pInt[j], pcx);
2045                 }
2046                 else
2047                     elemdesc->u.paramdesc.pparamdescex = NULL;
2048
2049                 /* custom info */
2050                 if (optional > (FIELD_OFFSET(MSFT_FuncRecord, oArgCustData) +
2051                                 j*sizeof(pFuncRec->oArgCustData[0])) &&
2052                     pFuncRec->FKCCIC & 0x80 )
2053                 {
2054                     MSFT_CustData(pcx,
2055                                   pFuncRec->oArgCustData[j],
2056                                   &(*pptfd)->pParamDesc[j].pCustData);
2057                 }
2058
2059                 /* SEEK value = jump to offset,
2060                  * from there jump to the end of record,
2061                  * go back by (j-1) arguments
2062                  */
2063                 MSFT_ReadLEDWords( &paraminfo ,
2064                            sizeof(MSFT_ParameterInfo), pcx,
2065                            recoffset + reclength - ((pFuncRec->nrargs - j - 1)
2066                                                * sizeof(MSFT_ParameterInfo)));
2067             }
2068         }
2069
2070         /* scode is not used: archaic win16 stuff FIXME: right? */
2071         (*pptfd)->funcdesc.cScodes   = 0 ;
2072         (*pptfd)->funcdesc.lprgscode = NULL ;
2073
2074         ptfd_prev = *pptfd;
2075         pptfd      = & ((*pptfd)->next);
2076         recoffset += reclength;
2077     }
2078     HeapFree(GetProcessHeap(), 0, recbuf);
2079 }
2080
2081 static void MSFT_DoVars(TLBContext *pcx, ITypeInfoImpl *pTI, int cFuncs,
2082                        int cVars, int offset, TLBVarDesc ** pptvd)
2083 {
2084     int infolen, nameoffset, reclength;
2085     char recbuf[256];
2086     MSFT_VarRecord *pVarRec = (MSFT_VarRecord*)recbuf;
2087     int i;
2088     int recoffset;
2089
2090     TRACE_(typelib)("\n");
2091
2092     MSFT_ReadLEDWords(&infolen,sizeof(INT), pcx, offset);
2093     MSFT_ReadLEDWords(&recoffset,sizeof(INT), pcx, offset + infolen +
2094                       ((cFuncs+cVars)*2+cFuncs + 1)*sizeof(INT));
2095     recoffset += offset+sizeof(INT);
2096     for(i=0;i<cVars;i++){
2097         *pptvd=TLB_Alloc(sizeof(TLBVarDesc));
2098     /* name, eventually add to a hash table */
2099         MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx,
2100                           offset + infolen + (2*cFuncs + cVars + i + 1) * sizeof(INT));
2101         (*pptvd)->Name=MSFT_ReadName(pcx, nameoffset);
2102     /* read the variable information record */
2103         MSFT_ReadLEDWords(&reclength, sizeof(pVarRec->Info), pcx, recoffset);
2104         reclength &= 0xff;
2105         MSFT_ReadLEDWords(&pVarRec->DataType, reclength - FIELD_OFFSET(MSFT_VarRecord, DataType), pcx, DO_NOT_SEEK);
2106
2107         /* optional data */
2108         if(reclength > FIELD_OFFSET(MSFT_VarRecord, HelpContext))
2109             (*pptvd)->HelpContext = pVarRec->HelpContext;
2110
2111         if(reclength > FIELD_OFFSET(MSFT_VarRecord, HelpString))
2112             (*pptvd)->HelpString = MSFT_ReadString(pcx, pVarRec->HelpString);
2113
2114         if(reclength > FIELD_OFFSET(MSFT_VarRecord, HelpStringContext))
2115             (*pptvd)->HelpStringContext = pVarRec->HelpStringContext;
2116
2117     /* fill the VarDesc Structure */
2118         MSFT_ReadLEDWords(&(*pptvd)->vardesc.memid, sizeof(INT), pcx,
2119                           offset + infolen + (cFuncs + i + 1) * sizeof(INT));
2120         (*pptvd)->vardesc.varkind = pVarRec->VarKind;
2121         (*pptvd)->vardesc.wVarFlags = pVarRec->Flags;
2122         MSFT_GetTdesc(pcx, pVarRec->DataType,
2123             &(*pptvd)->vardesc.elemdescVar.tdesc, pTI);
2124 /*   (*pptvd)->vardesc.lpstrSchema; is reserved (SDK) FIXME?? */
2125         if(pVarRec->VarKind == VAR_CONST ){
2126             (*pptvd)->vardesc.u.lpvarValue=TLB_Alloc(sizeof(VARIANT));
2127             MSFT_ReadValue((*pptvd)->vardesc.u.lpvarValue,
2128                 pVarRec->OffsValue, pcx);
2129         } else
2130             (*pptvd)->vardesc.u.oInst=pVarRec->OffsValue;
2131         MSFT_ResolveReferencedTypes(pcx, pTI, &(*pptvd)->vardesc.elemdescVar.tdesc);
2132         pptvd=&((*pptvd)->next);
2133         recoffset += reclength;
2134     }
2135 }
2136 /* fill in data for a hreftype (offset). When the referenced type is contained
2137  * in the typelib, it's just an (file) offset in the type info base dir.
2138  * If comes from import, it's an offset+1 in the ImpInfo table
2139  * */
2140 static void MSFT_DoRefType(TLBContext *pcx, ITypeLibImpl *pTL,
2141                           int offset)
2142 {
2143     TLBRefType *ref;
2144
2145     TRACE_(typelib)("TLB context %p, TLB offset %x\n", pcx, offset);
2146
2147     LIST_FOR_EACH_ENTRY(ref, &pTL->ref_list, TLBRefType, entry)
2148     {
2149         if(ref->reference == offset) return;
2150     }
2151
2152     ref = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ref));
2153     list_add_tail(&pTL->ref_list, &ref->entry);
2154
2155     if(!MSFT_HREFTYPE_INTHISFILE( offset)) {
2156         /* external typelib */
2157         MSFT_ImpInfo impinfo;
2158         TLBImpLib *pImpLib=(pcx->pLibInfo->pImpLibs);
2159
2160         TRACE_(typelib)("offset %x, masked offset %x\n", offset, offset + (offset & 0xfffffffc));
2161
2162         MSFT_ReadLEDWords(&impinfo, sizeof(impinfo), pcx,
2163                           pcx->pTblDir->pImpInfo.offset + (offset & 0xfffffffc));
2164         while (pImpLib){   /* search the known offsets of all import libraries */
2165             if(pImpLib->offset==impinfo.oImpFile) break;
2166             pImpLib=pImpLib->next;
2167         }
2168         if(pImpLib){
2169             ref->reference = offset;
2170             ref->pImpTLInfo = pImpLib;
2171             if(impinfo.flags & MSFT_IMPINFO_OFFSET_IS_GUID) {
2172                 MSFT_ReadGuid(&ref->guid, impinfo.oGuid, pcx);
2173                 TRACE("importing by guid %s\n", debugstr_guid(&ref->guid));
2174                 ref->index = TLB_REF_USE_GUID;
2175             } else
2176                 ref->index = impinfo.oGuid;
2177         }else{
2178             ERR("Cannot find a reference\n");
2179             ref->reference = -1;
2180             ref->pImpTLInfo = TLB_REF_NOT_FOUND;
2181         }
2182     }else{
2183         /* in this typelib */
2184         ref->index = MSFT_HREFTYPE_INDEX(offset);
2185         ref->reference = offset;
2186         ref->pImpTLInfo = TLB_REF_INTERNAL;
2187     }
2188 }
2189
2190 /* process Implemented Interfaces of a com class */
2191 static void MSFT_DoImplTypes(TLBContext *pcx, ITypeInfoImpl *pTI, int count,
2192                             int offset)
2193 {
2194     int i;
2195     MSFT_RefRecord refrec;
2196     TLBImplType **ppImpl = &pTI->impltypelist;
2197
2198     TRACE_(typelib)("\n");
2199
2200     for(i=0;i<count;i++){
2201         if(offset<0) break; /* paranoia */
2202         *ppImpl=TLB_Alloc(sizeof(**ppImpl));
2203         MSFT_ReadLEDWords(&refrec,sizeof(refrec),pcx,offset+pcx->pTblDir->pRefTab.offset);
2204         MSFT_DoRefType(pcx, pTI->pTypeLib, refrec.reftype);
2205         (*ppImpl)->hRef = refrec.reftype;
2206         (*ppImpl)->implflags=refrec.flags;
2207         (*ppImpl)->ctCustData=
2208             MSFT_CustData(pcx, refrec.oCustData, &(*ppImpl)->pCustData);
2209         offset=refrec.onext;
2210         ppImpl=&((*ppImpl)->next);
2211     }
2212 }
2213 /*
2214  * process a typeinfo record
2215  */
2216 static ITypeInfoImpl * MSFT_DoTypeInfo(
2217     TLBContext *pcx,
2218     int count,
2219     ITypeLibImpl * pLibInfo)
2220 {
2221     MSFT_TypeInfoBase tiBase;
2222     ITypeInfoImpl *ptiRet;
2223
2224     TRACE_(typelib)("count=%u\n", count);
2225
2226     ptiRet = (ITypeInfoImpl*) ITypeInfo_Constructor();
2227     MSFT_ReadLEDWords(&tiBase, sizeof(tiBase) ,pcx ,
2228                       pcx->pTblDir->pTypeInfoTab.offset+count*sizeof(tiBase));
2229
2230 /* this is where we are coming from */
2231     ptiRet->pTypeLib = pLibInfo;
2232     ptiRet->index=count;
2233 /* fill in the typeattr fields */
2234
2235     MSFT_ReadGuid(&ptiRet->TypeAttr.guid, tiBase.posguid, pcx);
2236     ptiRet->TypeAttr.lcid=pLibInfo->LibAttr.lcid;   /* FIXME: correct? */
2237     ptiRet->TypeAttr.lpstrSchema=NULL;              /* reserved */
2238     ptiRet->TypeAttr.cbSizeInstance=tiBase.size;
2239     ptiRet->TypeAttr.typekind=tiBase.typekind & 0xF;
2240     ptiRet->TypeAttr.cFuncs=LOWORD(tiBase.cElement);
2241     ptiRet->TypeAttr.cVars=HIWORD(tiBase.cElement);
2242     ptiRet->TypeAttr.cbAlignment=(tiBase.typekind >> 11 )& 0x1F; /* there are more flags there */
2243     ptiRet->TypeAttr.wTypeFlags=tiBase.flags;
2244     ptiRet->TypeAttr.wMajorVerNum=LOWORD(tiBase.version);
2245     ptiRet->TypeAttr.wMinorVerNum=HIWORD(tiBase.version);
2246     ptiRet->TypeAttr.cImplTypes=tiBase.cImplTypes;
2247     ptiRet->TypeAttr.cbSizeVft=tiBase.cbSizeVft; /* FIXME: this is only the non inherited part */
2248     if(ptiRet->TypeAttr.typekind == TKIND_ALIAS)
2249         MSFT_GetTdesc(pcx, tiBase.datatype1,
2250             &ptiRet->TypeAttr.tdescAlias, ptiRet);
2251
2252 /*  FIXME: */
2253 /*    IDLDESC  idldescType; *//* never saw this one != zero  */
2254
2255 /* name, eventually add to a hash table */
2256     ptiRet->Name=MSFT_ReadName(pcx, tiBase.NameOffset);
2257     ptiRet->hreftype = MSFT_ReadHreftype(pcx, tiBase.NameOffset);
2258     TRACE_(typelib)("reading %s\n", debugstr_w(ptiRet->Name));
2259     /* help info */
2260     ptiRet->DocString=MSFT_ReadString(pcx, tiBase.docstringoffs);
2261     ptiRet->dwHelpStringContext=tiBase.helpstringcontext;
2262     ptiRet->dwHelpContext=tiBase.helpcontext;
2263
2264     if (ptiRet->TypeAttr.typekind == TKIND_MODULE)
2265         ptiRet->DllName = MSFT_ReadString(pcx, tiBase.datatype1);
2266
2267 /* note: InfoType's Help file and HelpStringDll come from the containing
2268  * library. Further HelpString and Docstring appear to be the same thing :(
2269  */
2270     /* functions */
2271     if(ptiRet->TypeAttr.cFuncs >0 )
2272         MSFT_DoFuncs(pcx, ptiRet, ptiRet->TypeAttr.cFuncs,
2273                     ptiRet->TypeAttr.cVars,
2274                     tiBase.memoffset, & ptiRet->funclist);
2275     /* variables */
2276     if(ptiRet->TypeAttr.cVars >0 )
2277         MSFT_DoVars(pcx, ptiRet, ptiRet->TypeAttr.cFuncs,
2278                    ptiRet->TypeAttr.cVars,
2279                    tiBase.memoffset, & ptiRet->varlist);
2280     if(ptiRet->TypeAttr.cImplTypes >0 ) {
2281         switch(ptiRet->TypeAttr.typekind)
2282         {
2283         case TKIND_COCLASS:
2284             MSFT_DoImplTypes(pcx, ptiRet, ptiRet->TypeAttr.cImplTypes ,
2285                 tiBase.datatype1);
2286             break;
2287         case TKIND_DISPATCH:
2288             /* This is not -1 when the interface is a non-base dual interface or
2289                when a dispinterface wraps an interface, i.e., the idl 'dispinterface x {interface y;};'.
2290                Note however that GetRefTypeOfImplType(0) always returns a ref to IDispatch and
2291                not this interface.
2292             */
2293
2294             if (tiBase.datatype1 != -1)
2295             {
2296                 ptiRet->impltypelist = TLB_Alloc(sizeof(TLBImplType));
2297                 ptiRet->impltypelist->hRef = tiBase.datatype1;
2298                 MSFT_DoRefType(pcx, pLibInfo, tiBase.datatype1);
2299             }
2300           break;
2301         default:
2302             ptiRet->impltypelist=TLB_Alloc(sizeof(TLBImplType));
2303             MSFT_DoRefType(pcx, pLibInfo, tiBase.datatype1);
2304             ptiRet->impltypelist->hRef = tiBase.datatype1;
2305             break;
2306        }
2307     }
2308     ptiRet->ctCustData=
2309         MSFT_CustData(pcx, tiBase.oCustData, &ptiRet->pCustData);
2310
2311     TRACE_(typelib)("%s guid: %s kind:%s\n",
2312        debugstr_w(ptiRet->Name),
2313        debugstr_guid(&ptiRet->TypeAttr.guid),
2314        typekind_desc[ptiRet->TypeAttr.typekind]);
2315     if (TRACE_ON(typelib))
2316       dump_TypeInfo(ptiRet);
2317
2318     return ptiRet;
2319 }
2320
2321 /* Because type library parsing has some degree of overhead, and some apps repeatedly load the same
2322  * typelibs over and over, we cache them here. According to MSDN Microsoft have a similar scheme in
2323  * place. This will cause a deliberate memory leak, but generally losing RAM for cycles is an acceptable
2324  * tradeoff here.
2325  */
2326 static ITypeLibImpl *tlb_cache_first;
2327 static CRITICAL_SECTION cache_section;
2328 static CRITICAL_SECTION_DEBUG cache_section_debug =
2329 {
2330     0, 0, &cache_section,
2331     { &cache_section_debug.ProcessLocksList, &cache_section_debug.ProcessLocksList },
2332       0, 0, { (DWORD_PTR)(__FILE__ ": typelib loader cache") }
2333 };
2334 static CRITICAL_SECTION cache_section = { &cache_section_debug, -1, 0, 0, 0, 0 };
2335
2336
2337 typedef struct TLB_PEFile
2338 {
2339     const IUnknownVtbl *lpvtbl;
2340     LONG refs;
2341     HMODULE dll;
2342     HRSRC typelib_resource;
2343     HGLOBAL typelib_global;
2344     LPVOID typelib_base;
2345 } TLB_PEFile;
2346
2347 static HRESULT WINAPI TLB_PEFile_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2348 {
2349     if (IsEqualIID(riid, &IID_IUnknown))
2350     {
2351         *ppv = iface;
2352         IUnknown_AddRef(iface);
2353         return S_OK;
2354     }
2355     *ppv = NULL;
2356     return E_NOINTERFACE;
2357 }
2358
2359 static ULONG WINAPI TLB_PEFile_AddRef(IUnknown *iface)
2360 {
2361     TLB_PEFile *This = (TLB_PEFile *)iface;
2362     return InterlockedIncrement(&This->refs);
2363 }
2364
2365 static ULONG WINAPI TLB_PEFile_Release(IUnknown *iface)
2366 {
2367     TLB_PEFile *This = (TLB_PEFile *)iface;
2368     ULONG refs = InterlockedDecrement(&This->refs);
2369     if (!refs)
2370     {
2371         if (This->typelib_global)
2372             FreeResource(This->typelib_global);
2373         if (This->dll)
2374             FreeLibrary(This->dll);
2375         HeapFree(GetProcessHeap(), 0, This);
2376     }
2377     return refs;
2378 }
2379
2380 static const IUnknownVtbl TLB_PEFile_Vtable =
2381 {
2382     TLB_PEFile_QueryInterface,
2383     TLB_PEFile_AddRef,
2384     TLB_PEFile_Release
2385 };
2386
2387 static HRESULT TLB_PEFile_Open(LPCWSTR path, INT index, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile)
2388 {
2389     TLB_PEFile *This;
2390
2391     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
2392     if (!This)
2393         return E_OUTOFMEMORY;
2394
2395     This->lpvtbl = &TLB_PEFile_Vtable;
2396     This->refs = 1;
2397     This->dll = NULL;
2398     This->typelib_resource = NULL;
2399     This->typelib_global = NULL;
2400     This->typelib_base = NULL;
2401
2402     This->dll = LoadLibraryExW(path, 0, DONT_RESOLVE_DLL_REFERENCES |
2403                     LOAD_LIBRARY_AS_DATAFILE | LOAD_WITH_ALTERED_SEARCH_PATH);
2404
2405     if (This->dll)
2406     {
2407         static const WCHAR TYPELIBW[] = {'T','Y','P','E','L','I','B',0};
2408         This->typelib_resource = FindResourceW(This->dll, MAKEINTRESOURCEW(index), TYPELIBW);
2409         if (This->typelib_resource)
2410         {
2411             This->typelib_global = LoadResource(This->dll, This->typelib_resource);
2412             if (This->typelib_global)
2413             {
2414                 This->typelib_base = LockResource(This->typelib_global);
2415
2416                 if (This->typelib_base)
2417                 {
2418                     *pdwTLBLength = SizeofResource(This->dll, This->typelib_resource);
2419                     *ppBase = This->typelib_base;
2420                     *ppFile = (IUnknown *)&This->lpvtbl;
2421                     return S_OK;
2422                 }
2423             }
2424         }
2425     }
2426
2427     TLB_PEFile_Release((IUnknown *)&This->lpvtbl);
2428     return TYPE_E_CANTLOADLIBRARY;
2429 }
2430
2431 typedef struct TLB_NEFile
2432 {
2433     const IUnknownVtbl *lpvtbl;
2434     LONG refs;
2435     LPVOID typelib_base;
2436 } TLB_NEFile;
2437
2438 static HRESULT WINAPI TLB_NEFile_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2439 {
2440     if (IsEqualIID(riid, &IID_IUnknown))
2441     {
2442         *ppv = iface;
2443         IUnknown_AddRef(iface);
2444         return S_OK;
2445     }
2446     *ppv = NULL;
2447     return E_NOINTERFACE;
2448 }
2449
2450 static ULONG WINAPI TLB_NEFile_AddRef(IUnknown *iface)
2451 {
2452     TLB_NEFile *This = (TLB_NEFile *)iface;
2453     return InterlockedIncrement(&This->refs);
2454 }
2455
2456 static ULONG WINAPI TLB_NEFile_Release(IUnknown *iface)
2457 {
2458     TLB_NEFile *This = (TLB_NEFile *)iface;
2459     ULONG refs = InterlockedDecrement(&This->refs);
2460     if (!refs)
2461     {
2462         HeapFree(GetProcessHeap(), 0, This->typelib_base);
2463         HeapFree(GetProcessHeap(), 0, This);
2464     }
2465     return refs;
2466 }
2467
2468 static const IUnknownVtbl TLB_NEFile_Vtable =
2469 {
2470     TLB_NEFile_QueryInterface,
2471     TLB_NEFile_AddRef,
2472     TLB_NEFile_Release
2473 };
2474
2475 /***********************************************************************
2476  *           read_xx_header         [internal]
2477  */
2478 static int read_xx_header( HFILE lzfd )
2479 {
2480     IMAGE_DOS_HEADER mzh;
2481     char magic[3];
2482
2483     LZSeek( lzfd, 0, SEEK_SET );
2484     if ( sizeof(mzh) != LZRead( lzfd, (LPSTR)&mzh, sizeof(mzh) ) )
2485         return 0;
2486     if ( mzh.e_magic != IMAGE_DOS_SIGNATURE )
2487         return 0;
2488
2489     LZSeek( lzfd, mzh.e_lfanew, SEEK_SET );
2490     if ( 2 != LZRead( lzfd, magic, 2 ) )
2491         return 0;
2492
2493     LZSeek( lzfd, mzh.e_lfanew, SEEK_SET );
2494
2495     if ( magic[0] == 'N' && magic[1] == 'E' )
2496         return IMAGE_OS2_SIGNATURE;
2497     if ( magic[0] == 'P' && magic[1] == 'E' )
2498         return IMAGE_NT_SIGNATURE;
2499
2500     magic[2] = '\0';
2501     WARN("Can't handle %s files.\n", magic );
2502     return 0;
2503 }
2504
2505
2506 /***********************************************************************
2507  *           find_ne_resource         [internal]
2508  */
2509 static BOOL find_ne_resource( HFILE lzfd, LPCSTR typeid, LPCSTR resid,
2510                                 DWORD *resLen, DWORD *resOff )
2511 {
2512     IMAGE_OS2_HEADER nehd;
2513     NE_TYPEINFO *typeInfo;
2514     NE_NAMEINFO *nameInfo;
2515     DWORD nehdoffset;
2516     LPBYTE resTab;
2517     DWORD resTabSize;
2518     int count;
2519
2520     /* Read in NE header */
2521     nehdoffset = LZSeek( lzfd, 0, SEEK_CUR );
2522     if ( sizeof(nehd) != LZRead( lzfd, (LPSTR)&nehd, sizeof(nehd) ) ) return 0;
2523
2524     resTabSize = nehd.ne_restab - nehd.ne_rsrctab;
2525     if ( !resTabSize )
2526     {
2527         TRACE("No resources in NE dll\n" );
2528         return FALSE;
2529     }
2530
2531     /* Read in resource table */
2532     resTab = HeapAlloc( GetProcessHeap(), 0, resTabSize );
2533     if ( !resTab ) return FALSE;
2534
2535     LZSeek( lzfd, nehd.ne_rsrctab + nehdoffset, SEEK_SET );
2536     if ( resTabSize != LZRead( lzfd, (char*)resTab, resTabSize ) )
2537     {
2538         HeapFree( GetProcessHeap(), 0, resTab );
2539         return FALSE;
2540     }
2541
2542     /* Find resource */
2543     typeInfo = (NE_TYPEINFO *)(resTab + 2);
2544
2545     if (!IS_INTRESOURCE(typeid))  /* named type */
2546     {
2547         BYTE len = strlen( typeid );
2548         while (typeInfo->type_id)
2549         {
2550             if (!(typeInfo->type_id & 0x8000))
2551             {
2552                 BYTE *p = resTab + typeInfo->type_id;
2553                 if ((*p == len) && !strncasecmp( (char*)p+1, typeid, len )) goto found_type;
2554             }
2555             typeInfo = (NE_TYPEINFO *)((char *)(typeInfo + 1) +
2556                                        typeInfo->count * sizeof(NE_NAMEINFO));
2557         }
2558     }
2559     else  /* numeric type id */
2560     {
2561         WORD id = LOWORD(typeid) | 0x8000;
2562         while (typeInfo->type_id)
2563         {
2564             if (typeInfo->type_id == id) goto found_type;
2565             typeInfo = (NE_TYPEINFO *)((char *)(typeInfo + 1) +
2566                                        typeInfo->count * sizeof(NE_NAMEINFO));
2567         }
2568     }
2569     TRACE("No typeid entry found for %p\n", typeid );
2570     HeapFree( GetProcessHeap(), 0, resTab );
2571     return FALSE;
2572
2573  found_type:
2574     nameInfo = (NE_NAMEINFO *)(typeInfo + 1);
2575
2576     if (!IS_INTRESOURCE(resid))  /* named resource */
2577     {
2578         BYTE len = strlen( resid );
2579         for (count = typeInfo->count; count > 0; count--, nameInfo++)
2580         {
2581             BYTE *p = resTab + nameInfo->id;
2582             if (nameInfo->id & 0x8000) continue;
2583             if ((*p == len) && !strncasecmp( (char*)p+1, resid, len )) goto found_name;
2584         }
2585     }
2586     else  /* numeric resource id */
2587     {
2588         WORD id = LOWORD(resid) | 0x8000;
2589         for (count = typeInfo->count; count > 0; count--, nameInfo++)
2590             if (nameInfo->id == id) goto found_name;
2591     }
2592     TRACE("No resid entry found for %p\n", typeid );
2593     HeapFree( GetProcessHeap(), 0, resTab );
2594     return FALSE;
2595
2596  found_name:
2597     /* Return resource data */
2598     if ( resLen ) *resLen = nameInfo->length << *(WORD *)resTab;
2599     if ( resOff ) *resOff = nameInfo->offset << *(WORD *)resTab;
2600
2601     HeapFree( GetProcessHeap(), 0, resTab );
2602     return TRUE;
2603 }
2604
2605 static HRESULT TLB_NEFile_Open(LPCWSTR path, INT index, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile){
2606
2607     HFILE lzfd = -1;
2608     OFSTRUCT ofs;
2609     HRESULT hr = TYPE_E_CANTLOADLIBRARY;
2610     TLB_NEFile *This = NULL;
2611
2612     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
2613     if (!This) return E_OUTOFMEMORY;
2614
2615     This->lpvtbl = &TLB_NEFile_Vtable;
2616     This->refs = 1;
2617     This->typelib_base = NULL;
2618
2619     lzfd = LZOpenFileW( (LPWSTR)path, &ofs, OF_READ );
2620     if ( lzfd >= 0 && read_xx_header( lzfd ) == IMAGE_OS2_SIGNATURE )
2621     {
2622         DWORD reslen, offset;
2623         if( find_ne_resource( lzfd, "TYPELIB", MAKEINTRESOURCEA(index), &reslen, &offset ) )
2624         {
2625             This->typelib_base = HeapAlloc(GetProcessHeap(), 0, reslen);
2626             if( !This->typelib_base )
2627                 hr = E_OUTOFMEMORY;
2628             else
2629             {
2630                 LZSeek( lzfd, offset, SEEK_SET );
2631                 reslen = LZRead( lzfd, This->typelib_base, reslen );
2632                 LZClose( lzfd );
2633                 *ppBase = This->typelib_base;
2634                 *pdwTLBLength = reslen;
2635                 *ppFile = (IUnknown *)&This->lpvtbl;
2636                 return S_OK;
2637             }
2638         }
2639     }
2640
2641     if( lzfd >= 0) LZClose( lzfd );
2642     TLB_NEFile_Release((IUnknown *)&This->lpvtbl);
2643     return hr;
2644 }
2645
2646 typedef struct TLB_Mapping
2647 {
2648     const IUnknownVtbl *lpvtbl;
2649     LONG refs;
2650     HANDLE file;
2651     HANDLE mapping;
2652     LPVOID typelib_base;
2653 } TLB_Mapping;
2654
2655 static HRESULT WINAPI TLB_Mapping_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2656 {
2657     if (IsEqualIID(riid, &IID_IUnknown))
2658     {
2659         *ppv = iface;
2660         IUnknown_AddRef(iface);
2661         return S_OK;
2662     }
2663     *ppv = NULL;
2664     return E_NOINTERFACE;
2665 }
2666
2667 static ULONG WINAPI TLB_Mapping_AddRef(IUnknown *iface)
2668 {
2669     TLB_Mapping *This = (TLB_Mapping *)iface;
2670     return InterlockedIncrement(&This->refs);
2671 }
2672
2673 static ULONG WINAPI TLB_Mapping_Release(IUnknown *iface)
2674 {
2675     TLB_Mapping *This = (TLB_Mapping *)iface;
2676     ULONG refs = InterlockedDecrement(&This->refs);
2677     if (!refs)
2678     {
2679         if (This->typelib_base)
2680             UnmapViewOfFile(This->typelib_base);
2681         if (This->mapping)
2682             CloseHandle(This->mapping);
2683         if (This->file != INVALID_HANDLE_VALUE)
2684             CloseHandle(This->file);
2685         HeapFree(GetProcessHeap(), 0, This);
2686     }
2687     return refs;
2688 }
2689
2690 static const IUnknownVtbl TLB_Mapping_Vtable =
2691 {
2692     TLB_Mapping_QueryInterface,
2693     TLB_Mapping_AddRef,
2694     TLB_Mapping_Release
2695 };
2696
2697 static HRESULT TLB_Mapping_Open(LPCWSTR path, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile)
2698 {
2699     TLB_Mapping *This;
2700
2701     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
2702     if (!This)
2703         return E_OUTOFMEMORY;
2704
2705     This->lpvtbl = &TLB_Mapping_Vtable;
2706     This->refs = 1;
2707     This->file = INVALID_HANDLE_VALUE;
2708     This->mapping = NULL;
2709     This->typelib_base = NULL;
2710
2711     This->file = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
2712     if (INVALID_HANDLE_VALUE != This->file)
2713     {
2714         This->mapping = CreateFileMappingW(This->file, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL);
2715         if (This->mapping)
2716         {
2717             This->typelib_base = MapViewOfFile(This->mapping, FILE_MAP_READ, 0, 0, 0);
2718             if(This->typelib_base)
2719             {
2720                 /* retrieve file size */
2721                 *pdwTLBLength = GetFileSize(This->file, NULL);
2722                 *ppBase = This->typelib_base;
2723                 *ppFile = (IUnknown *)&This->lpvtbl;
2724                 return S_OK;
2725             }
2726         }
2727     }
2728
2729     IUnknown_Release((IUnknown *)&This->lpvtbl);
2730     return TYPE_E_CANTLOADLIBRARY;
2731 }
2732
2733 /****************************************************************************
2734  *      TLB_ReadTypeLib
2735  *
2736  * find the type of the typelib file and map the typelib resource into
2737  * the memory
2738  */
2739
2740 #define SLTG_SIGNATURE 0x47544c53 /* "SLTG" */
2741 static HRESULT TLB_ReadTypeLib(LPCWSTR pszFileName, LPWSTR pszPath, UINT cchPath, ITypeLib2 **ppTypeLib)
2742 {
2743     ITypeLibImpl *entry;
2744     HRESULT ret;
2745     INT index = 1;
2746     LPWSTR index_str, file = (LPWSTR)pszFileName;
2747     LPVOID pBase = NULL;
2748     DWORD dwTLBLength = 0;
2749     IUnknown *pFile = NULL;
2750
2751     *ppTypeLib = NULL;
2752
2753     index_str = strrchrW(pszFileName, '\\');
2754     if(index_str && *++index_str != '\0')
2755     {
2756         LPWSTR end_ptr;
2757         LONG idx = strtolW(index_str, &end_ptr, 10);
2758         if(*end_ptr == '\0')
2759         {
2760             int str_len = index_str - pszFileName - 1;
2761             index = idx;
2762             file = HeapAlloc(GetProcessHeap(), 0, (str_len + 1) * sizeof(WCHAR));
2763             memcpy(file, pszFileName, str_len * sizeof(WCHAR));
2764             file[str_len] = 0;
2765         }
2766     }
2767
2768     if(!SearchPathW(NULL, file, NULL, cchPath, pszPath, NULL))
2769     {
2770         if(strchrW(file, '\\'))
2771         {
2772             lstrcpyW(pszPath, file);
2773         }
2774         else
2775         {
2776             int len = GetSystemDirectoryW(pszPath, cchPath);
2777             pszPath[len] = '\\';
2778             memcpy(pszPath + len + 1, file, (strlenW(file) + 1) * sizeof(WCHAR));
2779         }
2780     }
2781
2782     if(file != pszFileName) HeapFree(GetProcessHeap(), 0, file);
2783
2784     TRACE_(typelib)("File %s index %d\n", debugstr_w(pszPath), index);
2785
2786     /* We look the path up in the typelib cache. If found, we just addref it, and return the pointer. */
2787     EnterCriticalSection(&cache_section);
2788     for (entry = tlb_cache_first; entry != NULL; entry = entry->next)
2789     {
2790         if (!strcmpiW(entry->path, pszPath) && entry->index == index)
2791         {
2792             TRACE("cache hit\n");
2793             *ppTypeLib = (ITypeLib2*)entry;
2794             ITypeLib_AddRef(*ppTypeLib);
2795             LeaveCriticalSection(&cache_section);
2796             return S_OK;
2797         }
2798     }
2799     LeaveCriticalSection(&cache_section);
2800
2801     /* now actually load and parse the typelib */
2802
2803     ret = TLB_PEFile_Open(pszPath, index, &pBase, &dwTLBLength, &pFile);
2804     if (ret == TYPE_E_CANTLOADLIBRARY)
2805         ret = TLB_NEFile_Open(pszPath, index, &pBase, &dwTLBLength, &pFile);
2806     if (ret == TYPE_E_CANTLOADLIBRARY)
2807         ret = TLB_Mapping_Open(pszPath, &pBase, &dwTLBLength, &pFile);
2808     if (SUCCEEDED(ret))
2809     {
2810         if (dwTLBLength >= 4)
2811         {
2812             DWORD dwSignature = FromLEDWord(*((DWORD*) pBase));
2813             if (dwSignature == MSFT_SIGNATURE)
2814                 *ppTypeLib = ITypeLib2_Constructor_MSFT(pBase, dwTLBLength);
2815             else if (dwSignature == SLTG_SIGNATURE)
2816                 *ppTypeLib = ITypeLib2_Constructor_SLTG(pBase, dwTLBLength);
2817             else
2818             {
2819                 FIXME("Header type magic 0x%08x not supported.\n",dwSignature);
2820                 ret = TYPE_E_CANTLOADLIBRARY;
2821             }
2822         }
2823         else
2824             ret = TYPE_E_CANTLOADLIBRARY;
2825         IUnknown_Release(pFile);
2826     }
2827
2828     if(*ppTypeLib) {
2829         ITypeLibImpl *impl = (ITypeLibImpl*)*ppTypeLib;
2830
2831         TRACE("adding to cache\n");
2832         impl->path = HeapAlloc(GetProcessHeap(), 0, (strlenW(pszPath)+1) * sizeof(WCHAR));
2833         lstrcpyW(impl->path, pszPath);
2834         /* We should really canonicalise the path here. */
2835         impl->index = index;
2836
2837         /* FIXME: check if it has added already in the meantime */
2838         EnterCriticalSection(&cache_section);
2839         if ((impl->next = tlb_cache_first) != NULL) impl->next->prev = impl;
2840         impl->prev = NULL;
2841         tlb_cache_first = impl;
2842         LeaveCriticalSection(&cache_section);
2843         ret = S_OK;
2844     } else
2845         ERR("Loading of typelib %s failed with error %d\n", debugstr_w(pszFileName), GetLastError());
2846
2847     return ret;
2848 }
2849
2850 /*================== ITypeLib(2) Methods ===================================*/
2851
2852 static ITypeLibImpl* TypeLibImpl_Constructor(void)
2853 {
2854     ITypeLibImpl* pTypeLibImpl;
2855
2856     pTypeLibImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeLibImpl));
2857     if (!pTypeLibImpl) return NULL;
2858
2859     pTypeLibImpl->lpVtbl = &tlbvt;
2860     pTypeLibImpl->lpVtblTypeComp = &tlbtcvt;
2861     pTypeLibImpl->ref = 1;
2862
2863     list_init(&pTypeLibImpl->ref_list);
2864     pTypeLibImpl->dispatch_href = -1;
2865
2866     return pTypeLibImpl;
2867 }
2868
2869 /****************************************************************************
2870  *      ITypeLib2_Constructor_MSFT
2871  *
2872  * loading an MSFT typelib from an in-memory image
2873  */
2874 static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength)
2875 {
2876     TLBContext cx;
2877     LONG lPSegDir;
2878     MSFT_Header tlbHeader;
2879     MSFT_SegDir tlbSegDir;
2880     ITypeLibImpl * pTypeLibImpl;
2881
2882     TRACE("%p, TLB length = %d\n", pLib, dwTLBLength);
2883
2884     pTypeLibImpl = TypeLibImpl_Constructor();
2885     if (!pTypeLibImpl) return NULL;
2886
2887     /* get pointer to beginning of typelib data */
2888     cx.pos = 0;
2889     cx.oStart=0;
2890     cx.mapping = pLib;
2891     cx.pLibInfo = pTypeLibImpl;
2892     cx.length = dwTLBLength;
2893
2894     /* read header */
2895     MSFT_ReadLEDWords((void*)&tlbHeader, sizeof(tlbHeader), &cx, 0);
2896     TRACE_(typelib)("header:\n");
2897     TRACE_(typelib)("\tmagic1=0x%08x ,magic2=0x%08x\n",tlbHeader.magic1,tlbHeader.magic2 );
2898     if (tlbHeader.magic1 != MSFT_SIGNATURE) {
2899         FIXME("Header type magic 0x%08x not supported.\n",tlbHeader.magic1);
2900         return NULL;
2901     }
2902     TRACE_(typelib)("\tdispatchpos = 0x%x\n", tlbHeader.dispatchpos);
2903
2904     /* there is a small amount of information here until the next important
2905      * part:
2906      * the segment directory . Try to calculate the amount of data */
2907     lPSegDir = sizeof(tlbHeader) + (tlbHeader.nrtypeinfos)*4 + ((tlbHeader.varflags & HELPDLLFLAG)? 4 :0);
2908
2909     /* now read the segment directory */
2910     TRACE("read segment directory (at %d)\n",lPSegDir);
2911     MSFT_ReadLEDWords(&tlbSegDir, sizeof(tlbSegDir), &cx, lPSegDir);
2912     cx.pTblDir = &tlbSegDir;
2913
2914     /* just check two entries */
2915     if ( tlbSegDir.pTypeInfoTab.res0c != 0x0F || tlbSegDir.pImpInfo.res0c != 0x0F)
2916     {
2917         ERR("cannot find the table directory, ptr=0x%x\n",lPSegDir);
2918         HeapFree(GetProcessHeap(),0,pTypeLibImpl);
2919         return NULL;
2920     }
2921
2922     /* now fill our internal data */
2923     /* TLIBATTR fields */
2924     MSFT_ReadGuid(&pTypeLibImpl->LibAttr.guid, tlbHeader.posguid, &cx);
2925
2926     pTypeLibImpl->LibAttr.lcid = tlbHeader.lcid2;
2927     pTypeLibImpl->LibAttr.syskind = tlbHeader.varflags & 0x0f; /* check the mask */
2928     pTypeLibImpl->LibAttr.wMajorVerNum = LOWORD(tlbHeader.version);
2929     pTypeLibImpl->LibAttr.wMinorVerNum = HIWORD(tlbHeader.version);
2930     pTypeLibImpl->LibAttr.wLibFlags = (WORD) tlbHeader.flags & 0xffff;/* check mask */
2931
2932     pTypeLibImpl->lcid = tlbHeader.lcid;
2933
2934     /* name, eventually add to a hash table */
2935     pTypeLibImpl->Name = MSFT_ReadName(&cx, tlbHeader.NameOffset);
2936
2937     /* help info */
2938     pTypeLibImpl->DocString = MSFT_ReadString(&cx, tlbHeader.helpstring);
2939     pTypeLibImpl->HelpFile = MSFT_ReadString(&cx, tlbHeader.helpfile);
2940
2941     if( tlbHeader.varflags & HELPDLLFLAG)
2942     {
2943             int offset;
2944             MSFT_ReadLEDWords(&offset, sizeof(offset), &cx, sizeof(tlbHeader));
2945             pTypeLibImpl->HelpStringDll = MSFT_ReadString(&cx, offset);
2946     }
2947
2948     pTypeLibImpl->dwHelpContext = tlbHeader.helpstringcontext;
2949
2950     /* custom data */
2951     if(tlbHeader.CustomDataOffset >= 0)
2952     {
2953         pTypeLibImpl->ctCustData = MSFT_CustData(&cx, tlbHeader.CustomDataOffset, &pTypeLibImpl->pCustData);
2954     }
2955
2956     /* fill in type descriptions */
2957     if(tlbSegDir.pTypdescTab.length > 0)
2958     {
2959         int i, j, cTD = tlbSegDir.pTypdescTab.length / (2*sizeof(INT));
2960         INT16 td[4];
2961         pTypeLibImpl->ctTypeDesc = cTD;
2962         pTypeLibImpl->pTypeDesc = TLB_Alloc( cTD * sizeof(TYPEDESC));
2963         MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pTypdescTab.offset);
2964         for(i=0; i<cTD; )
2965         {
2966             /* FIXME: add several sanity checks here */
2967             pTypeLibImpl->pTypeDesc[i].vt = td[0] & VT_TYPEMASK;
2968             if(td[0] == VT_PTR || td[0] == VT_SAFEARRAY)
2969             {
2970                 /* FIXME: check safearray */
2971                 if(td[3] < 0)
2972                     pTypeLibImpl->pTypeDesc[i].u.lptdesc= & stndTypeDesc[td[2]];
2973                 else
2974                     pTypeLibImpl->pTypeDesc[i].u.lptdesc= & pTypeLibImpl->pTypeDesc[td[2]/8];
2975             }
2976             else if(td[0] == VT_CARRAY)
2977             {
2978                 /* array descr table here */
2979                 pTypeLibImpl->pTypeDesc[i].u.lpadesc = (void *)(INT_PTR)td[2];  /* temp store offset in*/
2980             }
2981             else if(td[0] == VT_USERDEFINED)
2982             {
2983                 pTypeLibImpl->pTypeDesc[i].u.hreftype = MAKELONG(td[2],td[3]);
2984             }
2985             if(++i<cTD) MSFT_ReadLEWords(td, sizeof(td), &cx, DO_NOT_SEEK);
2986         }
2987
2988         /* second time around to fill the array subscript info */
2989         for(i=0;i<cTD;i++)
2990         {
2991             if(pTypeLibImpl->pTypeDesc[i].vt != VT_CARRAY) continue;
2992             if(tlbSegDir.pArrayDescriptions.offset>0)
2993             {
2994                 MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pArrayDescriptions.offset + (INT_PTR)pTypeLibImpl->pTypeDesc[i].u.lpadesc);
2995                 pTypeLibImpl->pTypeDesc[i].u.lpadesc = TLB_Alloc(sizeof(ARRAYDESC)+sizeof(SAFEARRAYBOUND)*(td[3]-1));
2996
2997                 if(td[1]<0)
2998                     pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem.vt = td[0] & VT_TYPEMASK;
2999                 else
3000                     pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem = cx.pLibInfo->pTypeDesc[td[0]/(2*sizeof(INT))];
3001
3002                 pTypeLibImpl->pTypeDesc[i].u.lpadesc->cDims = td[2];
3003
3004                 for(j = 0; j<td[2]; j++)
3005                 {
3006                     MSFT_ReadLEDWords(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].cElements,
3007                                       sizeof(INT), &cx, DO_NOT_SEEK);
3008                     MSFT_ReadLEDWords(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].lLbound,
3009                                       sizeof(INT), &cx, DO_NOT_SEEK);
3010                 }
3011             }
3012             else
3013             {
3014                 pTypeLibImpl->pTypeDesc[i].u.lpadesc = NULL;
3015                 ERR("didn't find array description data\n");
3016             }
3017         }
3018     }
3019
3020     /* imported type libs */
3021     if(tlbSegDir.pImpFiles.offset>0)
3022     {
3023         TLBImpLib **ppImpLib = &(pTypeLibImpl->pImpLibs);
3024         int oGuid, offset = tlbSegDir.pImpFiles.offset;
3025         UINT16 size;
3026
3027         while(offset < tlbSegDir.pImpFiles.offset +tlbSegDir.pImpFiles.length)
3028         {
3029             char *name;
3030
3031             *ppImpLib = TLB_Alloc(sizeof(TLBImpLib));
3032             (*ppImpLib)->offset = offset - tlbSegDir.pImpFiles.offset;
3033             MSFT_ReadLEDWords(&oGuid, sizeof(INT), &cx, offset);
3034
3035             MSFT_ReadLEDWords(&(*ppImpLib)->lcid,         sizeof(LCID),   &cx, DO_NOT_SEEK);
3036             MSFT_ReadLEWords(&(*ppImpLib)->wVersionMajor, sizeof(WORD),   &cx, DO_NOT_SEEK);
3037             MSFT_ReadLEWords(&(*ppImpLib)->wVersionMinor, sizeof(WORD),   &cx, DO_NOT_SEEK);
3038             MSFT_ReadLEWords(& size,                      sizeof(UINT16), &cx, DO_NOT_SEEK);
3039
3040             size >>= 2;
3041             name = TLB_Alloc(size+1);
3042             MSFT_Read(name, size, &cx, DO_NOT_SEEK);
3043             (*ppImpLib)->name = TLB_MultiByteToBSTR(name);
3044             TLB_Free(name);
3045
3046             MSFT_ReadGuid(&(*ppImpLib)->guid, oGuid, &cx);
3047             offset = (offset + sizeof(INT) + sizeof(DWORD) + sizeof(LCID) + sizeof(UINT16) + size + 3) & ~3;
3048
3049             ppImpLib = &(*ppImpLib)->next;
3050         }
3051     }
3052
3053     pTypeLibImpl->dispatch_href = tlbHeader.dispatchpos;
3054     if(pTypeLibImpl->dispatch_href != -1)
3055         MSFT_DoRefType(&cx, pTypeLibImpl, pTypeLibImpl->dispatch_href);
3056
3057     /* type info's */
3058     if(tlbHeader.nrtypeinfos >= 0 )
3059     {
3060         /*pTypeLibImpl->TypeInfoCount=tlbHeader.nrtypeinfos; */
3061         ITypeInfoImpl **ppTI = &(pTypeLibImpl->pTypeInfo);
3062         int i;
3063
3064         for(i = 0; i < tlbHeader.nrtypeinfos; i++)
3065         {
3066             *ppTI = MSFT_DoTypeInfo(&cx, i, pTypeLibImpl);
3067
3068             ppTI = &((*ppTI)->next);
3069             (pTypeLibImpl->TypeInfoCount)++;
3070         }
3071     }
3072
3073     TRACE("(%p)\n", pTypeLibImpl);
3074     return (ITypeLib2*) pTypeLibImpl;
3075 }
3076
3077
3078 static BOOL TLB_GUIDFromString(const char *str, GUID *guid)
3079 {
3080   char b[3];
3081   int i;
3082   short s;
3083
3084   if(sscanf(str, "%x-%hx-%hx-%hx", &guid->Data1, &guid->Data2, &guid->Data3, &s) != 4) {
3085     FIXME("Can't parse guid %s\n", debugstr_guid(guid));
3086     return FALSE;
3087   }
3088
3089   guid->Data4[0] = s >> 8;
3090   guid->Data4[1] = s & 0xff;
3091
3092   b[2] = '\0';
3093   for(i = 0; i < 6; i++) {
3094     memcpy(b, str + 24 + 2 * i, 2);
3095     guid->Data4[i + 2] = strtol(b, NULL, 16);
3096   }
3097   return TRUE;
3098 }
3099
3100 static WORD SLTG_ReadString(const char *ptr, BSTR *pBstr)
3101 {
3102     WORD bytelen;
3103     DWORD len;
3104
3105     *pBstr = NULL;
3106     bytelen = *(const WORD*)ptr;
3107     if(bytelen == 0xffff) return 2;
3108     len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, NULL, 0);
3109     *pBstr = SysAllocStringLen(NULL, len);
3110     if (*pBstr)
3111         len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, *pBstr, len);
3112     return bytelen + 2;
3113 }
3114
3115 static WORD SLTG_ReadStringA(const char *ptr, char **str)
3116 {
3117     WORD bytelen;
3118
3119     *str = NULL;
3120     bytelen = *(const WORD*)ptr;
3121     if(bytelen == 0xffff) return 2;
3122     *str = HeapAlloc(GetProcessHeap(), 0, bytelen + 1);
3123     memcpy(*str, ptr + 2, bytelen);
3124     (*str)[bytelen] = '\0';
3125     return bytelen + 2;
3126 }
3127
3128 static DWORD SLTG_ReadLibBlk(LPVOID pLibBlk, ITypeLibImpl *pTypeLibImpl)
3129 {
3130     char *ptr = pLibBlk;
3131     WORD w;
3132
3133     if((w = *(WORD*)ptr) != SLTG_LIBBLK_MAGIC) {
3134         FIXME("libblk magic = %04x\n", w);
3135         return 0;
3136     }
3137
3138     ptr += 6;
3139     if((w = *(WORD*)ptr) != 0xffff) {
3140         FIXME("LibBlk.res06 = %04x. Assumung string and skipping\n", w);
3141         ptr += w;
3142     }
3143     ptr += 2;
3144
3145     ptr += SLTG_ReadString(ptr, &pTypeLibImpl->DocString);
3146
3147     ptr += SLTG_ReadString(ptr, &pTypeLibImpl->HelpFile);
3148
3149     pTypeLibImpl->dwHelpContext = *(DWORD*)ptr;
3150     ptr += 4;
3151
3152     pTypeLibImpl->LibAttr.syskind = *(WORD*)ptr;
3153     ptr += 2;
3154
3155     if(SUBLANGID(*(WORD*)ptr) == SUBLANG_NEUTRAL)
3156         pTypeLibImpl->lcid = pTypeLibImpl->LibAttr.lcid = MAKELCID(MAKELANGID(PRIMARYLANGID(*(WORD*)ptr),0),0);
3157     else
3158         pTypeLibImpl->lcid = pTypeLibImpl->LibAttr.lcid = 0;
3159     ptr += 2;
3160
3161     ptr += 4; /* skip res12 */
3162
3163     pTypeLibImpl->LibAttr.wLibFlags = *(WORD*)ptr;
3164     ptr += 2;
3165
3166     pTypeLibImpl->LibAttr.wMajorVerNum = *(WORD*)ptr;
3167     ptr += 2;
3168
3169     pTypeLibImpl->LibAttr.wMinorVerNum = *(WORD*)ptr;
3170     ptr += 2;
3171
3172     memcpy(&pTypeLibImpl->LibAttr.guid, ptr, sizeof(GUID));
3173     ptr += sizeof(GUID);
3174
3175     return ptr - (char*)pLibBlk;
3176 }
3177
3178 /* stores a mapping between the sltg typeinfo's references and the typelib's HREFTYPEs */
3179 typedef struct
3180 {
3181     unsigned int num;
3182     HREFTYPE refs[1];
3183 } sltg_ref_lookup_t;
3184
3185 static HRESULT sltg_get_typelib_ref(const sltg_ref_lookup_t *table, DWORD typeinfo_ref,
3186                                     HREFTYPE *typelib_ref)
3187 {
3188     if(table && typeinfo_ref < table->num)
3189     {
3190         *typelib_ref = table->refs[typeinfo_ref];
3191         return S_OK;
3192     }
3193
3194     ERR_(typelib)("Unable to find reference\n");
3195     *typelib_ref = -1;
3196     return E_FAIL;
3197 }
3198
3199 static WORD *SLTG_DoType(WORD *pType, char *pBlk, TYPEDESC *pTD, const sltg_ref_lookup_t *ref_lookup)
3200 {
3201     BOOL done = FALSE;
3202
3203     while(!done) {
3204         if((*pType & 0xe00) == 0xe00) {
3205             pTD->vt = VT_PTR;
3206             pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3207                                        sizeof(TYPEDESC));
3208             pTD = pTD->u.lptdesc;
3209         }
3210         switch(*pType & 0x3f) {
3211         case VT_PTR:
3212             pTD->vt = VT_PTR;
3213             pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3214                                        sizeof(TYPEDESC));
3215             pTD = pTD->u.lptdesc;
3216             break;
3217
3218         case VT_USERDEFINED:
3219             pTD->vt = VT_USERDEFINED;
3220             sltg_get_typelib_ref(ref_lookup, *(++pType) / 4, &pTD->u.hreftype);
3221             done = TRUE;
3222             break;
3223
3224         case VT_CARRAY:
3225           {
3226             /* *(pType+1) is offset to a SAFEARRAY, *(pType+2) is type of
3227                array */
3228
3229             SAFEARRAY *pSA = (SAFEARRAY *)(pBlk + *(++pType));
3230
3231             pTD->vt = VT_CARRAY;
3232             pTD->u.lpadesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3233                                 sizeof(ARRAYDESC) +
3234                                 (pSA->cDims - 1) * sizeof(SAFEARRAYBOUND));
3235             pTD->u.lpadesc->cDims = pSA->cDims;
3236             memcpy(pTD->u.lpadesc->rgbounds, pSA->rgsabound,
3237                    pSA->cDims * sizeof(SAFEARRAYBOUND));
3238
3239             pTD = &pTD->u.lpadesc->tdescElem;
3240             break;
3241           }
3242
3243         case VT_SAFEARRAY:
3244           {
3245             /* FIXME: *(pType+1) gives an offset to SAFEARRAY, is this
3246                useful? */
3247
3248             pType++;
3249             pTD->vt = VT_SAFEARRAY;
3250             pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3251                                        sizeof(TYPEDESC));
3252             pTD = pTD->u.lptdesc;
3253             break;
3254           }
3255         default:
3256             pTD->vt = *pType & 0x3f;
3257             done = TRUE;
3258             break;
3259         }
3260         pType++;
3261     }
3262     return pType;
3263 }
3264
3265 static WORD *SLTG_DoElem(WORD *pType, char *pBlk,
3266                          ELEMDESC *pElem, const sltg_ref_lookup_t *ref_lookup)
3267 {
3268     /* Handle [in/out] first */
3269     if((*pType & 0xc000) == 0xc000)
3270         pElem->u.paramdesc.wParamFlags = PARAMFLAG_NONE;
3271     else if(*pType & 0x8000)
3272         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN | PARAMFLAG_FOUT;
3273     else if(*pType & 0x4000)
3274         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FOUT;
3275     else
3276         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN;
3277
3278     if(*pType & 0x2000)
3279         pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FLCID;
3280
3281     if(*pType & 0x80)
3282         pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FRETVAL;
3283
3284     return SLTG_DoType(pType, pBlk, &pElem->tdesc, ref_lookup);
3285 }
3286
3287
3288 static sltg_ref_lookup_t *SLTG_DoRefs(SLTG_RefInfo *pRef, ITypeLibImpl *pTL,
3289                         char *pNameTable)
3290 {
3291     unsigned int ref;
3292     char *name;
3293     TLBRefType *ref_type;
3294     sltg_ref_lookup_t *table;
3295     HREFTYPE typelib_ref;
3296
3297     if(pRef->magic != SLTG_REF_MAGIC) {
3298         FIXME("Ref magic = %x\n", pRef->magic);
3299         return NULL;
3300     }
3301     name = ( (char*)pRef->names + pRef->number);
3302
3303     table = HeapAlloc(GetProcessHeap(), 0, sizeof(*table) + ((pRef->number >> 3) - 1) * sizeof(table->refs[0]));
3304     table->num = pRef->number >> 3;
3305
3306     /* FIXME should scan the existing list and reuse matching refs added by previous typeinfos */
3307
3308     /* We don't want the first href to be 0 */
3309     typelib_ref = (list_count(&pTL->ref_list) + 1) << 2;
3310
3311     for(ref = 0; ref < pRef->number >> 3; ref++) {
3312         char *refname;
3313         unsigned int lib_offs, type_num;
3314
3315         ref_type = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ref_type));
3316
3317         name += SLTG_ReadStringA(name, &refname);
3318         if(sscanf(refname, "*\\R%x*#%x", &lib_offs, &type_num) != 2)
3319             FIXME_(typelib)("Can't sscanf ref\n");
3320         if(lib_offs != 0xffff) {
3321             TLBImpLib **import = &pTL->pImpLibs;
3322
3323             while(*import) {
3324                 if((*import)->offset == lib_offs)
3325                     break;
3326                 import = &(*import)->next;
3327             }
3328             if(!*import) {
3329                 char fname[MAX_PATH+1];
3330                 int len;
3331
3332                 *import = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3333                                     sizeof(**import));
3334                 (*import)->offset = lib_offs;
3335                 TLB_GUIDFromString( pNameTable + lib_offs + 4,
3336                                     &(*import)->guid);
3337                 if(sscanf(pNameTable + lib_offs + 40, "}#%hd.%hd#%x#%s",
3338                           &(*import)->wVersionMajor,
3339                           &(*import)->wVersionMinor,
3340                           &(*import)->lcid, fname) != 4) {
3341                   FIXME_(typelib)("can't sscanf ref %s\n",
3342                         pNameTable + lib_offs + 40);
3343                 }
3344                 len = strlen(fname);
3345                 if(fname[len-1] != '#')
3346                     FIXME("fname = %s\n", fname);
3347                 fname[len-1] = '\0';
3348                 (*import)->name = TLB_MultiByteToBSTR(fname);
3349             }
3350             ref_type->pImpTLInfo = *import;
3351
3352             /* Store a reference to IDispatch */
3353             if(pTL->dispatch_href == -1 && IsEqualGUID(&(*import)->guid, &IID_StdOle) && type_num == 4)
3354                 pTL->dispatch_href = typelib_ref;
3355
3356         } else { /* internal ref */
3357           ref_type->pImpTLInfo = TLB_REF_INTERNAL;
3358         }
3359         ref_type->reference = typelib_ref;
3360         ref_type->index = type_num;
3361
3362         HeapFree(GetProcessHeap(), 0, refname);
3363         list_add_tail(&pTL->ref_list, &ref_type->entry);
3364
3365         table->refs[ref] = typelib_ref;
3366         typelib_ref += 4;
3367     }
3368     if((BYTE)*name != SLTG_REF_MAGIC)
3369       FIXME_(typelib)("End of ref block magic = %x\n", *name);
3370     dump_TLBRefType(pTL);
3371     return table;
3372 }
3373
3374 static char *SLTG_DoImpls(char *pBlk, ITypeInfoImpl *pTI,
3375                           BOOL OneOnly, const sltg_ref_lookup_t *ref_lookup)
3376 {
3377     SLTG_ImplInfo *info;
3378     TLBImplType **ppImplType = &pTI->impltypelist;
3379     /* I don't really get this structure, usually it's 0x16 bytes
3380        long, but iuser.tlb contains some that are 0x18 bytes long.
3381        That's ok because we can use the next ptr to jump to the next
3382        one. But how do we know the length of the last one?  The WORD
3383        at offs 0x8 might be the clue.  For now I'm just assuming that
3384        the last one is the regular 0x16 bytes. */
3385
3386     info = (SLTG_ImplInfo*)pBlk;
3387     while(1) {
3388         *ppImplType = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3389                                 sizeof(**ppImplType));
3390         sltg_get_typelib_ref(ref_lookup, info->ref, &(*ppImplType)->hRef);
3391         (*ppImplType)->implflags = info->impltypeflags;
3392         pTI->TypeAttr.cImplTypes++;
3393         ppImplType = &(*ppImplType)->next;
3394
3395         if(info->next == 0xffff)
3396             break;
3397         if(OneOnly)
3398             FIXME_(typelib)("Interface inheriting more than one interface\n");
3399         info = (SLTG_ImplInfo*)(pBlk + info->next);
3400     }
3401     info++; /* see comment at top of function */
3402     return (char*)info;
3403 }
3404
3405 static void SLTG_DoVars(char *pBlk, char *pFirstItem, ITypeInfoImpl *pTI, unsigned short cVars,
3406                         const char *pNameTable, const sltg_ref_lookup_t *ref_lookup)
3407 {
3408   TLBVarDesc **ppVarDesc = &pTI->varlist;
3409   BSTR bstrPrevName = NULL;
3410   SLTG_Variable *pItem;
3411   unsigned short i;
3412   WORD *pType;
3413
3414   for(pItem = (SLTG_Variable *)pFirstItem, i = 0; i < cVars;
3415       pItem = (SLTG_Variable *)(pBlk + pItem->next), i++) {
3416
3417       *ppVarDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3418                              sizeof(**ppVarDesc));
3419       (*ppVarDesc)->vardesc.memid = pItem->memid;
3420
3421       if (pItem->magic != SLTG_VAR_MAGIC &&
3422           pItem->magic != SLTG_VAR_WITH_FLAGS_MAGIC) {
3423           FIXME_(typelib)("var magic = %02x\n", pItem->magic);
3424           return;
3425       }
3426
3427       if (pItem->name == 0xfffe)
3428         (*ppVarDesc)->Name = SysAllocString(bstrPrevName);
3429       else
3430         (*ppVarDesc)->Name = TLB_MultiByteToBSTR(pItem->name + pNameTable);
3431
3432       TRACE_(typelib)("name: %s\n", debugstr_w((*ppVarDesc)->Name));
3433       TRACE_(typelib)("byte_offs = 0x%x\n", pItem->byte_offs);
3434       TRACE_(typelib)("memid = 0x%x\n", pItem->memid);
3435
3436       if(pItem->flags & 0x02)
3437           pType = &pItem->type;
3438       else
3439           pType = (WORD*)(pBlk + pItem->type);
3440
3441       if (pItem->flags & ~0xda)
3442         FIXME_(typelib)("unhandled flags = %02x\n", pItem->flags & ~0xda);
3443
3444       SLTG_DoElem(pType, pBlk,
3445                   &(*ppVarDesc)->vardesc.elemdescVar, ref_lookup);
3446
3447       if (TRACE_ON(typelib)) {
3448           char buf[300];
3449           dump_TypeDesc(&(*ppVarDesc)->vardesc.elemdescVar.tdesc, buf);
3450           TRACE_(typelib)("elemdescVar: %s\n", buf);
3451       }
3452
3453       if (pItem->flags & 0x40) {
3454         TRACE_(typelib)("VAR_DISPATCH\n");
3455         (*ppVarDesc)->vardesc.varkind = VAR_DISPATCH;
3456       }
3457       else if (pItem->flags & 0x10) {
3458         TRACE_(typelib)("VAR_CONST\n");
3459         (*ppVarDesc)->vardesc.varkind = VAR_CONST;
3460         (*ppVarDesc)->vardesc.u.lpvarValue = HeapAlloc(GetProcessHeap(), 0,
3461                                                        sizeof(VARIANT));
3462         V_VT((*ppVarDesc)->vardesc.u.lpvarValue) = VT_INT;
3463         if (pItem->flags & 0x08)
3464           V_INT((*ppVarDesc)->vardesc.u.lpvarValue) = pItem->byte_offs;
3465         else {
3466           switch ((*ppVarDesc)->vardesc.elemdescVar.tdesc.vt)
3467           {
3468             case VT_LPSTR:
3469             case VT_LPWSTR:
3470             case VT_BSTR:
3471             {
3472               WORD len = *(WORD *)(pBlk + pItem->byte_offs);
3473               BSTR str;
3474               TRACE_(typelib)("len = %u\n", len);
3475               if (len == 0xffff) {
3476                 str = NULL;
3477               } else {
3478                 INT alloc_len = MultiByteToWideChar(CP_ACP, 0, pBlk + pItem->byte_offs + 2, len, NULL, 0);
3479                 str = SysAllocStringLen(NULL, alloc_len);
3480                 MultiByteToWideChar(CP_ACP, 0, pBlk + pItem->byte_offs + 2, len, str, alloc_len);
3481               }
3482               V_VT((*ppVarDesc)->vardesc.u.lpvarValue) = VT_BSTR;
3483               V_BSTR((*ppVarDesc)->vardesc.u.lpvarValue) = str;
3484               break;
3485             }
3486             case VT_I2:
3487             case VT_UI2:
3488             case VT_I4:
3489             case VT_UI4:
3490             case VT_INT:
3491             case VT_UINT:
3492               V_INT((*ppVarDesc)->vardesc.u.lpvarValue) =
3493                 *(INT*)(pBlk + pItem->byte_offs);
3494               break;
3495             default:
3496               FIXME_(typelib)("VAR_CONST unimplemented for type %d\n", (*ppVarDesc)->vardesc.elemdescVar.tdesc.vt);
3497           }
3498         }
3499       }
3500       else {
3501         TRACE_(typelib)("VAR_PERINSTANCE\n");
3502         (*ppVarDesc)->vardesc.u.oInst = pItem->byte_offs;
3503         (*ppVarDesc)->vardesc.varkind = VAR_PERINSTANCE;
3504       }
3505
3506       if (pItem->magic == SLTG_VAR_WITH_FLAGS_MAGIC)
3507         (*ppVarDesc)->vardesc.wVarFlags = pItem->varflags;
3508
3509       if (pItem->flags & 0x80)
3510         (*ppVarDesc)->vardesc.wVarFlags |= VARFLAG_FREADONLY;
3511
3512       bstrPrevName = (*ppVarDesc)->Name;
3513       ppVarDesc = &((*ppVarDesc)->next);
3514   }
3515   pTI->TypeAttr.cVars = cVars;
3516 }
3517
3518 static void SLTG_DoFuncs(char *pBlk, char *pFirstItem, ITypeInfoImpl *pTI,
3519                          unsigned short cFuncs, char *pNameTable, const sltg_ref_lookup_t *ref_lookup)
3520 {
3521     SLTG_Function *pFunc;
3522     unsigned short i;
3523     TLBFuncDesc **ppFuncDesc = &pTI->funclist;
3524
3525     for(pFunc = (SLTG_Function*)pFirstItem, i = 0; i < cFuncs;
3526         pFunc = (SLTG_Function*)(pBlk + pFunc->next), i++) {
3527
3528         int param;
3529         WORD *pType, *pArg;
3530
3531         *ppFuncDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3532                                 sizeof(**ppFuncDesc));
3533
3534         switch (pFunc->magic & ~SLTG_FUNCTION_FLAGS_PRESENT) {
3535         case SLTG_FUNCTION_MAGIC:
3536             (*ppFuncDesc)->funcdesc.funckind = FUNC_PUREVIRTUAL;
3537             break;
3538         case SLTG_DISPATCH_FUNCTION_MAGIC:
3539             (*ppFuncDesc)->funcdesc.funckind = FUNC_DISPATCH;
3540             break;
3541         case SLTG_STATIC_FUNCTION_MAGIC:
3542             (*ppFuncDesc)->funcdesc.funckind = FUNC_STATIC;
3543             break;
3544         default:
3545             FIXME("unimplemented func magic = %02x\n", pFunc->magic & ~SLTG_FUNCTION_FLAGS_PRESENT);
3546             HeapFree(GetProcessHeap(), 0, *ppFuncDesc);
3547             *ppFuncDesc = NULL;
3548             return;
3549         }
3550         (*ppFuncDesc)->Name = TLB_MultiByteToBSTR(pFunc->name + pNameTable);
3551
3552         (*ppFuncDesc)->funcdesc.memid = pFunc->dispid;
3553         (*ppFuncDesc)->funcdesc.invkind = pFunc->inv >> 4;
3554         (*ppFuncDesc)->funcdesc.callconv = pFunc->nacc & 0x7;
3555         (*ppFuncDesc)->funcdesc.cParams = pFunc->nacc >> 3;
3556         (*ppFuncDesc)->funcdesc.cParamsOpt = (pFunc->retnextopt & 0x7e) >> 1;
3557         (*ppFuncDesc)->funcdesc.oVft = pFunc->vtblpos;
3558
3559         if(pFunc->magic & SLTG_FUNCTION_FLAGS_PRESENT)
3560             (*ppFuncDesc)->funcdesc.wFuncFlags = pFunc->funcflags;
3561
3562         if(pFunc->retnextopt & 0x80)
3563             pType = &pFunc->rettype;
3564         else
3565             pType = (WORD*)(pBlk + pFunc->rettype);
3566
3567         SLTG_DoElem(pType, pBlk, &(*ppFuncDesc)->funcdesc.elemdescFunc, ref_lookup);
3568
3569         (*ppFuncDesc)->funcdesc.lprgelemdescParam =
3570           HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3571                     (*ppFuncDesc)->funcdesc.cParams * sizeof(ELEMDESC));
3572         (*ppFuncDesc)->pParamDesc =
3573           HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3574                     (*ppFuncDesc)->funcdesc.cParams * sizeof(TLBParDesc));
3575
3576         pArg = (WORD*)(pBlk + pFunc->arg_off);
3577
3578         for(param = 0; param < (*ppFuncDesc)->funcdesc.cParams; param++) {
3579             char *paramName = pNameTable + *pArg;
3580             BOOL HaveOffs;
3581             /* If arg type follows then paramName points to the 2nd
3582                letter of the name, else the next WORD is an offset to
3583                the arg type and paramName points to the first letter.
3584                So let's take one char off paramName and see if we're
3585                pointing at an alpha-numeric char.  However if *pArg is
3586                0xffff or 0xfffe then the param has no name, the former
3587                meaning that the next WORD is the type, the latter
3588                meaning that the next WORD is an offset to the type. */
3589
3590             HaveOffs = FALSE;
3591             if(*pArg == 0xffff)
3592                 paramName = NULL;
3593             else if(*pArg == 0xfffe) {
3594                 paramName = NULL;
3595                 HaveOffs = TRUE;
3596             }
3597             else if(paramName[-1] && !isalnum(paramName[-1]))
3598                 HaveOffs = TRUE;
3599
3600             pArg++;
3601
3602             if(HaveOffs) { /* the next word is an offset to type */
3603                 pType = (WORD*)(pBlk + *pArg);
3604                 SLTG_DoElem(pType, pBlk,
3605                             &(*ppFuncDesc)->funcdesc.lprgelemdescParam[param], ref_lookup);
3606                 pArg++;
3607             } else {
3608                 if(paramName)
3609                   paramName--;
3610                 pArg = SLTG_DoElem(pArg, pBlk,
3611                                    &(*ppFuncDesc)->funcdesc.lprgelemdescParam[param], ref_lookup);
3612             }
3613
3614             /* Are we an optional param ? */
3615             if((*ppFuncDesc)->funcdesc.cParams - param <=
3616                (*ppFuncDesc)->funcdesc.cParamsOpt)
3617               (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].u.paramdesc.wParamFlags |= PARAMFLAG_FOPT;
3618
3619             if(paramName) {
3620                 (*ppFuncDesc)->pParamDesc[param].Name =
3621                   TLB_MultiByteToBSTR(paramName);
3622             } else {
3623                 (*ppFuncDesc)->pParamDesc[param].Name =
3624                   SysAllocString((*ppFuncDesc)->Name);
3625             }
3626         }
3627
3628         ppFuncDesc = &((*ppFuncDesc)->next);
3629         if(pFunc->next == 0xffff) break;
3630     }
3631     pTI->TypeAttr.cFuncs = cFuncs;
3632 }
3633
3634 static void SLTG_ProcessCoClass(char *pBlk, ITypeInfoImpl *pTI,
3635                                 char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3636                                 SLTG_TypeInfoTail *pTITail)
3637 {
3638     char *pFirstItem;
3639     sltg_ref_lookup_t *ref_lookup = NULL;
3640
3641     if(pTIHeader->href_table != 0xffffffff) {
3642         ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3643                     pNameTable);
3644     }
3645
3646     pFirstItem = pBlk;
3647
3648     if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
3649         SLTG_DoImpls(pFirstItem, pTI, FALSE, ref_lookup);
3650     }
3651     HeapFree(GetProcessHeap(), 0, ref_lookup);
3652 }
3653
3654
3655 static void SLTG_ProcessInterface(char *pBlk, ITypeInfoImpl *pTI,
3656                                   char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3657                                   const SLTG_TypeInfoTail *pTITail)
3658 {
3659     char *pFirstItem;
3660     sltg_ref_lookup_t *ref_lookup = NULL;
3661
3662     if(pTIHeader->href_table != 0xffffffff) {
3663         ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3664                     pNameTable);
3665     }
3666
3667     pFirstItem = pBlk;
3668
3669     if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
3670         SLTG_DoImpls(pFirstItem, pTI, TRUE, ref_lookup);
3671     }
3672
3673     if (pTITail->funcs_off != 0xffff)
3674         SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup);
3675
3676     HeapFree(GetProcessHeap(), 0, ref_lookup);
3677
3678     if (TRACE_ON(typelib))
3679         dump_TLBFuncDesc(pTI->funclist);
3680 }
3681
3682 static void SLTG_ProcessRecord(char *pBlk, ITypeInfoImpl *pTI,
3683                                const char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3684                                const SLTG_TypeInfoTail *pTITail)
3685 {
3686   SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, NULL);
3687 }
3688
3689 static void SLTG_ProcessAlias(char *pBlk, ITypeInfoImpl *pTI,
3690                               char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3691                               const SLTG_TypeInfoTail *pTITail)
3692 {
3693   WORD *pType;
3694   sltg_ref_lookup_t *ref_lookup = NULL;
3695
3696   if (pTITail->simple_alias) {
3697     /* if simple alias, no more processing required */
3698     pTI->TypeAttr.tdescAlias.vt = pTITail->tdescalias_vt;
3699     return;
3700   }
3701
3702   if(pTIHeader->href_table != 0xffffffff) {
3703       ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3704                   pNameTable);
3705   }
3706
3707   /* otherwise it is an offset to a type */
3708   pType = (WORD *)(pBlk + pTITail->tdescalias_vt);
3709
3710   SLTG_DoType(pType, pBlk, &pTI->TypeAttr.tdescAlias, ref_lookup);
3711
3712   HeapFree(GetProcessHeap(), 0, ref_lookup);
3713 }
3714
3715 static void SLTG_ProcessDispatch(char *pBlk, ITypeInfoImpl *pTI,
3716                                  char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3717                                  const SLTG_TypeInfoTail *pTITail)
3718 {
3719   sltg_ref_lookup_t *ref_lookup = NULL;
3720   if (pTIHeader->href_table != 0xffffffff)
3721       ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3722                                   pNameTable);
3723
3724   if (pTITail->vars_off != 0xffff)
3725     SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, ref_lookup);
3726
3727   if (pTITail->funcs_off != 0xffff)
3728     SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup);
3729
3730   if (pTITail->impls_off != 0xffff)
3731     SLTG_DoImpls(pBlk + pTITail->impls_off, pTI, FALSE, ref_lookup);
3732
3733   /* this is necessary to cope with MSFT typelibs that set cFuncs to the number
3734    * of dispinterface functions including the IDispatch ones, so
3735    * ITypeInfo::GetFuncDesc takes the real value for cFuncs from cbSizeVft */
3736   pTI->TypeAttr.cbSizeVft = pTI->TypeAttr.cFuncs * sizeof(void *);
3737
3738   HeapFree(GetProcessHeap(), 0, ref_lookup);
3739   if (TRACE_ON(typelib))
3740       dump_TLBFuncDesc(pTI->funclist);
3741 }
3742
3743 static void SLTG_ProcessEnum(char *pBlk, ITypeInfoImpl *pTI,
3744                              const char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3745                              const SLTG_TypeInfoTail *pTITail)
3746 {
3747   SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, NULL);
3748 }
3749
3750 static void SLTG_ProcessModule(char *pBlk, ITypeInfoImpl *pTI,
3751                                char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3752                                const SLTG_TypeInfoTail *pTITail)
3753 {
3754   sltg_ref_lookup_t *ref_lookup = NULL;
3755   if (pTIHeader->href_table != 0xffffffff)
3756       ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3757                                   pNameTable);
3758
3759   if (pTITail->vars_off != 0xffff)
3760     SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, ref_lookup);
3761
3762   if (pTITail->funcs_off != 0xffff)
3763     SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup);
3764   HeapFree(GetProcessHeap(), 0, ref_lookup);
3765   if (TRACE_ON(typelib))
3766     dump_TypeInfo(pTI);
3767 }
3768
3769 /* Because SLTG_OtherTypeInfo is such a painful struct, we make a more
3770    managable copy of it into this */
3771 typedef struct {
3772   WORD small_no;
3773   char *index_name;
3774   char *other_name;
3775   WORD res1a;
3776   WORD name_offs;
3777   WORD more_bytes;
3778   char *extra;
3779   WORD res20;
3780   DWORD helpcontext;
3781   WORD res26;
3782   GUID uuid;
3783 } SLTG_InternalOtherTypeInfo;
3784
3785 /****************************************************************************
3786  *      ITypeLib2_Constructor_SLTG
3787  *
3788  * loading a SLTG typelib from an in-memory image
3789  */
3790 static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength)
3791 {
3792     ITypeLibImpl *pTypeLibImpl;
3793     SLTG_Header *pHeader;
3794     SLTG_BlkEntry *pBlkEntry;
3795     SLTG_Magic *pMagic;
3796     SLTG_Index *pIndex;
3797     SLTG_Pad9 *pPad9;
3798     LPVOID pBlk, pFirstBlk;
3799     SLTG_LibBlk *pLibBlk;
3800     SLTG_InternalOtherTypeInfo *pOtherTypeInfoBlks;
3801     char *pAfterOTIBlks = NULL;
3802     char *pNameTable, *ptr;
3803     int i;
3804     DWORD len, order;
3805     ITypeInfoImpl **ppTypeInfoImpl;
3806
3807     TRACE_(typelib)("%p, TLB length = %d\n", pLib, dwTLBLength);
3808
3809
3810     pTypeLibImpl = TypeLibImpl_Constructor();
3811     if (!pTypeLibImpl) return NULL;
3812
3813     pHeader = pLib;
3814
3815     TRACE_(typelib)("header:\n");
3816     TRACE_(typelib)("\tmagic=0x%08x, file blocks = %d\n", pHeader->SLTG_magic,
3817           pHeader->nrOfFileBlks );
3818     if (pHeader->SLTG_magic != SLTG_SIGNATURE) {
3819         FIXME_(typelib)("Header type magic 0x%08x not supported.\n",
3820               pHeader->SLTG_magic);
3821         return NULL;
3822     }
3823
3824     /* There are pHeader->nrOfFileBlks - 2 TypeInfo records in this typelib */
3825     pTypeLibImpl->TypeInfoCount = pHeader->nrOfFileBlks - 2;
3826
3827     /* This points to pHeader->nrOfFileBlks - 1 of SLTG_BlkEntry */
3828     pBlkEntry = (SLTG_BlkEntry*)(pHeader + 1);
3829
3830     /* Next we have a magic block */
3831     pMagic = (SLTG_Magic*)(pBlkEntry + pHeader->nrOfFileBlks - 1);
3832
3833     /* Let's see if we're still in sync */
3834     if(memcmp(pMagic->CompObj_magic, SLTG_COMPOBJ_MAGIC,
3835               sizeof(SLTG_COMPOBJ_MAGIC))) {
3836         FIXME_(typelib)("CompObj magic = %s\n", pMagic->CompObj_magic);
3837         return NULL;
3838     }
3839     if(memcmp(pMagic->dir_magic, SLTG_DIR_MAGIC,
3840               sizeof(SLTG_DIR_MAGIC))) {
3841         FIXME_(typelib)("dir magic = %s\n", pMagic->dir_magic);
3842         return NULL;
3843     }
3844
3845     pIndex = (SLTG_Index*)(pMagic+1);
3846
3847     pPad9 = (SLTG_Pad9*)(pIndex + pTypeLibImpl->TypeInfoCount);
3848
3849     pFirstBlk = pPad9 + 1;
3850
3851     /* We'll set up a ptr to the main library block, which is the last one. */
3852
3853     for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0;
3854           pBlkEntry[order].next != 0;
3855           order = pBlkEntry[order].next - 1, i++) {
3856        pBlk = (char*)pBlk + pBlkEntry[order].len;
3857     }
3858     pLibBlk = pBlk;
3859
3860     len = SLTG_ReadLibBlk(pLibBlk, pTypeLibImpl);
3861
3862     /* Now there's 0x40 bytes of 0xffff with the numbers 0 to TypeInfoCount
3863        interspersed */
3864
3865     len += 0x40;
3866
3867     /* And now TypeInfoCount of SLTG_OtherTypeInfo */
3868
3869     pOtherTypeInfoBlks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3870                                    sizeof(*pOtherTypeInfoBlks) *
3871                                    pTypeLibImpl->TypeInfoCount);
3872
3873
3874     ptr = (char*)pLibBlk + len;
3875
3876     for(i = 0; i < pTypeLibImpl->TypeInfoCount; i++) {
3877         WORD w, extra;
3878         len = 0;
3879
3880         pOtherTypeInfoBlks[i].small_no = *(WORD*)ptr;
3881
3882         w = *(WORD*)(ptr + 2);
3883         if(w != 0xffff) {
3884             len += w;
3885             pOtherTypeInfoBlks[i].index_name = HeapAlloc(GetProcessHeap(),0,
3886                                                          w+1);
3887             memcpy(pOtherTypeInfoBlks[i].index_name, ptr + 4, w);
3888             pOtherTypeInfoBlks[i].index_name[w] = '\0';
3889         }
3890         w = *(WORD*)(ptr + 4 + len);
3891         if(w != 0xffff) {
3892             TRACE_(typelib)("\twith %s\n", debugstr_an(ptr + 6 + len, w));
3893             len += w;
3894             pOtherTypeInfoBlks[i].other_name = HeapAlloc(GetProcessHeap(),0,
3895                                                          w+1);
3896             memcpy(pOtherTypeInfoBlks[i].other_name, ptr + 6 + len, w);
3897             pOtherTypeInfoBlks[i].other_name[w] = '\0';
3898         }
3899         pOtherTypeInfoBlks[i].res1a = *(WORD*)(ptr + len + 6);
3900         pOtherTypeInfoBlks[i].name_offs = *(WORD*)(ptr + len + 8);
3901         extra = pOtherTypeInfoBlks[i].more_bytes = *(WORD*)(ptr + 10 + len);
3902         if(extra) {
3903             pOtherTypeInfoBlks[i].extra = HeapAlloc(GetProcessHeap(),0,
3904                                                     extra);
3905             memcpy(pOtherTypeInfoBlks[i].extra, ptr + 12, extra);
3906             len += extra;
3907         }
3908         pOtherTypeInfoBlks[i].res20 = *(WORD*)(ptr + 12 + len);
3909         pOtherTypeInfoBlks[i].helpcontext = *(DWORD*)(ptr + 14 + len);
3910         pOtherTypeInfoBlks[i].res26 = *(WORD*)(ptr + 18 + len);
3911         memcpy(&pOtherTypeInfoBlks[i].uuid, ptr + 20 + len, sizeof(GUID));
3912         len += sizeof(SLTG_OtherTypeInfo);
3913         ptr += len;
3914     }
3915
3916     pAfterOTIBlks = ptr;
3917
3918     /* Skip this WORD and get the next DWORD */
3919     len = *(DWORD*)(pAfterOTIBlks + 2);
3920
3921     /* Now add this to pLibBLk look at what we're pointing at and
3922        possibly add 0x20, then add 0x216, sprinkle a bit a magic
3923        dust and we should be pointing at the beginning of the name
3924        table */
3925
3926     pNameTable = (char*)pLibBlk + len;
3927
3928    switch(*(WORD*)pNameTable) {
3929    case 0xffff:
3930        break;
3931    case 0x0200:
3932        pNameTable += 0x20;
3933        break;
3934    default:
3935        FIXME_(typelib)("pNameTable jump = %x\n", *(WORD*)pNameTable);
3936        break;
3937    }
3938
3939     pNameTable += 0x216;
3940
3941     pNameTable += 2;
3942
3943     TRACE_(typelib)("Library name is %s\n", pNameTable + pLibBlk->name);
3944
3945     pTypeLibImpl->Name = TLB_MultiByteToBSTR(pNameTable + pLibBlk->name);
3946
3947
3948     /* Hopefully we now have enough ptrs set up to actually read in
3949        some TypeInfos.  It's not clear which order to do them in, so
3950        I'll just follow the links along the BlkEntry chain and read
3951        them in the order in which they are in the file */
3952
3953     ppTypeInfoImpl = &(pTypeLibImpl->pTypeInfo);
3954
3955     for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0;
3956         pBlkEntry[order].next != 0;
3957         order = pBlkEntry[order].next - 1, i++) {
3958
3959       SLTG_TypeInfoHeader *pTIHeader;
3960       SLTG_TypeInfoTail *pTITail;
3961       SLTG_MemberHeader *pMemHeader;
3962
3963       if(strcmp(pBlkEntry[order].index_string + (char*)pMagic,
3964                 pOtherTypeInfoBlks[i].index_name)) {
3965         FIXME_(typelib)("Index strings don't match\n");
3966         return NULL;
3967       }
3968
3969       pTIHeader = pBlk;
3970       if(pTIHeader->magic != SLTG_TIHEADER_MAGIC) {
3971         FIXME_(typelib)("TypeInfoHeader magic = %04x\n", pTIHeader->magic);
3972         return NULL;
3973       }
3974       TRACE_(typelib)("pTIHeader->res06 = %x, pTIHeader->res0e = %x, "
3975         "pTIHeader->res16 = %x, pTIHeader->res1e = %x\n",
3976         pTIHeader->res06, pTIHeader->res0e, pTIHeader->res16, pTIHeader->res1e);
3977
3978       *ppTypeInfoImpl = (ITypeInfoImpl*)ITypeInfo_Constructor();
3979       (*ppTypeInfoImpl)->pTypeLib = pTypeLibImpl;
3980       (*ppTypeInfoImpl)->index = i;
3981       (*ppTypeInfoImpl)->Name = TLB_MultiByteToBSTR(
3982                                              pOtherTypeInfoBlks[i].name_offs +
3983                                              pNameTable);
3984       (*ppTypeInfoImpl)->dwHelpContext = pOtherTypeInfoBlks[i].helpcontext;
3985       (*ppTypeInfoImpl)->TypeAttr.guid = pOtherTypeInfoBlks[i].uuid;
3986       (*ppTypeInfoImpl)->TypeAttr.typekind = pTIHeader->typekind;
3987       (*ppTypeInfoImpl)->TypeAttr.wMajorVerNum = pTIHeader->major_version;
3988       (*ppTypeInfoImpl)->TypeAttr.wMinorVerNum = pTIHeader->minor_version;
3989       (*ppTypeInfoImpl)->TypeAttr.wTypeFlags =
3990         (pTIHeader->typeflags1 >> 3) | (pTIHeader->typeflags2 << 5);
3991
3992       if((*ppTypeInfoImpl)->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL)
3993         (*ppTypeInfoImpl)->TypeAttr.typekind = TKIND_DISPATCH;
3994
3995       if((pTIHeader->typeflags1 & 7) != 2)
3996         FIXME_(typelib)("typeflags1 = %02x\n", pTIHeader->typeflags1);
3997       if(pTIHeader->typeflags3 != 2)
3998         FIXME_(typelib)("typeflags3 = %02x\n", pTIHeader->typeflags3);
3999
4000       TRACE_(typelib)("TypeInfo %s of kind %s guid %s typeflags %04x\n",
4001             debugstr_w((*ppTypeInfoImpl)->Name),
4002             typekind_desc[pTIHeader->typekind],
4003             debugstr_guid(&(*ppTypeInfoImpl)->TypeAttr.guid),
4004             (*ppTypeInfoImpl)->TypeAttr.wTypeFlags);
4005
4006       pMemHeader = (SLTG_MemberHeader*)((char *)pBlk + pTIHeader->elem_table);
4007
4008       pTITail = (SLTG_TypeInfoTail*)((char *)(pMemHeader + 1) + pMemHeader->cbExtra);
4009
4010       (*ppTypeInfoImpl)->TypeAttr.cbAlignment = pTITail->cbAlignment;
4011       (*ppTypeInfoImpl)->TypeAttr.cbSizeInstance = pTITail->cbSizeInstance;
4012       (*ppTypeInfoImpl)->TypeAttr.cbSizeVft = pTITail->cbSizeVft;
4013
4014       switch(pTIHeader->typekind) {
4015       case TKIND_ENUM:
4016         SLTG_ProcessEnum((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
4017                          pTIHeader, pTITail);
4018         break;
4019
4020       case TKIND_RECORD:
4021         SLTG_ProcessRecord((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
4022                            pTIHeader, pTITail);
4023         break;
4024
4025       case TKIND_INTERFACE:
4026         SLTG_ProcessInterface((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
4027                               pTIHeader, pTITail);
4028         break;
4029
4030       case TKIND_COCLASS:
4031         SLTG_ProcessCoClass((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
4032                             pTIHeader, pTITail);
4033         break;
4034
4035       case TKIND_ALIAS:
4036         SLTG_ProcessAlias((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
4037                           pTIHeader, pTITail);
4038         break;
4039
4040       case TKIND_DISPATCH:
4041         SLTG_ProcessDispatch((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
4042                              pTIHeader, pTITail);
4043         break;
4044
4045       case TKIND_MODULE:
4046         SLTG_ProcessModule((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
4047                            pTIHeader, pTITail);
4048         break;
4049
4050       default:
4051         FIXME("Not processing typekind %d\n", pTIHeader->typekind);
4052         break;
4053
4054       }
4055
4056       /* could get cFuncs, cVars and cImplTypes from here
4057                        but we've already set those */
4058 #define X(x) TRACE_(typelib)("tt "#x": %x\n",pTITail->res##x);
4059       X(06);
4060       X(16);
4061       X(18);
4062       X(1a);
4063       X(1e);
4064       X(24);
4065       X(26);
4066       X(2a);
4067       X(2c);
4068       X(2e);
4069       X(30);
4070       X(32);
4071       X(34);
4072 #undef X
4073       ppTypeInfoImpl = &((*ppTypeInfoImpl)->next);
4074       pBlk = (char*)pBlk + pBlkEntry[order].len;
4075     }
4076
4077     if(i != pTypeLibImpl->TypeInfoCount) {
4078       FIXME("Somehow processed %d TypeInfos\n", i);
4079       return NULL;
4080     }
4081
4082     HeapFree(GetProcessHeap(), 0, pOtherTypeInfoBlks);
4083     return (ITypeLib2*)pTypeLibImpl;
4084 }
4085
4086 /* ITypeLib::QueryInterface
4087  */
4088 static HRESULT WINAPI ITypeLib2_fnQueryInterface(
4089         ITypeLib2 * iface,
4090         REFIID riid,
4091         VOID **ppvObject)
4092 {
4093     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4094
4095     TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
4096
4097     *ppvObject=NULL;
4098     if(IsEqualIID(riid, &IID_IUnknown) ||
4099        IsEqualIID(riid,&IID_ITypeLib)||
4100        IsEqualIID(riid,&IID_ITypeLib2))
4101     {
4102         *ppvObject = This;
4103     }
4104
4105     if(*ppvObject)
4106     {
4107         ITypeLib2_AddRef(iface);
4108         TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
4109         return S_OK;
4110     }
4111     TRACE("-- Interface: E_NOINTERFACE\n");
4112     return E_NOINTERFACE;
4113 }
4114
4115 /* ITypeLib::AddRef
4116  */
4117 static ULONG WINAPI ITypeLib2_fnAddRef( ITypeLib2 *iface)
4118 {
4119     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4120     ULONG ref = InterlockedIncrement(&This->ref);
4121
4122     TRACE("(%p)->ref was %u\n",This, ref - 1);
4123
4124     return ref;
4125 }
4126
4127 /* ITypeLib::Release
4128  */
4129 static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface)
4130 {
4131     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4132     ULONG ref = InterlockedDecrement(&This->ref);
4133
4134     TRACE("(%p)->(%u)\n",This, ref);
4135
4136     if (!ref)
4137     {
4138       TLBImpLib *pImpLib, *pImpLibNext;
4139       TLBCustData *pCustData, *pCustDataNext;
4140       TLBRefType *ref_type;
4141       void *cursor2;
4142       int i;
4143       ITypeInfoImpl *pTI, *pTINext;
4144
4145       /* remove cache entry */
4146       if(This->path)
4147       {
4148           TRACE("removing from cache list\n");
4149           EnterCriticalSection(&cache_section);
4150           if (This->next) This->next->prev = This->prev;
4151           if (This->prev) This->prev->next = This->next;
4152           else tlb_cache_first = This->next;
4153           LeaveCriticalSection(&cache_section);
4154           HeapFree(GetProcessHeap(), 0, This->path);
4155       }
4156       TRACE(" destroying ITypeLib(%p)\n",This);
4157
4158       SysFreeString(This->Name);
4159       This->Name = NULL;
4160
4161       SysFreeString(This->DocString);
4162       This->DocString = NULL;
4163
4164       SysFreeString(This->HelpFile);
4165       This->HelpFile = NULL;
4166
4167       SysFreeString(This->HelpStringDll);
4168       This->HelpStringDll = NULL;
4169
4170       for (pCustData = This->pCustData; pCustData; pCustData = pCustDataNext)
4171       {
4172           VariantClear(&pCustData->data);
4173
4174           pCustDataNext = pCustData->next;
4175           TLB_Free(pCustData);
4176       }
4177
4178       for (i = 0; i < This->ctTypeDesc; i++)
4179           if (This->pTypeDesc[i].vt == VT_CARRAY)
4180               TLB_Free(This->pTypeDesc[i].u.lpadesc);
4181
4182       TLB_Free(This->pTypeDesc);
4183
4184       for (pImpLib = This->pImpLibs; pImpLib; pImpLib = pImpLibNext)
4185       {
4186           if (pImpLib->pImpTypeLib)
4187               ITypeLib_Release((ITypeLib *)pImpLib->pImpTypeLib);
4188           SysFreeString(pImpLib->name);
4189
4190           pImpLibNext = pImpLib->next;
4191           TLB_Free(pImpLib);
4192       }
4193
4194       LIST_FOR_EACH_ENTRY_SAFE(ref_type, cursor2, &This->ref_list, TLBRefType, entry)
4195       {
4196           list_remove(&ref_type->entry);
4197           TLB_Free(ref_type);
4198       }
4199
4200       for (pTI = This->pTypeInfo; pTI; pTI = pTINext)
4201       {
4202           pTINext = pTI->next;
4203           ITypeInfo_fnDestroy(pTI);
4204       }
4205       HeapFree(GetProcessHeap(),0,This);
4206       return 0;
4207     }
4208
4209     return ref;
4210 }
4211
4212 /* ITypeLib::GetTypeInfoCount
4213  *
4214  * Returns the number of type descriptions in the type library
4215  */
4216 static UINT WINAPI ITypeLib2_fnGetTypeInfoCount( ITypeLib2 *iface)
4217 {
4218     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4219     TRACE("(%p)->count is %d\n",This, This->TypeInfoCount);
4220     return This->TypeInfoCount;
4221 }
4222
4223 /* ITypeLib::GetTypeInfo
4224  *
4225  * retrieves the specified type description in the library.
4226  */
4227 static HRESULT WINAPI ITypeLib2_fnGetTypeInfo(
4228     ITypeLib2 *iface,
4229     UINT index,
4230     ITypeInfo **ppTInfo)
4231 {
4232     UINT i;
4233
4234     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4235     ITypeInfoImpl *pTypeInfo = This->pTypeInfo;
4236
4237     TRACE("(%p)->(index=%d)\n", This, index);
4238
4239     if (!ppTInfo) return E_INVALIDARG;
4240
4241     /* search element n in list */
4242     for(i=0; i < index; i++)
4243     {
4244       pTypeInfo = pTypeInfo->next;
4245       if (!pTypeInfo)
4246       {
4247         TRACE("-- element not found\n");
4248         return TYPE_E_ELEMENTNOTFOUND;
4249       }
4250     }
4251
4252     *ppTInfo = (ITypeInfo *) pTypeInfo;
4253
4254     ITypeInfo_AddRef(*ppTInfo);
4255     TRACE("-- found (%p)\n",*ppTInfo);
4256     return S_OK;
4257 }
4258
4259
4260 /* ITypeLibs::GetTypeInfoType
4261  *
4262  * Retrieves the type of a type description.
4263  */
4264 static HRESULT WINAPI ITypeLib2_fnGetTypeInfoType(
4265     ITypeLib2 *iface,
4266     UINT index,
4267     TYPEKIND *pTKind)
4268 {
4269     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4270     UINT i;
4271     ITypeInfoImpl *pTInfo = This->pTypeInfo;
4272
4273     TRACE("(%p, %d, %p)\n", This, index, pTKind);
4274
4275     if(!pTKind) return E_INVALIDARG;
4276
4277     if(ITypeLib2_GetTypeInfoCount(iface) <= index)
4278         return TYPE_E_ELEMENTNOTFOUND;
4279
4280     /* search element n in list */
4281     for(i=0; i < index; i++)
4282     {
4283       if(!pTInfo)
4284       {
4285         TRACE("-- element not found\n");
4286         return TYPE_E_ELEMENTNOTFOUND;
4287       }
4288       pTInfo = pTInfo->next;
4289     }
4290
4291     *pTKind = pTInfo->TypeAttr.typekind;
4292     TRACE("-- found Type (%d)\n", *pTKind);
4293     return S_OK;
4294 }
4295
4296 /* ITypeLib::GetTypeInfoOfGuid
4297  *
4298  * Retrieves the type description that corresponds to the specified GUID.
4299  *
4300  */
4301 static HRESULT WINAPI ITypeLib2_fnGetTypeInfoOfGuid(
4302     ITypeLib2 *iface,
4303     REFGUID guid,
4304     ITypeInfo **ppTInfo)
4305 {
4306     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4307     ITypeInfoImpl *pTypeInfo = This->pTypeInfo; /* head of list */
4308
4309     TRACE("(%p)\n\tguid:\t%s)\n",This,debugstr_guid(guid));
4310
4311     if (!pTypeInfo)
4312     {
4313         WARN("-- element not found\n");
4314         return TYPE_E_ELEMENTNOTFOUND;
4315     }
4316
4317     /* search linked list for guid */
4318     while( !IsEqualIID(guid,&pTypeInfo->TypeAttr.guid) )
4319     {
4320       pTypeInfo = pTypeInfo->next;
4321
4322       if (!pTypeInfo)
4323       {
4324         /* end of list reached */
4325         WARN("-- element not found\n");
4326         return TYPE_E_ELEMENTNOTFOUND;
4327       }
4328     }
4329
4330     TRACE("-- found (%p, %s)\n",
4331           pTypeInfo,
4332           debugstr_w(pTypeInfo->Name));
4333
4334     *ppTInfo = (ITypeInfo*)pTypeInfo;
4335     ITypeInfo_AddRef(*ppTInfo);
4336     return S_OK;
4337 }
4338
4339 /* ITypeLib::GetLibAttr
4340  *
4341  * Retrieves the structure that contains the library's attributes.
4342  *
4343  */
4344 static HRESULT WINAPI ITypeLib2_fnGetLibAttr(
4345         ITypeLib2 *iface,
4346         LPTLIBATTR *attr)
4347 {
4348     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4349
4350     TRACE("(%p, %p)\n", This, attr);
4351
4352     if (!attr) return E_INVALIDARG;
4353
4354     *attr = HeapAlloc(GetProcessHeap(), 0, sizeof(**attr));
4355     if (!*attr) return E_OUTOFMEMORY;
4356
4357     **attr = This->LibAttr;
4358     return S_OK;
4359 }
4360
4361 /* ITypeLib::GetTypeComp
4362  *
4363  * Enables a client compiler to bind to a library's types, variables,
4364  * constants, and global functions.
4365  *
4366  */
4367 static HRESULT WINAPI ITypeLib2_fnGetTypeComp(
4368         ITypeLib2 *iface,
4369         ITypeComp **ppTComp)
4370 {
4371     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4372
4373     TRACE("(%p)->(%p)\n",This,ppTComp);
4374     *ppTComp = (ITypeComp *)&This->lpVtblTypeComp;
4375     ITypeComp_AddRef(*ppTComp);
4376
4377     return S_OK;
4378 }
4379
4380 /* ITypeLib::GetDocumentation
4381  *
4382  * Retrieves the library's documentation string, the complete Help file name
4383  * and path, and the context identifier for the library Help topic in the Help
4384  * file.
4385  *
4386  * On a successful return all non-null BSTR pointers will have been set,
4387  * possibly to NULL.
4388  */
4389 static HRESULT WINAPI ITypeLib2_fnGetDocumentation(
4390     ITypeLib2 *iface,
4391     INT index,
4392     BSTR *pBstrName,
4393     BSTR *pBstrDocString,
4394     DWORD *pdwHelpContext,
4395     BSTR *pBstrHelpFile)
4396 {
4397     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4398
4399     HRESULT result = E_INVALIDARG;
4400
4401     ITypeInfo *pTInfo;
4402
4403
4404     TRACE("(%p) index %d Name(%p) DocString(%p) HelpContext(%p) HelpFile(%p)\n",
4405         This, index,
4406         pBstrName, pBstrDocString,
4407         pdwHelpContext, pBstrHelpFile);
4408
4409     if(index<0)
4410     {
4411         /* documentation for the typelib */
4412         if(pBstrName)
4413         {
4414             if (This->Name)
4415             {
4416                 if(!(*pBstrName = SysAllocString(This->Name)))
4417                     goto memerr1;
4418             }
4419             else
4420                 *pBstrName = NULL;
4421         }
4422         if(pBstrDocString)
4423         {
4424             if (This->DocString)
4425             {
4426                 if(!(*pBstrDocString = SysAllocString(This->DocString)))
4427                     goto memerr2;
4428             }
4429             else if (This->Name)
4430             {
4431                 if(!(*pBstrDocString = SysAllocString(This->Name)))
4432                     goto memerr2;
4433             }
4434             else
4435                 *pBstrDocString = NULL;
4436         }
4437         if(pdwHelpContext)
4438         {
4439             *pdwHelpContext = This->dwHelpContext;
4440         }
4441         if(pBstrHelpFile)
4442         {
4443             if (This->HelpFile)
4444             {
4445                 if(!(*pBstrHelpFile = SysAllocString(This->HelpFile)))
4446                     goto memerr3;
4447             }
4448             else
4449                 *pBstrHelpFile = NULL;
4450         }
4451
4452         result = S_OK;
4453     }
4454     else
4455     {
4456         /* for a typeinfo */
4457         result = ITypeLib2_fnGetTypeInfo(iface, index, &pTInfo);
4458
4459         if(SUCCEEDED(result))
4460         {
4461             result = ITypeInfo_GetDocumentation(pTInfo,
4462                                           MEMBERID_NIL,
4463                                           pBstrName,
4464                                           pBstrDocString,
4465                                           pdwHelpContext, pBstrHelpFile);
4466
4467             ITypeInfo_Release(pTInfo);
4468         }
4469     }
4470     return result;
4471 memerr3:
4472     if (pBstrDocString) SysFreeString (*pBstrDocString);
4473 memerr2:
4474     if (pBstrName) SysFreeString (*pBstrName);
4475 memerr1:
4476     return STG_E_INSUFFICIENTMEMORY;
4477 }
4478
4479 /* ITypeLib::IsName
4480  *
4481  * Indicates whether a passed-in string contains the name of a type or member
4482  * described in the library.
4483  *
4484  */
4485 static HRESULT WINAPI ITypeLib2_fnIsName(
4486         ITypeLib2 *iface,
4487         LPOLESTR szNameBuf,
4488         ULONG lHashVal,
4489         BOOL *pfName)
4490 {
4491     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4492     ITypeInfoImpl *pTInfo;
4493     TLBFuncDesc *pFInfo;
4494     TLBVarDesc *pVInfo;
4495     int i;
4496     UINT nNameBufLen = (lstrlenW(szNameBuf)+1)*sizeof(WCHAR);
4497
4498     TRACE("(%p)->(%s,%08x,%p)\n", This, debugstr_w(szNameBuf), lHashVal,
4499           pfName);
4500
4501     *pfName=TRUE;
4502     for(pTInfo=This->pTypeInfo;pTInfo;pTInfo=pTInfo->next){
4503         if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
4504         for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
4505             if(!memcmp(szNameBuf,pFInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
4506             for(i=0;i<pFInfo->funcdesc.cParams;i++)
4507                 if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name, nNameBufLen))
4508                     goto ITypeLib2_fnIsName_exit;
4509         }
4510         for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next)
4511             if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
4512
4513     }
4514     *pfName=FALSE;
4515
4516 ITypeLib2_fnIsName_exit:
4517     TRACE("(%p)slow! search for %s: %s found!\n", This,
4518           debugstr_w(szNameBuf), *pfName?"NOT":"");
4519
4520     return S_OK;
4521 }
4522
4523 /* ITypeLib::FindName
4524  *
4525  * Finds occurrences of a type description in a type library. This may be used
4526  * to quickly verify that a name exists in a type library.
4527  *
4528  */
4529 static HRESULT WINAPI ITypeLib2_fnFindName(
4530         ITypeLib2 *iface,
4531         LPOLESTR szNameBuf,
4532         ULONG lHashVal,
4533         ITypeInfo **ppTInfo,
4534         MEMBERID *rgMemId,
4535         UINT16 *pcFound)
4536 {
4537     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4538     ITypeInfoImpl *pTInfo;
4539     TLBFuncDesc *pFInfo;
4540     TLBVarDesc *pVInfo;
4541     int i,j = 0;
4542     UINT nNameBufLen = (lstrlenW(szNameBuf)+1)*sizeof(WCHAR);
4543
4544     for(pTInfo=This->pTypeInfo;pTInfo && j<*pcFound; pTInfo=pTInfo->next){
4545         if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit;
4546         for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
4547             if(!memcmp(szNameBuf,pFInfo->Name,nNameBufLen)) goto ITypeLib2_fnFindName_exit;
4548             for(i=0;i<pFInfo->funcdesc.cParams;i++) {
4549                 if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name,nNameBufLen))
4550                     goto ITypeLib2_fnFindName_exit;
4551             }
4552         }
4553         for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next)
4554             if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit;
4555         continue;
4556 ITypeLib2_fnFindName_exit:
4557         ITypeInfo_AddRef((ITypeInfo*)pTInfo);
4558         ppTInfo[j]=(LPTYPEINFO)pTInfo;
4559         j++;
4560     }
4561     TRACE("(%p)slow! search for %d with %s: found %d TypeInfo's!\n",
4562           This, *pcFound, debugstr_w(szNameBuf), j);
4563
4564     *pcFound=j;
4565
4566     return S_OK;
4567 }
4568
4569 /* ITypeLib::ReleaseTLibAttr
4570  *
4571  * Releases the TLIBATTR originally obtained from ITypeLib::GetLibAttr.
4572  *
4573  */
4574 static VOID WINAPI ITypeLib2_fnReleaseTLibAttr(
4575         ITypeLib2 *iface,
4576         TLIBATTR *pTLibAttr)
4577 {
4578     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4579     TRACE("freeing (%p)\n",This);
4580     HeapFree(GetProcessHeap(),0,pTLibAttr);
4581
4582 }
4583
4584 /* ITypeLib2::GetCustData
4585  *
4586  * gets the custom data
4587  */
4588 static HRESULT WINAPI ITypeLib2_fnGetCustData(
4589         ITypeLib2 * iface,
4590         REFGUID guid,
4591         VARIANT *pVarVal)
4592 {
4593     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4594     TLBCustData *pCData;
4595
4596     for(pCData=This->pCustData; pCData; pCData = pCData->next)
4597     {
4598       if( IsEqualIID(guid, &pCData->guid)) break;
4599     }
4600
4601     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
4602
4603     if(pCData)
4604     {
4605         VariantInit( pVarVal);
4606         VariantCopy( pVarVal, &pCData->data);
4607         return S_OK;
4608     }
4609     return E_INVALIDARG;  /* FIXME: correct? */
4610 }
4611
4612 /* ITypeLib2::GetLibStatistics
4613  *
4614  * Returns statistics about a type library that are required for efficient
4615  * sizing of hash tables.
4616  *
4617  */
4618 static HRESULT WINAPI ITypeLib2_fnGetLibStatistics(
4619         ITypeLib2 * iface,
4620         ULONG *pcUniqueNames,
4621         ULONG *pcchUniqueNames)
4622 {
4623     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4624
4625     FIXME("(%p): stub!\n", This);
4626
4627     if(pcUniqueNames) *pcUniqueNames=1;
4628     if(pcchUniqueNames) *pcchUniqueNames=1;
4629     return S_OK;
4630 }
4631
4632 /* ITypeLib2::GetDocumentation2
4633  *
4634  * Retrieves the library's documentation string, the complete Help file name
4635  * and path, the localization context to use, and the context ID for the
4636  * library Help topic in the Help file.
4637  *
4638  */
4639 static HRESULT WINAPI ITypeLib2_fnGetDocumentation2(
4640         ITypeLib2 * iface,
4641         INT index,
4642         LCID lcid,
4643         BSTR *pbstrHelpString,
4644         DWORD *pdwHelpStringContext,
4645         BSTR *pbstrHelpStringDll)
4646 {
4647     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4648     HRESULT result;
4649     ITypeInfo *pTInfo;
4650
4651     FIXME("(%p) index %d lcid %d half implemented stub!\n", This, index, lcid);
4652
4653     /* the help string should be obtained from the helpstringdll,
4654      * using the _DLLGetDocumentation function, based on the supplied
4655      * lcid. Nice to do sometime...
4656      */
4657     if(index<0)
4658     {
4659       /* documentation for the typelib */
4660       if(pbstrHelpString)
4661         *pbstrHelpString=SysAllocString(This->DocString);
4662       if(pdwHelpStringContext)
4663         *pdwHelpStringContext=This->dwHelpContext;
4664       if(pbstrHelpStringDll)
4665         *pbstrHelpStringDll=SysAllocString(This->HelpStringDll);
4666
4667       result = S_OK;
4668     }
4669     else
4670     {
4671       /* for a typeinfo */
4672       result=ITypeLib2_GetTypeInfo(iface, index, &pTInfo);
4673
4674       if(SUCCEEDED(result))
4675       {
4676         ITypeInfo2 * pTInfo2;
4677         result = ITypeInfo_QueryInterface(pTInfo,
4678                                           &IID_ITypeInfo2,
4679                                           (LPVOID*) &pTInfo2);
4680
4681         if(SUCCEEDED(result))
4682         {
4683           result = ITypeInfo2_GetDocumentation2(pTInfo2,
4684                                            MEMBERID_NIL,
4685                                            lcid,
4686                                            pbstrHelpString,
4687                                            pdwHelpStringContext,
4688                                            pbstrHelpStringDll);
4689
4690           ITypeInfo2_Release(pTInfo2);
4691         }
4692
4693         ITypeInfo_Release(pTInfo);
4694       }
4695     }
4696     return result;
4697 }
4698
4699 /* ITypeLib2::GetAllCustData
4700  *
4701  * Gets all custom data items for the library.
4702  *
4703  */
4704 static HRESULT WINAPI ITypeLib2_fnGetAllCustData(
4705         ITypeLib2 * iface,
4706         CUSTDATA *pCustData)
4707 {
4708     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4709     TLBCustData *pCData;
4710     int i;
4711     TRACE("(%p) returning %d items\n", This, This->ctCustData);
4712     pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
4713     if(pCustData->prgCustData ){
4714         pCustData->cCustData=This->ctCustData;
4715         for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
4716             pCustData->prgCustData[i].guid=pCData->guid;
4717             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
4718         }
4719     }else{
4720         ERR(" OUT OF MEMORY!\n");
4721         return E_OUTOFMEMORY;
4722     }
4723     return S_OK;
4724 }
4725
4726 static const ITypeLib2Vtbl tlbvt = {
4727     ITypeLib2_fnQueryInterface,
4728     ITypeLib2_fnAddRef,
4729     ITypeLib2_fnRelease,
4730     ITypeLib2_fnGetTypeInfoCount,
4731     ITypeLib2_fnGetTypeInfo,
4732     ITypeLib2_fnGetTypeInfoType,
4733     ITypeLib2_fnGetTypeInfoOfGuid,
4734     ITypeLib2_fnGetLibAttr,
4735     ITypeLib2_fnGetTypeComp,
4736     ITypeLib2_fnGetDocumentation,
4737     ITypeLib2_fnIsName,
4738     ITypeLib2_fnFindName,
4739     ITypeLib2_fnReleaseTLibAttr,
4740
4741     ITypeLib2_fnGetCustData,
4742     ITypeLib2_fnGetLibStatistics,
4743     ITypeLib2_fnGetDocumentation2,
4744     ITypeLib2_fnGetAllCustData
4745  };
4746
4747
4748 static HRESULT WINAPI ITypeLibComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
4749 {
4750     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4751
4752     return ITypeLib2_QueryInterface((ITypeLib *)This, riid, ppv);
4753 }
4754
4755 static ULONG WINAPI ITypeLibComp_fnAddRef(ITypeComp * iface)
4756 {
4757     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4758
4759     return ITypeLib2_AddRef((ITypeLib2 *)This);
4760 }
4761
4762 static ULONG WINAPI ITypeLibComp_fnRelease(ITypeComp * iface)
4763 {
4764     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4765
4766     return ITypeLib2_Release((ITypeLib2 *)This);
4767 }
4768
4769 static HRESULT WINAPI ITypeLibComp_fnBind(
4770     ITypeComp * iface,
4771     OLECHAR * szName,
4772     ULONG lHash,
4773     WORD wFlags,
4774     ITypeInfo ** ppTInfo,
4775     DESCKIND * pDescKind,
4776     BINDPTR * pBindPtr)
4777 {
4778     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4779     ITypeInfoImpl *pTypeInfo;
4780     int typemismatch=0;
4781
4782     TRACE("(%s, 0x%x, 0x%x, %p, %p, %p)\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
4783
4784     *pDescKind = DESCKIND_NONE;
4785     pBindPtr->lptcomp = NULL;
4786     *ppTInfo = NULL;
4787
4788     for (pTypeInfo = This->pTypeInfo; pTypeInfo; pTypeInfo = pTypeInfo->next)
4789     {
4790         TRACE("testing %s\n", debugstr_w(pTypeInfo->Name));
4791
4792         /* FIXME: check wFlags here? */
4793         /* FIXME: we should use a hash table to look this info up using lHash
4794          * instead of an O(n) search */
4795         if ((pTypeInfo->TypeAttr.typekind == TKIND_ENUM) ||
4796             (pTypeInfo->TypeAttr.typekind == TKIND_MODULE))
4797         {
4798             if (pTypeInfo->Name && !strcmpW(pTypeInfo->Name, szName))
4799             {
4800                 *pDescKind = DESCKIND_TYPECOMP;
4801                 pBindPtr->lptcomp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4802                 ITypeComp_AddRef(pBindPtr->lptcomp);
4803                 TRACE("module or enum: %s\n", debugstr_w(szName));
4804                 return S_OK;
4805             }
4806         }
4807
4808         if ((pTypeInfo->TypeAttr.typekind == TKIND_MODULE) ||
4809             (pTypeInfo->TypeAttr.typekind == TKIND_ENUM))
4810         {
4811             ITypeComp *pSubTypeComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4812             HRESULT hr;
4813
4814             hr = ITypeComp_Bind(pSubTypeComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
4815             if (SUCCEEDED(hr) && (*pDescKind != DESCKIND_NONE))
4816             {
4817                 TRACE("found in module or in enum: %s\n", debugstr_w(szName));
4818                 return S_OK;
4819             }
4820             else if (hr == TYPE_E_TYPEMISMATCH)
4821                 typemismatch = 1;
4822         }
4823
4824         if ((pTypeInfo->TypeAttr.typekind == TKIND_COCLASS) &&
4825             (pTypeInfo->TypeAttr.wTypeFlags & TYPEFLAG_FAPPOBJECT))
4826         {
4827             ITypeComp *pSubTypeComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4828             HRESULT hr;
4829             ITypeInfo *subtypeinfo;
4830             BINDPTR subbindptr;
4831             DESCKIND subdesckind;
4832
4833             hr = ITypeComp_Bind(pSubTypeComp, szName, lHash, wFlags,
4834                 &subtypeinfo, &subdesckind, &subbindptr);
4835             if (SUCCEEDED(hr) && (subdesckind != DESCKIND_NONE))
4836             {
4837                 TYPEDESC tdesc_appobject;
4838                 const VARDESC vardesc_appobject =
4839                 {
4840                     -2,         /* memid */
4841                     NULL,       /* lpstrSchema */
4842                     {
4843                         0       /* oInst */
4844                     },
4845                     {
4846                                 /* ELEMDESC */
4847                         {
4848                                 /* TYPEDESC */
4849                                 {
4850                                     &tdesc_appobject
4851                                 },
4852                                 VT_PTR
4853                         },
4854                     },
4855                     0,          /* wVarFlags */
4856                     VAR_STATIC  /* varkind */
4857                 };
4858
4859                 tdesc_appobject.u.hreftype = pTypeInfo->hreftype;
4860                 tdesc_appobject.vt = VT_USERDEFINED;
4861
4862                 TRACE("found in implicit app object: %s\n", debugstr_w(szName));
4863
4864                 /* cleanup things filled in by Bind call so we can put our
4865                  * application object data in there instead */
4866                 switch (subdesckind)
4867                 {
4868                 case DESCKIND_FUNCDESC:
4869                     ITypeInfo_ReleaseFuncDesc(subtypeinfo, subbindptr.lpfuncdesc);
4870                     break;
4871                 case DESCKIND_VARDESC:
4872                     ITypeInfo_ReleaseVarDesc(subtypeinfo, subbindptr.lpvardesc);
4873                     break;
4874                 default:
4875                     break;
4876                 }
4877                 if (subtypeinfo) ITypeInfo_Release(subtypeinfo);
4878
4879                 if (pTypeInfo->hreftype == -1)
4880                     FIXME("no hreftype for interface %p\n", pTypeInfo);
4881
4882                 hr = TLB_AllocAndInitVarDesc(&vardesc_appobject, &pBindPtr->lpvardesc);
4883                 if (FAILED(hr))
4884                     return hr;
4885
4886                 *pDescKind = DESCKIND_IMPLICITAPPOBJ;
4887                 *ppTInfo = (ITypeInfo *)pTypeInfo;
4888                 ITypeInfo_AddRef(*ppTInfo);
4889                 return S_OK;
4890             }
4891             else if (hr == TYPE_E_TYPEMISMATCH)
4892                 typemismatch = 1;
4893         }
4894     }
4895
4896     if (typemismatch)
4897     {
4898         TRACE("type mismatch %s\n", debugstr_w(szName));
4899         return TYPE_E_TYPEMISMATCH;
4900     }
4901     else
4902     {
4903         TRACE("name not found %s\n", debugstr_w(szName));
4904         return S_OK;
4905     }
4906 }
4907
4908 static HRESULT WINAPI ITypeLibComp_fnBindType(
4909     ITypeComp * iface,
4910     OLECHAR * szName,
4911     ULONG lHash,
4912     ITypeInfo ** ppTInfo,
4913     ITypeComp ** ppTComp)
4914 {
4915     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4916     ITypeInfoImpl *pTypeInfo;
4917
4918     TRACE("(%s, %x, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
4919
4920     for (pTypeInfo = This->pTypeInfo; pTypeInfo; pTypeInfo = pTypeInfo->next)
4921     {
4922         /* FIXME: should use lHash to do the search */
4923         if (pTypeInfo->Name && !strcmpW(pTypeInfo->Name, szName))
4924         {
4925             TRACE("returning %p\n", pTypeInfo);
4926             *ppTInfo = (ITypeInfo *)&pTypeInfo->lpVtbl;
4927             ITypeInfo_AddRef(*ppTInfo);
4928             *ppTComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4929             ITypeComp_AddRef(*ppTComp);
4930             return S_OK;
4931         }
4932     }
4933
4934     TRACE("not found\n");
4935     *ppTInfo = NULL;
4936     *ppTComp = NULL;
4937     return S_OK;
4938 }
4939
4940 static const ITypeCompVtbl tlbtcvt =
4941 {
4942
4943     ITypeLibComp_fnQueryInterface,
4944     ITypeLibComp_fnAddRef,
4945     ITypeLibComp_fnRelease,
4946
4947     ITypeLibComp_fnBind,
4948     ITypeLibComp_fnBindType
4949 };
4950
4951 /*================== ITypeInfo(2) Methods ===================================*/
4952 static ITypeInfo2 * ITypeInfo_Constructor(void)
4953 {
4954     ITypeInfoImpl * pTypeInfoImpl;
4955
4956     pTypeInfoImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeInfoImpl));
4957     if (pTypeInfoImpl)
4958     {
4959       pTypeInfoImpl->lpVtbl = &tinfvt;
4960       pTypeInfoImpl->lpVtblTypeComp = &tcompvt;
4961       pTypeInfoImpl->ref = 0;
4962       pTypeInfoImpl->hreftype = -1;
4963       pTypeInfoImpl->TypeAttr.memidConstructor = MEMBERID_NIL;
4964       pTypeInfoImpl->TypeAttr.memidDestructor = MEMBERID_NIL;
4965     }
4966     TRACE("(%p)\n", pTypeInfoImpl);
4967     return (ITypeInfo2*) pTypeInfoImpl;
4968 }
4969
4970 /* ITypeInfo::QueryInterface
4971  */
4972 static HRESULT WINAPI ITypeInfo_fnQueryInterface(
4973         ITypeInfo2 *iface,
4974         REFIID riid,
4975         VOID **ppvObject)
4976 {
4977     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4978
4979     TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
4980
4981     *ppvObject=NULL;
4982     if(IsEqualIID(riid, &IID_IUnknown) ||
4983             IsEqualIID(riid,&IID_ITypeInfo)||
4984             IsEqualIID(riid,&IID_ITypeInfo2))
4985         *ppvObject = This;
4986
4987     if(*ppvObject){
4988         ITypeInfo_AddRef(iface);
4989         TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
4990         return S_OK;
4991     }
4992     TRACE("-- Interface: E_NOINTERFACE\n");
4993     return E_NOINTERFACE;
4994 }
4995
4996 /* ITypeInfo::AddRef
4997  */
4998 static ULONG WINAPI ITypeInfo_fnAddRef( ITypeInfo2 *iface)
4999 {
5000     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5001     ULONG ref = InterlockedIncrement(&This->ref);
5002
5003     TRACE("(%p)->ref is %u\n",This, ref);
5004
5005     if (ref == 1 /* incremented from 0 */)
5006         ITypeLib2_AddRef((ITypeLib2*)This->pTypeLib);
5007
5008     return ref;
5009 }
5010
5011 static void ITypeInfo_fnDestroy(ITypeInfoImpl *This)
5012 {
5013     TLBFuncDesc *pFInfo, *pFInfoNext;
5014     TLBVarDesc *pVInfo, *pVInfoNext;
5015     TLBImplType *pImpl, *pImplNext;
5016
5017     TRACE("destroying ITypeInfo(%p)\n",This);
5018
5019     SysFreeString(This->Name);
5020     This->Name = NULL;
5021
5022     SysFreeString(This->DocString);
5023     This->DocString = NULL;
5024
5025     SysFreeString(This->DllName);
5026     This->DllName = NULL;
5027
5028     for (pFInfo = This->funclist; pFInfo; pFInfo = pFInfoNext)
5029     {
5030         INT i;
5031         for(i = 0;i < pFInfo->funcdesc.cParams; i++)
5032         {
5033             ELEMDESC *elemdesc = &pFInfo->funcdesc.lprgelemdescParam[i];
5034             if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
5035             {
5036                 VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue);
5037                 TLB_Free(elemdesc->u.paramdesc.pparamdescex);
5038             }
5039             SysFreeString(pFInfo->pParamDesc[i].Name);
5040         }
5041         TLB_Free(pFInfo->funcdesc.lprgelemdescParam);
5042         TLB_Free(pFInfo->pParamDesc);
5043         TLB_FreeCustData(pFInfo->pCustData);
5044         if (!IS_INTRESOURCE(pFInfo->Entry) && pFInfo->Entry != (BSTR)-1)
5045             SysFreeString(pFInfo->Entry);
5046         SysFreeString(pFInfo->HelpString);
5047         SysFreeString(pFInfo->Name);
5048
5049         pFInfoNext = pFInfo->next;
5050         TLB_Free(pFInfo);
5051     }
5052     for (pVInfo = This->varlist; pVInfo; pVInfo = pVInfoNext)
5053     {
5054         if (pVInfo->vardesc.varkind == VAR_CONST)
5055         {
5056             VariantClear(pVInfo->vardesc.u.lpvarValue);
5057             TLB_Free(pVInfo->vardesc.u.lpvarValue);
5058         }
5059         TLB_FreeCustData(pVInfo->pCustData);
5060         SysFreeString(pVInfo->Name);
5061         pVInfoNext = pVInfo->next;
5062         TLB_Free(pVInfo);
5063     }
5064     for (pImpl = This->impltypelist; pImpl; pImpl = pImplNext)
5065     {
5066         TLB_FreeCustData(pImpl->pCustData);
5067         pImplNext = pImpl->next;
5068         TLB_Free(pImpl);
5069     }
5070     TLB_FreeCustData(This->pCustData);
5071
5072     HeapFree(GetProcessHeap(), 0, This);
5073 }
5074
5075 /* ITypeInfo::Release
5076  */
5077 static ULONG WINAPI ITypeInfo_fnRelease(ITypeInfo2 *iface)
5078 {
5079     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5080     ULONG ref = InterlockedDecrement(&This->ref);
5081
5082     TRACE("(%p)->(%u)\n",This, ref);
5083
5084     if (!ref)
5085     {
5086         BOOL not_attached_to_typelib = This->not_attached_to_typelib;
5087         ITypeLib2_Release((ITypeLib2*)This->pTypeLib);
5088         if (not_attached_to_typelib)
5089             HeapFree(GetProcessHeap(), 0, This);
5090         /* otherwise This will be freed when typelib is freed */
5091     }
5092
5093     return ref;
5094 }
5095
5096 /* ITypeInfo::GetTypeAttr
5097  *
5098  * Retrieves a TYPEATTR structure that contains the attributes of the type
5099  * description.
5100  *
5101  */
5102 static HRESULT WINAPI ITypeInfo_fnGetTypeAttr( ITypeInfo2 *iface,
5103         LPTYPEATTR  *ppTypeAttr)
5104 {
5105     const ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5106     SIZE_T size;
5107
5108     TRACE("(%p)\n",This);
5109
5110     size = sizeof(**ppTypeAttr);
5111     if (This->TypeAttr.typekind == TKIND_ALIAS)
5112         size += TLB_SizeTypeDesc(&This->TypeAttr.tdescAlias, FALSE);
5113
5114     *ppTypeAttr = HeapAlloc(GetProcessHeap(), 0, size);
5115     if (!*ppTypeAttr)
5116         return E_OUTOFMEMORY;
5117
5118     **ppTypeAttr = This->TypeAttr;
5119
5120     if (This->TypeAttr.typekind == TKIND_ALIAS)
5121         TLB_CopyTypeDesc(&(*ppTypeAttr)->tdescAlias,
5122             &This->TypeAttr.tdescAlias, *ppTypeAttr + 1);
5123
5124     if((*ppTypeAttr)->typekind == TKIND_DISPATCH) {
5125         /* This should include all the inherited funcs */
5126         (*ppTypeAttr)->cFuncs = (*ppTypeAttr)->cbSizeVft / sizeof(void *);
5127         (*ppTypeAttr)->cbSizeVft = 7 * sizeof(void *); /* This is always the size of IDispatch's vtbl */
5128         (*ppTypeAttr)->wTypeFlags &= ~TYPEFLAG_FOLEAUTOMATION;
5129     }
5130     return S_OK;
5131 }
5132
5133 /* ITypeInfo::GetTypeComp
5134  *
5135  * Retrieves the ITypeComp interface for the type description, which enables a
5136  * client compiler to bind to the type description's members.
5137  *
5138  */
5139 static HRESULT WINAPI ITypeInfo_fnGetTypeComp( ITypeInfo2 *iface,
5140         ITypeComp  * *ppTComp)
5141 {
5142     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5143
5144     TRACE("(%p)->(%p)\n", This, ppTComp);
5145
5146     *ppTComp = (ITypeComp *)&This->lpVtblTypeComp;
5147     ITypeComp_AddRef(*ppTComp);
5148     return S_OK;
5149 }
5150
5151 static SIZE_T TLB_SizeElemDesc( const ELEMDESC *elemdesc )
5152 {
5153     SIZE_T size = TLB_SizeTypeDesc(&elemdesc->tdesc, FALSE);
5154     if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
5155         size += sizeof(*elemdesc->u.paramdesc.pparamdescex);
5156     return size;
5157 }
5158
5159 static HRESULT TLB_CopyElemDesc( const ELEMDESC *src, ELEMDESC *dest, char **buffer )
5160 {
5161     *dest = *src;
5162     *buffer = TLB_CopyTypeDesc(&dest->tdesc, &src->tdesc, *buffer);
5163     if (src->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
5164     {
5165         const PARAMDESCEX *pparamdescex_src = src->u.paramdesc.pparamdescex;
5166         PARAMDESCEX *pparamdescex_dest = dest->u.paramdesc.pparamdescex = (PARAMDESCEX *)*buffer;
5167         *buffer += sizeof(PARAMDESCEX);
5168         *pparamdescex_dest = *pparamdescex_src;
5169         VariantInit(&pparamdescex_dest->varDefaultValue);
5170         return VariantCopy(&pparamdescex_dest->varDefaultValue, 
5171                            (VARIANTARG *)&pparamdescex_src->varDefaultValue);
5172     }
5173     else
5174         dest->u.paramdesc.pparamdescex = NULL;
5175     return S_OK;
5176 }
5177
5178 static void TLB_FreeElemDesc( ELEMDESC *elemdesc )
5179 {
5180     if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
5181         VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue);
5182 }
5183
5184 static HRESULT TLB_AllocAndInitFuncDesc( const FUNCDESC *src, FUNCDESC **dest_ptr, BOOL dispinterface )
5185 {
5186     FUNCDESC *dest;
5187     char *buffer;
5188     SIZE_T size = sizeof(*src);
5189     SHORT i;
5190     HRESULT hr;
5191
5192     size += sizeof(*src->lprgscode) * src->cScodes;
5193     size += TLB_SizeElemDesc(&src->elemdescFunc);
5194     for (i = 0; i < src->cParams; i++)
5195     {
5196         size += sizeof(ELEMDESC);
5197         size += TLB_SizeElemDesc(&src->lprgelemdescParam[i]);
5198     }
5199
5200     dest = (FUNCDESC *)SysAllocStringByteLen(NULL, size);
5201     if (!dest) return E_OUTOFMEMORY;
5202
5203     *dest = *src;
5204     if (dispinterface)    /* overwrite funckind */
5205         dest->funckind = FUNC_DISPATCH;
5206     buffer = (char *)(dest + 1);
5207
5208     dest->lprgscode = (SCODE *)buffer;
5209     memcpy(dest->lprgscode, src->lprgscode, sizeof(*src->lprgscode) * src->cScodes);
5210     buffer += sizeof(*src->lprgscode) * src->cScodes;
5211
5212     hr = TLB_CopyElemDesc(&src->elemdescFunc, &dest->elemdescFunc, &buffer);
5213     if (FAILED(hr))
5214     {
5215         SysFreeString((BSTR)dest);
5216         return hr;
5217     }
5218
5219     dest->lprgelemdescParam = (ELEMDESC *)buffer;
5220     buffer += sizeof(ELEMDESC) * src->cParams;
5221     for (i = 0; i < src->cParams; i++)
5222     {
5223         hr = TLB_CopyElemDesc(&src->lprgelemdescParam[i], &dest->lprgelemdescParam[i], &buffer);
5224         if (FAILED(hr))
5225             break;
5226     }
5227     if (FAILED(hr))
5228     {
5229         /* undo the above actions */
5230         for (i = i - 1; i >= 0; i--)
5231             TLB_FreeElemDesc(&dest->lprgelemdescParam[i]);
5232         TLB_FreeElemDesc(&dest->elemdescFunc);
5233         SysFreeString((BSTR)dest);
5234         return hr;
5235     }
5236
5237     /* special treatment for dispinterfaces: this makes functions appear
5238      * to return their [retval] value when it is really returning an
5239      * HRESULT */
5240     if (dispinterface && dest->elemdescFunc.tdesc.vt == VT_HRESULT)
5241     {
5242         if (dest->cParams &&
5243             (dest->lprgelemdescParam[dest->cParams - 1].u.paramdesc.wParamFlags & PARAMFLAG_FRETVAL))
5244         {
5245             ELEMDESC *elemdesc = &dest->lprgelemdescParam[dest->cParams - 1];
5246             if (elemdesc->tdesc.vt != VT_PTR)
5247             {
5248                 ERR("elemdesc should have started with VT_PTR instead of:\n");
5249                 if (ERR_ON(ole))
5250                     dump_ELEMDESC(elemdesc);
5251                 return E_UNEXPECTED;
5252             }
5253
5254             /* copy last parameter to the return value. we are using a flat
5255              * buffer so there is no danger of leaking memory in
5256              * elemdescFunc */
5257             dest->elemdescFunc.tdesc = *elemdesc->tdesc.u.lptdesc;
5258
5259             /* remove the last parameter */
5260             dest->cParams--;
5261         }
5262         else
5263             /* otherwise this function is made to appear to have no return
5264              * value */
5265             dest->elemdescFunc.tdesc.vt = VT_VOID;
5266
5267     }
5268
5269     *dest_ptr = dest;
5270     return S_OK;
5271 }
5272
5273 HRESULT ITypeInfoImpl_GetInternalFuncDesc( ITypeInfo *iface, UINT index, const FUNCDESC **ppFuncDesc )
5274 {
5275     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5276     const TLBFuncDesc *pFDesc;
5277     UINT i;
5278
5279     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++, pFDesc=pFDesc->next)
5280         ;
5281
5282     if (pFDesc)
5283     {
5284         *ppFuncDesc = &pFDesc->funcdesc;
5285         return S_OK;
5286     }
5287
5288     return TYPE_E_ELEMENTNOTFOUND;
5289 }
5290
5291 /* internal function to make the inherited interfaces' methods appear
5292  * part of the interface */
5293 static HRESULT ITypeInfoImpl_GetInternalDispatchFuncDesc( ITypeInfo *iface,
5294     UINT index, const FUNCDESC **ppFuncDesc, UINT *funcs, UINT *hrefoffset)
5295 {
5296     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5297     HRESULT hr;
5298     UINT implemented_funcs = 0;
5299
5300     if (funcs)
5301         *funcs = 0;
5302     else
5303         *hrefoffset = DISPATCH_HREF_OFFSET;
5304
5305     if(This->impltypelist)
5306     {
5307         ITypeInfo *pSubTypeInfo;
5308         UINT sub_funcs;
5309
5310         hr = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef, &pSubTypeInfo);
5311         if (FAILED(hr))
5312             return hr;
5313
5314         hr = ITypeInfoImpl_GetInternalDispatchFuncDesc(pSubTypeInfo,
5315                                                        index,
5316                                                        ppFuncDesc,
5317                                                        &sub_funcs, hrefoffset);
5318         implemented_funcs += sub_funcs;
5319         ITypeInfo_Release(pSubTypeInfo);
5320         if (SUCCEEDED(hr))
5321             return hr;
5322         *hrefoffset += DISPATCH_HREF_OFFSET;
5323     }
5324
5325     if (funcs)
5326         *funcs = implemented_funcs + This->TypeAttr.cFuncs;
5327     else
5328         *hrefoffset = 0;
5329     
5330     if (index < implemented_funcs)
5331         return E_INVALIDARG;
5332     return ITypeInfoImpl_GetInternalFuncDesc(iface, index - implemented_funcs,
5333                                              ppFuncDesc);
5334 }
5335
5336 static inline void ITypeInfoImpl_ElemDescAddHrefOffset( LPELEMDESC pElemDesc, UINT hrefoffset)
5337 {
5338     TYPEDESC *pTypeDesc = &pElemDesc->tdesc;
5339     while (TRUE)
5340     {
5341         switch (pTypeDesc->vt)
5342         {
5343         case VT_USERDEFINED:
5344             pTypeDesc->u.hreftype += hrefoffset;
5345             return;
5346         case VT_PTR:
5347         case VT_SAFEARRAY:
5348             pTypeDesc = pTypeDesc->u.lptdesc;
5349             break;
5350         case VT_CARRAY:
5351             pTypeDesc = &pTypeDesc->u.lpadesc->tdescElem;
5352             break;
5353         default:
5354             return;
5355         }
5356     }
5357 }
5358
5359 static inline void ITypeInfoImpl_FuncDescAddHrefOffset( LPFUNCDESC pFuncDesc, UINT hrefoffset)
5360 {
5361     SHORT i;
5362     for (i = 0; i < pFuncDesc->cParams; i++)
5363         ITypeInfoImpl_ElemDescAddHrefOffset(&pFuncDesc->lprgelemdescParam[i], hrefoffset);
5364     ITypeInfoImpl_ElemDescAddHrefOffset(&pFuncDesc->elemdescFunc, hrefoffset);
5365 }
5366
5367 /* ITypeInfo::GetFuncDesc
5368  *
5369  * Retrieves the FUNCDESC structure that contains information about a
5370  * specified function.
5371  *
5372  */
5373 static HRESULT WINAPI ITypeInfo_fnGetFuncDesc( ITypeInfo2 *iface, UINT index,
5374         LPFUNCDESC  *ppFuncDesc)
5375 {
5376     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5377     const FUNCDESC *internal_funcdesc;
5378     HRESULT hr;
5379     UINT hrefoffset = 0;
5380
5381     TRACE("(%p) index %d\n", This, index);
5382
5383     if (This->TypeAttr.typekind == TKIND_DISPATCH)
5384         hr = ITypeInfoImpl_GetInternalDispatchFuncDesc((ITypeInfo *)iface, index,
5385                                                        &internal_funcdesc, NULL,
5386                                                        &hrefoffset);
5387     else
5388         hr = ITypeInfoImpl_GetInternalFuncDesc((ITypeInfo *)iface, index,
5389                                                &internal_funcdesc);
5390     if (FAILED(hr))
5391     {
5392         WARN("description for function %d not found\n", index);
5393         return hr;
5394     }
5395
5396     hr = TLB_AllocAndInitFuncDesc(
5397         internal_funcdesc,
5398         ppFuncDesc,
5399         This->TypeAttr.typekind == TKIND_DISPATCH);
5400
5401     if ((This->TypeAttr.typekind == TKIND_DISPATCH) && hrefoffset)
5402         ITypeInfoImpl_FuncDescAddHrefOffset(*ppFuncDesc, hrefoffset);
5403
5404     TRACE("-- 0x%08x\n", hr);
5405     return hr;
5406 }
5407
5408 static HRESULT TLB_AllocAndInitVarDesc( const VARDESC *src, VARDESC **dest_ptr )
5409 {
5410     VARDESC *dest;
5411     char *buffer;
5412     SIZE_T size = sizeof(*src);
5413     HRESULT hr;
5414
5415     if (src->lpstrSchema) size += (strlenW(src->lpstrSchema) + 1) * sizeof(WCHAR);
5416     if (src->varkind == VAR_CONST)
5417         size += sizeof(VARIANT);
5418     size += TLB_SizeElemDesc(&src->elemdescVar);
5419
5420     dest = (VARDESC *)SysAllocStringByteLen(NULL, size);
5421     if (!dest) return E_OUTOFMEMORY;
5422
5423     *dest = *src;
5424     buffer = (char *)(dest + 1);
5425     if (src->lpstrSchema)
5426     {
5427         int len;
5428         dest->lpstrSchema = (LPOLESTR)buffer;
5429         len = strlenW(src->lpstrSchema);
5430         memcpy(dest->lpstrSchema, src->lpstrSchema, (len + 1) * sizeof(WCHAR));
5431         buffer += (len + 1) * sizeof(WCHAR);
5432     }
5433
5434     if (src->varkind == VAR_CONST)
5435     {
5436         HRESULT hr;
5437
5438         dest->u.lpvarValue = (VARIANT *)buffer;
5439         *dest->u.lpvarValue = *src->u.lpvarValue;
5440         buffer += sizeof(VARIANT);
5441         VariantInit(dest->u.lpvarValue);
5442         hr = VariantCopy(dest->u.lpvarValue, src->u.lpvarValue);
5443         if (FAILED(hr))
5444         {
5445             SysFreeString((BSTR)dest);
5446             return hr;
5447         }
5448     }
5449     hr = TLB_CopyElemDesc(&src->elemdescVar, &dest->elemdescVar, &buffer);
5450     if (FAILED(hr))
5451     {
5452         if (src->varkind == VAR_CONST)
5453             VariantClear(dest->u.lpvarValue);
5454         SysFreeString((BSTR)dest);
5455         return hr;
5456     }
5457     *dest_ptr = dest;
5458     return S_OK;
5459 }
5460
5461 /* ITypeInfo::GetVarDesc
5462  *
5463  * Retrieves a VARDESC structure that describes the specified variable.
5464  *
5465  */
5466 static HRESULT WINAPI ITypeInfo_fnGetVarDesc( ITypeInfo2 *iface, UINT index,
5467         LPVARDESC  *ppVarDesc)
5468 {
5469     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5470     UINT i;
5471     const TLBVarDesc *pVDesc;
5472
5473     TRACE("(%p) index %d\n", This, index);
5474
5475     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next)
5476         ;
5477
5478     if (pVDesc)
5479         return TLB_AllocAndInitVarDesc(&pVDesc->vardesc, ppVarDesc);
5480
5481     return E_INVALIDARG;
5482 }
5483
5484 /* ITypeInfo_GetNames
5485  *
5486  * Retrieves the variable with the specified member ID (or the name of the
5487  * property or method and its parameters) that correspond to the specified
5488  * function ID.
5489  */
5490 static HRESULT WINAPI ITypeInfo_fnGetNames( ITypeInfo2 *iface, MEMBERID memid,
5491         BSTR  *rgBstrNames, UINT cMaxNames, UINT  *pcNames)
5492 {
5493     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5494     const TLBFuncDesc *pFDesc;
5495     const TLBVarDesc *pVDesc;
5496     int i;
5497     TRACE("(%p) memid=0x%08x Maxname=%d\n", This, memid, cMaxNames);
5498     for(pFDesc=This->funclist; pFDesc && pFDesc->funcdesc.memid != memid; pFDesc=pFDesc->next);
5499     if(pFDesc)
5500     {
5501       /* function found, now return function and parameter names */
5502       for(i=0; i<cMaxNames && i <= pFDesc->funcdesc.cParams; i++)
5503       {
5504         if(!i)
5505           *rgBstrNames=SysAllocString(pFDesc->Name);
5506         else
5507           rgBstrNames[i]=SysAllocString(pFDesc->pParamDesc[i-1].Name);
5508       }
5509       *pcNames=i;
5510     }
5511     else
5512     {
5513       for(pVDesc=This->varlist; pVDesc && pVDesc->vardesc.memid != memid; pVDesc=pVDesc->next);
5514       if(pVDesc)
5515       {
5516         *rgBstrNames=SysAllocString(pVDesc->Name);
5517         *pcNames=1;
5518       }
5519       else
5520       {
5521         if(This->impltypelist &&
5522            (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
5523           /* recursive search */
5524           ITypeInfo *pTInfo;
5525           HRESULT result;
5526           result=ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef,
5527                                           &pTInfo);
5528           if(SUCCEEDED(result))
5529           {
5530             result=ITypeInfo_GetNames(pTInfo, memid, rgBstrNames, cMaxNames, pcNames);
5531             ITypeInfo_Release(pTInfo);
5532             return result;
5533           }
5534           WARN("Could not search inherited interface!\n");
5535         }
5536         else
5537         {
5538           WARN("no names found\n");
5539         }
5540         *pcNames=0;
5541         return TYPE_E_ELEMENTNOTFOUND;
5542       }
5543     }
5544     return S_OK;
5545 }
5546
5547
5548 /* ITypeInfo::GetRefTypeOfImplType
5549  *
5550  * If a type description describes a COM class, it retrieves the type
5551  * description of the implemented interface types. For an interface,
5552  * GetRefTypeOfImplType returns the type information for inherited interfaces,
5553  * if any exist.
5554  *
5555  */
5556 static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType(
5557         ITypeInfo2 *iface,
5558         UINT index,
5559         HREFTYPE  *pRefType)
5560 {
5561     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5562     UINT i;
5563     HRESULT hr = S_OK;
5564     const TLBImplType *pImpl = This->impltypelist;
5565
5566     TRACE("(%p) index %d\n", This, index);
5567     if (TRACE_ON(ole)) dump_TypeInfo(This);
5568
5569     if(index==(UINT)-1)
5570     {
5571       /* only valid on dual interfaces;
5572          retrieve the associated TKIND_INTERFACE handle for the current TKIND_DISPATCH
5573       */
5574       if( This->TypeAttr.typekind != TKIND_DISPATCH) return E_INVALIDARG;
5575
5576       if (This->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL)
5577       {
5578         *pRefType = -1;
5579       }
5580       else
5581       {
5582         hr = TYPE_E_ELEMENTNOTFOUND;
5583       }
5584     }
5585     else if(index == 0 && This->TypeAttr.typekind == TKIND_DISPATCH)
5586     {
5587       /* All TKIND_DISPATCHs are made to look like they inherit from IDispatch */
5588       *pRefType = This->pTypeLib->dispatch_href;
5589     }
5590     else
5591     {
5592       /* get element n from linked list */
5593       for(i=0; pImpl && i<index; i++)
5594       {
5595         pImpl = pImpl->next;
5596       }
5597
5598       if (pImpl)
5599         *pRefType = pImpl->hRef;
5600       else
5601         hr = TYPE_E_ELEMENTNOTFOUND;
5602     }
5603
5604     if(TRACE_ON(ole))
5605     {
5606         if(SUCCEEDED(hr))
5607             TRACE("SUCCESS -- hRef = 0x%08x\n", *pRefType );
5608         else
5609             TRACE("FAILURE -- hresult = 0x%08x\n", hr);
5610     }
5611
5612     return hr;
5613 }
5614
5615 /* ITypeInfo::GetImplTypeFlags
5616  *
5617  * Retrieves the IMPLTYPEFLAGS enumeration for one implemented interface
5618  * or base interface in a type description.
5619  */
5620 static HRESULT WINAPI ITypeInfo_fnGetImplTypeFlags( ITypeInfo2 *iface,
5621         UINT index, INT  *pImplTypeFlags)
5622 {
5623     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5624     UINT i;
5625     TLBImplType *pImpl;
5626
5627     TRACE("(%p) index %d\n", This, index);
5628     for(i=0, pImpl=This->impltypelist; i<index && pImpl;
5629         i++, pImpl=pImpl->next)
5630         ;
5631     if(i==index && pImpl){
5632         *pImplTypeFlags=pImpl->implflags;
5633         return S_OK;
5634     }
5635     *pImplTypeFlags=0;
5636
5637     if(This->TypeAttr.typekind==TKIND_DISPATCH && !index)
5638         return S_OK;
5639
5640     WARN("ImplType %d not found\n", index);
5641     return TYPE_E_ELEMENTNOTFOUND;
5642 }
5643
5644 /* GetIDsOfNames
5645  * Maps between member names and member IDs, and parameter names and
5646  * parameter IDs.
5647  */
5648 static HRESULT WINAPI ITypeInfo_fnGetIDsOfNames( ITypeInfo2 *iface,
5649         LPOLESTR  *rgszNames, UINT cNames, MEMBERID  *pMemId)
5650 {
5651     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5652     const TLBFuncDesc *pFDesc;
5653     const TLBVarDesc *pVDesc;
5654     HRESULT ret=S_OK;
5655     UINT i;
5656
5657     TRACE("(%p) Name %s cNames %d\n", This, debugstr_w(*rgszNames),
5658             cNames);
5659
5660     /* init out parameters in case of failure */
5661     for (i = 0; i < cNames; i++)
5662         pMemId[i] = MEMBERID_NIL;
5663
5664     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next) {
5665         int j;
5666         if(!lstrcmpiW(*rgszNames, pFDesc->Name)) {
5667             if(cNames) *pMemId=pFDesc->funcdesc.memid;
5668             for(i=1; i < cNames; i++){
5669                 for(j=0; j<pFDesc->funcdesc.cParams; j++)
5670                     if(!lstrcmpiW(rgszNames[i],pFDesc->pParamDesc[j].Name))
5671                             break;
5672                 if( j<pFDesc->funcdesc.cParams)
5673                     pMemId[i]=j;
5674                 else
5675                    ret=DISP_E_UNKNOWNNAME;
5676             };
5677             TRACE("-- 0x%08x\n", ret);
5678             return ret;
5679         }
5680     }
5681     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) {
5682         if(!lstrcmpiW(*rgszNames, pVDesc->Name)) {
5683             if(cNames) *pMemId=pVDesc->vardesc.memid;
5684             return ret;
5685         }
5686     }
5687     /* not found, see if it can be found in an inherited interface */
5688     if(This->impltypelist) {
5689         /* recursive search */
5690         ITypeInfo *pTInfo;
5691         ret=ITypeInfo_GetRefTypeInfo(iface,
5692                 This->impltypelist->hRef, &pTInfo);
5693         if(SUCCEEDED(ret)){
5694             ret=ITypeInfo_GetIDsOfNames(pTInfo, rgszNames, cNames, pMemId );
5695             ITypeInfo_Release(pTInfo);
5696             return ret;
5697         }
5698         WARN("Could not search inherited interface!\n");
5699     } else
5700         WARN("no names found\n");
5701     return DISP_E_UNKNOWNNAME;
5702 }
5703
5704
5705 #ifdef __i386__
5706
5707 extern LONGLONG call_method( void *func, int nb_args, const DWORD *args, int *stack_offset );
5708 __ASM_GLOBAL_FUNC( call_method,
5709                    "pushl %ebp\n\t"
5710                    __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
5711                    __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
5712                    "movl %esp,%ebp\n\t"
5713                    __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
5714                    "pushl %esi\n\t"
5715                   __ASM_CFI(".cfi_rel_offset %esi,-4\n\t")
5716                    "pushl %edi\n\t"
5717                   __ASM_CFI(".cfi_rel_offset %edi,-8\n\t")
5718                    "movl 12(%ebp),%edx\n\t"
5719                    "movl %esp,%edi\n\t"
5720                    "shll $2,%edx\n\t"
5721                    "jz 1f\n\t"
5722                    "subl %edx,%edi\n\t"
5723                    "andl $~15,%edi\n\t"
5724                    "movl %edi,%esp\n\t"
5725                    "movl 12(%ebp),%ecx\n\t"
5726                    "movl 16(%ebp),%esi\n\t"
5727                    "cld\n\t"
5728                    "rep; movsl\n"
5729                    "1:\tcall *8(%ebp)\n\t"
5730                    "subl %esp,%edi\n\t"
5731                    "movl 20(%ebp),%ecx\n\t"
5732                    "movl %edi,(%ecx)\n\t"
5733                    "leal -8(%ebp),%esp\n\t"
5734                    "popl %edi\n\t"
5735                    __ASM_CFI(".cfi_same_value %edi\n\t")
5736                    "popl %esi\n\t"
5737                    __ASM_CFI(".cfi_same_value %esi\n\t")
5738                    "popl %ebp\n\t"
5739                    __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
5740                    __ASM_CFI(".cfi_same_value %ebp\n\t")
5741                    "ret" )
5742
5743 /* same function but returning floating point */
5744 static double (* const call_double_method)(void*,int,const DWORD*,int*) = (void *)call_method;
5745
5746 /* ITypeInfo::Invoke
5747  *
5748  * Invokes a method, or accesses a property of an object, that implements the
5749  * interface described by the type description.
5750  */
5751 DWORD
5752 _invoke(FARPROC func,CALLCONV callconv, int nrargs, DWORD *args) {
5753     DWORD res;
5754     int stack_offset;
5755
5756     if (TRACE_ON(ole)) {
5757         int i;
5758         TRACE("Calling %p(",func);
5759         for (i=0;i<min(nrargs,30);i++) TRACE("%08x,",args[i]);
5760         if (nrargs > 30) TRACE("...");
5761         TRACE(")\n");
5762     }
5763
5764     switch (callconv) {
5765     case CC_STDCALL:
5766     case CC_CDECL:
5767         res = call_method( func, nrargs, args, &stack_offset );
5768         break;
5769     default:
5770         FIXME("unsupported calling convention %d\n",callconv);
5771         res = -1;
5772         break;
5773     }
5774     TRACE("returns %08x\n",res);
5775     return res;
5776 }
5777
5778 #elif defined(__x86_64__)
5779
5780 extern DWORD_PTR CDECL call_method( void *func, int nb_args, const DWORD_PTR *args );
5781 __ASM_GLOBAL_FUNC( call_method,
5782                    "pushq %rbp\n\t"
5783                    __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t")
5784                    __ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
5785                    "movq %rsp,%rbp\n\t"
5786                    __ASM_CFI(".cfi_def_cfa_register %rbp\n\t")
5787                    "pushq %rsi\n\t"
5788                    __ASM_CFI(".cfi_rel_offset %rsi,-8\n\t")
5789                    "pushq %rdi\n\t"
5790                    __ASM_CFI(".cfi_rel_offset %rdi,-16\n\t")
5791                    "movq %rcx,%rax\n\t"
5792                    "movq $4,%rcx\n\t"
5793                    "cmp %rcx,%rdx\n\t"
5794                    "cmovgq %rdx,%rcx\n\t"
5795                    "leaq 0(,%rcx,8),%rdx\n\t"
5796                    "subq %rdx,%rsp\n\t"
5797                    "andq $~15,%rsp\n\t"
5798                    "movq %rsp,%rdi\n\t"
5799                    "movq %r8,%rsi\n\t"
5800                    "rep; movsq\n\t"
5801                    "movq 0(%rsp),%rcx\n\t"
5802                    "movq 8(%rsp),%rdx\n\t"
5803                    "movq 16(%rsp),%r8\n\t"
5804                    "movq 24(%rsp),%r9\n\t"
5805                    "movq %rcx,%xmm0\n\t"
5806                    "movq %rdx,%xmm1\n\t"
5807                    "movq %r8,%xmm2\n\t"
5808                    "movq %r9,%xmm3\n\t"
5809                    "callq *%rax\n\t"
5810                    "leaq -16(%rbp),%rsp\n\t"
5811                    "popq %rdi\n\t"
5812                    __ASM_CFI(".cfi_same_value %rdi\n\t")
5813                    "popq %rsi\n\t"
5814                    __ASM_CFI(".cfi_same_value %rsi\n\t")
5815                    __ASM_CFI(".cfi_def_cfa_register %rsp\n\t")
5816                    "popq %rbp\n\t"
5817                    __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t")
5818                    __ASM_CFI(".cfi_same_value %rbp\n\t")
5819                    "ret")
5820
5821 /* same function but returning floating point */
5822 static double (CDECL * const call_double_method)(void*,int,const DWORD_PTR*) = (void *)call_method;
5823
5824 #endif  /* __x86_64__ */
5825
5826 static HRESULT userdefined_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
5827 {
5828     HRESULT hr = S_OK;
5829     ITypeInfo *tinfo2 = NULL;
5830     TYPEATTR *tattr = NULL;
5831
5832     hr = ITypeInfo_GetRefTypeInfo(tinfo, tdesc->u.hreftype, &tinfo2);
5833     if (hr)
5834     {
5835         ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED, "
5836             "hr = 0x%08x\n",
5837               tdesc->u.hreftype, hr);
5838         return hr;
5839     }
5840     hr = ITypeInfo_GetTypeAttr(tinfo2, &tattr);
5841     if (hr)
5842     {
5843         ERR("ITypeInfo_GetTypeAttr failed, hr = 0x%08x\n", hr);
5844         ITypeInfo_Release(tinfo2);
5845         return hr;
5846     }
5847
5848     switch (tattr->typekind)
5849     {
5850     case TKIND_ENUM:
5851         *vt |= VT_I4;
5852         break;
5853
5854     case TKIND_ALIAS:
5855         tdesc = &tattr->tdescAlias;
5856         hr = typedescvt_to_variantvt(tinfo2, &tattr->tdescAlias, vt);
5857         break;
5858
5859     case TKIND_INTERFACE:
5860         if (tattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE)
5861            *vt |= VT_DISPATCH;
5862         else
5863            *vt |= VT_UNKNOWN;
5864         break;
5865
5866     case TKIND_DISPATCH:
5867         *vt |= VT_DISPATCH;
5868         break;
5869
5870     case TKIND_COCLASS:
5871         *vt |= VT_DISPATCH;
5872         break;
5873
5874     case TKIND_RECORD:
5875         FIXME("TKIND_RECORD unhandled.\n");
5876         hr = E_NOTIMPL;
5877         break;
5878
5879     case TKIND_UNION:
5880         FIXME("TKIND_UNION unhandled.\n");
5881         hr = E_NOTIMPL;
5882         break;
5883
5884     default:
5885         FIXME("TKIND %d unhandled.\n",tattr->typekind);
5886         hr = E_NOTIMPL;
5887         break;
5888     }
5889     ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
5890     ITypeInfo_Release(tinfo2);
5891     return hr;
5892 }
5893
5894 static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
5895 {
5896     HRESULT hr = S_OK;
5897
5898     /* enforce only one level of pointer indirection */
5899     if (!(*vt & VT_BYREF) && !(*vt & VT_ARRAY) && (tdesc->vt == VT_PTR))
5900     {
5901         tdesc = tdesc->u.lptdesc;
5902
5903         /* munch VT_PTR -> VT_USERDEFINED(interface) into VT_UNKNOWN or
5904          * VT_DISPATCH and VT_PTR -> VT_PTR -> VT_USERDEFINED(interface) into 
5905          * VT_BYREF|VT_DISPATCH or VT_BYREF|VT_UNKNOWN */
5906         if ((tdesc->vt == VT_USERDEFINED) ||
5907             ((tdesc->vt == VT_PTR) && (tdesc->u.lptdesc->vt == VT_USERDEFINED)))
5908         {
5909             VARTYPE vt_userdefined = 0;
5910             const TYPEDESC *tdesc_userdefined = tdesc;
5911             if (tdesc->vt == VT_PTR)
5912             {
5913                 vt_userdefined = VT_BYREF;
5914                 tdesc_userdefined = tdesc->u.lptdesc;
5915             }
5916             hr = userdefined_to_variantvt(tinfo, tdesc_userdefined, &vt_userdefined);
5917             if ((hr == S_OK) && 
5918                 (((vt_userdefined & VT_TYPEMASK) == VT_UNKNOWN) ||
5919                  ((vt_userdefined & VT_TYPEMASK) == VT_DISPATCH)))
5920             {
5921                 *vt |= vt_userdefined;
5922                 return S_OK;
5923             }
5924         }
5925         *vt = VT_BYREF;
5926     }
5927
5928     switch (tdesc->vt)
5929     {
5930     case VT_HRESULT:
5931         *vt |= VT_ERROR;
5932         break;
5933     case VT_USERDEFINED:
5934         hr = userdefined_to_variantvt(tinfo, tdesc, vt);
5935         break;
5936     case VT_VOID:
5937     case VT_CARRAY:
5938     case VT_PTR:
5939     case VT_LPSTR:
5940     case VT_LPWSTR:
5941         ERR("cannot convert type %d into variant VT\n", tdesc->vt);
5942         hr = DISP_E_BADVARTYPE;
5943         break;
5944     case VT_SAFEARRAY:
5945         *vt |= VT_ARRAY;
5946         hr = typedescvt_to_variantvt(tinfo, tdesc->u.lptdesc, vt);
5947         break;
5948     case VT_INT:
5949         *vt |= VT_I4;
5950         break;
5951     case VT_UINT:
5952         *vt |= VT_UI4;
5953         break;
5954     default:
5955         *vt |= tdesc->vt;
5956         break;
5957     }
5958     return hr;
5959 }
5960
5961 /***********************************************************************
5962  *              DispCallFunc (OLEAUT32.@)
5963  *
5964  * Invokes a function of the specified calling convention, passing the
5965  * specified arguments and returns the result.
5966  *
5967  * PARAMS
5968  *  pvInstance  [I] Optional pointer to the instance whose function to invoke.
5969  *  oVft        [I] The offset in the vtable. See notes.
5970  *  cc          [I] Calling convention of the function to call.
5971  *  vtReturn    [I] The return type of the function.
5972  *  cActuals    [I] Number of parameters.
5973  *  prgvt       [I] The types of the parameters to pass. This is used for sizing only.
5974  *  prgpvarg    [I] The arguments to pass.
5975  *  pvargResult [O] The return value of the function. Can be NULL.
5976  *
5977  * RETURNS
5978  *  Success: S_OK.
5979  *  Failure: HRESULT code.
5980  *
5981  * NOTES
5982  *  The HRESULT return value of this function is not affected by the return
5983  *  value of the user supplied function, which is returned in pvargResult.
5984  *
5985  *  If pvInstance is NULL then a non-object function is to be called and oVft
5986  *  is the address of the function to call.
5987  *
5988  * The cc parameter can be one of the following values:
5989  *|CC_FASTCALL
5990  *|CC_CDECL
5991  *|CC_PASCAL
5992  *|CC_STDCALL
5993  *|CC_FPFASTCALL
5994  *|CC_SYSCALL
5995  *|CC_MPWCDECL
5996  *|CC_MPWPASCAL
5997  *
5998  */
5999 HRESULT WINAPI
6000 DispCallFunc(
6001     void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals,
6002     VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult)
6003 {
6004 #ifdef __i386__
6005     int argspos, stack_offset;
6006     void *func;
6007     UINT i;
6008     DWORD *args;
6009
6010     TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
6011         pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
6012         pvargResult, V_VT(pvargResult));
6013
6014     if (cc != CC_STDCALL && cc != CC_CDECL)
6015     {
6016         FIXME("unsupported calling convention %d\n",cc);
6017         return E_INVALIDARG;
6018     }
6019
6020     /* maximum size for an argument is sizeof(VARIANT) */
6021     args = HeapAlloc( GetProcessHeap(), 0, sizeof(VARIANT) * cActuals + sizeof(DWORD) * 2 );
6022
6023     /* start at 1 in case we need to pass a pointer to the return value as arg 0 */
6024     argspos = 1;
6025     if (pvInstance)
6026     {
6027         const FARPROC *vtable = *(FARPROC **)pvInstance;
6028         func = vtable[oVft/sizeof(void *)];
6029         args[argspos++] = (DWORD)pvInstance; /* the This pointer is always the first parameter */
6030     }
6031     else func = (void *)oVft;
6032
6033     for (i = 0; i < cActuals; i++)
6034     {
6035         VARIANT *arg = prgpvarg[i];
6036
6037         switch (prgvt[i])
6038         {
6039         case VT_EMPTY:
6040             break;
6041         case VT_I8:
6042         case VT_UI8:
6043         case VT_R8:
6044         case VT_DATE:
6045         case VT_CY:
6046             memcpy( &args[argspos], &V_I8(arg), sizeof(V_I8(arg)) );
6047             argspos += sizeof(V_I8(arg)) / sizeof(DWORD);
6048             break;
6049         case VT_DECIMAL:
6050         case VT_VARIANT:
6051             memcpy( &args[argspos], arg, sizeof(*arg) );
6052             argspos += sizeof(*arg) / sizeof(DWORD);
6053             break;
6054         case VT_BOOL:  /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
6055             args[argspos++] = V_BOOL(arg);
6056             break;
6057         default:
6058             args[argspos++] = V_UI4(arg);
6059             break;
6060         }
6061         TRACE("arg %u: type %d\n",i,prgvt[i]);
6062         dump_Variant(arg);
6063     }
6064
6065     switch (vtReturn)
6066     {
6067     case VT_EMPTY:
6068         call_method( func, argspos - 1, args + 1, &stack_offset );
6069         break;
6070     case VT_R4:
6071         V_R4(pvargResult) = call_double_method( func, argspos - 1, args + 1, &stack_offset );
6072         break;
6073     case VT_R8:
6074     case VT_DATE:
6075         V_R8(pvargResult) = call_double_method( func, argspos - 1, args + 1, &stack_offset );
6076         break;
6077     case VT_DECIMAL:
6078     case VT_VARIANT:
6079         args[0] = (DWORD)pvargResult;  /* arg 0 is a pointer to the result */
6080         call_method( func, argspos, args, &stack_offset );
6081         break;
6082     case VT_I8:
6083     case VT_UI8:
6084     case VT_CY:
6085         V_UI8(pvargResult) = call_method( func, argspos - 1, args + 1, &stack_offset );
6086         break;
6087     default:
6088         V_UI4(pvargResult) = call_method( func, argspos - 1, args + 1, &stack_offset );
6089         break;
6090     }
6091     HeapFree( GetProcessHeap(), 0, args );
6092     if (stack_offset && cc == CC_STDCALL)
6093     {
6094         WARN( "stack pointer off by %d\n", stack_offset );
6095         return DISP_E_BADCALLEE;
6096     }
6097     if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
6098     TRACE("retval: "); dump_Variant(pvargResult);
6099     return S_OK;
6100
6101 #elif defined(__x86_64__)
6102     int argspos;
6103     UINT i;
6104     DWORD_PTR *args;
6105     void *func;
6106
6107     TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
6108           pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
6109           pvargResult, V_VT(pvargResult));
6110
6111     if (cc != CC_STDCALL && cc != CC_CDECL)
6112     {
6113         FIXME("unsupported calling convention %d\n",cc);
6114         return E_INVALIDARG;
6115     }
6116
6117     /* maximum size for an argument is sizeof(DWORD_PTR) */
6118     args = HeapAlloc( GetProcessHeap(), 0, sizeof(DWORD_PTR) * (cActuals + 2) );
6119
6120     /* start at 1 in case we need to pass a pointer to the return value as arg 0 */
6121     argspos = 1;
6122     if (pvInstance)
6123     {
6124         const FARPROC *vtable = *(FARPROC **)pvInstance;
6125         func = vtable[oVft/sizeof(void *)];
6126         args[argspos++] = (DWORD_PTR)pvInstance; /* the This pointer is always the first parameter */
6127     }
6128     else func = (void *)oVft;
6129
6130     for (i = 0; i < cActuals; i++)
6131     {
6132         VARIANT *arg = prgpvarg[i];
6133
6134         switch (prgvt[i])
6135         {
6136         case VT_DECIMAL:
6137         case VT_VARIANT:
6138             args[argspos++] = (ULONG_PTR)arg;
6139             break;
6140         case VT_BOOL:  /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
6141             args[argspos++] = V_BOOL(arg);
6142             break;
6143         default:
6144             args[argspos++] = V_UI8(arg);
6145             break;
6146         }
6147         TRACE("arg %u: type %d\n",i,prgvt[i]);
6148         dump_Variant(arg);
6149     }
6150
6151     switch (vtReturn)
6152     {
6153     case VT_R4:
6154         V_R4(pvargResult) = call_double_method( func, argspos - 1, args + 1 );
6155         break;
6156     case VT_R8:
6157     case VT_DATE:
6158         V_R8(pvargResult) = call_double_method( func, argspos - 1, args + 1 );
6159         break;
6160     case VT_DECIMAL:
6161     case VT_VARIANT:
6162         args[0] = (DWORD_PTR)pvargResult;  /* arg 0 is a pointer to the result */
6163         call_method( func, argspos, args );
6164         break;
6165     default:
6166         V_UI8(pvargResult) = call_method( func, argspos - 1, args + 1 );
6167         break;
6168     }
6169     HeapFree( GetProcessHeap(), 0, args );
6170     if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
6171     TRACE("retval: "); dump_Variant(pvargResult);
6172     return S_OK;
6173
6174 #else
6175     FIXME( "(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d)): not implemented for this CPU\n",
6176            pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg, pvargResult, V_VT(pvargResult));
6177     return E_NOTIMPL;
6178 #endif
6179 }
6180
6181 #define INVBUF_ELEMENT_SIZE \
6182     (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *) + sizeof(VARTYPE))
6183 #define INVBUF_GET_ARG_ARRAY(buffer, params) (buffer)
6184 #define INVBUF_GET_MISSING_ARG_ARRAY(buffer, params) \
6185     ((VARIANTARG *)((char *)(buffer) + sizeof(VARIANTARG) * (params)))
6186 #define INVBUF_GET_ARG_PTR_ARRAY(buffer, params) \
6187     ((VARIANTARG **)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG)) * (params)))
6188 #define INVBUF_GET_ARG_TYPE_ARRAY(buffer, params) \
6189     ((VARTYPE *)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *)) * (params)))
6190
6191 static HRESULT WINAPI ITypeInfo_fnInvoke(
6192     ITypeInfo2 *iface,
6193     VOID  *pIUnk,
6194     MEMBERID memid,
6195     UINT16 wFlags,
6196     DISPPARAMS  *pDispParams,
6197     VARIANT  *pVarResult,
6198     EXCEPINFO  *pExcepInfo,
6199     UINT  *pArgErr)
6200 {
6201     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6202     int i;
6203     unsigned int var_index;
6204     TYPEKIND type_kind;
6205     HRESULT hres;
6206     const TLBFuncDesc *pFuncInfo;
6207
6208     TRACE("(%p)(%p,id=%d,flags=0x%08x,%p,%p,%p,%p)\n",
6209       This,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr
6210     );
6211
6212     if( This->TypeAttr.wTypeFlags & TYPEFLAG_FRESTRICTED )
6213         return DISP_E_MEMBERNOTFOUND;
6214
6215     if (!pDispParams)
6216     {
6217         ERR("NULL pDispParams not allowed\n");
6218         return E_INVALIDARG;
6219     }
6220
6221     dump_DispParms(pDispParams);
6222
6223     if (pDispParams->cNamedArgs > pDispParams->cArgs)
6224     {
6225         ERR("named argument array cannot be bigger than argument array (%d/%d)\n",
6226             pDispParams->cNamedArgs, pDispParams->cArgs);
6227         return E_INVALIDARG;
6228     }
6229
6230     /* we do this instead of using GetFuncDesc since it will return a fake
6231      * FUNCDESC for dispinterfaces and we want the real function description */
6232     for (pFuncInfo = This->funclist; pFuncInfo; pFuncInfo=pFuncInfo->next)
6233         if ((memid == pFuncInfo->funcdesc.memid) &&
6234             (wFlags & pFuncInfo->funcdesc.invkind) &&
6235             (pFuncInfo->funcdesc.wFuncFlags & FUNCFLAG_FRESTRICTED) == 0)
6236             break;
6237
6238     if (pFuncInfo) {
6239         const FUNCDESC *func_desc = &pFuncInfo->funcdesc;
6240
6241         if (TRACE_ON(ole))
6242         {
6243             TRACE("invoking:\n");
6244             dump_TLBFuncDescOne(pFuncInfo);
6245         }
6246         
6247         switch (func_desc->funckind) {
6248         case FUNC_PUREVIRTUAL:
6249         case FUNC_VIRTUAL: {
6250             void *buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INVBUF_ELEMENT_SIZE * func_desc->cParams);
6251             VARIANT varresult;
6252             VARIANT retval; /* pointer for storing byref retvals in */
6253             VARIANTARG **prgpvarg = INVBUF_GET_ARG_PTR_ARRAY(buffer, func_desc->cParams);
6254             VARIANTARG *rgvarg = INVBUF_GET_ARG_ARRAY(buffer, func_desc->cParams);
6255             VARTYPE *rgvt = INVBUF_GET_ARG_TYPE_ARRAY(buffer, func_desc->cParams);
6256             UINT cNamedArgs = pDispParams->cNamedArgs;
6257             DISPID *rgdispidNamedArgs = pDispParams->rgdispidNamedArgs;
6258             UINT vargs_converted=0;
6259
6260             hres = S_OK;
6261
6262             if (func_desc->invkind & (INVOKE_PROPERTYPUT|INVOKE_PROPERTYPUTREF))
6263             {
6264                 if (!cNamedArgs || (rgdispidNamedArgs[0] != DISPID_PROPERTYPUT))
6265                 {
6266                     ERR("first named arg for property put invocation must be DISPID_PROPERTYPUT\n");
6267                     hres = DISP_E_PARAMNOTFOUND;
6268                     goto func_fail;
6269                 }
6270             }
6271
6272             if (func_desc->cParamsOpt < 0 && cNamedArgs)
6273             {
6274                 ERR("functions with the vararg attribute do not support named arguments\n");
6275                 hres = DISP_E_NONAMEDARGS;
6276                 goto func_fail;
6277             }
6278
6279             for (i = 0; i < func_desc->cParams; i++)
6280             {
6281                 TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc;
6282                 hres = typedescvt_to_variantvt((ITypeInfo *)iface, tdesc, &rgvt[i]);
6283                 if (FAILED(hres))
6284                     goto func_fail;
6285             }
6286
6287             TRACE("changing args\n");
6288             for (i = 0; i < func_desc->cParams; i++)
6289             {
6290                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
6291                 VARIANTARG *src_arg;
6292
6293                 if (wParamFlags & PARAMFLAG_FLCID)
6294                 {
6295                     VARIANTARG *arg;
6296                     arg = prgpvarg[i] = &rgvarg[i];
6297                     V_VT(arg) = VT_I4;
6298                     V_I4(arg) = This->pTypeLib->lcid;
6299                     continue;
6300                 }
6301
6302                 src_arg = NULL;
6303
6304                 if (cNamedArgs)
6305                 {
6306                     USHORT j;
6307                     for (j = 0; j < cNamedArgs; j++)
6308                         if (rgdispidNamedArgs[j] == i || (i == func_desc->cParams-1 && rgdispidNamedArgs[j] == DISPID_PROPERTYPUT))
6309                         {
6310                             src_arg = &pDispParams->rgvarg[j];
6311                             break;
6312                         }
6313                 }
6314
6315                 if (!src_arg && vargs_converted + cNamedArgs < pDispParams->cArgs)
6316                 {
6317                     src_arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted];
6318                     vargs_converted++;
6319                 }
6320
6321                 if (wParamFlags & PARAMFLAG_FRETVAL)
6322                 {
6323                     /* under most conditions the caller is not allowed to
6324                      * pass in a dispparam arg in the index of what would be
6325                      * the retval parameter. however, there is an exception
6326                      * where the extra parameter is used in an extra
6327                      * IDispatch::Invoke below */
6328                     if ((i < pDispParams->cArgs) &&
6329                         ((func_desc->cParams != 1) || !pVarResult ||
6330                          !(func_desc->invkind & INVOKE_PROPERTYGET)))
6331                     {
6332                         hres = DISP_E_BADPARAMCOUNT;
6333                         break;
6334                     }
6335
6336                     /* note: this check is placed so that if the caller passes
6337                      * in a VARIANTARG for the retval we just ignore it, like
6338                      * native does */
6339                     if (i == func_desc->cParams - 1)
6340                     {
6341                         VARIANTARG *arg;
6342                         arg = prgpvarg[i] = &rgvarg[i];
6343                         memset(arg, 0, sizeof(*arg));
6344                         V_VT(arg) = rgvt[i];
6345                         memset(&retval, 0, sizeof(retval));
6346                         V_BYREF(arg) = &retval;
6347                     }
6348                     else
6349                     {
6350                         ERR("[retval] parameter must be the last parameter of the method (%d/%d)\n", i, func_desc->cParams);
6351                         hres = E_UNEXPECTED;
6352                         break;
6353                     }
6354                 }
6355                 else if (src_arg)
6356                 {
6357                     dump_Variant(src_arg);
6358
6359                     if (rgvt[i] == VT_VARIANT)
6360                         hres = VariantCopy(&rgvarg[i], src_arg);
6361                     else if (rgvt[i] == (VT_VARIANT | VT_BYREF))
6362                     {
6363                         if (rgvt[i] == V_VT(src_arg))
6364                             V_VARIANTREF(&rgvarg[i]) = V_VARIANTREF(src_arg);
6365                         else
6366                         {
6367                             VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
6368                             if (wParamFlags & PARAMFLAG_FIN)
6369                                 hres = VariantCopy(&missing_arg[i], src_arg);
6370                             V_VARIANTREF(&rgvarg[i]) = &missing_arg[i];
6371                         }
6372                         V_VT(&rgvarg[i]) = rgvt[i];
6373                     }
6374                     else if (rgvt[i] == (VT_VARIANT | VT_ARRAY) && func_desc->cParamsOpt < 0 && i == func_desc->cParams-1)
6375                     {
6376                         SAFEARRAY *a;
6377                         SAFEARRAYBOUND bound;
6378                         VARIANT *v;
6379                         LONG j;
6380                         bound.lLbound = 0;
6381                         bound.cElements = pDispParams->cArgs-i;
6382                         if (!(a = SafeArrayCreate(VT_VARIANT, 1, &bound)))
6383                         {
6384                             ERR("SafeArrayCreate failed\n");
6385                             break;
6386                         }
6387                         hres = SafeArrayAccessData(a, (LPVOID)&v);
6388                         if (hres != S_OK)
6389                         {
6390                             ERR("SafeArrayAccessData failed with %x\n", hres);
6391                             break;
6392                         }
6393                         for (j = 0; j < bound.cElements; j++)
6394                             VariantCopy(&v[j], &pDispParams->rgvarg[pDispParams->cArgs - 1 - i - j]);
6395                         hres = SafeArrayUnaccessData(a);
6396                         if (hres != S_OK)
6397                         {
6398                             ERR("SafeArrayUnaccessData failed with %x\n", hres);
6399                             break;
6400                         }
6401                         V_ARRAY(&rgvarg[i]) = a;
6402                         V_VT(&rgvarg[i]) = rgvt[i];
6403                     }
6404                     else if ((rgvt[i] & VT_BYREF) && !V_ISBYREF(src_arg))
6405                     {
6406                         VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
6407                         if (wParamFlags & PARAMFLAG_FIN)
6408                             hres = VariantChangeType(&missing_arg[i], src_arg, 0, rgvt[i] & ~VT_BYREF);
6409                         else
6410                             V_VT(&missing_arg[i]) = rgvt[i] & ~VT_BYREF;
6411                         V_BYREF(&rgvarg[i]) = &V_NONE(&missing_arg[i]);
6412                         V_VT(&rgvarg[i]) = rgvt[i];
6413                     }
6414                     else if ((rgvt[i] & VT_BYREF) && (rgvt[i] == V_VT(src_arg)))
6415                     {
6416                         V_BYREF(&rgvarg[i]) = V_BYREF(src_arg);
6417                         V_VT(&rgvarg[i]) = rgvt[i];
6418                     }
6419                     else
6420                     {
6421                         /* FIXME: this doesn't work for VT_BYREF arguments if
6422                          * they are not the same type as in the paramdesc */
6423                         V_VT(&rgvarg[i]) = V_VT(src_arg);
6424                         hres = VariantChangeType(&rgvarg[i], src_arg, 0, rgvt[i]);
6425                         V_VT(&rgvarg[i]) = rgvt[i];
6426                     }
6427
6428                     if (FAILED(hres))
6429                     {
6430                         ERR("failed to convert param %d to %s%s from %s%s\n", i,
6431                             debugstr_vt(rgvt[i]), debugstr_vf(rgvt[i]),
6432                             debugstr_VT(src_arg), debugstr_VF(src_arg));
6433                         break;
6434                     }
6435                     prgpvarg[i] = &rgvarg[i];
6436                 }
6437                 else if (wParamFlags & PARAMFLAG_FOPT)
6438                 {
6439                     VARIANTARG *arg;
6440                     arg = prgpvarg[i] = &rgvarg[i];
6441                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
6442                     {
6443                         hres = VariantCopy(arg, &func_desc->lprgelemdescParam[i].u.paramdesc.pparamdescex->varDefaultValue);
6444                         if (FAILED(hres))
6445                             break;
6446                     }
6447                     else
6448                     {
6449                         VARIANTARG *missing_arg;
6450                         /* if the function wants a pointer to a variant then
6451                          * set that up, otherwise just pass the VT_ERROR in
6452                          * the argument by value */
6453                         if (rgvt[i] & VT_BYREF)
6454                         {
6455                             missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams) + i;
6456                             V_VT(arg) = VT_VARIANT | VT_BYREF;
6457                             V_VARIANTREF(arg) = missing_arg;
6458                         }
6459                         else
6460                             missing_arg = arg;
6461                         V_VT(missing_arg) = VT_ERROR;
6462                         V_ERROR(missing_arg) = DISP_E_PARAMNOTFOUND;
6463                     }
6464                 }
6465                 else
6466                 {
6467                     hres = DISP_E_BADPARAMCOUNT;
6468                     break;
6469                 }
6470             }
6471             if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
6472
6473             /* VT_VOID is a special case for return types, so it is not
6474              * handled in the general function */
6475             if (func_desc->elemdescFunc.tdesc.vt == VT_VOID)
6476                 V_VT(&varresult) = VT_EMPTY;
6477             else
6478             {
6479                 V_VT(&varresult) = 0;
6480                 hres = typedescvt_to_variantvt((ITypeInfo *)iface, &func_desc->elemdescFunc.tdesc, &V_VT(&varresult));
6481                 if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
6482             }
6483
6484             hres = DispCallFunc(pIUnk, func_desc->oVft, func_desc->callconv,
6485                                 V_VT(&varresult), func_desc->cParams, rgvt,
6486                                 prgpvarg, &varresult);
6487
6488             vargs_converted = 0;
6489
6490             for (i = 0; i < func_desc->cParams; i++)
6491             {
6492                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
6493                 VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
6494
6495                 if (wParamFlags & PARAMFLAG_FLCID)
6496                     continue;
6497                 else if (wParamFlags & PARAMFLAG_FRETVAL)
6498                 {
6499                     if (TRACE_ON(ole))
6500                     {
6501                         TRACE("[retval] value: ");
6502                         dump_Variant(prgpvarg[i]);
6503                     }
6504
6505                     if (pVarResult)
6506                     {
6507                         VariantInit(pVarResult);
6508                         /* deref return value */
6509                         hres = VariantCopyInd(pVarResult, prgpvarg[i]);
6510                     }
6511
6512                     VARIANT_ClearInd(prgpvarg[i]);
6513                 }
6514                 else if (vargs_converted < pDispParams->cArgs)
6515                 {
6516                     VARIANTARG *arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted];
6517                     if (wParamFlags & PARAMFLAG_FOUT)
6518                     {
6519                         if ((rgvt[i] & VT_BYREF) && !(V_VT(arg) & VT_BYREF))
6520                         {
6521                             hres = VariantChangeType(arg, &rgvarg[i], 0, V_VT(arg));
6522
6523                             if (FAILED(hres))
6524                             {
6525                                 ERR("failed to convert param %d to vt %d\n", i,
6526                                     V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted]));
6527                                 break;
6528                             }
6529                         }
6530                     }
6531                     else if (V_VT(prgpvarg[i]) == (VT_VARIANT | VT_ARRAY) &&
6532                              func_desc->cParamsOpt < 0 &&
6533                              i == func_desc->cParams-1)
6534                     {
6535                         SAFEARRAY *a = V_ARRAY(prgpvarg[i]);
6536                         LONG j, ubound;
6537                         VARIANT *v;
6538                         hres = SafeArrayGetUBound(a, 1, &ubound);
6539                         if (hres != S_OK)
6540                         {
6541                             ERR("SafeArrayGetUBound failed with %x\n", hres);
6542                             break;
6543                         }
6544                         hres = SafeArrayAccessData(a, (LPVOID)&v);
6545                         if (hres != S_OK)
6546                         {
6547                             ERR("SafeArrayAccessData failed with %x\n", hres);
6548                             break;
6549                         }
6550                         for (j = 0; j <= ubound; j++)
6551                             VariantClear(&v[j]);
6552                         hres = SafeArrayUnaccessData(a);
6553                         if (hres != S_OK)
6554                         {
6555                             ERR("SafeArrayUnaccessData failed with %x\n", hres);
6556                             break;
6557                         }
6558                     }
6559                     VariantClear(&rgvarg[i]);
6560                     vargs_converted++;
6561                 }
6562                 else if (wParamFlags & PARAMFLAG_FOPT)
6563                 {
6564                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
6565                         VariantClear(&rgvarg[i]);
6566                 }
6567
6568                 VariantClear(&missing_arg[i]);
6569             }
6570
6571             if ((V_VT(&varresult) == VT_ERROR) && FAILED(V_ERROR(&varresult)))
6572             {
6573                 WARN("invoked function failed with error 0x%08x\n", V_ERROR(&varresult));
6574                 hres = DISP_E_EXCEPTION;
6575                 if (pExcepInfo)
6576                 {
6577                     IErrorInfo *pErrorInfo;
6578                     pExcepInfo->scode = V_ERROR(&varresult);
6579                     if (GetErrorInfo(0, &pErrorInfo) == S_OK)
6580                     {
6581                         IErrorInfo_GetDescription(pErrorInfo, &pExcepInfo->bstrDescription);
6582                         IErrorInfo_GetHelpFile(pErrorInfo, &pExcepInfo->bstrHelpFile);
6583                         IErrorInfo_GetSource(pErrorInfo, &pExcepInfo->bstrSource);
6584                         IErrorInfo_GetHelpContext(pErrorInfo, &pExcepInfo->dwHelpContext);
6585
6586                         IErrorInfo_Release(pErrorInfo);
6587                     }
6588                 }
6589             }
6590             if (V_VT(&varresult) != VT_ERROR)
6591             {
6592                 TRACE("varresult value: ");
6593                 dump_Variant(&varresult);
6594
6595                 if (pVarResult)
6596                 {
6597                     VariantClear(pVarResult);
6598                     *pVarResult = varresult;
6599                 }
6600                 else
6601                     VariantClear(&varresult);
6602             }
6603
6604             if (SUCCEEDED(hres) && pVarResult && (func_desc->cParams == 1) &&
6605                 (func_desc->invkind & INVOKE_PROPERTYGET) &&
6606                 (func_desc->lprgelemdescParam[0].u.paramdesc.wParamFlags & PARAMFLAG_FRETVAL) &&
6607                 (pDispParams->cArgs != 0))
6608             {
6609                 if (V_VT(pVarResult) == VT_DISPATCH)
6610                 {
6611                     IDispatch *pDispatch = V_DISPATCH(pVarResult);
6612                     /* Note: not VariantClear; we still need the dispatch
6613                      * pointer to be valid */
6614                     VariantInit(pVarResult);
6615                     hres = IDispatch_Invoke(pDispatch, DISPID_VALUE, &IID_NULL,
6616                         GetSystemDefaultLCID(), INVOKE_PROPERTYGET,
6617                         pDispParams, pVarResult, pExcepInfo, pArgErr);
6618                     IDispatch_Release(pDispatch);
6619                 }
6620                 else
6621                 {
6622                     VariantClear(pVarResult);
6623                     hres = DISP_E_NOTACOLLECTION;
6624                 }
6625             }
6626
6627 func_fail:
6628             HeapFree(GetProcessHeap(), 0, buffer);
6629             break;
6630         }
6631         case FUNC_DISPATCH:  {
6632            IDispatch *disp;
6633
6634            hres = IUnknown_QueryInterface((LPUNKNOWN)pIUnk,&IID_IDispatch,(LPVOID*)&disp);
6635            if (SUCCEEDED(hres)) {
6636                FIXME("Calling Invoke in IDispatch iface. untested!\n");
6637                hres = IDispatch_Invoke(
6638                                      disp,memid,&IID_NULL,LOCALE_USER_DEFAULT,wFlags,pDispParams,
6639                                      pVarResult,pExcepInfo,pArgErr
6640                                      );
6641                if (FAILED(hres))
6642                    FIXME("IDispatch::Invoke failed with %08x. (Could be not a real error?)\n", hres);
6643                IDispatch_Release(disp);
6644            } else
6645                FIXME("FUNC_DISPATCH used on object without IDispatch iface?\n");
6646            break;
6647         }
6648         default:
6649             FIXME("Unknown function invocation type %d\n", func_desc->funckind);
6650             hres = E_FAIL;
6651             break;
6652         }
6653
6654         TRACE("-- 0x%08x\n", hres);
6655         return hres;
6656
6657     } else if(SUCCEEDED(hres = ITypeInfo2_GetVarIndexOfMemId(iface, memid, &var_index))) {
6658         VARDESC *var_desc;
6659
6660         hres = ITypeInfo2_GetVarDesc(iface, var_index, &var_desc);
6661         if(FAILED(hres)) return hres;
6662         
6663         FIXME("varseek: Found memid, but variable-based invoking not supported\n");
6664         dump_VARDESC(var_desc);
6665         ITypeInfo2_ReleaseVarDesc(iface, var_desc);
6666         return E_NOTIMPL;
6667     }
6668
6669     /* not found, look for it in inherited interfaces */
6670     ITypeInfo2_GetTypeKind(iface, &type_kind);
6671     if(type_kind == TKIND_INTERFACE || type_kind == TKIND_DISPATCH) {
6672         if(This->impltypelist) {
6673             /* recursive search */
6674             ITypeInfo *pTInfo;
6675             hres = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef, &pTInfo);
6676             if(SUCCEEDED(hres)){
6677                 hres = ITypeInfo_Invoke(pTInfo,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr);
6678                 ITypeInfo_Release(pTInfo);
6679                 return hres;
6680             }
6681             WARN("Could not search inherited interface!\n");
6682         }
6683     }
6684     WARN("did not find member id %d, flags 0x%x!\n", memid, wFlags);
6685     return DISP_E_MEMBERNOTFOUND;
6686 }
6687
6688 /* ITypeInfo::GetDocumentation
6689  *
6690  * Retrieves the documentation string, the complete Help file name and path,
6691  * and the context ID for the Help topic for a specified type description.
6692  *
6693  * (Can be tested by the Visual Basic Editor in Word for instance.)
6694  */
6695 static HRESULT WINAPI ITypeInfo_fnGetDocumentation( ITypeInfo2 *iface,
6696         MEMBERID memid, BSTR  *pBstrName, BSTR  *pBstrDocString,
6697         DWORD  *pdwHelpContext, BSTR  *pBstrHelpFile)
6698 {
6699     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6700     const TLBFuncDesc *pFDesc;
6701     const TLBVarDesc *pVDesc;
6702     TRACE("(%p) memid %d Name(%p) DocString(%p)"
6703           " HelpContext(%p) HelpFile(%p)\n",
6704         This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
6705     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
6706         if(pBstrName)
6707             *pBstrName=SysAllocString(This->Name);
6708         if(pBstrDocString)
6709             *pBstrDocString=SysAllocString(This->DocString);
6710         if(pdwHelpContext)
6711             *pdwHelpContext=This->dwHelpContext;
6712         if(pBstrHelpFile)
6713             *pBstrHelpFile=SysAllocString(This->DocString);/* FIXME */
6714         return S_OK;
6715     }else {/* for a member */
6716     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
6717         if(pFDesc->funcdesc.memid==memid){
6718           if(pBstrName)
6719             *pBstrName = SysAllocString(pFDesc->Name);
6720           if(pBstrDocString)
6721             *pBstrDocString=SysAllocString(pFDesc->HelpString);
6722           if(pdwHelpContext)
6723             *pdwHelpContext=pFDesc->helpcontext;
6724           return S_OK;
6725         }
6726     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
6727         if(pVDesc->vardesc.memid==memid){
6728             if(pBstrName)
6729               *pBstrName = SysAllocString(pVDesc->Name);
6730             if(pBstrDocString)
6731               *pBstrDocString=SysAllocString(pVDesc->HelpString);
6732             if(pdwHelpContext)
6733               *pdwHelpContext=pVDesc->HelpContext;
6734             return S_OK;
6735         }
6736     }
6737
6738     if(This->impltypelist &&
6739        (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
6740         /* recursive search */
6741         ITypeInfo *pTInfo;
6742         HRESULT result;
6743         result = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef,
6744                                         &pTInfo);
6745         if(SUCCEEDED(result)) {
6746             result = ITypeInfo_GetDocumentation(pTInfo, memid, pBstrName,
6747                 pBstrDocString, pdwHelpContext, pBstrHelpFile);
6748             ITypeInfo_Release(pTInfo);
6749             return result;
6750         }
6751         WARN("Could not search inherited interface!\n");
6752     }
6753
6754     WARN("member %d not found\n", memid);
6755     return TYPE_E_ELEMENTNOTFOUND;
6756 }
6757
6758 /*  ITypeInfo::GetDllEntry
6759  *
6760  * Retrieves a description or specification of an entry point for a function
6761  * in a DLL.
6762  */
6763 static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid,
6764         INVOKEKIND invKind, BSTR  *pBstrDllName, BSTR  *pBstrName,
6765         WORD  *pwOrdinal)
6766 {
6767     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6768     const TLBFuncDesc *pFDesc;
6769
6770     TRACE("(%p)->(memid %x, %d, %p, %p, %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
6771
6772     if (pBstrDllName) *pBstrDllName = NULL;
6773     if (pBstrName) *pBstrName = NULL;
6774     if (pwOrdinal) *pwOrdinal = 0;
6775
6776     if (This->TypeAttr.typekind != TKIND_MODULE)
6777         return TYPE_E_BADMODULEKIND;
6778
6779     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
6780         if(pFDesc->funcdesc.memid==memid){
6781             dump_TypeInfo(This);
6782             if (TRACE_ON(ole))
6783                 dump_TLBFuncDescOne(pFDesc);
6784
6785             if (pBstrDllName)
6786                 *pBstrDllName = SysAllocString(This->DllName);
6787
6788             if (!IS_INTRESOURCE(pFDesc->Entry) && (pFDesc->Entry != (void*)-1)) {
6789                 if (pBstrName)
6790                     *pBstrName = SysAllocString(pFDesc->Entry);
6791                 if (pwOrdinal)
6792                     *pwOrdinal = -1;
6793                 return S_OK;
6794             }
6795             if (pBstrName)
6796                 *pBstrName = NULL;
6797             if (pwOrdinal)
6798                 *pwOrdinal = LOWORD(pFDesc->Entry);
6799             return S_OK;
6800         }
6801     return TYPE_E_ELEMENTNOTFOUND;
6802 }
6803
6804 /* internal function to make the inherited interfaces' methods appear
6805  * part of the interface */
6806 static HRESULT ITypeInfoImpl_GetDispatchRefTypeInfo( ITypeInfo *iface,
6807     HREFTYPE *hRefType, ITypeInfo  **ppTInfo)
6808 {
6809     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6810     HRESULT hr;
6811
6812     TRACE("%p, 0x%x\n", iface, *hRefType);
6813
6814     if (This->impltypelist && (*hRefType & DISPATCH_HREF_MASK))
6815     {
6816         ITypeInfo *pSubTypeInfo;
6817
6818         hr = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef, &pSubTypeInfo);
6819         if (FAILED(hr))
6820             return hr;
6821
6822         hr = ITypeInfoImpl_GetDispatchRefTypeInfo(pSubTypeInfo,
6823                                                   hRefType, ppTInfo);
6824         ITypeInfo_Release(pSubTypeInfo);
6825         if (SUCCEEDED(hr))
6826             return hr;
6827     }
6828     *hRefType -= DISPATCH_HREF_OFFSET;
6829
6830     if (!(*hRefType & DISPATCH_HREF_MASK))
6831         return ITypeInfo_GetRefTypeInfo(iface, *hRefType, ppTInfo);
6832     else
6833         return E_FAIL;
6834 }
6835
6836 /* ITypeInfo::GetRefTypeInfo
6837  *
6838  * If a type description references other type descriptions, it retrieves
6839  * the referenced type descriptions.
6840  */
6841 static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo(
6842         ITypeInfo2 *iface,
6843         HREFTYPE hRefType,
6844         ITypeInfo  **ppTInfo)
6845 {
6846     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6847     HRESULT result = E_FAIL;
6848
6849     if ((This->hreftype != -1) && (This->hreftype == hRefType))
6850     {
6851         *ppTInfo = (ITypeInfo *)&This->lpVtbl;
6852         ITypeInfo_AddRef(*ppTInfo);
6853         result = S_OK;
6854     }
6855     else if (hRefType == -1 &&
6856         (This->TypeAttr.typekind   == TKIND_DISPATCH) &&
6857         (This->TypeAttr.wTypeFlags &  TYPEFLAG_FDUAL))
6858     {
6859           /* when we meet a DUAL dispinterface, we must create the interface
6860           * version of it.
6861           */
6862           ITypeInfoImpl* pTypeInfoImpl = (ITypeInfoImpl*) ITypeInfo_Constructor();
6863
6864
6865           /* the interface version contains the same information as the dispinterface
6866            * copy the contents of the structs.
6867            */
6868           *pTypeInfoImpl = *This;
6869           pTypeInfoImpl->ref = 0;
6870
6871           /* change the type to interface */
6872           pTypeInfoImpl->TypeAttr.typekind = TKIND_INTERFACE;
6873
6874           *ppTInfo = (ITypeInfo*) pTypeInfoImpl;
6875
6876           /* the AddRef implicitly adds a reference to the parent typelib, which
6877            * stops the copied data from being destroyed until the new typeinfo's
6878            * refcount goes to zero, but we need to signal to the new instance to
6879            * not free its data structures when it is destroyed */
6880           pTypeInfoImpl->not_attached_to_typelib = TRUE;
6881
6882           ITypeInfo_AddRef(*ppTInfo);
6883
6884           result = S_OK;
6885
6886     } else if ((hRefType != -1) && (hRefType & DISPATCH_HREF_MASK) &&
6887         (This->TypeAttr.typekind   == TKIND_DISPATCH))
6888     {
6889         HREFTYPE href_dispatch = hRefType;
6890         result = ITypeInfoImpl_GetDispatchRefTypeInfo((ITypeInfo *)iface, &href_dispatch, ppTInfo);
6891     } else {
6892         TLBRefType *ref_type;
6893         LIST_FOR_EACH_ENTRY(ref_type, &This->pTypeLib->ref_list, TLBRefType, entry)
6894         {
6895             if(ref_type->reference == hRefType)
6896                 break;
6897         }
6898         if(&ref_type->entry == &This->pTypeLib->ref_list)
6899         {
6900             FIXME("Can't find pRefType for ref %x\n", hRefType);
6901             goto end;
6902         }
6903         if(hRefType != -1) {
6904             ITypeLib *pTLib = NULL;
6905
6906             if(ref_type->pImpTLInfo == TLB_REF_INTERNAL) {
6907                 UINT Index;
6908                 result = ITypeInfo_GetContainingTypeLib(iface, &pTLib, &Index);
6909             } else {
6910                 if(ref_type->pImpTLInfo->pImpTypeLib) {
6911                     TRACE("typeinfo in imported typelib that is already loaded\n");
6912                     pTLib = (ITypeLib*)ref_type->pImpTLInfo->pImpTypeLib;
6913                     ITypeLib2_AddRef(pTLib);
6914                     result = S_OK;
6915                 } else {
6916                     TRACE("typeinfo in imported typelib that isn't already loaded\n");
6917                     result = LoadRegTypeLib( &ref_type->pImpTLInfo->guid,
6918                                              ref_type->pImpTLInfo->wVersionMajor,
6919                                              ref_type->pImpTLInfo->wVersionMinor,
6920                                              ref_type->pImpTLInfo->lcid,
6921                                              &pTLib);
6922
6923                     if(FAILED(result)) {
6924                         BSTR libnam=SysAllocString(ref_type->pImpTLInfo->name);
6925                         result=LoadTypeLib(libnam, &pTLib);
6926                         SysFreeString(libnam);
6927                     }
6928                     if(SUCCEEDED(result)) {
6929                         ref_type->pImpTLInfo->pImpTypeLib = (ITypeLibImpl*)pTLib;
6930                         ITypeLib2_AddRef(pTLib);
6931                     }
6932                 }
6933             }
6934             if(SUCCEEDED(result)) {
6935                 if(ref_type->index == TLB_REF_USE_GUID)
6936                     result = ITypeLib2_GetTypeInfoOfGuid(pTLib,
6937                                                          &ref_type->guid,
6938                                                          ppTInfo);
6939                 else
6940                     result = ITypeLib2_GetTypeInfo(pTLib, ref_type->index,
6941                                                    ppTInfo);
6942             }
6943             if (pTLib != NULL)
6944                 ITypeLib2_Release(pTLib);
6945         }
6946     }
6947
6948 end:
6949     TRACE("(%p) hreftype 0x%04x loaded %s (%p)\n", This, hRefType,
6950           SUCCEEDED(result)? "SUCCESS":"FAILURE", *ppTInfo);
6951     return result;
6952 }
6953
6954 /* ITypeInfo::AddressOfMember
6955  *
6956  * Retrieves the addresses of static functions or variables, such as those
6957  * defined in a DLL.
6958  */
6959 static HRESULT WINAPI ITypeInfo_fnAddressOfMember( ITypeInfo2 *iface,
6960         MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
6961 {
6962     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6963     HRESULT hr;
6964     BSTR dll, entry;
6965     WORD ordinal;
6966     HMODULE module;
6967
6968     TRACE("(%p)->(0x%x, 0x%x, %p)\n", This, memid, invKind, ppv);
6969
6970     hr = ITypeInfo_GetDllEntry(iface, memid, invKind, &dll, &entry, &ordinal);
6971     if (FAILED(hr))
6972         return hr;
6973
6974     module = LoadLibraryW(dll);
6975     if (!module)
6976     {
6977         ERR("couldn't load %s\n", debugstr_w(dll));
6978         SysFreeString(dll);
6979         SysFreeString(entry);
6980         return STG_E_FILENOTFOUND;
6981     }
6982     /* FIXME: store library somewhere where we can free it */
6983
6984     if (entry)
6985     {
6986         LPSTR entryA;
6987         INT len = WideCharToMultiByte(CP_ACP, 0, entry, -1, NULL, 0, NULL, NULL);
6988         entryA = HeapAlloc(GetProcessHeap(), 0, len);
6989         WideCharToMultiByte(CP_ACP, 0, entry, -1, entryA, len, NULL, NULL);
6990
6991         *ppv = GetProcAddress(module, entryA);
6992         if (!*ppv)
6993             ERR("function not found %s\n", debugstr_a(entryA));
6994
6995         HeapFree(GetProcessHeap(), 0, entryA);
6996     }
6997     else
6998     {
6999         *ppv = GetProcAddress(module, MAKEINTRESOURCEA(ordinal));
7000         if (!*ppv)
7001             ERR("function not found %d\n", ordinal);
7002     }
7003
7004     SysFreeString(dll);
7005     SysFreeString(entry);
7006
7007     if (!*ppv)
7008         return TYPE_E_DLLFUNCTIONNOTFOUND;
7009
7010     return S_OK;
7011 }
7012
7013 /* ITypeInfo::CreateInstance
7014  *
7015  * Creates a new instance of a type that describes a component object class
7016  * (coclass).
7017  */
7018 static HRESULT WINAPI ITypeInfo_fnCreateInstance( ITypeInfo2 *iface,
7019         IUnknown *pOuterUnk, REFIID riid, VOID  **ppvObj)
7020 {
7021     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7022     HRESULT hr;
7023     TYPEATTR *pTA;
7024
7025     TRACE("(%p)->(%p, %s, %p)\n", This, pOuterUnk, debugstr_guid(riid), ppvObj);
7026
7027     *ppvObj = NULL;
7028
7029     if(pOuterUnk)
7030     {
7031         WARN("Not able to aggregate\n");
7032         return CLASS_E_NOAGGREGATION;
7033     }
7034
7035     hr = ITypeInfo_GetTypeAttr(iface, &pTA);
7036     if(FAILED(hr)) return hr;
7037
7038     if(pTA->typekind != TKIND_COCLASS)
7039     {
7040         WARN("CreateInstance on typeinfo of type %x\n", pTA->typekind);
7041         hr = E_INVALIDARG;
7042         goto end;
7043     }
7044
7045     hr = S_FALSE;
7046     if(pTA->wTypeFlags & TYPEFLAG_FAPPOBJECT)
7047     {
7048         IUnknown *pUnk;
7049         hr = GetActiveObject(&pTA->guid, NULL, &pUnk);
7050         TRACE("GetActiveObject rets %08x\n", hr);
7051         if(hr == S_OK)
7052         {
7053             hr = IUnknown_QueryInterface(pUnk, riid, ppvObj);
7054             IUnknown_Release(pUnk);
7055         }
7056     }
7057
7058     if(hr != S_OK)
7059         hr = CoCreateInstance(&pTA->guid, NULL,
7060                               CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
7061                               riid, ppvObj);
7062
7063 end:
7064     ITypeInfo_ReleaseTypeAttr(iface, pTA);
7065     return hr;
7066 }
7067
7068 /* ITypeInfo::GetMops
7069  *
7070  * Retrieves marshalling information.
7071  */
7072 static HRESULT WINAPI ITypeInfo_fnGetMops( ITypeInfo2 *iface, MEMBERID memid,
7073                                 BSTR  *pBstrMops)
7074 {
7075     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7076     FIXME("(%p %d) stub!\n", This, memid);
7077     *pBstrMops = NULL;
7078     return S_OK;
7079 }
7080
7081 /* ITypeInfo::GetContainingTypeLib
7082  *
7083  * Retrieves the containing type library and the index of the type description
7084  * within that type library.
7085  */
7086 static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( ITypeInfo2 *iface,
7087         ITypeLib  * *ppTLib, UINT  *pIndex)
7088 {
7089     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7090     
7091     /* If a pointer is null, we simply ignore it, the ATL in particular passes pIndex as 0 */
7092     if (pIndex) {
7093       *pIndex=This->index;
7094       TRACE("returning pIndex=%d\n", *pIndex);
7095     }
7096     
7097     if (ppTLib) {
7098       *ppTLib=(LPTYPELIB )(This->pTypeLib);
7099       ITypeLib2_AddRef(*ppTLib);
7100       TRACE("returning ppTLib=%p\n", *ppTLib);
7101     }
7102     
7103     return S_OK;
7104 }
7105
7106 /* ITypeInfo::ReleaseTypeAttr
7107  *
7108  * Releases a TYPEATTR previously returned by GetTypeAttr.
7109  *
7110  */
7111 static void WINAPI ITypeInfo_fnReleaseTypeAttr( ITypeInfo2 *iface,
7112         TYPEATTR* pTypeAttr)
7113 {
7114     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7115     TRACE("(%p)->(%p)\n", This, pTypeAttr);
7116     HeapFree(GetProcessHeap(), 0, pTypeAttr);
7117 }
7118
7119 /* ITypeInfo::ReleaseFuncDesc
7120  *
7121  * Releases a FUNCDESC previously returned by GetFuncDesc. *
7122  */
7123 static void WINAPI ITypeInfo_fnReleaseFuncDesc(
7124         ITypeInfo2 *iface,
7125         FUNCDESC *pFuncDesc)
7126 {
7127     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7128     SHORT i;
7129
7130     TRACE("(%p)->(%p)\n", This, pFuncDesc);
7131
7132     for (i = 0; i < pFuncDesc->cParams; i++)
7133         TLB_FreeElemDesc(&pFuncDesc->lprgelemdescParam[i]);
7134     TLB_FreeElemDesc(&pFuncDesc->elemdescFunc);
7135
7136     SysFreeString((BSTR)pFuncDesc);
7137 }
7138
7139 /* ITypeInfo::ReleaseVarDesc
7140  *
7141  * Releases a VARDESC previously returned by GetVarDesc.
7142  */
7143 static void WINAPI ITypeInfo_fnReleaseVarDesc( ITypeInfo2 *iface,
7144         VARDESC *pVarDesc)
7145 {
7146     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7147     TRACE("(%p)->(%p)\n", This, pVarDesc);
7148
7149     TLB_FreeElemDesc(&pVarDesc->elemdescVar);
7150     if (pVarDesc->varkind == VAR_CONST)
7151         VariantClear(pVarDesc->u.lpvarValue);
7152     SysFreeString((BSTR)pVarDesc);
7153 }
7154
7155 /* ITypeInfo2::GetTypeKind
7156  *
7157  * Returns the TYPEKIND enumeration quickly, without doing any allocations.
7158  *
7159  */
7160 static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo2 * iface,
7161     TYPEKIND *pTypeKind)
7162 {
7163     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7164     *pTypeKind=This->TypeAttr.typekind;
7165     TRACE("(%p) type 0x%0x\n", This,*pTypeKind);
7166     return S_OK;
7167 }
7168
7169 /* ITypeInfo2::GetTypeFlags
7170  *
7171  * Returns the type flags without any allocations. This returns a DWORD type
7172  * flag, which expands the type flags without growing the TYPEATTR (type
7173  * attribute).
7174  *
7175  */
7176 static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo2 *iface, ULONG *pTypeFlags)
7177 {
7178     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7179     *pTypeFlags=This->TypeAttr.wTypeFlags;
7180     TRACE("(%p) flags 0x%x\n", This,*pTypeFlags);
7181     return S_OK;
7182 }
7183
7184 /* ITypeInfo2::GetFuncIndexOfMemId
7185  * Binds to a specific member based on a known DISPID, where the member name
7186  * is not known (for example, when binding to a default member).
7187  *
7188  */
7189 static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo2 * iface,
7190     MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex)
7191 {
7192     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7193     const TLBFuncDesc *pFuncInfo;
7194     int i;
7195     HRESULT result;
7196
7197     for(i = 0, pFuncInfo = This->funclist; pFuncInfo; i++, pFuncInfo=pFuncInfo->next)
7198         if(memid == pFuncInfo->funcdesc.memid && (invKind & pFuncInfo->funcdesc.invkind))
7199             break;
7200     if(pFuncInfo) {
7201         *pFuncIndex = i;
7202         result = S_OK;
7203     } else
7204         result = TYPE_E_ELEMENTNOTFOUND;
7205
7206     TRACE("(%p) memid 0x%08x invKind 0x%04x -> %s\n", This,
7207           memid, invKind, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
7208     return result;
7209 }
7210
7211 /* TypeInfo2::GetVarIndexOfMemId
7212  *
7213  * Binds to a specific member based on a known DISPID, where the member name
7214  * is not known (for example, when binding to a default member).
7215  *
7216  */
7217 static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( ITypeInfo2 * iface,
7218     MEMBERID memid, UINT *pVarIndex)
7219 {
7220     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7221     TLBVarDesc *pVarInfo;
7222     int i;
7223     HRESULT result;
7224     for(i=0, pVarInfo=This->varlist; pVarInfo &&
7225             memid != pVarInfo->vardesc.memid; i++, pVarInfo=pVarInfo->next)
7226         ;
7227     if(pVarInfo) {
7228         *pVarIndex = i;
7229         result = S_OK;
7230     } else
7231         result = TYPE_E_ELEMENTNOTFOUND;
7232
7233     TRACE("(%p) memid 0x%08x -> %s\n", This,
7234           memid, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
7235     return result;
7236 }
7237
7238 /* ITypeInfo2::GetCustData
7239  *
7240  * Gets the custom data
7241  */
7242 static HRESULT WINAPI ITypeInfo2_fnGetCustData(
7243         ITypeInfo2 * iface,
7244         REFGUID guid,
7245         VARIANT *pVarVal)
7246 {
7247     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7248     TLBCustData *pCData;
7249
7250     for(pCData=This->pCustData; pCData; pCData = pCData->next)
7251         if( IsEqualIID(guid, &pCData->guid)) break;
7252
7253     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
7254
7255     VariantInit( pVarVal);
7256     if (pCData)
7257         VariantCopy( pVarVal, &pCData->data);
7258     else
7259         VariantClear( pVarVal );
7260     return S_OK;
7261 }
7262
7263 /* ITypeInfo2::GetFuncCustData
7264  *
7265  * Gets the custom data
7266  */
7267 static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData(
7268         ITypeInfo2 * iface,
7269         UINT index,
7270         REFGUID guid,
7271         VARIANT *pVarVal)
7272 {
7273     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7274     TLBCustData *pCData=NULL;
7275     TLBFuncDesc * pFDesc;
7276     UINT i;
7277     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
7278             pFDesc=pFDesc->next);
7279
7280     if(pFDesc)
7281         for(pCData=pFDesc->pCustData; pCData; pCData = pCData->next)
7282             if( IsEqualIID(guid, &pCData->guid)) break;
7283
7284     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
7285
7286     if(pCData){
7287         VariantInit( pVarVal);
7288         VariantCopy( pVarVal, &pCData->data);
7289         return S_OK;
7290     }
7291     return E_INVALIDARG;  /* FIXME: correct? */
7292 }
7293
7294 /* ITypeInfo2::GetParamCustData
7295  *
7296  * Gets the custom data
7297  */
7298 static HRESULT WINAPI ITypeInfo2_fnGetParamCustData(
7299         ITypeInfo2 * iface,
7300         UINT indexFunc,
7301         UINT indexParam,
7302         REFGUID guid,
7303         VARIANT *pVarVal)
7304 {
7305     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7306     TLBCustData *pCData=NULL;
7307     TLBFuncDesc * pFDesc;
7308     UINT i;
7309
7310     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,pFDesc=pFDesc->next);
7311
7312     if(pFDesc && indexParam<pFDesc->funcdesc.cParams)
7313         for(pCData=pFDesc->pParamDesc[indexParam].pCustData; pCData;
7314                 pCData = pCData->next)
7315             if( IsEqualIID(guid, &pCData->guid)) break;
7316
7317     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
7318
7319     if(pCData)
7320     {
7321         VariantInit( pVarVal);
7322         VariantCopy( pVarVal, &pCData->data);
7323         return S_OK;
7324     }
7325     return E_INVALIDARG;  /* FIXME: correct? */
7326 }
7327
7328 /* ITypeInfo2::GetVarCustData
7329  *
7330  * Gets the custom data
7331  */
7332 static HRESULT WINAPI ITypeInfo2_fnGetVarCustData(
7333         ITypeInfo2 * iface,
7334         UINT index,
7335         REFGUID guid,
7336         VARIANT *pVarVal)
7337 {
7338     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7339     TLBCustData *pCData=NULL;
7340     TLBVarDesc * pVDesc;
7341     UINT i;
7342
7343     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next);
7344
7345     if(pVDesc)
7346     {
7347       for(pCData=pVDesc->pCustData; pCData; pCData = pCData->next)
7348       {
7349         if( IsEqualIID(guid, &pCData->guid)) break;
7350       }
7351     }
7352
7353     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
7354
7355     if(pCData)
7356     {
7357         VariantInit( pVarVal);
7358         VariantCopy( pVarVal, &pCData->data);
7359         return S_OK;
7360     }
7361     return E_INVALIDARG;  /* FIXME: correct? */
7362 }
7363
7364 /* ITypeInfo2::GetImplCustData
7365  *
7366  * Gets the custom data
7367  */
7368 static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData(
7369         ITypeInfo2 * iface,
7370         UINT index,
7371         REFGUID guid,
7372         VARIANT *pVarVal)
7373 {
7374     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7375     TLBCustData *pCData=NULL;
7376     TLBImplType * pRDesc;
7377     UINT i;
7378
7379     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++, pRDesc=pRDesc->next);
7380
7381     if(pRDesc)
7382     {
7383       for(pCData=pRDesc->pCustData; pCData; pCData = pCData->next)
7384       {
7385         if( IsEqualIID(guid, &pCData->guid)) break;
7386       }
7387     }
7388
7389     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
7390
7391     if(pCData)
7392     {
7393         VariantInit( pVarVal);
7394         VariantCopy( pVarVal, &pCData->data);
7395         return S_OK;
7396     }
7397     return E_INVALIDARG;  /* FIXME: correct? */
7398 }
7399
7400 /* ITypeInfo2::GetDocumentation2
7401  *
7402  * Retrieves the documentation string, the complete Help file name and path,
7403  * the localization context to use, and the context ID for the library Help
7404  * topic in the Help file.
7405  *
7406  */
7407 static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2(
7408         ITypeInfo2 * iface,
7409         MEMBERID memid,
7410         LCID lcid,
7411         BSTR *pbstrHelpString,
7412         DWORD *pdwHelpStringContext,
7413         BSTR *pbstrHelpStringDll)
7414 {
7415     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7416     const TLBFuncDesc *pFDesc;
7417     const TLBVarDesc *pVDesc;
7418     TRACE("(%p) memid %d lcid(0x%x)  HelpString(%p) "
7419           "HelpStringContext(%p) HelpStringDll(%p)\n",
7420           This, memid, lcid, pbstrHelpString, pdwHelpStringContext,
7421           pbstrHelpStringDll );
7422     /* the help string should be obtained from the helpstringdll,
7423      * using the _DLLGetDocumentation function, based on the supplied
7424      * lcid. Nice to do sometime...
7425      */
7426     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
7427         if(pbstrHelpString)
7428             *pbstrHelpString=SysAllocString(This->Name);
7429         if(pdwHelpStringContext)
7430             *pdwHelpStringContext=This->dwHelpStringContext;
7431         if(pbstrHelpStringDll)
7432             *pbstrHelpStringDll=
7433                 SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
7434         return S_OK;
7435     }else {/* for a member */
7436     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
7437         if(pFDesc->funcdesc.memid==memid){
7438              if(pbstrHelpString)
7439                 *pbstrHelpString=SysAllocString(pFDesc->HelpString);
7440             if(pdwHelpStringContext)
7441                 *pdwHelpStringContext=pFDesc->HelpStringContext;
7442             if(pbstrHelpStringDll)
7443                 *pbstrHelpStringDll=
7444                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
7445         return S_OK;
7446     }
7447     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
7448         if(pVDesc->vardesc.memid==memid){
7449              if(pbstrHelpString)
7450                 *pbstrHelpString=SysAllocString(pVDesc->HelpString);
7451             if(pdwHelpStringContext)
7452                 *pdwHelpStringContext=pVDesc->HelpStringContext;
7453             if(pbstrHelpStringDll)
7454                 *pbstrHelpStringDll=
7455                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
7456             return S_OK;
7457         }
7458     }
7459     return TYPE_E_ELEMENTNOTFOUND;
7460 }
7461
7462 /* ITypeInfo2::GetAllCustData
7463  *
7464  * Gets all custom data items for the Type info.
7465  *
7466  */
7467 static HRESULT WINAPI ITypeInfo2_fnGetAllCustData(
7468         ITypeInfo2 * iface,
7469         CUSTDATA *pCustData)
7470 {
7471     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7472     TLBCustData *pCData;
7473     int i;
7474
7475     TRACE("(%p) returning %d items\n", This, This->ctCustData);
7476
7477     pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
7478     if(pCustData->prgCustData ){
7479         pCustData->cCustData=This->ctCustData;
7480         for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
7481             pCustData->prgCustData[i].guid=pCData->guid;
7482             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
7483         }
7484     }else{
7485         ERR(" OUT OF MEMORY!\n");
7486         return E_OUTOFMEMORY;
7487     }
7488     return S_OK;
7489 }
7490
7491 /* ITypeInfo2::GetAllFuncCustData
7492  *
7493  * Gets all custom data items for the specified Function
7494  *
7495  */
7496 static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData(
7497         ITypeInfo2 * iface,
7498         UINT index,
7499         CUSTDATA *pCustData)
7500 {
7501     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7502     TLBCustData *pCData;
7503     TLBFuncDesc * pFDesc;
7504     UINT i;
7505     TRACE("(%p) index %d\n", This, index);
7506     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
7507             pFDesc=pFDesc->next)
7508         ;
7509     if(pFDesc){
7510         pCustData->prgCustData =
7511             TLB_Alloc(pFDesc->ctCustData * sizeof(CUSTDATAITEM));
7512         if(pCustData->prgCustData ){
7513             pCustData->cCustData=pFDesc->ctCustData;
7514             for(i=0, pCData=pFDesc->pCustData; pCData; i++,
7515                     pCData = pCData->next){
7516                 pCustData->prgCustData[i].guid=pCData->guid;
7517                 VariantCopy(& pCustData->prgCustData[i].varValue,
7518                         & pCData->data);
7519             }
7520         }else{
7521             ERR(" OUT OF MEMORY!\n");
7522             return E_OUTOFMEMORY;
7523         }
7524         return S_OK;
7525     }
7526     return TYPE_E_ELEMENTNOTFOUND;
7527 }
7528
7529 /* ITypeInfo2::GetAllParamCustData
7530  *
7531  * Gets all custom data items for the Functions
7532  *
7533  */
7534 static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo2 * iface,
7535     UINT indexFunc, UINT indexParam, CUSTDATA *pCustData)
7536 {
7537     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7538     TLBCustData *pCData=NULL;
7539     TLBFuncDesc * pFDesc;
7540     UINT i;
7541     TRACE("(%p) index %d\n", This, indexFunc);
7542     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,
7543             pFDesc=pFDesc->next)
7544         ;
7545     if(pFDesc && indexParam<pFDesc->funcdesc.cParams){
7546         pCustData->prgCustData =
7547             TLB_Alloc(pFDesc->pParamDesc[indexParam].ctCustData *
7548                     sizeof(CUSTDATAITEM));
7549         if(pCustData->prgCustData ){
7550             pCustData->cCustData=pFDesc->pParamDesc[indexParam].ctCustData;
7551             for(i=0, pCData=pFDesc->pParamDesc[indexParam].pCustData;
7552                     pCData; i++, pCData = pCData->next){
7553                 pCustData->prgCustData[i].guid=pCData->guid;
7554                 VariantCopy(& pCustData->prgCustData[i].varValue,
7555                         & pCData->data);
7556             }
7557         }else{
7558             ERR(" OUT OF MEMORY!\n");
7559             return E_OUTOFMEMORY;
7560         }
7561         return S_OK;
7562     }
7563     return TYPE_E_ELEMENTNOTFOUND;
7564 }
7565
7566 /* ITypeInfo2::GetAllVarCustData
7567  *
7568  * Gets all custom data items for the specified Variable
7569  *
7570  */
7571 static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo2 * iface,
7572     UINT index, CUSTDATA *pCustData)
7573 {
7574     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7575     TLBCustData *pCData;
7576     TLBVarDesc * pVDesc;
7577     UINT i;
7578     TRACE("(%p) index %d\n", This, index);
7579     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++,
7580             pVDesc=pVDesc->next)
7581         ;
7582     if(pVDesc){
7583         pCustData->prgCustData =
7584             TLB_Alloc(pVDesc->ctCustData * sizeof(CUSTDATAITEM));
7585         if(pCustData->prgCustData ){
7586             pCustData->cCustData=pVDesc->ctCustData;
7587             for(i=0, pCData=pVDesc->pCustData; pCData; i++,
7588                     pCData = pCData->next){
7589                 pCustData->prgCustData[i].guid=pCData->guid;
7590                 VariantCopy(& pCustData->prgCustData[i].varValue,
7591                         & pCData->data);
7592             }
7593         }else{
7594             ERR(" OUT OF MEMORY!\n");
7595             return E_OUTOFMEMORY;
7596         }
7597         return S_OK;
7598     }
7599     return TYPE_E_ELEMENTNOTFOUND;
7600 }
7601
7602 /* ITypeInfo2::GetAllImplCustData
7603  *
7604  * Gets all custom data items for the specified implementation type
7605  *
7606  */
7607 static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData(
7608         ITypeInfo2 * iface,
7609         UINT index,
7610         CUSTDATA *pCustData)
7611 {
7612     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7613     TLBCustData *pCData;
7614     TLBImplType * pRDesc;
7615     UINT i;
7616     TRACE("(%p) index %d\n", This, index);
7617     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++,
7618             pRDesc=pRDesc->next)
7619         ;
7620     if(pRDesc){
7621         pCustData->prgCustData =
7622             TLB_Alloc(pRDesc->ctCustData * sizeof(CUSTDATAITEM));
7623         if(pCustData->prgCustData ){
7624             pCustData->cCustData=pRDesc->ctCustData;
7625             for(i=0, pCData=pRDesc->pCustData; pCData; i++,
7626                     pCData = pCData->next){
7627                 pCustData->prgCustData[i].guid=pCData->guid;
7628                 VariantCopy(& pCustData->prgCustData[i].varValue,
7629                         & pCData->data);
7630             }
7631         }else{
7632             ERR(" OUT OF MEMORY!\n");
7633             return E_OUTOFMEMORY;
7634         }
7635         return S_OK;
7636     }
7637     return TYPE_E_ELEMENTNOTFOUND;
7638 }
7639
7640 static const ITypeInfo2Vtbl tinfvt =
7641 {
7642
7643     ITypeInfo_fnQueryInterface,
7644     ITypeInfo_fnAddRef,
7645     ITypeInfo_fnRelease,
7646
7647     ITypeInfo_fnGetTypeAttr,
7648     ITypeInfo_fnGetTypeComp,
7649     ITypeInfo_fnGetFuncDesc,
7650     ITypeInfo_fnGetVarDesc,
7651     ITypeInfo_fnGetNames,
7652     ITypeInfo_fnGetRefTypeOfImplType,
7653     ITypeInfo_fnGetImplTypeFlags,
7654     ITypeInfo_fnGetIDsOfNames,
7655     ITypeInfo_fnInvoke,
7656     ITypeInfo_fnGetDocumentation,
7657     ITypeInfo_fnGetDllEntry,
7658     ITypeInfo_fnGetRefTypeInfo,
7659     ITypeInfo_fnAddressOfMember,
7660     ITypeInfo_fnCreateInstance,
7661     ITypeInfo_fnGetMops,
7662     ITypeInfo_fnGetContainingTypeLib,
7663     ITypeInfo_fnReleaseTypeAttr,
7664     ITypeInfo_fnReleaseFuncDesc,
7665     ITypeInfo_fnReleaseVarDesc,
7666
7667     ITypeInfo2_fnGetTypeKind,
7668     ITypeInfo2_fnGetTypeFlags,
7669     ITypeInfo2_fnGetFuncIndexOfMemId,
7670     ITypeInfo2_fnGetVarIndexOfMemId,
7671     ITypeInfo2_fnGetCustData,
7672     ITypeInfo2_fnGetFuncCustData,
7673     ITypeInfo2_fnGetParamCustData,
7674     ITypeInfo2_fnGetVarCustData,
7675     ITypeInfo2_fnGetImplTypeCustData,
7676     ITypeInfo2_fnGetDocumentation2,
7677     ITypeInfo2_fnGetAllCustData,
7678     ITypeInfo2_fnGetAllFuncCustData,
7679     ITypeInfo2_fnGetAllParamCustData,
7680     ITypeInfo2_fnGetAllVarCustData,
7681     ITypeInfo2_fnGetAllImplTypeCustData,
7682 };
7683
7684 /******************************************************************************
7685  * CreateDispTypeInfo [OLEAUT32.31]
7686  *
7687  * Build type information for an object so it can be called through an
7688  * IDispatch interface.
7689  *
7690  * RETURNS
7691  *  Success: S_OK. pptinfo contains the created ITypeInfo object.
7692  *  Failure: E_INVALIDARG, if one or more arguments is invalid.
7693  *
7694  * NOTES
7695  *  This call allows an objects methods to be accessed through IDispatch, by
7696  *  building an ITypeInfo object that IDispatch can use to call through.
7697  */
7698 HRESULT WINAPI CreateDispTypeInfo(
7699         INTERFACEDATA *pidata, /* [I] Description of the interface to build type info for */
7700         LCID lcid, /* [I] Locale Id */
7701         ITypeInfo **pptinfo) /* [O] Destination for created ITypeInfo object */
7702 {
7703     ITypeInfoImpl *pTIClass, *pTIIface;
7704     ITypeLibImpl *pTypeLibImpl;
7705     unsigned int param, func;
7706     TLBFuncDesc **ppFuncDesc;
7707     TLBRefType *ref;
7708
7709     TRACE("\n");
7710     pTypeLibImpl = TypeLibImpl_Constructor();
7711     if (!pTypeLibImpl) return E_FAIL;
7712
7713     pTIIface = (ITypeInfoImpl*)ITypeInfo_Constructor();
7714     pTIIface->pTypeLib = pTypeLibImpl;
7715     pTIIface->index = 0;
7716     pTIIface->Name = NULL;
7717     pTIIface->dwHelpContext = -1;
7718     memset(&pTIIface->TypeAttr.guid, 0, sizeof(GUID));
7719     pTIIface->TypeAttr.lcid = lcid;
7720     pTIIface->TypeAttr.typekind = TKIND_INTERFACE;
7721     pTIIface->TypeAttr.wMajorVerNum = 0;
7722     pTIIface->TypeAttr.wMinorVerNum = 0;
7723     pTIIface->TypeAttr.cbAlignment = 2;
7724     pTIIface->TypeAttr.cbSizeInstance = -1;
7725     pTIIface->TypeAttr.cbSizeVft = -1;
7726     pTIIface->TypeAttr.cFuncs = 0;
7727     pTIIface->TypeAttr.cImplTypes = 0;
7728     pTIIface->TypeAttr.cVars = 0;
7729     pTIIface->TypeAttr.wTypeFlags = 0;
7730
7731     ppFuncDesc = &pTIIface->funclist;
7732     for(func = 0; func < pidata->cMembers; func++) {
7733         METHODDATA *md = pidata->pmethdata + func;
7734         *ppFuncDesc = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppFuncDesc));
7735         (*ppFuncDesc)->Name = SysAllocString(md->szName);
7736         (*ppFuncDesc)->funcdesc.memid = md->dispid;
7737         (*ppFuncDesc)->funcdesc.lprgscode = NULL;
7738         (*ppFuncDesc)->funcdesc.funckind = FUNC_VIRTUAL;
7739         (*ppFuncDesc)->funcdesc.invkind = md->wFlags;
7740         (*ppFuncDesc)->funcdesc.callconv = md->cc;
7741         (*ppFuncDesc)->funcdesc.cParams = md->cArgs;
7742         (*ppFuncDesc)->funcdesc.cParamsOpt = 0;
7743         (*ppFuncDesc)->funcdesc.oVft = md->iMeth * sizeof(void *);
7744         (*ppFuncDesc)->funcdesc.cScodes = 0;
7745         (*ppFuncDesc)->funcdesc.wFuncFlags = 0;
7746         (*ppFuncDesc)->funcdesc.elemdescFunc.tdesc.vt = md->vtReturn;
7747         (*ppFuncDesc)->funcdesc.elemdescFunc.u.paramdesc.wParamFlags = PARAMFLAG_NONE;
7748         (*ppFuncDesc)->funcdesc.elemdescFunc.u.paramdesc.pparamdescex = NULL;
7749         (*ppFuncDesc)->funcdesc.lprgelemdescParam = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7750                                                               md->cArgs * sizeof(ELEMDESC));
7751         (*ppFuncDesc)->pParamDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7752                                               md->cArgs * sizeof(TLBParDesc));
7753         for(param = 0; param < md->cArgs; param++) {
7754             (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].tdesc.vt = md->ppdata[param].vt;
7755             (*ppFuncDesc)->pParamDesc[param].Name = SysAllocString(md->ppdata[param].szName);
7756         }
7757         (*ppFuncDesc)->helpcontext = 0;
7758         (*ppFuncDesc)->HelpStringContext = 0;
7759         (*ppFuncDesc)->HelpString = NULL;
7760         (*ppFuncDesc)->Entry = NULL;
7761         (*ppFuncDesc)->ctCustData = 0;
7762         (*ppFuncDesc)->pCustData = NULL;
7763         (*ppFuncDesc)->next = NULL;
7764         pTIIface->TypeAttr.cFuncs++;
7765         ppFuncDesc = &(*ppFuncDesc)->next;
7766     }
7767
7768     dump_TypeInfo(pTIIface);
7769
7770     pTypeLibImpl->pTypeInfo = pTIIface;
7771     pTypeLibImpl->TypeInfoCount++;
7772
7773     pTIClass = (ITypeInfoImpl*)ITypeInfo_Constructor();
7774     pTIClass->pTypeLib = pTypeLibImpl;
7775     pTIClass->index = 1;
7776     pTIClass->Name = NULL;
7777     pTIClass->dwHelpContext = -1;
7778     memset(&pTIClass->TypeAttr.guid, 0, sizeof(GUID));
7779     pTIClass->TypeAttr.lcid = lcid;
7780     pTIClass->TypeAttr.typekind = TKIND_COCLASS;
7781     pTIClass->TypeAttr.wMajorVerNum = 0;
7782     pTIClass->TypeAttr.wMinorVerNum = 0;
7783     pTIClass->TypeAttr.cbAlignment = 2;
7784     pTIClass->TypeAttr.cbSizeInstance = -1;
7785     pTIClass->TypeAttr.cbSizeVft = -1;
7786     pTIClass->TypeAttr.cFuncs = 0;
7787     pTIClass->TypeAttr.cImplTypes = 1;
7788     pTIClass->TypeAttr.cVars = 0;
7789     pTIClass->TypeAttr.wTypeFlags = 0;
7790
7791     pTIClass->impltypelist = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pTIClass->impltypelist));
7792     pTIClass->impltypelist->hRef = 0;
7793
7794     ref = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ref));
7795     ref->index = 0;
7796     ref->reference = 0;
7797     ref->pImpTLInfo = TLB_REF_INTERNAL;
7798     list_add_head(&pTypeLibImpl->ref_list, &ref->entry);
7799
7800     dump_TypeInfo(pTIClass);
7801
7802     pTIIface->next = pTIClass;
7803     pTypeLibImpl->TypeInfoCount++;
7804
7805     *pptinfo = (ITypeInfo*)pTIClass;
7806
7807     ITypeInfo_AddRef(*pptinfo);
7808     ITypeLib_Release((ITypeLib *)&pTypeLibImpl->lpVtbl);
7809
7810     return S_OK;
7811
7812 }
7813
7814 static HRESULT WINAPI ITypeComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
7815 {
7816     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7817
7818     return ITypeInfo_QueryInterface((ITypeInfo *)This, riid, ppv);
7819 }
7820
7821 static ULONG WINAPI ITypeComp_fnAddRef(ITypeComp * iface)
7822 {
7823     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7824
7825     return ITypeInfo_AddRef((ITypeInfo *)This);
7826 }
7827
7828 static ULONG WINAPI ITypeComp_fnRelease(ITypeComp * iface)
7829 {
7830     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7831
7832     return ITypeInfo_Release((ITypeInfo *)This);
7833 }
7834
7835 static HRESULT WINAPI ITypeComp_fnBind(
7836     ITypeComp * iface,
7837     OLECHAR * szName,
7838     ULONG lHash,
7839     WORD wFlags,
7840     ITypeInfo ** ppTInfo,
7841     DESCKIND * pDescKind,
7842     BINDPTR * pBindPtr)
7843 {
7844     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7845     const TLBFuncDesc *pFDesc;
7846     const TLBVarDesc *pVDesc;
7847     HRESULT hr = DISP_E_MEMBERNOTFOUND;
7848
7849     TRACE("(%p)->(%s, %x, 0x%x, %p, %p, %p)\n", This, debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
7850
7851     *pDescKind = DESCKIND_NONE;
7852     pBindPtr->lpfuncdesc = NULL;
7853     *ppTInfo = NULL;
7854
7855     for(pFDesc = This->funclist; pFDesc; pFDesc = pFDesc->next)
7856         if (!strcmpiW(pFDesc->Name, szName)) {
7857             if (!wFlags || (pFDesc->funcdesc.invkind & wFlags))
7858                 break;
7859             else
7860                 /* name found, but wrong flags */
7861                 hr = TYPE_E_TYPEMISMATCH;
7862         }
7863
7864     if (pFDesc)
7865     {
7866         HRESULT hr = TLB_AllocAndInitFuncDesc(
7867             &pFDesc->funcdesc,
7868             &pBindPtr->lpfuncdesc,
7869             This->TypeAttr.typekind == TKIND_DISPATCH);
7870         if (FAILED(hr))
7871             return hr;
7872         *pDescKind = DESCKIND_FUNCDESC;
7873         *ppTInfo = (ITypeInfo *)&This->lpVtbl;
7874         ITypeInfo_AddRef(*ppTInfo);
7875         return S_OK;
7876     } else {
7877         for(pVDesc = This->varlist; pVDesc; pVDesc = pVDesc->next) {
7878             if (!strcmpiW(pVDesc->Name, szName)) {
7879                 HRESULT hr = TLB_AllocAndInitVarDesc(&pVDesc->vardesc, &pBindPtr->lpvardesc);
7880                 if (FAILED(hr))
7881                     return hr;
7882                 *pDescKind = DESCKIND_VARDESC;
7883                 *ppTInfo = (ITypeInfo *)&This->lpVtbl;
7884                 ITypeInfo_AddRef(*ppTInfo);
7885                 return S_OK;
7886             }
7887         }
7888     }
7889     /* FIXME: search each inherited interface, not just the first */
7890     if (hr == DISP_E_MEMBERNOTFOUND && This->impltypelist) {
7891         /* recursive search */
7892         ITypeInfo *pTInfo;
7893         ITypeComp *pTComp;
7894         HRESULT hr;
7895         hr=ITypeInfo_GetRefTypeInfo((ITypeInfo *)&This->lpVtbl, This->impltypelist->hRef, &pTInfo);
7896         if (SUCCEEDED(hr))
7897         {
7898             hr = ITypeInfo_GetTypeComp(pTInfo,&pTComp);
7899             ITypeInfo_Release(pTInfo);
7900         }
7901         if (SUCCEEDED(hr))
7902         {
7903             hr = ITypeComp_Bind(pTComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
7904             ITypeComp_Release(pTComp);
7905             return hr;
7906         }
7907         WARN("Could not search inherited interface!\n");
7908     }
7909     if (hr == DISP_E_MEMBERNOTFOUND)
7910         hr = S_OK;
7911     TRACE("did not find member with name %s, flags 0x%x\n", debugstr_w(szName), wFlags);
7912     return hr;
7913 }
7914
7915 static HRESULT WINAPI ITypeComp_fnBindType(
7916     ITypeComp * iface,
7917     OLECHAR * szName,
7918     ULONG lHash,
7919     ITypeInfo ** ppTInfo,
7920     ITypeComp ** ppTComp)
7921 {
7922     TRACE("(%s, %x, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
7923
7924     /* strange behaviour (does nothing) but like the
7925      * original */
7926
7927     if (!ppTInfo || !ppTComp)
7928         return E_POINTER;
7929
7930     *ppTInfo = NULL;
7931     *ppTComp = NULL;
7932
7933     return S_OK;
7934 }
7935
7936 static const ITypeCompVtbl tcompvt =
7937 {
7938
7939     ITypeComp_fnQueryInterface,
7940     ITypeComp_fnAddRef,
7941     ITypeComp_fnRelease,
7942
7943     ITypeComp_fnBind,
7944     ITypeComp_fnBindType
7945 };