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