Release 1.5.29.
[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     int 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     int tic;
4557     UINT nNameBufLen = (lstrlenW(szNameBuf)+1)*sizeof(WCHAR), fdc, vrc;
4558
4559     TRACE("(%p)->(%s,%08x,%p)\n", This, debugstr_w(szNameBuf), lHashVal,
4560           pfName);
4561
4562     *pfName=TRUE;
4563     for(tic = 0; tic < This->TypeInfoCount; ++tic){
4564         ITypeInfoImpl *pTInfo = This->typeinfos[tic];
4565         if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
4566         for(fdc = 0; fdc < pTInfo->TypeAttr.cFuncs; ++fdc) {
4567             TLBFuncDesc *pFInfo = &pTInfo->funcdescs[fdc];
4568             int pc;
4569
4570             if(!memcmp(szNameBuf,pFInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
4571             for(pc=0; pc < pFInfo->funcdesc.cParams; pc++)
4572                 if(!memcmp(szNameBuf,pFInfo->pParamDesc[pc].Name, nNameBufLen))
4573                     goto ITypeLib2_fnIsName_exit;
4574         }
4575         for(vrc = 0; vrc < pTInfo->TypeAttr.cVars; ++vrc){
4576             TLBVarDesc *pVInfo = &pTInfo->vardescs[vrc];
4577             if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
4578         }
4579
4580     }
4581     *pfName=FALSE;
4582
4583 ITypeLib2_fnIsName_exit:
4584     TRACE("(%p)slow! search for %s: %s found!\n", This,
4585           debugstr_w(szNameBuf), *pfName?"NOT":"");
4586
4587     return S_OK;
4588 }
4589
4590 /* ITypeLib::FindName
4591  *
4592  * Finds occurrences of a type description in a type library. This may be used
4593  * to quickly verify that a name exists in a type library.
4594  *
4595  */
4596 static HRESULT WINAPI ITypeLib2_fnFindName(
4597         ITypeLib2 *iface,
4598         LPOLESTR name,
4599         ULONG hash,
4600         ITypeInfo **ppTInfo,
4601         MEMBERID *memid,
4602         UINT16 *found)
4603 {
4604     ITypeLibImpl *This = impl_from_ITypeLib2(iface);
4605     int tic;
4606     UINT count = 0;
4607     UINT len;
4608
4609     TRACE("(%p)->(%s %u %p %p %p)\n", This, debugstr_w(name), hash, ppTInfo, memid, found);
4610
4611     if ((!name && hash == 0) || !ppTInfo || !memid || !found)
4612         return E_INVALIDARG;
4613
4614     len = (lstrlenW(name) + 1)*sizeof(WCHAR);
4615     for(tic = 0; tic < This->TypeInfoCount; ++tic) {
4616         ITypeInfoImpl *pTInfo = This->typeinfos[tic];
4617         TLBVarDesc *var;
4618         UINT fdc;
4619
4620         if(!memcmp(name, pTInfo->Name, len)) goto ITypeLib2_fnFindName_exit;
4621         for(fdc = 0; fdc < pTInfo->TypeAttr.cFuncs; ++fdc) {
4622             TLBFuncDesc *func = &pTInfo->funcdescs[fdc];
4623             int pc;
4624
4625             if(!memcmp(name, func->Name, len)) goto ITypeLib2_fnFindName_exit;
4626             for(pc = 0; pc < func->funcdesc.cParams; pc++) {
4627                 if(!memcmp(name, func->pParamDesc[pc].Name, len))
4628                     goto ITypeLib2_fnFindName_exit;
4629             }
4630         }
4631
4632         var = TLB_get_vardesc_by_name(pTInfo->vardescs, pTInfo->TypeAttr.cVars, name);
4633         if (var)
4634             goto ITypeLib2_fnFindName_exit;
4635
4636         continue;
4637 ITypeLib2_fnFindName_exit:
4638         ITypeInfo_AddRef((ITypeInfo*)pTInfo);
4639         ppTInfo[count]=(LPTYPEINFO)pTInfo;
4640         count++;
4641     }
4642     TRACE("found %d typeinfos\n", count);
4643
4644     *found = count;
4645
4646     return S_OK;
4647 }
4648
4649 /* ITypeLib::ReleaseTLibAttr
4650  *
4651  * Releases the TLIBATTR originally obtained from ITypeLib::GetLibAttr.
4652  *
4653  */
4654 static VOID WINAPI ITypeLib2_fnReleaseTLibAttr(
4655         ITypeLib2 *iface,
4656         TLIBATTR *pTLibAttr)
4657 {
4658     ITypeLibImpl *This = impl_from_ITypeLib2(iface);
4659     TRACE("(%p)->(%p)\n", This, pTLibAttr);
4660     heap_free(pTLibAttr);
4661 }
4662
4663 /* ITypeLib2::GetCustData
4664  *
4665  * gets the custom data
4666  */
4667 static HRESULT WINAPI ITypeLib2_fnGetCustData(
4668         ITypeLib2 * iface,
4669         REFGUID guid,
4670         VARIANT *pVarVal)
4671 {
4672     ITypeLibImpl *This = impl_from_ITypeLib2(iface);
4673     TLBCustData *pCData;
4674
4675     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(guid), pVarVal);
4676
4677     pCData = TLB_get_custdata_by_guid(&This->custdata_list, guid);
4678     if(!pCData)
4679         return TYPE_E_ELEMENTNOTFOUND;
4680
4681     VariantInit(pVarVal);
4682     VariantCopy(pVarVal, &pCData->data);
4683
4684     return S_OK;
4685 }
4686
4687 /* ITypeLib2::GetLibStatistics
4688  *
4689  * Returns statistics about a type library that are required for efficient
4690  * sizing of hash tables.
4691  *
4692  */
4693 static HRESULT WINAPI ITypeLib2_fnGetLibStatistics(
4694         ITypeLib2 * iface,
4695         ULONG *pcUniqueNames,
4696         ULONG *pcchUniqueNames)
4697 {
4698     ITypeLibImpl *This = impl_from_ITypeLib2(iface);
4699
4700     FIXME("(%p): stub!\n", This);
4701
4702     if(pcUniqueNames) *pcUniqueNames=1;
4703     if(pcchUniqueNames) *pcchUniqueNames=1;
4704     return S_OK;
4705 }
4706
4707 /* ITypeLib2::GetDocumentation2
4708  *
4709  * Retrieves the library's documentation string, the complete Help file name
4710  * and path, the localization context to use, and the context ID for the
4711  * library Help topic in the Help file.
4712  *
4713  */
4714 static HRESULT WINAPI ITypeLib2_fnGetDocumentation2(
4715         ITypeLib2 * iface,
4716         INT index,
4717         LCID lcid,
4718         BSTR *pbstrHelpString,
4719         DWORD *pdwHelpStringContext,
4720         BSTR *pbstrHelpStringDll)
4721 {
4722     ITypeLibImpl *This = impl_from_ITypeLib2(iface);
4723     HRESULT result;
4724     ITypeInfo *pTInfo;
4725
4726     FIXME("(%p) index %d lcid %d half implemented stub!\n", This, index, lcid);
4727
4728     /* the help string should be obtained from the helpstringdll,
4729      * using the _DLLGetDocumentation function, based on the supplied
4730      * lcid. Nice to do sometime...
4731      */
4732     if(index<0)
4733     {
4734       /* documentation for the typelib */
4735       if(pbstrHelpString)
4736         *pbstrHelpString=SysAllocString(This->DocString);
4737       if(pdwHelpStringContext)
4738         *pdwHelpStringContext=This->dwHelpContext;
4739       if(pbstrHelpStringDll)
4740         *pbstrHelpStringDll=SysAllocString(This->HelpStringDll);
4741
4742       result = S_OK;
4743     }
4744     else
4745     {
4746       /* for a typeinfo */
4747       result=ITypeLib2_GetTypeInfo(iface, index, &pTInfo);
4748
4749       if(SUCCEEDED(result))
4750       {
4751         ITypeInfo2 * pTInfo2;
4752         result = ITypeInfo_QueryInterface(pTInfo,
4753                                           &IID_ITypeInfo2,
4754                                           (LPVOID*) &pTInfo2);
4755
4756         if(SUCCEEDED(result))
4757         {
4758           result = ITypeInfo2_GetDocumentation2(pTInfo2,
4759                                            MEMBERID_NIL,
4760                                            lcid,
4761                                            pbstrHelpString,
4762                                            pdwHelpStringContext,
4763                                            pbstrHelpStringDll);
4764
4765           ITypeInfo2_Release(pTInfo2);
4766         }
4767
4768         ITypeInfo_Release(pTInfo);
4769       }
4770     }
4771     return result;
4772 }
4773
4774 static HRESULT TLB_copy_all_custdata(struct list *custdata_list, CUSTDATA *pCustData)
4775 {
4776     TLBCustData *pCData;
4777     unsigned int ct;
4778     CUSTDATAITEM *cdi;
4779
4780     ct = list_count(custdata_list);
4781
4782     pCustData->prgCustData = heap_alloc_zero(ct * sizeof(CUSTDATAITEM));
4783     if(!pCustData->prgCustData)
4784         return E_OUTOFMEMORY;
4785
4786     pCustData->cCustData = ct;
4787
4788     cdi = pCustData->prgCustData;
4789     LIST_FOR_EACH_ENTRY(pCData, custdata_list, TLBCustData, entry){
4790         cdi->guid = pCData->guid;
4791         VariantCopy(&cdi->varValue, &pCData->data);
4792         ++cdi;
4793     }
4794
4795     return S_OK;
4796 }
4797
4798
4799 /* ITypeLib2::GetAllCustData
4800  *
4801  * Gets all custom data items for the library.
4802  *
4803  */
4804 static HRESULT WINAPI ITypeLib2_fnGetAllCustData(
4805         ITypeLib2 * iface,
4806         CUSTDATA *pCustData)
4807 {
4808     ITypeLibImpl *This = impl_from_ITypeLib2(iface);
4809     TRACE("(%p)->(%p)\n", This, pCustData);
4810     return TLB_copy_all_custdata(&This->custdata_list, pCustData);
4811 }
4812
4813 static const ITypeLib2Vtbl tlbvt = {
4814     ITypeLib2_fnQueryInterface,
4815     ITypeLib2_fnAddRef,
4816     ITypeLib2_fnRelease,
4817     ITypeLib2_fnGetTypeInfoCount,
4818     ITypeLib2_fnGetTypeInfo,
4819     ITypeLib2_fnGetTypeInfoType,
4820     ITypeLib2_fnGetTypeInfoOfGuid,
4821     ITypeLib2_fnGetLibAttr,
4822     ITypeLib2_fnGetTypeComp,
4823     ITypeLib2_fnGetDocumentation,
4824     ITypeLib2_fnIsName,
4825     ITypeLib2_fnFindName,
4826     ITypeLib2_fnReleaseTLibAttr,
4827
4828     ITypeLib2_fnGetCustData,
4829     ITypeLib2_fnGetLibStatistics,
4830     ITypeLib2_fnGetDocumentation2,
4831     ITypeLib2_fnGetAllCustData
4832  };
4833
4834
4835 static HRESULT WINAPI ITypeLibComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
4836 {
4837     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4838
4839     return ITypeLib2_QueryInterface(&This->ITypeLib2_iface, riid, ppv);
4840 }
4841
4842 static ULONG WINAPI ITypeLibComp_fnAddRef(ITypeComp * iface)
4843 {
4844     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4845
4846     return ITypeLib2_AddRef(&This->ITypeLib2_iface);
4847 }
4848
4849 static ULONG WINAPI ITypeLibComp_fnRelease(ITypeComp * iface)
4850 {
4851     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4852
4853     return ITypeLib2_Release(&This->ITypeLib2_iface);
4854 }
4855
4856 static HRESULT WINAPI ITypeLibComp_fnBind(
4857     ITypeComp * iface,
4858     OLECHAR * szName,
4859     ULONG lHash,
4860     WORD wFlags,
4861     ITypeInfo ** ppTInfo,
4862     DESCKIND * pDescKind,
4863     BINDPTR * pBindPtr)
4864 {
4865     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4866     int typemismatch=0, i;
4867
4868     TRACE("(%s, 0x%x, 0x%x, %p, %p, %p)\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
4869
4870     *pDescKind = DESCKIND_NONE;
4871     pBindPtr->lptcomp = NULL;
4872     *ppTInfo = NULL;
4873
4874     for(i = 0; i < This->TypeInfoCount; ++i){
4875         ITypeInfoImpl *pTypeInfo = This->typeinfos[i];
4876         TRACE("testing %s\n", debugstr_w(pTypeInfo->Name));
4877
4878         /* FIXME: check wFlags here? */
4879         /* FIXME: we should use a hash table to look this info up using lHash
4880          * instead of an O(n) search */
4881         if ((pTypeInfo->TypeAttr.typekind == TKIND_ENUM) ||
4882             (pTypeInfo->TypeAttr.typekind == TKIND_MODULE))
4883         {
4884             if (pTypeInfo->Name && !strcmpW(pTypeInfo->Name, szName))
4885             {
4886                 *pDescKind = DESCKIND_TYPECOMP;
4887                 pBindPtr->lptcomp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4888                 ITypeComp_AddRef(pBindPtr->lptcomp);
4889                 TRACE("module or enum: %s\n", debugstr_w(szName));
4890                 return S_OK;
4891             }
4892         }
4893
4894         if ((pTypeInfo->TypeAttr.typekind == TKIND_MODULE) ||
4895             (pTypeInfo->TypeAttr.typekind == TKIND_ENUM))
4896         {
4897             ITypeComp *pSubTypeComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4898             HRESULT hr;
4899
4900             hr = ITypeComp_Bind(pSubTypeComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
4901             if (SUCCEEDED(hr) && (*pDescKind != DESCKIND_NONE))
4902             {
4903                 TRACE("found in module or in enum: %s\n", debugstr_w(szName));
4904                 return S_OK;
4905             }
4906             else if (hr == TYPE_E_TYPEMISMATCH)
4907                 typemismatch = 1;
4908         }
4909
4910         if ((pTypeInfo->TypeAttr.typekind == TKIND_COCLASS) &&
4911             (pTypeInfo->TypeAttr.wTypeFlags & TYPEFLAG_FAPPOBJECT))
4912         {
4913             ITypeComp *pSubTypeComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4914             HRESULT hr;
4915             ITypeInfo *subtypeinfo;
4916             BINDPTR subbindptr;
4917             DESCKIND subdesckind;
4918
4919             hr = ITypeComp_Bind(pSubTypeComp, szName, lHash, wFlags,
4920                 &subtypeinfo, &subdesckind, &subbindptr);
4921             if (SUCCEEDED(hr) && (subdesckind != DESCKIND_NONE))
4922             {
4923                 TYPEDESC tdesc_appobject;
4924                 const VARDESC vardesc_appobject =
4925                 {
4926                     -2,         /* memid */
4927                     NULL,       /* lpstrSchema */
4928                     {
4929                         0       /* oInst */
4930                     },
4931                     {
4932                                 /* ELEMDESC */
4933                         {
4934                                 /* TYPEDESC */
4935                                 {
4936                                     &tdesc_appobject
4937                                 },
4938                                 VT_PTR
4939                         },
4940                     },
4941                     0,          /* wVarFlags */
4942                     VAR_STATIC  /* varkind */
4943                 };
4944
4945                 tdesc_appobject.u.hreftype = pTypeInfo->hreftype;
4946                 tdesc_appobject.vt = VT_USERDEFINED;
4947
4948                 TRACE("found in implicit app object: %s\n", debugstr_w(szName));
4949
4950                 /* cleanup things filled in by Bind call so we can put our
4951                  * application object data in there instead */
4952                 switch (subdesckind)
4953                 {
4954                 case DESCKIND_FUNCDESC:
4955                     ITypeInfo_ReleaseFuncDesc(subtypeinfo, subbindptr.lpfuncdesc);
4956                     break;
4957                 case DESCKIND_VARDESC:
4958                     ITypeInfo_ReleaseVarDesc(subtypeinfo, subbindptr.lpvardesc);
4959                     break;
4960                 default:
4961                     break;
4962                 }
4963                 if (subtypeinfo) ITypeInfo_Release(subtypeinfo);
4964
4965                 if (pTypeInfo->hreftype == -1)
4966                     FIXME("no hreftype for interface %p\n", pTypeInfo);
4967
4968                 hr = TLB_AllocAndInitVarDesc(&vardesc_appobject, &pBindPtr->lpvardesc);
4969                 if (FAILED(hr))
4970                     return hr;
4971
4972                 *pDescKind = DESCKIND_IMPLICITAPPOBJ;
4973                 *ppTInfo = (ITypeInfo *)pTypeInfo;
4974                 ITypeInfo_AddRef(*ppTInfo);
4975                 return S_OK;
4976             }
4977             else if (hr == TYPE_E_TYPEMISMATCH)
4978                 typemismatch = 1;
4979         }
4980     }
4981
4982     if (typemismatch)
4983     {
4984         TRACE("type mismatch %s\n", debugstr_w(szName));
4985         return TYPE_E_TYPEMISMATCH;
4986     }
4987     else
4988     {
4989         TRACE("name not found %s\n", debugstr_w(szName));
4990         return S_OK;
4991     }
4992 }
4993
4994 static HRESULT WINAPI ITypeLibComp_fnBindType(
4995     ITypeComp * iface,
4996     OLECHAR * szName,
4997     ULONG lHash,
4998     ITypeInfo ** ppTInfo,
4999     ITypeComp ** ppTComp)
5000 {
5001     ITypeLibImpl *This = impl_from_ITypeComp(iface);
5002     int i;
5003
5004     TRACE("(%s, %x, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
5005
5006     if(!szName || !ppTInfo || !ppTComp)
5007         return E_INVALIDARG;
5008
5009     for(i = 0; i < This->TypeInfoCount; ++i)
5010     {
5011         ITypeInfoImpl *pTypeInfo = This->typeinfos[i];
5012         /* FIXME: should use lHash to do the search */
5013         if (pTypeInfo->Name && !strcmpiW(pTypeInfo->Name, szName))
5014         {
5015             TRACE("returning %p\n", pTypeInfo);
5016             *ppTInfo = (ITypeInfo *)&pTypeInfo->lpVtbl;
5017             ITypeInfo_AddRef(*ppTInfo);
5018             *ppTComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
5019             ITypeComp_AddRef(*ppTComp);
5020             return S_OK;
5021         }
5022     }
5023
5024     TRACE("not found\n");
5025     *ppTInfo = NULL;
5026     *ppTComp = NULL;
5027     return S_OK;
5028 }
5029
5030 static const ITypeCompVtbl tlbtcvt =
5031 {
5032
5033     ITypeLibComp_fnQueryInterface,
5034     ITypeLibComp_fnAddRef,
5035     ITypeLibComp_fnRelease,
5036
5037     ITypeLibComp_fnBind,
5038     ITypeLibComp_fnBindType
5039 };
5040
5041 /*================== ITypeInfo(2) Methods ===================================*/
5042 static ITypeInfoImpl* ITypeInfoImpl_Constructor(void)
5043 {
5044     ITypeInfoImpl *pTypeInfoImpl;
5045
5046     pTypeInfoImpl = heap_alloc_zero(sizeof(ITypeInfoImpl));
5047     if (pTypeInfoImpl)
5048     {
5049       pTypeInfoImpl->lpVtbl = &tinfvt;
5050       pTypeInfoImpl->lpVtblTypeComp = &tcompvt;
5051       pTypeInfoImpl->ref = 0;
5052       pTypeInfoImpl->hreftype = -1;
5053       pTypeInfoImpl->TypeAttr.memidConstructor = MEMBERID_NIL;
5054       pTypeInfoImpl->TypeAttr.memidDestructor = MEMBERID_NIL;
5055       list_init(&pTypeInfoImpl->custdata_list);
5056     }
5057     TRACE("(%p)\n", pTypeInfoImpl);
5058     return pTypeInfoImpl;
5059 }
5060
5061 /* ITypeInfo::QueryInterface
5062  */
5063 static HRESULT WINAPI ITypeInfo_fnQueryInterface(
5064         ITypeInfo2 *iface,
5065         REFIID riid,
5066         VOID **ppvObject)
5067 {
5068     ITypeLibImpl *This = (ITypeLibImpl *)iface;
5069
5070     TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
5071
5072     *ppvObject=NULL;
5073     if(IsEqualIID(riid, &IID_IUnknown) ||
5074             IsEqualIID(riid,&IID_ITypeInfo)||
5075             IsEqualIID(riid,&IID_ITypeInfo2))
5076         *ppvObject = This;
5077
5078     if(*ppvObject){
5079         ITypeInfo2_AddRef(iface);
5080         TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
5081         return S_OK;
5082     }
5083     TRACE("-- Interface: E_NOINTERFACE\n");
5084     return E_NOINTERFACE;
5085 }
5086
5087 /* ITypeInfo::AddRef
5088  */
5089 static ULONG WINAPI ITypeInfo_fnAddRef( ITypeInfo2 *iface)
5090 {
5091     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5092     ULONG ref = InterlockedIncrement(&This->ref);
5093
5094     TRACE("(%p)->ref is %u\n",This, ref);
5095
5096     if (ref == 1 /* incremented from 0 */)
5097         ITypeLib2_AddRef(&This->pTypeLib->ITypeLib2_iface);
5098
5099     return ref;
5100 }
5101
5102 static void ITypeInfoImpl_Destroy(ITypeInfoImpl *This)
5103 {
5104     UINT i;
5105
5106     TRACE("destroying ITypeInfo(%p)\n",This);
5107
5108     SysFreeString(This->Name);
5109     This->Name = NULL;
5110
5111     SysFreeString(This->DocString);
5112     This->DocString = NULL;
5113
5114     SysFreeString(This->DllName);
5115     This->DllName = NULL;
5116
5117     for (i = 0; i < This->TypeAttr.cFuncs; ++i)
5118     {
5119         int j;
5120         TLBFuncDesc *pFInfo = &This->funcdescs[i];
5121         for(j = 0; j < pFInfo->funcdesc.cParams; j++)
5122         {
5123             ELEMDESC *elemdesc = &pFInfo->funcdesc.lprgelemdescParam[j];
5124             if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
5125             {
5126                 VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue);
5127                 heap_free(elemdesc->u.paramdesc.pparamdescex);
5128             }
5129             TLB_FreeCustData(&pFInfo->pParamDesc[j].custdata_list);
5130             SysFreeString(pFInfo->pParamDesc[j].Name);
5131         }
5132         heap_free(pFInfo->funcdesc.lprgelemdescParam);
5133         heap_free(pFInfo->pParamDesc);
5134         TLB_FreeCustData(&pFInfo->custdata_list);
5135         if (!IS_INTRESOURCE(pFInfo->Entry) && pFInfo->Entry != (BSTR)-1)
5136             SysFreeString(pFInfo->Entry);
5137         SysFreeString(pFInfo->HelpString);
5138         SysFreeString(pFInfo->Name);
5139     }
5140     heap_free(This->funcdescs);
5141
5142     for(i = 0; i < This->TypeAttr.cVars; ++i)
5143     {
5144         TLBVarDesc *pVInfo = &This->vardescs[i];
5145         if (pVInfo->vardesc.varkind == VAR_CONST)
5146         {
5147             VariantClear(pVInfo->vardesc.u.lpvarValue);
5148             heap_free(pVInfo->vardesc.u.lpvarValue);
5149         }
5150         TLB_FreeCustData(&pVInfo->custdata_list);
5151         SysFreeString(pVInfo->Name);
5152         SysFreeString(pVInfo->HelpString);
5153     }
5154     heap_free(This->vardescs);
5155
5156     if(This->impltypes){
5157         for (i = 0; i < This->TypeAttr.cImplTypes; ++i){
5158             TLBImplType *pImpl = &This->impltypes[i];
5159             TLB_FreeCustData(&pImpl->custdata_list);
5160         }
5161         heap_free(This->impltypes);
5162     }
5163
5164     TLB_FreeCustData(&This->custdata_list);
5165
5166     heap_free(This);
5167 }
5168
5169 /* ITypeInfo::Release
5170  */
5171 static ULONG WINAPI ITypeInfo_fnRelease(ITypeInfo2 *iface)
5172 {
5173     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5174     ULONG ref = InterlockedDecrement(&This->ref);
5175
5176     TRACE("(%p)->(%u)\n",This, ref);
5177
5178     if (!ref)
5179     {
5180         BOOL not_attached_to_typelib = This->not_attached_to_typelib;
5181         ITypeLib2_Release(&This->pTypeLib->ITypeLib2_iface);
5182         if (not_attached_to_typelib)
5183             heap_free(This);
5184         /* otherwise This will be freed when typelib is freed */
5185     }
5186
5187     return ref;
5188 }
5189
5190 /* ITypeInfo::GetTypeAttr
5191  *
5192  * Retrieves a TYPEATTR structure that contains the attributes of the type
5193  * description.
5194  *
5195  */
5196 static HRESULT WINAPI ITypeInfo_fnGetTypeAttr( ITypeInfo2 *iface,
5197         LPTYPEATTR  *ppTypeAttr)
5198 {
5199     const ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5200     SIZE_T size;
5201
5202     TRACE("(%p)\n",This);
5203
5204     size = sizeof(**ppTypeAttr);
5205     if (This->TypeAttr.typekind == TKIND_ALIAS)
5206         size += TLB_SizeTypeDesc(&This->TypeAttr.tdescAlias, FALSE);
5207
5208     *ppTypeAttr = heap_alloc(size);
5209     if (!*ppTypeAttr)
5210         return E_OUTOFMEMORY;
5211
5212     **ppTypeAttr = This->TypeAttr;
5213
5214     if (This->TypeAttr.typekind == TKIND_ALIAS)
5215         TLB_CopyTypeDesc(&(*ppTypeAttr)->tdescAlias,
5216             &This->TypeAttr.tdescAlias, *ppTypeAttr + 1);
5217
5218     if((*ppTypeAttr)->typekind == TKIND_DISPATCH) {
5219         /* This should include all the inherited funcs */
5220         (*ppTypeAttr)->cFuncs = (*ppTypeAttr)->cbSizeVft / sizeof(void *);
5221         /* This is always the size of IDispatch's vtbl */
5222         (*ppTypeAttr)->cbSizeVft = sizeof(IDispatchVtbl);
5223         (*ppTypeAttr)->wTypeFlags &= ~TYPEFLAG_FOLEAUTOMATION;
5224     }
5225     return S_OK;
5226 }
5227
5228 /* ITypeInfo::GetTypeComp
5229  *
5230  * Retrieves the ITypeComp interface for the type description, which enables a
5231  * client compiler to bind to the type description's members.
5232  *
5233  */
5234 static HRESULT WINAPI ITypeInfo_fnGetTypeComp( ITypeInfo2 *iface,
5235         ITypeComp  * *ppTComp)
5236 {
5237     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5238
5239     TRACE("(%p)->(%p)\n", This, ppTComp);
5240
5241     *ppTComp = (ITypeComp *)&This->lpVtblTypeComp;
5242     ITypeComp_AddRef(*ppTComp);
5243     return S_OK;
5244 }
5245
5246 static SIZE_T TLB_SizeElemDesc( const ELEMDESC *elemdesc )
5247 {
5248     SIZE_T size = TLB_SizeTypeDesc(&elemdesc->tdesc, FALSE);
5249     if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
5250         size += sizeof(*elemdesc->u.paramdesc.pparamdescex);
5251     return size;
5252 }
5253
5254 static HRESULT TLB_CopyElemDesc( const ELEMDESC *src, ELEMDESC *dest, char **buffer )
5255 {
5256     *dest = *src;
5257     *buffer = TLB_CopyTypeDesc(&dest->tdesc, &src->tdesc, *buffer);
5258     if (src->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
5259     {
5260         const PARAMDESCEX *pparamdescex_src = src->u.paramdesc.pparamdescex;
5261         PARAMDESCEX *pparamdescex_dest = dest->u.paramdesc.pparamdescex = (PARAMDESCEX *)*buffer;
5262         *buffer += sizeof(PARAMDESCEX);
5263         *pparamdescex_dest = *pparamdescex_src;
5264         VariantInit(&pparamdescex_dest->varDefaultValue);
5265         return VariantCopy(&pparamdescex_dest->varDefaultValue, 
5266                            (VARIANTARG *)&pparamdescex_src->varDefaultValue);
5267     }
5268     else
5269         dest->u.paramdesc.pparamdescex = NULL;
5270     return S_OK;
5271 }
5272
5273 static void TLB_FreeElemDesc( ELEMDESC *elemdesc )
5274 {
5275     if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
5276         VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue);
5277 }
5278
5279 static HRESULT TLB_AllocAndInitFuncDesc( const FUNCDESC *src, FUNCDESC **dest_ptr, BOOL dispinterface )
5280 {
5281     FUNCDESC *dest;
5282     char *buffer;
5283     SIZE_T size = sizeof(*src);
5284     SHORT i;
5285     HRESULT hr;
5286
5287     size += sizeof(*src->lprgscode) * src->cScodes;
5288     size += TLB_SizeElemDesc(&src->elemdescFunc);
5289     for (i = 0; i < src->cParams; i++)
5290     {
5291         size += sizeof(ELEMDESC);
5292         size += TLB_SizeElemDesc(&src->lprgelemdescParam[i]);
5293     }
5294
5295     dest = (FUNCDESC *)SysAllocStringByteLen(NULL, size);
5296     if (!dest) return E_OUTOFMEMORY;
5297
5298     *dest = *src;
5299     if (dispinterface)    /* overwrite funckind */
5300         dest->funckind = FUNC_DISPATCH;
5301     buffer = (char *)(dest + 1);
5302
5303     dest->lprgscode = (SCODE *)buffer;
5304     memcpy(dest->lprgscode, src->lprgscode, sizeof(*src->lprgscode) * src->cScodes);
5305     buffer += sizeof(*src->lprgscode) * src->cScodes;
5306
5307     hr = TLB_CopyElemDesc(&src->elemdescFunc, &dest->elemdescFunc, &buffer);
5308     if (FAILED(hr))
5309     {
5310         SysFreeString((BSTR)dest);
5311         return hr;
5312     }
5313
5314     dest->lprgelemdescParam = (ELEMDESC *)buffer;
5315     buffer += sizeof(ELEMDESC) * src->cParams;
5316     for (i = 0; i < src->cParams; i++)
5317     {
5318         hr = TLB_CopyElemDesc(&src->lprgelemdescParam[i], &dest->lprgelemdescParam[i], &buffer);
5319         if (FAILED(hr))
5320             break;
5321     }
5322     if (FAILED(hr))
5323     {
5324         /* undo the above actions */
5325         for (i = i - 1; i >= 0; i--)
5326             TLB_FreeElemDesc(&dest->lprgelemdescParam[i]);
5327         TLB_FreeElemDesc(&dest->elemdescFunc);
5328         SysFreeString((BSTR)dest);
5329         return hr;
5330     }
5331
5332     /* special treatment for dispinterfaces: this makes functions appear
5333      * to return their [retval] value when it is really returning an
5334      * HRESULT */
5335     if (dispinterface && dest->elemdescFunc.tdesc.vt == VT_HRESULT)
5336     {
5337         if (dest->cParams &&
5338             (dest->lprgelemdescParam[dest->cParams - 1].u.paramdesc.wParamFlags & PARAMFLAG_FRETVAL))
5339         {
5340             ELEMDESC *elemdesc = &dest->lprgelemdescParam[dest->cParams - 1];
5341             if (elemdesc->tdesc.vt != VT_PTR)
5342             {
5343                 ERR("elemdesc should have started with VT_PTR instead of:\n");
5344                 if (ERR_ON(ole))
5345                     dump_ELEMDESC(elemdesc);
5346                 return E_UNEXPECTED;
5347             }
5348
5349             /* copy last parameter to the return value. we are using a flat
5350              * buffer so there is no danger of leaking memory in
5351              * elemdescFunc */
5352             dest->elemdescFunc.tdesc = *elemdesc->tdesc.u.lptdesc;
5353
5354             /* remove the last parameter */
5355             dest->cParams--;
5356         }
5357         else
5358             /* otherwise this function is made to appear to have no return
5359              * value */
5360             dest->elemdescFunc.tdesc.vt = VT_VOID;
5361
5362     }
5363
5364     *dest_ptr = dest;
5365     return S_OK;
5366 }
5367
5368 HRESULT ITypeInfoImpl_GetInternalFuncDesc( ITypeInfo *iface, UINT index, const FUNCDESC **ppFuncDesc )
5369 {
5370     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5371
5372     if (index >= This->TypeAttr.cFuncs)
5373         return TYPE_E_ELEMENTNOTFOUND;
5374
5375     *ppFuncDesc = &This->funcdescs[index].funcdesc;
5376     return S_OK;
5377 }
5378
5379 /* internal function to make the inherited interfaces' methods appear
5380  * part of the interface */
5381 static HRESULT ITypeInfoImpl_GetInternalDispatchFuncDesc( ITypeInfo *iface,
5382     UINT index, const FUNCDESC **ppFuncDesc, UINT *funcs, UINT *hrefoffset)
5383 {
5384     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5385     HRESULT hr;
5386     UINT implemented_funcs = 0;
5387
5388     if (funcs)
5389         *funcs = 0;
5390     else
5391         *hrefoffset = DISPATCH_HREF_OFFSET;
5392
5393     if(This->impltypes)
5394     {
5395         ITypeInfo *pSubTypeInfo;
5396         UINT sub_funcs;
5397
5398         hr = ITypeInfo_GetRefTypeInfo(iface, This->impltypes[0].hRef, &pSubTypeInfo);
5399         if (FAILED(hr))
5400             return hr;
5401
5402         hr = ITypeInfoImpl_GetInternalDispatchFuncDesc(pSubTypeInfo,
5403                                                        index,
5404                                                        ppFuncDesc,
5405                                                        &sub_funcs, hrefoffset);
5406         implemented_funcs += sub_funcs;
5407         ITypeInfo_Release(pSubTypeInfo);
5408         if (SUCCEEDED(hr))
5409             return hr;
5410         *hrefoffset += DISPATCH_HREF_OFFSET;
5411     }
5412
5413     if (funcs)
5414         *funcs = implemented_funcs + This->TypeAttr.cFuncs;
5415     else
5416         *hrefoffset = 0;
5417     
5418     if (index < implemented_funcs)
5419         return E_INVALIDARG;
5420     return ITypeInfoImpl_GetInternalFuncDesc(iface, index - implemented_funcs,
5421                                              ppFuncDesc);
5422 }
5423
5424 static inline void ITypeInfoImpl_ElemDescAddHrefOffset( LPELEMDESC pElemDesc, UINT hrefoffset)
5425 {
5426     TYPEDESC *pTypeDesc = &pElemDesc->tdesc;
5427     while (TRUE)
5428     {
5429         switch (pTypeDesc->vt)
5430         {
5431         case VT_USERDEFINED:
5432             pTypeDesc->u.hreftype += hrefoffset;
5433             return;
5434         case VT_PTR:
5435         case VT_SAFEARRAY:
5436             pTypeDesc = pTypeDesc->u.lptdesc;
5437             break;
5438         case VT_CARRAY:
5439             pTypeDesc = &pTypeDesc->u.lpadesc->tdescElem;
5440             break;
5441         default:
5442             return;
5443         }
5444     }
5445 }
5446
5447 static inline void ITypeInfoImpl_FuncDescAddHrefOffset( LPFUNCDESC pFuncDesc, UINT hrefoffset)
5448 {
5449     SHORT i;
5450     for (i = 0; i < pFuncDesc->cParams; i++)
5451         ITypeInfoImpl_ElemDescAddHrefOffset(&pFuncDesc->lprgelemdescParam[i], hrefoffset);
5452     ITypeInfoImpl_ElemDescAddHrefOffset(&pFuncDesc->elemdescFunc, hrefoffset);
5453 }
5454
5455 /* ITypeInfo::GetFuncDesc
5456  *
5457  * Retrieves the FUNCDESC structure that contains information about a
5458  * specified function.
5459  *
5460  */
5461 static HRESULT WINAPI ITypeInfo_fnGetFuncDesc( ITypeInfo2 *iface, UINT index,
5462         LPFUNCDESC  *ppFuncDesc)
5463 {
5464     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5465     const FUNCDESC *internal_funcdesc;
5466     HRESULT hr;
5467     UINT hrefoffset = 0;
5468
5469     TRACE("(%p) index %d\n", This, index);
5470
5471     if (This->TypeAttr.typekind == TKIND_DISPATCH)
5472         hr = ITypeInfoImpl_GetInternalDispatchFuncDesc((ITypeInfo *)iface, index,
5473                                                        &internal_funcdesc, NULL,
5474                                                        &hrefoffset);
5475     else
5476         hr = ITypeInfoImpl_GetInternalFuncDesc((ITypeInfo *)iface, index,
5477                                                &internal_funcdesc);
5478     if (FAILED(hr))
5479     {
5480         WARN("description for function %d not found\n", index);
5481         return hr;
5482     }
5483
5484     hr = TLB_AllocAndInitFuncDesc(
5485         internal_funcdesc,
5486         ppFuncDesc,
5487         This->TypeAttr.typekind == TKIND_DISPATCH);
5488
5489     if ((This->TypeAttr.typekind == TKIND_DISPATCH) && hrefoffset)
5490         ITypeInfoImpl_FuncDescAddHrefOffset(*ppFuncDesc, hrefoffset);
5491
5492     TRACE("-- 0x%08x\n", hr);
5493     return hr;
5494 }
5495
5496 static HRESULT TLB_AllocAndInitVarDesc( const VARDESC *src, VARDESC **dest_ptr )
5497 {
5498     VARDESC *dest;
5499     char *buffer;
5500     SIZE_T size = sizeof(*src);
5501     HRESULT hr;
5502
5503     if (src->lpstrSchema) size += (strlenW(src->lpstrSchema) + 1) * sizeof(WCHAR);
5504     if (src->varkind == VAR_CONST)
5505         size += sizeof(VARIANT);
5506     size += TLB_SizeElemDesc(&src->elemdescVar);
5507
5508     dest = (VARDESC *)SysAllocStringByteLen(NULL, size);
5509     if (!dest) return E_OUTOFMEMORY;
5510
5511     *dest = *src;
5512     buffer = (char *)(dest + 1);
5513     if (src->lpstrSchema)
5514     {
5515         int len;
5516         dest->lpstrSchema = (LPOLESTR)buffer;
5517         len = strlenW(src->lpstrSchema);
5518         memcpy(dest->lpstrSchema, src->lpstrSchema, (len + 1) * sizeof(WCHAR));
5519         buffer += (len + 1) * sizeof(WCHAR);
5520     }
5521
5522     if (src->varkind == VAR_CONST)
5523     {
5524         HRESULT hr;
5525
5526         dest->u.lpvarValue = (VARIANT *)buffer;
5527         *dest->u.lpvarValue = *src->u.lpvarValue;
5528         buffer += sizeof(VARIANT);
5529         VariantInit(dest->u.lpvarValue);
5530         hr = VariantCopy(dest->u.lpvarValue, src->u.lpvarValue);
5531         if (FAILED(hr))
5532         {
5533             SysFreeString((BSTR)dest);
5534             return hr;
5535         }
5536     }
5537     hr = TLB_CopyElemDesc(&src->elemdescVar, &dest->elemdescVar, &buffer);
5538     if (FAILED(hr))
5539     {
5540         if (src->varkind == VAR_CONST)
5541             VariantClear(dest->u.lpvarValue);
5542         SysFreeString((BSTR)dest);
5543         return hr;
5544     }
5545     *dest_ptr = dest;
5546     return S_OK;
5547 }
5548
5549 /* ITypeInfo::GetVarDesc
5550  *
5551  * Retrieves a VARDESC structure that describes the specified variable.
5552  *
5553  */
5554 static HRESULT WINAPI ITypeInfo_fnGetVarDesc( ITypeInfo2 *iface, UINT index,
5555         LPVARDESC  *ppVarDesc)
5556 {
5557     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5558     const TLBVarDesc *pVDesc = &This->vardescs[index];
5559
5560     TRACE("(%p) index %d\n", This, index);
5561
5562     if(index >= This->TypeAttr.cVars)
5563         return TYPE_E_ELEMENTNOTFOUND;
5564
5565     return TLB_AllocAndInitVarDesc(&pVDesc->vardesc, ppVarDesc);
5566 }
5567
5568 /* ITypeInfo_GetNames
5569  *
5570  * Retrieves the variable with the specified member ID (or the name of the
5571  * property or method and its parameters) that correspond to the specified
5572  * function ID.
5573  */
5574 static HRESULT WINAPI ITypeInfo_fnGetNames( ITypeInfo2 *iface, MEMBERID memid,
5575         BSTR  *rgBstrNames, UINT cMaxNames, UINT  *pcNames)
5576 {
5577     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5578     const TLBFuncDesc *pFDesc;
5579     const TLBVarDesc *pVDesc;
5580     int i;
5581     TRACE("(%p) memid=0x%08x Maxname=%d\n", This, memid, cMaxNames);
5582     pFDesc = TLB_get_funcdesc_by_memberid(This->funcdescs, This->TypeAttr.cFuncs, memid);
5583     if(pFDesc)
5584     {
5585       /* function found, now return function and parameter names */
5586       for(i=0; i<cMaxNames && i <= pFDesc->funcdesc.cParams; i++)
5587       {
5588         if(!i)
5589           *rgBstrNames=SysAllocString(pFDesc->Name);
5590         else
5591           rgBstrNames[i]=SysAllocString(pFDesc->pParamDesc[i-1].Name);
5592       }
5593       *pcNames=i;
5594     }
5595     else
5596     {
5597       pVDesc = TLB_get_vardesc_by_memberid(This->vardescs, This->TypeAttr.cVars, memid);
5598       if(pVDesc)
5599       {
5600         *rgBstrNames=SysAllocString(pVDesc->Name);
5601         *pcNames=1;
5602       }
5603       else
5604       {
5605         if(This->impltypes &&
5606            (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
5607           /* recursive search */
5608           ITypeInfo *pTInfo;
5609           HRESULT result;
5610           result = ITypeInfo2_GetRefTypeInfo(iface, This->impltypes[0].hRef, &pTInfo);
5611           if(SUCCEEDED(result))
5612           {
5613             result=ITypeInfo_GetNames(pTInfo, memid, rgBstrNames, cMaxNames, pcNames);
5614             ITypeInfo_Release(pTInfo);
5615             return result;
5616           }
5617           WARN("Could not search inherited interface!\n");
5618         }
5619         else
5620         {
5621           WARN("no names found\n");
5622         }
5623         *pcNames=0;
5624         return TYPE_E_ELEMENTNOTFOUND;
5625       }
5626     }
5627     return S_OK;
5628 }
5629
5630
5631 /* ITypeInfo::GetRefTypeOfImplType
5632  *
5633  * If a type description describes a COM class, it retrieves the type
5634  * description of the implemented interface types. For an interface,
5635  * GetRefTypeOfImplType returns the type information for inherited interfaces,
5636  * if any exist.
5637  *
5638  */
5639 static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType(
5640         ITypeInfo2 *iface,
5641         UINT index,
5642         HREFTYPE  *pRefType)
5643 {
5644     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5645     HRESULT hr = S_OK;
5646
5647     TRACE("(%p) index %d\n", This, index);
5648     if (TRACE_ON(ole)) dump_TypeInfo(This);
5649
5650     if(index==(UINT)-1)
5651     {
5652       /* only valid on dual interfaces;
5653          retrieve the associated TKIND_INTERFACE handle for the current TKIND_DISPATCH
5654       */
5655       if( This->TypeAttr.typekind != TKIND_DISPATCH) return E_INVALIDARG;
5656
5657       if (This->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL)
5658       {
5659         *pRefType = -1;
5660       }
5661       else
5662       {
5663         hr = TYPE_E_ELEMENTNOTFOUND;
5664       }
5665     }
5666     else if(index == 0 && This->TypeAttr.typekind == TKIND_DISPATCH)
5667     {
5668       /* All TKIND_DISPATCHs are made to look like they inherit from IDispatch */
5669       *pRefType = This->pTypeLib->dispatch_href;
5670     }
5671     else
5672     {
5673         if(index >= This->TypeAttr.cImplTypes)
5674             hr = TYPE_E_ELEMENTNOTFOUND;
5675         else
5676             *pRefType = This->impltypes[index].hRef;
5677     }
5678
5679     if(TRACE_ON(ole))
5680     {
5681         if(SUCCEEDED(hr))
5682             TRACE("SUCCESS -- hRef = 0x%08x\n", *pRefType );
5683         else
5684             TRACE("FAILURE -- hresult = 0x%08x\n", hr);
5685     }
5686
5687     return hr;
5688 }
5689
5690 /* ITypeInfo::GetImplTypeFlags
5691  *
5692  * Retrieves the IMPLTYPEFLAGS enumeration for one implemented interface
5693  * or base interface in a type description.
5694  */
5695 static HRESULT WINAPI ITypeInfo_fnGetImplTypeFlags( ITypeInfo2 *iface,
5696         UINT index, INT  *pImplTypeFlags)
5697 {
5698     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5699
5700     TRACE("(%p) index %d\n", This, index);
5701
5702     if(This->TypeAttr.typekind == TKIND_DISPATCH && index == 0){
5703         *pImplTypeFlags = 0;
5704         return S_OK;
5705     }
5706
5707     if(index >= This->TypeAttr.cImplTypes)
5708         return TYPE_E_ELEMENTNOTFOUND;
5709
5710     *pImplTypeFlags = This->impltypes[index].implflags;
5711
5712     return S_OK;
5713 }
5714
5715 /* GetIDsOfNames
5716  * Maps between member names and member IDs, and parameter names and
5717  * parameter IDs.
5718  */
5719 static HRESULT WINAPI ITypeInfo_fnGetIDsOfNames( ITypeInfo2 *iface,
5720         LPOLESTR  *rgszNames, UINT cNames, MEMBERID  *pMemId)
5721 {
5722     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5723     const TLBVarDesc *pVDesc;
5724     HRESULT ret=S_OK;
5725     UINT i, fdc;
5726
5727     TRACE("(%p) Name %s cNames %d\n", This, debugstr_w(*rgszNames),
5728             cNames);
5729
5730     /* init out parameters in case of failure */
5731     for (i = 0; i < cNames; i++)
5732         pMemId[i] = MEMBERID_NIL;
5733
5734     for (fdc = 0; fdc < This->TypeAttr.cFuncs; ++fdc) {
5735         int j;
5736         const TLBFuncDesc *pFDesc = &This->funcdescs[fdc];
5737         if(!lstrcmpiW(*rgszNames, pFDesc->Name)) {
5738             if(cNames) *pMemId=pFDesc->funcdesc.memid;
5739             for(i=1; i < cNames; i++){
5740                 for(j=0; j<pFDesc->funcdesc.cParams; j++)
5741                     if(!lstrcmpiW(rgszNames[i],pFDesc->pParamDesc[j].Name))
5742                             break;
5743                 if( j<pFDesc->funcdesc.cParams)
5744                     pMemId[i]=j;
5745                 else
5746                    ret=DISP_E_UNKNOWNNAME;
5747             };
5748             TRACE("-- 0x%08x\n", ret);
5749             return ret;
5750         }
5751     }
5752     pVDesc = TLB_get_vardesc_by_name(This->vardescs, This->TypeAttr.cVars, *rgszNames);
5753     if(pVDesc){
5754         if(cNames)
5755             *pMemId = pVDesc->vardesc.memid;
5756         return ret;
5757     }
5758     /* not found, see if it can be found in an inherited interface */
5759     if(This->impltypes) {
5760         /* recursive search */
5761         ITypeInfo *pTInfo;
5762         ret = ITypeInfo2_GetRefTypeInfo(iface, This->impltypes[0].hRef, &pTInfo);
5763         if(SUCCEEDED(ret)){
5764             ret=ITypeInfo_GetIDsOfNames(pTInfo, rgszNames, cNames, pMemId );
5765             ITypeInfo_Release(pTInfo);
5766             return ret;
5767         }
5768         WARN("Could not search inherited interface!\n");
5769     } else
5770         WARN("no names found\n");
5771     return DISP_E_UNKNOWNNAME;
5772 }
5773
5774
5775 #ifdef __i386__
5776
5777 extern LONGLONG call_method( void *func, int nb_args, const DWORD *args, int *stack_offset );
5778 __ASM_GLOBAL_FUNC( call_method,
5779                    "pushl %ebp\n\t"
5780                    __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
5781                    __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
5782                    "movl %esp,%ebp\n\t"
5783                    __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
5784                    "pushl %esi\n\t"
5785                   __ASM_CFI(".cfi_rel_offset %esi,-4\n\t")
5786                    "pushl %edi\n\t"
5787                   __ASM_CFI(".cfi_rel_offset %edi,-8\n\t")
5788                    "movl 12(%ebp),%edx\n\t"
5789                    "movl %esp,%edi\n\t"
5790                    "shll $2,%edx\n\t"
5791                    "jz 1f\n\t"
5792                    "subl %edx,%edi\n\t"
5793                    "andl $~15,%edi\n\t"
5794                    "movl %edi,%esp\n\t"
5795                    "movl 12(%ebp),%ecx\n\t"
5796                    "movl 16(%ebp),%esi\n\t"
5797                    "cld\n\t"
5798                    "rep; movsl\n"
5799                    "1:\tcall *8(%ebp)\n\t"
5800                    "subl %esp,%edi\n\t"
5801                    "movl 20(%ebp),%ecx\n\t"
5802                    "movl %edi,(%ecx)\n\t"
5803                    "leal -8(%ebp),%esp\n\t"
5804                    "popl %edi\n\t"
5805                    __ASM_CFI(".cfi_same_value %edi\n\t")
5806                    "popl %esi\n\t"
5807                    __ASM_CFI(".cfi_same_value %esi\n\t")
5808                    "popl %ebp\n\t"
5809                    __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
5810                    __ASM_CFI(".cfi_same_value %ebp\n\t")
5811                    "ret" )
5812
5813 /* same function but returning floating point */
5814 static double (* const call_double_method)(void*,int,const DWORD*,int*) = (void *)call_method;
5815
5816 /* ITypeInfo::Invoke
5817  *
5818  * Invokes a method, or accesses a property of an object, that implements the
5819  * interface described by the type description.
5820  */
5821 DWORD
5822 _invoke(FARPROC func,CALLCONV callconv, int nrargs, DWORD *args) {
5823     DWORD res;
5824     int stack_offset;
5825
5826     if (TRACE_ON(ole)) {
5827         int i;
5828         TRACE("Calling %p(",func);
5829         for (i=0;i<min(nrargs,30);i++) TRACE("%08x,",args[i]);
5830         if (nrargs > 30) TRACE("...");
5831         TRACE(")\n");
5832     }
5833
5834     switch (callconv) {
5835     case CC_STDCALL:
5836     case CC_CDECL:
5837         res = call_method( func, nrargs, args, &stack_offset );
5838         break;
5839     default:
5840         FIXME("unsupported calling convention %d\n",callconv);
5841         res = -1;
5842         break;
5843     }
5844     TRACE("returns %08x\n",res);
5845     return res;
5846 }
5847
5848 #elif defined(__x86_64__)
5849
5850 extern DWORD_PTR CDECL call_method( void *func, int nb_args, const DWORD_PTR *args );
5851 __ASM_GLOBAL_FUNC( call_method,
5852                    "pushq %rbp\n\t"
5853                    __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t")
5854                    __ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
5855                    "movq %rsp,%rbp\n\t"
5856                    __ASM_CFI(".cfi_def_cfa_register %rbp\n\t")
5857                    "pushq %rsi\n\t"
5858                    __ASM_CFI(".cfi_rel_offset %rsi,-8\n\t")
5859                    "pushq %rdi\n\t"
5860                    __ASM_CFI(".cfi_rel_offset %rdi,-16\n\t")
5861                    "movq %rcx,%rax\n\t"
5862                    "movq $4,%rcx\n\t"
5863                    "cmp %rcx,%rdx\n\t"
5864                    "cmovgq %rdx,%rcx\n\t"
5865                    "leaq 0(,%rcx,8),%rdx\n\t"
5866                    "subq %rdx,%rsp\n\t"
5867                    "andq $~15,%rsp\n\t"
5868                    "movq %rsp,%rdi\n\t"
5869                    "movq %r8,%rsi\n\t"
5870                    "rep; movsq\n\t"
5871                    "movq 0(%rsp),%rcx\n\t"
5872                    "movq 8(%rsp),%rdx\n\t"
5873                    "movq 16(%rsp),%r8\n\t"
5874                    "movq 24(%rsp),%r9\n\t"
5875                    "movq %rcx,%xmm0\n\t"
5876                    "movq %rdx,%xmm1\n\t"
5877                    "movq %r8,%xmm2\n\t"
5878                    "movq %r9,%xmm3\n\t"
5879                    "callq *%rax\n\t"
5880                    "leaq -16(%rbp),%rsp\n\t"
5881                    "popq %rdi\n\t"
5882                    __ASM_CFI(".cfi_same_value %rdi\n\t")
5883                    "popq %rsi\n\t"
5884                    __ASM_CFI(".cfi_same_value %rsi\n\t")
5885                    __ASM_CFI(".cfi_def_cfa_register %rsp\n\t")
5886                    "popq %rbp\n\t"
5887                    __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t")
5888                    __ASM_CFI(".cfi_same_value %rbp\n\t")
5889                    "ret")
5890
5891 /* same function but returning floating point */
5892 static double (CDECL * const call_double_method)(void*,int,const DWORD_PTR*) = (void *)call_method;
5893
5894 #endif  /* __x86_64__ */
5895
5896 static HRESULT userdefined_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
5897 {
5898     HRESULT hr = S_OK;
5899     ITypeInfo *tinfo2 = NULL;
5900     TYPEATTR *tattr = NULL;
5901
5902     hr = ITypeInfo_GetRefTypeInfo(tinfo, tdesc->u.hreftype, &tinfo2);
5903     if (hr)
5904     {
5905         ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED, "
5906             "hr = 0x%08x\n",
5907               tdesc->u.hreftype, hr);
5908         return hr;
5909     }
5910     hr = ITypeInfo_GetTypeAttr(tinfo2, &tattr);
5911     if (hr)
5912     {
5913         ERR("ITypeInfo_GetTypeAttr failed, hr = 0x%08x\n", hr);
5914         ITypeInfo_Release(tinfo2);
5915         return hr;
5916     }
5917
5918     switch (tattr->typekind)
5919     {
5920     case TKIND_ENUM:
5921         *vt |= VT_I4;
5922         break;
5923
5924     case TKIND_ALIAS:
5925         tdesc = &tattr->tdescAlias;
5926         hr = typedescvt_to_variantvt(tinfo2, &tattr->tdescAlias, vt);
5927         break;
5928
5929     case TKIND_INTERFACE:
5930         if (tattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE)
5931            *vt |= VT_DISPATCH;
5932         else
5933            *vt |= VT_UNKNOWN;
5934         break;
5935
5936     case TKIND_DISPATCH:
5937         *vt |= VT_DISPATCH;
5938         break;
5939
5940     case TKIND_COCLASS:
5941         *vt |= VT_DISPATCH;
5942         break;
5943
5944     case TKIND_RECORD:
5945         FIXME("TKIND_RECORD unhandled.\n");
5946         hr = E_NOTIMPL;
5947         break;
5948
5949     case TKIND_UNION:
5950         FIXME("TKIND_UNION unhandled.\n");
5951         hr = E_NOTIMPL;
5952         break;
5953
5954     default:
5955         FIXME("TKIND %d unhandled.\n",tattr->typekind);
5956         hr = E_NOTIMPL;
5957         break;
5958     }
5959     ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
5960     ITypeInfo_Release(tinfo2);
5961     return hr;
5962 }
5963
5964 static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
5965 {
5966     HRESULT hr = S_OK;
5967
5968     /* enforce only one level of pointer indirection */
5969     if (!(*vt & VT_BYREF) && !(*vt & VT_ARRAY) && (tdesc->vt == VT_PTR))
5970     {
5971         tdesc = tdesc->u.lptdesc;
5972
5973         /* munch VT_PTR -> VT_USERDEFINED(interface) into VT_UNKNOWN or
5974          * VT_DISPATCH and VT_PTR -> VT_PTR -> VT_USERDEFINED(interface) into 
5975          * VT_BYREF|VT_DISPATCH or VT_BYREF|VT_UNKNOWN */
5976         if ((tdesc->vt == VT_USERDEFINED) ||
5977             ((tdesc->vt == VT_PTR) && (tdesc->u.lptdesc->vt == VT_USERDEFINED)))
5978         {
5979             VARTYPE vt_userdefined = 0;
5980             const TYPEDESC *tdesc_userdefined = tdesc;
5981             if (tdesc->vt == VT_PTR)
5982             {
5983                 vt_userdefined = VT_BYREF;
5984                 tdesc_userdefined = tdesc->u.lptdesc;
5985             }
5986             hr = userdefined_to_variantvt(tinfo, tdesc_userdefined, &vt_userdefined);
5987             if ((hr == S_OK) && 
5988                 (((vt_userdefined & VT_TYPEMASK) == VT_UNKNOWN) ||
5989                  ((vt_userdefined & VT_TYPEMASK) == VT_DISPATCH)))
5990             {
5991                 *vt |= vt_userdefined;
5992                 return S_OK;
5993             }
5994         }
5995         *vt = VT_BYREF;
5996     }
5997
5998     switch (tdesc->vt)
5999     {
6000     case VT_HRESULT:
6001         *vt |= VT_ERROR;
6002         break;
6003     case VT_USERDEFINED:
6004         hr = userdefined_to_variantvt(tinfo, tdesc, vt);
6005         break;
6006     case VT_VOID:
6007     case VT_CARRAY:
6008     case VT_PTR:
6009     case VT_LPSTR:
6010     case VT_LPWSTR:
6011         ERR("cannot convert type %d into variant VT\n", tdesc->vt);
6012         hr = DISP_E_BADVARTYPE;
6013         break;
6014     case VT_SAFEARRAY:
6015         *vt |= VT_ARRAY;
6016         hr = typedescvt_to_variantvt(tinfo, tdesc->u.lptdesc, vt);
6017         break;
6018     case VT_INT:
6019         *vt |= VT_I4;
6020         break;
6021     case VT_UINT:
6022         *vt |= VT_UI4;
6023         break;
6024     default:
6025         *vt |= tdesc->vt;
6026         break;
6027     }
6028     return hr;
6029 }
6030
6031 static HRESULT get_iface_guid(ITypeInfo *tinfo, const TYPEDESC *tdesc, GUID *guid)
6032 {
6033     ITypeInfo *tinfo2;
6034     TYPEATTR *tattr;
6035     HRESULT hres;
6036
6037     hres = ITypeInfo_GetRefTypeInfo(tinfo, tdesc->u.hreftype, &tinfo2);
6038     if(FAILED(hres))
6039         return hres;
6040
6041     hres = ITypeInfo_GetTypeAttr(tinfo2, &tattr);
6042     if(FAILED(hres)) {
6043         ITypeInfo_Release(tinfo2);
6044         return hres;
6045     }
6046
6047     switch(tattr->typekind) {
6048     case TKIND_ALIAS:
6049         hres = get_iface_guid(tinfo2, &tattr->tdescAlias, guid);
6050         break;
6051
6052     case TKIND_INTERFACE:
6053     case TKIND_DISPATCH:
6054         *guid = tattr->guid;
6055         break;
6056
6057     default:
6058         ERR("Unexpected typekind %d\n", tattr->typekind);
6059         hres = E_UNEXPECTED;
6060     }
6061
6062     ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
6063     ITypeInfo_Release(tinfo2);
6064     return hres;
6065 }
6066
6067 /***********************************************************************
6068  *              DispCallFunc (OLEAUT32.@)
6069  *
6070  * Invokes a function of the specified calling convention, passing the
6071  * specified arguments and returns the result.
6072  *
6073  * PARAMS
6074  *  pvInstance  [I] Optional pointer to the instance whose function to invoke.
6075  *  oVft        [I] The offset in the vtable. See notes.
6076  *  cc          [I] Calling convention of the function to call.
6077  *  vtReturn    [I] The return type of the function.
6078  *  cActuals    [I] Number of parameters.
6079  *  prgvt       [I] The types of the parameters to pass. This is used for sizing only.
6080  *  prgpvarg    [I] The arguments to pass.
6081  *  pvargResult [O] The return value of the function. Can be NULL.
6082  *
6083  * RETURNS
6084  *  Success: S_OK.
6085  *  Failure: HRESULT code.
6086  *
6087  * NOTES
6088  *  The HRESULT return value of this function is not affected by the return
6089  *  value of the user supplied function, which is returned in pvargResult.
6090  *
6091  *  If pvInstance is NULL then a non-object function is to be called and oVft
6092  *  is the address of the function to call.
6093  *
6094  * The cc parameter can be one of the following values:
6095  *|CC_FASTCALL
6096  *|CC_CDECL
6097  *|CC_PASCAL
6098  *|CC_STDCALL
6099  *|CC_FPFASTCALL
6100  *|CC_SYSCALL
6101  *|CC_MPWCDECL
6102  *|CC_MPWPASCAL
6103  *
6104  */
6105 HRESULT WINAPI
6106 DispCallFunc(
6107     void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals,
6108     VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult)
6109 {
6110 #ifdef __i386__
6111     int argspos, stack_offset;
6112     void *func;
6113     UINT i;
6114     DWORD *args;
6115
6116     TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
6117         pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
6118         pvargResult, V_VT(pvargResult));
6119
6120     if (cc != CC_STDCALL && cc != CC_CDECL)
6121     {
6122         FIXME("unsupported calling convention %d\n",cc);
6123         return E_INVALIDARG;
6124     }
6125
6126     /* maximum size for an argument is sizeof(VARIANT) */
6127     args = heap_alloc(sizeof(VARIANT) * cActuals + sizeof(DWORD) * 2 );
6128
6129     /* start at 1 in case we need to pass a pointer to the return value as arg 0 */
6130     argspos = 1;
6131     if (pvInstance)
6132     {
6133         const FARPROC *vtable = *(FARPROC **)pvInstance;
6134         func = vtable[oVft/sizeof(void *)];
6135         args[argspos++] = (DWORD)pvInstance; /* the This pointer is always the first parameter */
6136     }
6137     else func = (void *)oVft;
6138
6139     for (i = 0; i < cActuals; i++)
6140     {
6141         VARIANT *arg = prgpvarg[i];
6142
6143         switch (prgvt[i])
6144         {
6145         case VT_EMPTY:
6146             break;
6147         case VT_I8:
6148         case VT_UI8:
6149         case VT_R8:
6150         case VT_DATE:
6151         case VT_CY:
6152             memcpy( &args[argspos], &V_I8(arg), sizeof(V_I8(arg)) );
6153             argspos += sizeof(V_I8(arg)) / sizeof(DWORD);
6154             break;
6155         case VT_DECIMAL:
6156         case VT_VARIANT:
6157             memcpy( &args[argspos], arg, sizeof(*arg) );
6158             argspos += sizeof(*arg) / sizeof(DWORD);
6159             break;
6160         case VT_BOOL:  /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
6161             args[argspos++] = V_BOOL(arg);
6162             break;
6163         default:
6164             args[argspos++] = V_UI4(arg);
6165             break;
6166         }
6167         TRACE("arg %u: type %d\n",i,prgvt[i]);
6168         dump_Variant(arg);
6169     }
6170
6171     switch (vtReturn)
6172     {
6173     case VT_EMPTY:
6174         call_method( func, argspos - 1, args + 1, &stack_offset );
6175         break;
6176     case VT_R4:
6177         V_R4(pvargResult) = call_double_method( func, argspos - 1, args + 1, &stack_offset );
6178         break;
6179     case VT_R8:
6180     case VT_DATE:
6181         V_R8(pvargResult) = call_double_method( func, argspos - 1, args + 1, &stack_offset );
6182         break;
6183     case VT_DECIMAL:
6184     case VT_VARIANT:
6185         args[0] = (DWORD)pvargResult;  /* arg 0 is a pointer to the result */
6186         call_method( func, argspos, args, &stack_offset );
6187         break;
6188     case VT_I8:
6189     case VT_UI8:
6190     case VT_CY:
6191         V_UI8(pvargResult) = call_method( func, argspos - 1, args + 1, &stack_offset );
6192         break;
6193     case VT_HRESULT:
6194         WARN("invalid return type %u\n", vtReturn);
6195         heap_free( args );
6196         return E_INVALIDARG;
6197     default:
6198         V_UI4(pvargResult) = call_method( func, argspos - 1, args + 1, &stack_offset );
6199         break;
6200     }
6201     heap_free( args );
6202     if (stack_offset && cc == CC_STDCALL)
6203     {
6204         WARN( "stack pointer off by %d\n", stack_offset );
6205         return DISP_E_BADCALLEE;
6206     }
6207     if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
6208     TRACE("retval: "); dump_Variant(pvargResult);
6209     return S_OK;
6210
6211 #elif defined(__x86_64__)
6212     int argspos;
6213     UINT i;
6214     DWORD_PTR *args;
6215     void *func;
6216
6217     TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
6218           pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
6219           pvargResult, V_VT(pvargResult));
6220
6221     if (cc != CC_STDCALL && cc != CC_CDECL)
6222     {
6223         FIXME("unsupported calling convention %d\n",cc);
6224         return E_INVALIDARG;
6225     }
6226
6227     /* maximum size for an argument is sizeof(DWORD_PTR) */
6228     args = heap_alloc( sizeof(DWORD_PTR) * (cActuals + 2) );
6229
6230     /* start at 1 in case we need to pass a pointer to the return value as arg 0 */
6231     argspos = 1;
6232     if (pvInstance)
6233     {
6234         const FARPROC *vtable = *(FARPROC **)pvInstance;
6235         func = vtable[oVft/sizeof(void *)];
6236         args[argspos++] = (DWORD_PTR)pvInstance; /* the This pointer is always the first parameter */
6237     }
6238     else func = (void *)oVft;
6239
6240     for (i = 0; i < cActuals; i++)
6241     {
6242         VARIANT *arg = prgpvarg[i];
6243
6244         switch (prgvt[i])
6245         {
6246         case VT_DECIMAL:
6247         case VT_VARIANT:
6248             args[argspos++] = (ULONG_PTR)arg;
6249             break;
6250         case VT_BOOL:  /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
6251             args[argspos++] = V_BOOL(arg);
6252             break;
6253         default:
6254             args[argspos++] = V_UI8(arg);
6255             break;
6256         }
6257         TRACE("arg %u: type %d\n",i,prgvt[i]);
6258         dump_Variant(arg);
6259     }
6260
6261     switch (vtReturn)
6262     {
6263     case VT_R4:
6264         V_R4(pvargResult) = call_double_method( func, argspos - 1, args + 1 );
6265         break;
6266     case VT_R8:
6267     case VT_DATE:
6268         V_R8(pvargResult) = call_double_method( func, argspos - 1, args + 1 );
6269         break;
6270     case VT_DECIMAL:
6271     case VT_VARIANT:
6272         args[0] = (DWORD_PTR)pvargResult;  /* arg 0 is a pointer to the result */
6273         call_method( func, argspos, args );
6274         break;
6275     case VT_HRESULT:
6276         WARN("invalid return type %u\n", vtReturn);
6277         heap_free( args );
6278         return E_INVALIDARG;
6279     default:
6280         V_UI8(pvargResult) = call_method( func, argspos - 1, args + 1 );
6281         break;
6282     }
6283     heap_free( args );
6284     if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
6285     TRACE("retval: "); dump_Variant(pvargResult);
6286     return S_OK;
6287
6288 #else
6289     FIXME( "(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d)): not implemented for this CPU\n",
6290            pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg, pvargResult, V_VT(pvargResult));
6291     return E_NOTIMPL;
6292 #endif
6293 }
6294
6295 static inline BOOL func_restricted( const FUNCDESC *desc )
6296 {
6297     return (desc->wFuncFlags & FUNCFLAG_FRESTRICTED) && (desc->memid >= 0);
6298 }
6299
6300 #define INVBUF_ELEMENT_SIZE \
6301     (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *) + sizeof(VARTYPE))
6302 #define INVBUF_GET_ARG_ARRAY(buffer, params) (buffer)
6303 #define INVBUF_GET_MISSING_ARG_ARRAY(buffer, params) \
6304     ((VARIANTARG *)((char *)(buffer) + sizeof(VARIANTARG) * (params)))
6305 #define INVBUF_GET_ARG_PTR_ARRAY(buffer, params) \
6306     ((VARIANTARG **)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG)) * (params)))
6307 #define INVBUF_GET_ARG_TYPE_ARRAY(buffer, params) \
6308     ((VARTYPE *)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *)) * (params)))
6309
6310 static HRESULT WINAPI ITypeInfo_fnInvoke(
6311     ITypeInfo2 *iface,
6312     VOID  *pIUnk,
6313     MEMBERID memid,
6314     UINT16 wFlags,
6315     DISPPARAMS  *pDispParams,
6316     VARIANT  *pVarResult,
6317     EXCEPINFO  *pExcepInfo,
6318     UINT  *pArgErr)
6319 {
6320     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6321     int i;
6322     unsigned int var_index;
6323     TYPEKIND type_kind;
6324     HRESULT hres;
6325     const TLBFuncDesc *pFuncInfo;
6326     UINT fdc;
6327
6328     TRACE("(%p)(%p,id=%d,flags=0x%08x,%p,%p,%p,%p)\n",
6329       This,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr
6330     );
6331
6332     if( This->TypeAttr.wTypeFlags & TYPEFLAG_FRESTRICTED )
6333         return DISP_E_MEMBERNOTFOUND;
6334
6335     if (!pDispParams)
6336     {
6337         ERR("NULL pDispParams not allowed\n");
6338         return E_INVALIDARG;
6339     }
6340
6341     dump_DispParms(pDispParams);
6342
6343     if (pDispParams->cNamedArgs > pDispParams->cArgs)
6344     {
6345         ERR("named argument array cannot be bigger than argument array (%d/%d)\n",
6346             pDispParams->cNamedArgs, pDispParams->cArgs);
6347         return E_INVALIDARG;
6348     }
6349
6350     /* we do this instead of using GetFuncDesc since it will return a fake
6351      * FUNCDESC for dispinterfaces and we want the real function description */
6352     for (fdc = 0; fdc < This->TypeAttr.cFuncs; ++fdc){
6353         pFuncInfo = &This->funcdescs[fdc];
6354         if ((memid == pFuncInfo->funcdesc.memid) &&
6355             (wFlags & pFuncInfo->funcdesc.invkind) &&
6356             !func_restricted( &pFuncInfo->funcdesc ))
6357             break;
6358     }
6359
6360     if (fdc < This->TypeAttr.cFuncs) {
6361         const FUNCDESC *func_desc = &pFuncInfo->funcdesc;
6362
6363         if (TRACE_ON(ole))
6364         {
6365             TRACE("invoking:\n");
6366             dump_TLBFuncDescOne(pFuncInfo);
6367         }
6368         
6369         switch (func_desc->funckind) {
6370         case FUNC_PUREVIRTUAL:
6371         case FUNC_VIRTUAL: {
6372             void *buffer = heap_alloc_zero(INVBUF_ELEMENT_SIZE * func_desc->cParams);
6373             VARIANT varresult;
6374             VARIANT retval; /* pointer for storing byref retvals in */
6375             VARIANTARG **prgpvarg = INVBUF_GET_ARG_PTR_ARRAY(buffer, func_desc->cParams);
6376             VARIANTARG *rgvarg = INVBUF_GET_ARG_ARRAY(buffer, func_desc->cParams);
6377             VARTYPE *rgvt = INVBUF_GET_ARG_TYPE_ARRAY(buffer, func_desc->cParams);
6378             UINT cNamedArgs = pDispParams->cNamedArgs;
6379             DISPID *rgdispidNamedArgs = pDispParams->rgdispidNamedArgs;
6380             UINT vargs_converted=0;
6381
6382             hres = S_OK;
6383
6384             if (func_desc->invkind & (INVOKE_PROPERTYPUT|INVOKE_PROPERTYPUTREF))
6385             {
6386                 if (!cNamedArgs || (rgdispidNamedArgs[0] != DISPID_PROPERTYPUT))
6387                 {
6388                     ERR("first named arg for property put invocation must be DISPID_PROPERTYPUT\n");
6389                     hres = DISP_E_PARAMNOTFOUND;
6390                     goto func_fail;
6391                 }
6392             }
6393
6394             if (func_desc->cParamsOpt < 0 && cNamedArgs)
6395             {
6396                 ERR("functions with the vararg attribute do not support named arguments\n");
6397                 hres = DISP_E_NONAMEDARGS;
6398                 goto func_fail;
6399             }
6400
6401             for (i = 0; i < func_desc->cParams; i++)
6402             {
6403                 TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc;
6404                 hres = typedescvt_to_variantvt((ITypeInfo *)iface, tdesc, &rgvt[i]);
6405                 if (FAILED(hres))
6406                     goto func_fail;
6407             }
6408
6409             TRACE("changing args\n");
6410             for (i = 0; i < func_desc->cParams; i++)
6411             {
6412                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
6413                 TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc;
6414                 VARIANTARG *src_arg;
6415
6416                 if (wParamFlags & PARAMFLAG_FLCID)
6417                 {
6418                     VARIANTARG *arg;
6419                     arg = prgpvarg[i] = &rgvarg[i];
6420                     V_VT(arg) = VT_I4;
6421                     V_I4(arg) = This->pTypeLib->lcid;
6422                     continue;
6423                 }
6424
6425                 src_arg = NULL;
6426
6427                 if (cNamedArgs)
6428                 {
6429                     USHORT j;
6430                     for (j = 0; j < cNamedArgs; j++)
6431                         if (rgdispidNamedArgs[j] == i || (i == func_desc->cParams-1 && rgdispidNamedArgs[j] == DISPID_PROPERTYPUT))
6432                         {
6433                             src_arg = &pDispParams->rgvarg[j];
6434                             break;
6435                         }
6436                 }
6437
6438                 if (!src_arg && vargs_converted + cNamedArgs < pDispParams->cArgs)
6439                 {
6440                     src_arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted];
6441                     vargs_converted++;
6442                 }
6443
6444                 if (wParamFlags & PARAMFLAG_FRETVAL)
6445                 {
6446                     /* under most conditions the caller is not allowed to
6447                      * pass in a dispparam arg in the index of what would be
6448                      * the retval parameter. however, there is an exception
6449                      * where the extra parameter is used in an extra
6450                      * IDispatch::Invoke below */
6451                     if ((i < pDispParams->cArgs) &&
6452                         ((func_desc->cParams != 1) || !pVarResult ||
6453                          !(func_desc->invkind & INVOKE_PROPERTYGET)))
6454                     {
6455                         hres = DISP_E_BADPARAMCOUNT;
6456                         break;
6457                     }
6458
6459                     /* note: this check is placed so that if the caller passes
6460                      * in a VARIANTARG for the retval we just ignore it, like
6461                      * native does */
6462                     if (i == func_desc->cParams - 1)
6463                     {
6464                         VARIANTARG *arg;
6465                         arg = prgpvarg[i] = &rgvarg[i];
6466                         memset(arg, 0, sizeof(*arg));
6467                         V_VT(arg) = rgvt[i];
6468                         memset(&retval, 0, sizeof(retval));
6469                         V_BYREF(arg) = &retval;
6470                     }
6471                     else
6472                     {
6473                         ERR("[retval] parameter must be the last parameter of the method (%d/%d)\n", i, func_desc->cParams);
6474                         hres = E_UNEXPECTED;
6475                         break;
6476                     }
6477                 }
6478                 else if (src_arg)
6479                 {
6480                     dump_Variant(src_arg);
6481
6482                     if(rgvt[i]!=V_VT(src_arg))
6483                     {
6484                         if (rgvt[i] == VT_VARIANT)
6485                             hres = VariantCopy(&rgvarg[i], src_arg);
6486                         else if (rgvt[i] == (VT_VARIANT | VT_BYREF))
6487                         {
6488                             if (rgvt[i] == V_VT(src_arg))
6489                                 V_VARIANTREF(&rgvarg[i]) = V_VARIANTREF(src_arg);
6490                             else
6491                             {
6492                                 VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
6493                                 if (wParamFlags & PARAMFLAG_FIN)
6494                                     hres = VariantCopy(&missing_arg[i], src_arg);
6495                                 V_VARIANTREF(&rgvarg[i]) = &missing_arg[i];
6496                             }
6497                             V_VT(&rgvarg[i]) = rgvt[i];
6498                         }
6499                         else if (rgvt[i] == (VT_VARIANT | VT_ARRAY) && func_desc->cParamsOpt < 0 && i == func_desc->cParams-1)
6500                         {
6501                             SAFEARRAY *a;
6502                             SAFEARRAYBOUND bound;
6503                             VARIANT *v;
6504                             LONG j;
6505                             bound.lLbound = 0;
6506                             bound.cElements = pDispParams->cArgs-i;
6507                             if (!(a = SafeArrayCreate(VT_VARIANT, 1, &bound)))
6508                             {
6509                                 ERR("SafeArrayCreate failed\n");
6510                                 break;
6511                             }
6512                             hres = SafeArrayAccessData(a, (LPVOID)&v);
6513                             if (hres != S_OK)
6514                             {
6515                                 ERR("SafeArrayAccessData failed with %x\n", hres);
6516                                 SafeArrayDestroy(a);
6517                                 break;
6518                             }
6519                             for (j = 0; j < bound.cElements; j++)
6520                                 VariantCopy(&v[j], &pDispParams->rgvarg[pDispParams->cArgs - 1 - i - j]);
6521                             hres = SafeArrayUnaccessData(a);
6522                             if (hres != S_OK)
6523                             {
6524                                 ERR("SafeArrayUnaccessData failed with %x\n", hres);
6525                                 SafeArrayDestroy(a);
6526                                 break;
6527                             }
6528                             V_ARRAY(&rgvarg[i]) = a;
6529                             V_VT(&rgvarg[i]) = rgvt[i];
6530                         }
6531                         else if ((rgvt[i] & VT_BYREF) && !V_ISBYREF(src_arg))
6532                         {
6533                             VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
6534                             if (wParamFlags & PARAMFLAG_FIN)
6535                                 hres = VariantChangeType(&missing_arg[i], src_arg, 0, rgvt[i] & ~VT_BYREF);
6536                             else
6537                                 V_VT(&missing_arg[i]) = rgvt[i] & ~VT_BYREF;
6538                             V_BYREF(&rgvarg[i]) = &V_NONE(&missing_arg[i]);
6539                             V_VT(&rgvarg[i]) = rgvt[i];
6540                         }
6541                         else if ((rgvt[i] & VT_BYREF) && (rgvt[i] == V_VT(src_arg)))
6542                         {
6543                             V_BYREF(&rgvarg[i]) = V_BYREF(src_arg);
6544                             V_VT(&rgvarg[i]) = rgvt[i];
6545                         }
6546                         else
6547                         {
6548                             /* FIXME: this doesn't work for VT_BYREF arguments if
6549                              * they are not the same type as in the paramdesc */
6550                             V_VT(&rgvarg[i]) = V_VT(src_arg);
6551                             hres = VariantChangeType(&rgvarg[i], src_arg, 0, rgvt[i]);
6552                             V_VT(&rgvarg[i]) = rgvt[i];
6553                         }
6554
6555                         if (FAILED(hres))
6556                         {
6557                             ERR("failed to convert param %d to %s%s from %s%s\n", i,
6558                                 debugstr_vt(rgvt[i]), debugstr_vf(rgvt[i]),
6559                                 debugstr_VT(src_arg), debugstr_VF(src_arg));
6560                             break;
6561                         }
6562                         prgpvarg[i] = &rgvarg[i];
6563                     }
6564                     else
6565                     {
6566                         prgpvarg[i] = src_arg;
6567                     }
6568
6569                     if((tdesc->vt == VT_USERDEFINED || (tdesc->vt == VT_PTR && tdesc->u.lptdesc->vt == VT_USERDEFINED))
6570                        && (V_VT(prgpvarg[i]) == VT_DISPATCH || V_VT(prgpvarg[i]) == VT_UNKNOWN)
6571                        && V_UNKNOWN(prgpvarg[i])) {
6572                         IUnknown *userdefined_iface;
6573                         GUID guid;
6574
6575                         hres = get_iface_guid((ITypeInfo*)iface, tdesc->vt == VT_PTR ? tdesc->u.lptdesc : tdesc, &guid);
6576                         if(FAILED(hres))
6577                             break;
6578
6579                         hres = IUnknown_QueryInterface(V_UNKNOWN(prgpvarg[i]), &guid, (void**)&userdefined_iface);
6580                         if(FAILED(hres)) {
6581                             ERR("argument does not support %s interface\n", debugstr_guid(&guid));
6582                             break;
6583                         }
6584
6585                         IUnknown_Release(V_UNKNOWN(prgpvarg[i]));
6586                         V_UNKNOWN(prgpvarg[i]) = userdefined_iface;
6587                     }
6588                 }
6589                 else if (wParamFlags & PARAMFLAG_FOPT)
6590                 {
6591                     VARIANTARG *arg;
6592                     arg = prgpvarg[i] = &rgvarg[i];
6593                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
6594                     {
6595                         hres = VariantCopy(arg, &func_desc->lprgelemdescParam[i].u.paramdesc.pparamdescex->varDefaultValue);
6596                         if (FAILED(hres))
6597                             break;
6598                     }
6599                     else
6600                     {
6601                         VARIANTARG *missing_arg;
6602                         /* if the function wants a pointer to a variant then
6603                          * set that up, otherwise just pass the VT_ERROR in
6604                          * the argument by value */
6605                         if (rgvt[i] & VT_BYREF)
6606                         {
6607                             missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams) + i;
6608                             V_VT(arg) = VT_VARIANT | VT_BYREF;
6609                             V_VARIANTREF(arg) = missing_arg;
6610                         }
6611                         else
6612                             missing_arg = arg;
6613                         V_VT(missing_arg) = VT_ERROR;
6614                         V_ERROR(missing_arg) = DISP_E_PARAMNOTFOUND;
6615                     }
6616                 }
6617                 else
6618                 {
6619                     hres = DISP_E_BADPARAMCOUNT;
6620                     break;
6621                 }
6622             }
6623             if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
6624
6625             /* VT_VOID is a special case for return types, so it is not
6626              * handled in the general function */
6627             if (func_desc->elemdescFunc.tdesc.vt == VT_VOID)
6628                 V_VT(&varresult) = VT_EMPTY;
6629             else
6630             {
6631                 V_VT(&varresult) = 0;
6632                 hres = typedescvt_to_variantvt((ITypeInfo *)iface, &func_desc->elemdescFunc.tdesc, &V_VT(&varresult));
6633                 if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
6634             }
6635
6636             hres = DispCallFunc(pIUnk, func_desc->oVft, func_desc->callconv,
6637                                 V_VT(&varresult), func_desc->cParams, rgvt,
6638                                 prgpvarg, &varresult);
6639
6640             vargs_converted = 0;
6641
6642             for (i = 0; i < func_desc->cParams; i++)
6643             {
6644                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
6645                 VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
6646
6647                 if (wParamFlags & PARAMFLAG_FLCID)
6648                     continue;
6649                 else if (wParamFlags & PARAMFLAG_FRETVAL)
6650                 {
6651                     if (TRACE_ON(ole))
6652                     {
6653                         TRACE("[retval] value: ");
6654                         dump_Variant(prgpvarg[i]);
6655                     }
6656
6657                     if (pVarResult)
6658                     {
6659                         VariantInit(pVarResult);
6660                         /* deref return value */
6661                         hres = VariantCopyInd(pVarResult, prgpvarg[i]);
6662                     }
6663
6664                     VARIANT_ClearInd(prgpvarg[i]);
6665                 }
6666                 else if (vargs_converted < pDispParams->cArgs)
6667                 {
6668                     VARIANTARG *arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted];
6669                     if (wParamFlags & PARAMFLAG_FOUT)
6670                     {
6671                         if ((rgvt[i] & VT_BYREF) && !(V_VT(arg) & VT_BYREF))
6672                         {
6673                             hres = VariantChangeType(arg, &rgvarg[i], 0, V_VT(arg));
6674
6675                             if (FAILED(hres))
6676                             {
6677                                 ERR("failed to convert param %d to vt %d\n", i,
6678                                     V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted]));
6679                                 break;
6680                             }
6681                         }
6682                     }
6683                     else if (V_VT(prgpvarg[i]) == (VT_VARIANT | VT_ARRAY) &&
6684                              func_desc->cParamsOpt < 0 &&
6685                              i == func_desc->cParams-1)
6686                     {
6687                         SAFEARRAY *a = V_ARRAY(prgpvarg[i]);
6688                         LONG j, ubound;
6689                         VARIANT *v;
6690                         hres = SafeArrayGetUBound(a, 1, &ubound);
6691                         if (hres != S_OK)
6692                         {
6693                             ERR("SafeArrayGetUBound failed with %x\n", hres);
6694                             break;
6695                         }
6696                         hres = SafeArrayAccessData(a, (LPVOID)&v);
6697                         if (hres != S_OK)
6698                         {
6699                             ERR("SafeArrayAccessData failed with %x\n", hres);
6700                             break;
6701                         }
6702                         for (j = 0; j <= ubound; j++)
6703                             VariantClear(&v[j]);
6704                         hres = SafeArrayUnaccessData(a);
6705                         if (hres != S_OK)
6706                         {
6707                             ERR("SafeArrayUnaccessData failed with %x\n", hres);
6708                             break;
6709                         }
6710                     }
6711                     VariantClear(&rgvarg[i]);
6712                     vargs_converted++;
6713                 }
6714                 else if (wParamFlags & PARAMFLAG_FOPT)
6715                 {
6716                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
6717                         VariantClear(&rgvarg[i]);
6718                 }
6719
6720                 VariantClear(&missing_arg[i]);
6721             }
6722
6723             if ((V_VT(&varresult) == VT_ERROR) && FAILED(V_ERROR(&varresult)))
6724             {
6725                 WARN("invoked function failed with error 0x%08x\n", V_ERROR(&varresult));
6726                 hres = DISP_E_EXCEPTION;
6727                 if (pExcepInfo)
6728                 {
6729                     IErrorInfo *pErrorInfo;
6730                     pExcepInfo->scode = V_ERROR(&varresult);
6731                     if (GetErrorInfo(0, &pErrorInfo) == S_OK)
6732                     {
6733                         IErrorInfo_GetDescription(pErrorInfo, &pExcepInfo->bstrDescription);
6734                         IErrorInfo_GetHelpFile(pErrorInfo, &pExcepInfo->bstrHelpFile);
6735                         IErrorInfo_GetSource(pErrorInfo, &pExcepInfo->bstrSource);
6736                         IErrorInfo_GetHelpContext(pErrorInfo, &pExcepInfo->dwHelpContext);
6737
6738                         IErrorInfo_Release(pErrorInfo);
6739                     }
6740                 }
6741             }
6742             if (V_VT(&varresult) != VT_ERROR)
6743             {
6744                 TRACE("varresult value: ");
6745                 dump_Variant(&varresult);
6746
6747                 if (pVarResult)
6748                 {
6749                     VariantClear(pVarResult);
6750                     *pVarResult = varresult;
6751                 }
6752                 else
6753                     VariantClear(&varresult);
6754             }
6755
6756             if (SUCCEEDED(hres) && pVarResult && (func_desc->cParams == 1) &&
6757                 (func_desc->invkind & INVOKE_PROPERTYGET) &&
6758                 (func_desc->lprgelemdescParam[0].u.paramdesc.wParamFlags & PARAMFLAG_FRETVAL) &&
6759                 (pDispParams->cArgs != 0))
6760             {
6761                 if (V_VT(pVarResult) == VT_DISPATCH)
6762                 {
6763                     IDispatch *pDispatch = V_DISPATCH(pVarResult);
6764                     /* Note: not VariantClear; we still need the dispatch
6765                      * pointer to be valid */
6766                     VariantInit(pVarResult);
6767                     hres = IDispatch_Invoke(pDispatch, DISPID_VALUE, &IID_NULL,
6768                         GetSystemDefaultLCID(), INVOKE_PROPERTYGET,
6769                         pDispParams, pVarResult, pExcepInfo, pArgErr);
6770                     IDispatch_Release(pDispatch);
6771                 }
6772                 else
6773                 {
6774                     VariantClear(pVarResult);
6775                     hres = DISP_E_NOTACOLLECTION;
6776                 }
6777             }
6778
6779 func_fail:
6780             heap_free(buffer);
6781             break;
6782         }
6783         case FUNC_DISPATCH:  {
6784            IDispatch *disp;
6785
6786            hres = IUnknown_QueryInterface((LPUNKNOWN)pIUnk,&IID_IDispatch,(LPVOID*)&disp);
6787            if (SUCCEEDED(hres)) {
6788                FIXME("Calling Invoke in IDispatch iface. untested!\n");
6789                hres = IDispatch_Invoke(
6790                                      disp,memid,&IID_NULL,LOCALE_USER_DEFAULT,wFlags,pDispParams,
6791                                      pVarResult,pExcepInfo,pArgErr
6792                                      );
6793                if (FAILED(hres))
6794                    FIXME("IDispatch::Invoke failed with %08x. (Could be not a real error?)\n", hres);
6795                IDispatch_Release(disp);
6796            } else
6797                FIXME("FUNC_DISPATCH used on object without IDispatch iface?\n");
6798            break;
6799         }
6800         default:
6801             FIXME("Unknown function invocation type %d\n", func_desc->funckind);
6802             hres = E_FAIL;
6803             break;
6804         }
6805
6806         TRACE("-- 0x%08x\n", hres);
6807         return hres;
6808
6809     } else if(SUCCEEDED(hres = ITypeInfo2_GetVarIndexOfMemId(iface, memid, &var_index))) {
6810         VARDESC *var_desc;
6811
6812         hres = ITypeInfo2_GetVarDesc(iface, var_index, &var_desc);
6813         if(FAILED(hres)) return hres;
6814         
6815         FIXME("varseek: Found memid, but variable-based invoking not supported\n");
6816         dump_VARDESC(var_desc);
6817         ITypeInfo2_ReleaseVarDesc(iface, var_desc);
6818         return E_NOTIMPL;
6819     }
6820
6821     /* not found, look for it in inherited interfaces */
6822     ITypeInfo2_GetTypeKind(iface, &type_kind);
6823     if(type_kind == TKIND_INTERFACE || type_kind == TKIND_DISPATCH) {
6824         if(This->impltypes) {
6825             /* recursive search */
6826             ITypeInfo *pTInfo;
6827             hres = ITypeInfo2_GetRefTypeInfo(iface, This->impltypes[0].hRef, &pTInfo);
6828             if(SUCCEEDED(hres)){
6829                 hres = ITypeInfo_Invoke(pTInfo,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr);
6830                 ITypeInfo_Release(pTInfo);
6831                 return hres;
6832             }
6833             WARN("Could not search inherited interface!\n");
6834         }
6835     }
6836     WARN("did not find member id %d, flags 0x%x!\n", memid, wFlags);
6837     return DISP_E_MEMBERNOTFOUND;
6838 }
6839
6840 /* ITypeInfo::GetDocumentation
6841  *
6842  * Retrieves the documentation string, the complete Help file name and path,
6843  * and the context ID for the Help topic for a specified type description.
6844  *
6845  * (Can be tested by the Visual Basic Editor in Word for instance.)
6846  */
6847 static HRESULT WINAPI ITypeInfo_fnGetDocumentation( ITypeInfo2 *iface,
6848         MEMBERID memid, BSTR  *pBstrName, BSTR  *pBstrDocString,
6849         DWORD  *pdwHelpContext, BSTR  *pBstrHelpFile)
6850 {
6851     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6852     const TLBFuncDesc *pFDesc;
6853     const TLBVarDesc *pVDesc;
6854     TRACE("(%p) memid %d Name(%p) DocString(%p)"
6855           " HelpContext(%p) HelpFile(%p)\n",
6856         This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
6857     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
6858         if(pBstrName)
6859             *pBstrName=SysAllocString(This->Name);
6860         if(pBstrDocString)
6861             *pBstrDocString=SysAllocString(This->DocString);
6862         if(pdwHelpContext)
6863             *pdwHelpContext=This->dwHelpContext;
6864         if(pBstrHelpFile)
6865             *pBstrHelpFile=SysAllocString(This->DocString);/* FIXME */
6866         return S_OK;
6867     }else {/* for a member */
6868         pFDesc = TLB_get_funcdesc_by_memberid(This->funcdescs, This->TypeAttr.cFuncs, memid);
6869         if(pFDesc){
6870             if(pBstrName)
6871               *pBstrName = SysAllocString(pFDesc->Name);
6872             if(pBstrDocString)
6873               *pBstrDocString=SysAllocString(pFDesc->HelpString);
6874             if(pdwHelpContext)
6875               *pdwHelpContext=pFDesc->helpcontext;
6876             return S_OK;
6877         }
6878         pVDesc = TLB_get_vardesc_by_memberid(This->vardescs, This->TypeAttr.cVars, memid);
6879         if(pVDesc){
6880             if(pBstrName)
6881               *pBstrName = SysAllocString(pVDesc->Name);
6882             if(pBstrDocString)
6883               *pBstrDocString=SysAllocString(pVDesc->HelpString);
6884             if(pdwHelpContext)
6885               *pdwHelpContext=pVDesc->HelpContext;
6886             return S_OK;
6887         }
6888     }
6889
6890     if(This->impltypes &&
6891        (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
6892         /* recursive search */
6893         ITypeInfo *pTInfo;
6894         HRESULT result;
6895         result = ITypeInfo2_GetRefTypeInfo(iface, This->impltypes[0].hRef, &pTInfo);
6896         if(SUCCEEDED(result)) {
6897             result = ITypeInfo_GetDocumentation(pTInfo, memid, pBstrName,
6898                 pBstrDocString, pdwHelpContext, pBstrHelpFile);
6899             ITypeInfo_Release(pTInfo);
6900             return result;
6901         }
6902         WARN("Could not search inherited interface!\n");
6903     }
6904
6905     WARN("member %d not found\n", memid);
6906     return TYPE_E_ELEMENTNOTFOUND;
6907 }
6908
6909 /*  ITypeInfo::GetDllEntry
6910  *
6911  * Retrieves a description or specification of an entry point for a function
6912  * in a DLL.
6913  */
6914 static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid,
6915         INVOKEKIND invKind, BSTR  *pBstrDllName, BSTR  *pBstrName,
6916         WORD  *pwOrdinal)
6917 {
6918     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6919     const TLBFuncDesc *pFDesc;
6920
6921     TRACE("(%p)->(memid %x, %d, %p, %p, %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
6922
6923     if (pBstrDllName) *pBstrDllName = NULL;
6924     if (pBstrName) *pBstrName = NULL;
6925     if (pwOrdinal) *pwOrdinal = 0;
6926
6927     if (This->TypeAttr.typekind != TKIND_MODULE)
6928         return TYPE_E_BADMODULEKIND;
6929
6930     pFDesc = TLB_get_funcdesc_by_memberid(This->funcdescs, This->TypeAttr.cFuncs, memid);
6931     if(pFDesc){
6932             dump_TypeInfo(This);
6933             if (TRACE_ON(ole))
6934                 dump_TLBFuncDescOne(pFDesc);
6935
6936             if (pBstrDllName)
6937                 *pBstrDllName = SysAllocString(This->DllName);
6938
6939             if (!IS_INTRESOURCE(pFDesc->Entry) && (pFDesc->Entry != (void*)-1)) {
6940                 if (pBstrName)
6941                     *pBstrName = SysAllocString(pFDesc->Entry);
6942                 if (pwOrdinal)
6943                     *pwOrdinal = -1;
6944                 return S_OK;
6945             }
6946             if (pBstrName)
6947                 *pBstrName = NULL;
6948             if (pwOrdinal)
6949                 *pwOrdinal = LOWORD(pFDesc->Entry);
6950             return S_OK;
6951         }
6952     return TYPE_E_ELEMENTNOTFOUND;
6953 }
6954
6955 /* internal function to make the inherited interfaces' methods appear
6956  * part of the interface */
6957 static HRESULT ITypeInfoImpl_GetDispatchRefTypeInfo( ITypeInfo *iface,
6958     HREFTYPE *hRefType, ITypeInfo  **ppTInfo)
6959 {
6960     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6961     HRESULT hr;
6962
6963     TRACE("%p, 0x%x\n", iface, *hRefType);
6964
6965     if (This->impltypes && (*hRefType & DISPATCH_HREF_MASK))
6966     {
6967         ITypeInfo *pSubTypeInfo;
6968
6969         hr = ITypeInfo_GetRefTypeInfo(iface, This->impltypes[0].hRef, &pSubTypeInfo);
6970         if (FAILED(hr))
6971             return hr;
6972
6973         hr = ITypeInfoImpl_GetDispatchRefTypeInfo(pSubTypeInfo,
6974                                                   hRefType, ppTInfo);
6975         ITypeInfo_Release(pSubTypeInfo);
6976         if (SUCCEEDED(hr))
6977             return hr;
6978     }
6979     *hRefType -= DISPATCH_HREF_OFFSET;
6980
6981     if (!(*hRefType & DISPATCH_HREF_MASK))
6982         return ITypeInfo_GetRefTypeInfo(iface, *hRefType, ppTInfo);
6983     else
6984         return E_FAIL;
6985 }
6986
6987 /* ITypeInfo::GetRefTypeInfo
6988  *
6989  * If a type description references other type descriptions, it retrieves
6990  * the referenced type descriptions.
6991  */
6992 static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo(
6993         ITypeInfo2 *iface,
6994         HREFTYPE hRefType,
6995         ITypeInfo  **ppTInfo)
6996 {
6997     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6998     HRESULT result = E_FAIL;
6999
7000     if ((This->hreftype != -1) && (This->hreftype == hRefType))
7001     {
7002         *ppTInfo = (ITypeInfo *)&This->lpVtbl;
7003         ITypeInfo_AddRef(*ppTInfo);
7004         result = S_OK;
7005     }
7006     else if (hRefType == -1 &&
7007         (This->TypeAttr.typekind   == TKIND_DISPATCH) &&
7008         (This->TypeAttr.wTypeFlags &  TYPEFLAG_FDUAL))
7009     {
7010           /* when we meet a DUAL dispinterface, we must create the interface
7011           * version of it.
7012           */
7013           ITypeInfoImpl *pTypeInfoImpl = ITypeInfoImpl_Constructor();
7014
7015
7016           /* the interface version contains the same information as the dispinterface
7017            * copy the contents of the structs.
7018            */
7019           *pTypeInfoImpl = *This;
7020           pTypeInfoImpl->ref = 0;
7021
7022           /* change the type to interface */
7023           pTypeInfoImpl->TypeAttr.typekind = TKIND_INTERFACE;
7024
7025           *ppTInfo = (ITypeInfo*) pTypeInfoImpl;
7026
7027           /* the AddRef implicitly adds a reference to the parent typelib, which
7028            * stops the copied data from being destroyed until the new typeinfo's
7029            * refcount goes to zero, but we need to signal to the new instance to
7030            * not free its data structures when it is destroyed */
7031           pTypeInfoImpl->not_attached_to_typelib = TRUE;
7032
7033           ITypeInfo_AddRef(*ppTInfo);
7034
7035           result = S_OK;
7036
7037     } else if ((hRefType != -1) && (hRefType & DISPATCH_HREF_MASK) &&
7038         (This->TypeAttr.typekind   == TKIND_DISPATCH))
7039     {
7040         HREFTYPE href_dispatch = hRefType;
7041         result = ITypeInfoImpl_GetDispatchRefTypeInfo((ITypeInfo *)iface, &href_dispatch, ppTInfo);
7042     } else {
7043         TLBRefType *ref_type;
7044         LIST_FOR_EACH_ENTRY(ref_type, &This->pTypeLib->ref_list, TLBRefType, entry)
7045         {
7046             if(ref_type->reference == hRefType)
7047                 break;
7048         }
7049         if(&ref_type->entry == &This->pTypeLib->ref_list)
7050         {
7051             FIXME("Can't find pRefType for ref %x\n", hRefType);
7052             goto end;
7053         }
7054         if(hRefType != -1) {
7055             ITypeLib *pTLib = NULL;
7056
7057             if(ref_type->pImpTLInfo == TLB_REF_INTERNAL) {
7058                 UINT Index;
7059                 result = ITypeInfo2_GetContainingTypeLib(iface, &pTLib, &Index);
7060             } else {
7061                 if(ref_type->pImpTLInfo->pImpTypeLib) {
7062                     TRACE("typeinfo in imported typelib that is already loaded\n");
7063                     pTLib = (ITypeLib*)&ref_type->pImpTLInfo->pImpTypeLib->ITypeLib2_iface;
7064                     ITypeLib_AddRef(pTLib);
7065                     result = S_OK;
7066                 } else {
7067                     TRACE("typeinfo in imported typelib that isn't already loaded\n");
7068                     result = LoadRegTypeLib( &ref_type->pImpTLInfo->guid,
7069                                              ref_type->pImpTLInfo->wVersionMajor,
7070                                              ref_type->pImpTLInfo->wVersionMinor,
7071                                              ref_type->pImpTLInfo->lcid,
7072                                              &pTLib);
7073
7074                     if(FAILED(result)) {
7075                         BSTR libnam=SysAllocString(ref_type->pImpTLInfo->name);
7076                         result=LoadTypeLib(libnam, &pTLib);
7077                         SysFreeString(libnam);
7078                     }
7079                     if(SUCCEEDED(result)) {
7080                         ref_type->pImpTLInfo->pImpTypeLib = (ITypeLibImpl*)pTLib;
7081                         ITypeLib_AddRef(pTLib);
7082                     }
7083                 }
7084             }
7085             if(SUCCEEDED(result)) {
7086                 if(ref_type->index == TLB_REF_USE_GUID)
7087                     result = ITypeLib_GetTypeInfoOfGuid(pTLib, &ref_type->guid, ppTInfo);
7088                 else
7089                     result = ITypeLib_GetTypeInfo(pTLib, ref_type->index, ppTInfo);
7090             }
7091             if (pTLib != NULL)
7092                 ITypeLib_Release(pTLib);
7093         }
7094     }
7095
7096 end:
7097     TRACE("(%p) hreftype 0x%04x loaded %s (%p)\n", This, hRefType,
7098           SUCCEEDED(result)? "SUCCESS":"FAILURE", *ppTInfo);
7099     return result;
7100 }
7101
7102 /* ITypeInfo::AddressOfMember
7103  *
7104  * Retrieves the addresses of static functions or variables, such as those
7105  * defined in a DLL.
7106  */
7107 static HRESULT WINAPI ITypeInfo_fnAddressOfMember( ITypeInfo2 *iface,
7108         MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
7109 {
7110     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7111     HRESULT hr;
7112     BSTR dll, entry;
7113     WORD ordinal;
7114     HMODULE module;
7115
7116     TRACE("(%p)->(0x%x, 0x%x, %p)\n", This, memid, invKind, ppv);
7117
7118     hr = ITypeInfo2_GetDllEntry(iface, memid, invKind, &dll, &entry, &ordinal);
7119     if (FAILED(hr))
7120         return hr;
7121
7122     module = LoadLibraryW(dll);
7123     if (!module)
7124     {
7125         ERR("couldn't load %s\n", debugstr_w(dll));
7126         SysFreeString(dll);
7127         SysFreeString(entry);
7128         return STG_E_FILENOTFOUND;
7129     }
7130     /* FIXME: store library somewhere where we can free it */
7131
7132     if (entry)
7133     {
7134         LPSTR entryA;
7135         INT len = WideCharToMultiByte(CP_ACP, 0, entry, -1, NULL, 0, NULL, NULL);
7136         entryA = heap_alloc(len);
7137         WideCharToMultiByte(CP_ACP, 0, entry, -1, entryA, len, NULL, NULL);
7138
7139         *ppv = GetProcAddress(module, entryA);
7140         if (!*ppv)
7141             ERR("function not found %s\n", debugstr_a(entryA));
7142
7143         heap_free(entryA);
7144     }
7145     else
7146     {
7147         *ppv = GetProcAddress(module, MAKEINTRESOURCEA(ordinal));
7148         if (!*ppv)
7149             ERR("function not found %d\n", ordinal);
7150     }
7151
7152     SysFreeString(dll);
7153     SysFreeString(entry);
7154
7155     if (!*ppv)
7156         return TYPE_E_DLLFUNCTIONNOTFOUND;
7157
7158     return S_OK;
7159 }
7160
7161 /* ITypeInfo::CreateInstance
7162  *
7163  * Creates a new instance of a type that describes a component object class
7164  * (coclass).
7165  */
7166 static HRESULT WINAPI ITypeInfo_fnCreateInstance( ITypeInfo2 *iface,
7167         IUnknown *pOuterUnk, REFIID riid, VOID  **ppvObj)
7168 {
7169     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7170     HRESULT hr;
7171     TYPEATTR *pTA;
7172
7173     TRACE("(%p)->(%p, %s, %p)\n", This, pOuterUnk, debugstr_guid(riid), ppvObj);
7174
7175     *ppvObj = NULL;
7176
7177     if(pOuterUnk)
7178     {
7179         WARN("Not able to aggregate\n");
7180         return CLASS_E_NOAGGREGATION;
7181     }
7182
7183     hr = ITypeInfo2_GetTypeAttr(iface, &pTA);
7184     if(FAILED(hr)) return hr;
7185
7186     if(pTA->typekind != TKIND_COCLASS)
7187     {
7188         WARN("CreateInstance on typeinfo of type %x\n", pTA->typekind);
7189         hr = E_INVALIDARG;
7190         goto end;
7191     }
7192
7193     hr = S_FALSE;
7194     if(pTA->wTypeFlags & TYPEFLAG_FAPPOBJECT)
7195     {
7196         IUnknown *pUnk;
7197         hr = GetActiveObject(&pTA->guid, NULL, &pUnk);
7198         TRACE("GetActiveObject rets %08x\n", hr);
7199         if(hr == S_OK)
7200         {
7201             hr = IUnknown_QueryInterface(pUnk, riid, ppvObj);
7202             IUnknown_Release(pUnk);
7203         }
7204     }
7205
7206     if(hr != S_OK)
7207         hr = CoCreateInstance(&pTA->guid, NULL,
7208                               CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
7209                               riid, ppvObj);
7210
7211 end:
7212     ITypeInfo2_ReleaseTypeAttr(iface, pTA);
7213     return hr;
7214 }
7215
7216 /* ITypeInfo::GetMops
7217  *
7218  * Retrieves marshalling information.
7219  */
7220 static HRESULT WINAPI ITypeInfo_fnGetMops( ITypeInfo2 *iface, MEMBERID memid,
7221                                 BSTR  *pBstrMops)
7222 {
7223     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7224     FIXME("(%p %d) stub!\n", This, memid);
7225     *pBstrMops = NULL;
7226     return S_OK;
7227 }
7228
7229 /* ITypeInfo::GetContainingTypeLib
7230  *
7231  * Retrieves the containing type library and the index of the type description
7232  * within that type library.
7233  */
7234 static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( ITypeInfo2 *iface,
7235         ITypeLib  * *ppTLib, UINT  *pIndex)
7236 {
7237     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7238     
7239     /* If a pointer is null, we simply ignore it, the ATL in particular passes pIndex as 0 */
7240     if (pIndex) {
7241       *pIndex=This->index;
7242       TRACE("returning pIndex=%d\n", *pIndex);
7243     }
7244     
7245     if (ppTLib) {
7246       *ppTLib=(LPTYPELIB )(This->pTypeLib);
7247       ITypeLib_AddRef(*ppTLib);
7248       TRACE("returning ppTLib=%p\n", *ppTLib);
7249     }
7250     
7251     return S_OK;
7252 }
7253
7254 /* ITypeInfo::ReleaseTypeAttr
7255  *
7256  * Releases a TYPEATTR previously returned by GetTypeAttr.
7257  *
7258  */
7259 static void WINAPI ITypeInfo_fnReleaseTypeAttr( ITypeInfo2 *iface,
7260         TYPEATTR* pTypeAttr)
7261 {
7262     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7263     TRACE("(%p)->(%p)\n", This, pTypeAttr);
7264     heap_free(pTypeAttr);
7265 }
7266
7267 /* ITypeInfo::ReleaseFuncDesc
7268  *
7269  * Releases a FUNCDESC previously returned by GetFuncDesc. *
7270  */
7271 static void WINAPI ITypeInfo_fnReleaseFuncDesc(
7272         ITypeInfo2 *iface,
7273         FUNCDESC *pFuncDesc)
7274 {
7275     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7276     SHORT i;
7277
7278     TRACE("(%p)->(%p)\n", This, pFuncDesc);
7279
7280     for (i = 0; i < pFuncDesc->cParams; i++)
7281         TLB_FreeElemDesc(&pFuncDesc->lprgelemdescParam[i]);
7282     TLB_FreeElemDesc(&pFuncDesc->elemdescFunc);
7283
7284     SysFreeString((BSTR)pFuncDesc);
7285 }
7286
7287 /* ITypeInfo::ReleaseVarDesc
7288  *
7289  * Releases a VARDESC previously returned by GetVarDesc.
7290  */
7291 static void WINAPI ITypeInfo_fnReleaseVarDesc( ITypeInfo2 *iface,
7292         VARDESC *pVarDesc)
7293 {
7294     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7295     TRACE("(%p)->(%p)\n", This, pVarDesc);
7296
7297     TLB_FreeElemDesc(&pVarDesc->elemdescVar);
7298     if (pVarDesc->varkind == VAR_CONST)
7299         VariantClear(pVarDesc->u.lpvarValue);
7300     SysFreeString((BSTR)pVarDesc);
7301 }
7302
7303 /* ITypeInfo2::GetTypeKind
7304  *
7305  * Returns the TYPEKIND enumeration quickly, without doing any allocations.
7306  *
7307  */
7308 static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo2 * iface,
7309     TYPEKIND *pTypeKind)
7310 {
7311     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7312     *pTypeKind=This->TypeAttr.typekind;
7313     TRACE("(%p) type 0x%0x\n", This,*pTypeKind);
7314     return S_OK;
7315 }
7316
7317 /* ITypeInfo2::GetTypeFlags
7318  *
7319  * Returns the type flags without any allocations. This returns a DWORD type
7320  * flag, which expands the type flags without growing the TYPEATTR (type
7321  * attribute).
7322  *
7323  */
7324 static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo2 *iface, ULONG *pTypeFlags)
7325 {
7326     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7327     *pTypeFlags=This->TypeAttr.wTypeFlags;
7328     TRACE("(%p) flags 0x%x\n", This,*pTypeFlags);
7329     return S_OK;
7330 }
7331
7332 /* ITypeInfo2::GetFuncIndexOfMemId
7333  * Binds to a specific member based on a known DISPID, where the member name
7334  * is not known (for example, when binding to a default member).
7335  *
7336  */
7337 static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo2 * iface,
7338     MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex)
7339 {
7340     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7341     UINT fdc;
7342     HRESULT result;
7343
7344     for (fdc = 0; fdc < This->TypeAttr.cFuncs; ++fdc){
7345         const TLBFuncDesc *pFuncInfo = &This->funcdescs[fdc];
7346         if(memid == pFuncInfo->funcdesc.memid && (invKind & pFuncInfo->funcdesc.invkind))
7347             break;
7348     }
7349     if(fdc < This->TypeAttr.cFuncs) {
7350         *pFuncIndex = fdc;
7351         result = S_OK;
7352     } else
7353         result = TYPE_E_ELEMENTNOTFOUND;
7354
7355     TRACE("(%p) memid 0x%08x invKind 0x%04x -> %s\n", This,
7356           memid, invKind, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
7357     return result;
7358 }
7359
7360 /* TypeInfo2::GetVarIndexOfMemId
7361  *
7362  * Binds to a specific member based on a known DISPID, where the member name
7363  * is not known (for example, when binding to a default member).
7364  *
7365  */
7366 static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( ITypeInfo2 * iface,
7367     MEMBERID memid, UINT *pVarIndex)
7368 {
7369     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7370     TLBVarDesc *pVarInfo;
7371
7372     TRACE("%p %d %p\n", iface, memid, pVarIndex);
7373
7374     pVarInfo = TLB_get_vardesc_by_memberid(This->vardescs, This->TypeAttr.cVars, memid);
7375     if(!pVarInfo)
7376         return TYPE_E_ELEMENTNOTFOUND;
7377
7378     *pVarIndex = (pVarInfo - This->vardescs);
7379
7380     return S_OK;
7381 }
7382
7383 /* ITypeInfo2::GetCustData
7384  *
7385  * Gets the custom data
7386  */
7387 static HRESULT WINAPI ITypeInfo2_fnGetCustData(
7388         ITypeInfo2 * iface,
7389         REFGUID guid,
7390         VARIANT *pVarVal)
7391 {
7392     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7393     TLBCustData *pCData;
7394
7395     TRACE("%p %s %p\n", This, debugstr_guid(guid), pVarVal);
7396
7397     pCData = TLB_get_custdata_by_guid(&This->custdata_list, guid);
7398
7399     VariantInit( pVarVal);
7400     if (pCData)
7401         VariantCopy( pVarVal, &pCData->data);
7402     else
7403         VariantClear( pVarVal );
7404     return S_OK;
7405 }
7406
7407 /* ITypeInfo2::GetFuncCustData
7408  *
7409  * Gets the custom data
7410  */
7411 static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData(
7412         ITypeInfo2 * iface,
7413         UINT index,
7414         REFGUID guid,
7415         VARIANT *pVarVal)
7416 {
7417     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7418     TLBCustData *pCData;
7419     TLBFuncDesc *pFDesc = &This->funcdescs[index];
7420
7421     TRACE("%p %u %s %p\n", This, index, debugstr_guid(guid), pVarVal);
7422
7423     if(index >= This->TypeAttr.cFuncs)
7424         return TYPE_E_ELEMENTNOTFOUND;
7425
7426     pCData = TLB_get_custdata_by_guid(&pFDesc->custdata_list, guid);
7427     if(!pCData)
7428         return TYPE_E_ELEMENTNOTFOUND;
7429
7430     VariantInit(pVarVal);
7431     VariantCopy(pVarVal, &pCData->data);
7432
7433     return S_OK;
7434 }
7435
7436 /* ITypeInfo2::GetParamCustData
7437  *
7438  * Gets the custom data
7439  */
7440 static HRESULT WINAPI ITypeInfo2_fnGetParamCustData(
7441         ITypeInfo2 * iface,
7442         UINT indexFunc,
7443         UINT indexParam,
7444         REFGUID guid,
7445         VARIANT *pVarVal)
7446 {
7447     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7448     TLBCustData *pCData;
7449     TLBFuncDesc *pFDesc = &This->funcdescs[indexFunc];
7450
7451     TRACE("%p %u %u %s %p\n", This, indexFunc, indexParam,
7452             debugstr_guid(guid), pVarVal);
7453
7454     if(indexFunc >= This->TypeAttr.cFuncs)
7455         return TYPE_E_ELEMENTNOTFOUND;
7456
7457     if(indexParam >= pFDesc->funcdesc.cParams)
7458         return TYPE_E_ELEMENTNOTFOUND;
7459
7460     pCData = TLB_get_custdata_by_guid(&pFDesc->pParamDesc[indexParam].custdata_list, guid);
7461     if(!pCData)
7462         return TYPE_E_ELEMENTNOTFOUND;
7463
7464     VariantInit(pVarVal);
7465     VariantCopy(pVarVal, &pCData->data);
7466
7467     return S_OK;
7468 }
7469
7470 /* ITypeInfo2::GetVarCustData
7471  *
7472  * Gets the custom data
7473  */
7474 static HRESULT WINAPI ITypeInfo2_fnGetVarCustData(
7475         ITypeInfo2 * iface,
7476         UINT index,
7477         REFGUID guid,
7478         VARIANT *pVarVal)
7479 {
7480     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7481     TLBCustData *pCData;
7482     TLBVarDesc *pVDesc = &This->vardescs[index];
7483
7484     TRACE("%p %s %p\n", This, debugstr_guid(guid), pVarVal);
7485
7486     if(index >= This->TypeAttr.cVars)
7487         return TYPE_E_ELEMENTNOTFOUND;
7488
7489     pCData = TLB_get_custdata_by_guid(&pVDesc->custdata_list, guid);
7490     if(!pCData)
7491         return TYPE_E_ELEMENTNOTFOUND;
7492
7493     VariantInit(pVarVal);
7494     VariantCopy(pVarVal, &pCData->data);
7495
7496     return S_OK;
7497 }
7498
7499 /* ITypeInfo2::GetImplCustData
7500  *
7501  * Gets the custom data
7502  */
7503 static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData(
7504         ITypeInfo2 * iface,
7505         UINT index,
7506         REFGUID guid,
7507         VARIANT *pVarVal)
7508 {
7509     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7510     TLBCustData *pCData;
7511     TLBImplType *pRDesc = &This->impltypes[index];
7512
7513     TRACE("%p %u %s %p\n", This, index, debugstr_guid(guid), pVarVal);
7514
7515     if(index >= This->TypeAttr.cImplTypes)
7516         return TYPE_E_ELEMENTNOTFOUND;
7517
7518     pCData = TLB_get_custdata_by_guid(&pRDesc->custdata_list, guid);
7519     if(!pCData)
7520         return TYPE_E_ELEMENTNOTFOUND;
7521
7522     VariantInit(pVarVal);
7523     VariantCopy(pVarVal, &pCData->data);
7524
7525     return S_OK;
7526 }
7527
7528 /* ITypeInfo2::GetDocumentation2
7529  *
7530  * Retrieves the documentation string, the complete Help file name and path,
7531  * the localization context to use, and the context ID for the library Help
7532  * topic in the Help file.
7533  *
7534  */
7535 static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2(
7536         ITypeInfo2 * iface,
7537         MEMBERID memid,
7538         LCID lcid,
7539         BSTR *pbstrHelpString,
7540         DWORD *pdwHelpStringContext,
7541         BSTR *pbstrHelpStringDll)
7542 {
7543     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7544     const TLBFuncDesc *pFDesc;
7545     const TLBVarDesc *pVDesc;
7546     TRACE("(%p) memid %d lcid(0x%x)  HelpString(%p) "
7547           "HelpStringContext(%p) HelpStringDll(%p)\n",
7548           This, memid, lcid, pbstrHelpString, pdwHelpStringContext,
7549           pbstrHelpStringDll );
7550     /* the help string should be obtained from the helpstringdll,
7551      * using the _DLLGetDocumentation function, based on the supplied
7552      * lcid. Nice to do sometime...
7553      */
7554     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
7555         if(pbstrHelpString)
7556             *pbstrHelpString=SysAllocString(This->Name);
7557         if(pdwHelpStringContext)
7558             *pdwHelpStringContext=This->dwHelpStringContext;
7559         if(pbstrHelpStringDll)
7560             *pbstrHelpStringDll=
7561                 SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
7562         return S_OK;
7563     }else {/* for a member */
7564         pFDesc = TLB_get_funcdesc_by_memberid(This->funcdescs, This->TypeAttr.cFuncs, memid);
7565         if(pFDesc){
7566             if(pbstrHelpString)
7567                 *pbstrHelpString=SysAllocString(pFDesc->HelpString);
7568             if(pdwHelpStringContext)
7569                 *pdwHelpStringContext=pFDesc->HelpStringContext;
7570             if(pbstrHelpStringDll)
7571                 *pbstrHelpStringDll=
7572                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
7573             return S_OK;
7574         }
7575         pVDesc = TLB_get_vardesc_by_memberid(This->vardescs, This->TypeAttr.cVars, memid);
7576         if(pVDesc){
7577             if(pbstrHelpString)
7578                 *pbstrHelpString=SysAllocString(pVDesc->HelpString);
7579             if(pdwHelpStringContext)
7580                 *pdwHelpStringContext=pVDesc->HelpStringContext;
7581             if(pbstrHelpStringDll)
7582                 *pbstrHelpStringDll=
7583                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
7584             return S_OK;
7585         }
7586     }
7587     return TYPE_E_ELEMENTNOTFOUND;
7588 }
7589
7590 /* ITypeInfo2::GetAllCustData
7591  *
7592  * Gets all custom data items for the Type info.
7593  *
7594  */
7595 static HRESULT WINAPI ITypeInfo2_fnGetAllCustData(
7596         ITypeInfo2 * iface,
7597         CUSTDATA *pCustData)
7598 {
7599     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7600
7601     TRACE("%p %p\n", This, pCustData);
7602
7603     return TLB_copy_all_custdata(&This->custdata_list, pCustData);
7604 }
7605
7606 /* ITypeInfo2::GetAllFuncCustData
7607  *
7608  * Gets all custom data items for the specified Function
7609  *
7610  */
7611 static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData(
7612         ITypeInfo2 * iface,
7613         UINT index,
7614         CUSTDATA *pCustData)
7615 {
7616     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7617     TLBFuncDesc *pFDesc = &This->funcdescs[index];
7618
7619     TRACE("%p %u %p\n", This, index, pCustData);
7620
7621     if(index >= This->TypeAttr.cFuncs)
7622         return TYPE_E_ELEMENTNOTFOUND;
7623
7624     return TLB_copy_all_custdata(&pFDesc->custdata_list, pCustData);
7625 }
7626
7627 /* ITypeInfo2::GetAllParamCustData
7628  *
7629  * Gets all custom data items for the Functions
7630  *
7631  */
7632 static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo2 * iface,
7633     UINT indexFunc, UINT indexParam, CUSTDATA *pCustData)
7634 {
7635     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7636     TLBFuncDesc *pFDesc = &This->funcdescs[indexFunc];
7637
7638     TRACE("%p %u %u %p\n", This, indexFunc, indexParam, pCustData);
7639
7640     if(indexFunc >= This->TypeAttr.cFuncs)
7641         return TYPE_E_ELEMENTNOTFOUND;
7642
7643     if(indexParam >= pFDesc->funcdesc.cParams)
7644         return TYPE_E_ELEMENTNOTFOUND;
7645
7646     return TLB_copy_all_custdata(&pFDesc->pParamDesc[indexParam].custdata_list, pCustData);
7647 }
7648
7649 /* ITypeInfo2::GetAllVarCustData
7650  *
7651  * Gets all custom data items for the specified Variable
7652  *
7653  */
7654 static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo2 * iface,
7655     UINT index, CUSTDATA *pCustData)
7656 {
7657     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7658     TLBVarDesc * pVDesc = &This->vardescs[index];
7659
7660     TRACE("%p %u %p\n", This, index, pCustData);
7661
7662     if(index >= This->TypeAttr.cVars)
7663         return TYPE_E_ELEMENTNOTFOUND;
7664
7665     return TLB_copy_all_custdata(&pVDesc->custdata_list, pCustData);
7666 }
7667
7668 /* ITypeInfo2::GetAllImplCustData
7669  *
7670  * Gets all custom data items for the specified implementation type
7671  *
7672  */
7673 static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData(
7674         ITypeInfo2 * iface,
7675         UINT index,
7676         CUSTDATA *pCustData)
7677 {
7678     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7679     TLBImplType *pRDesc = &This->impltypes[index];
7680
7681     TRACE("%p %u %p\n", This, index, pCustData);
7682
7683     if(index >= This->TypeAttr.cImplTypes)
7684         return TYPE_E_ELEMENTNOTFOUND;
7685
7686     return TLB_copy_all_custdata(&pRDesc->custdata_list, pCustData);
7687 }
7688
7689 static const ITypeInfo2Vtbl tinfvt =
7690 {
7691
7692     ITypeInfo_fnQueryInterface,
7693     ITypeInfo_fnAddRef,
7694     ITypeInfo_fnRelease,
7695
7696     ITypeInfo_fnGetTypeAttr,
7697     ITypeInfo_fnGetTypeComp,
7698     ITypeInfo_fnGetFuncDesc,
7699     ITypeInfo_fnGetVarDesc,
7700     ITypeInfo_fnGetNames,
7701     ITypeInfo_fnGetRefTypeOfImplType,
7702     ITypeInfo_fnGetImplTypeFlags,
7703     ITypeInfo_fnGetIDsOfNames,
7704     ITypeInfo_fnInvoke,
7705     ITypeInfo_fnGetDocumentation,
7706     ITypeInfo_fnGetDllEntry,
7707     ITypeInfo_fnGetRefTypeInfo,
7708     ITypeInfo_fnAddressOfMember,
7709     ITypeInfo_fnCreateInstance,
7710     ITypeInfo_fnGetMops,
7711     ITypeInfo_fnGetContainingTypeLib,
7712     ITypeInfo_fnReleaseTypeAttr,
7713     ITypeInfo_fnReleaseFuncDesc,
7714     ITypeInfo_fnReleaseVarDesc,
7715
7716     ITypeInfo2_fnGetTypeKind,
7717     ITypeInfo2_fnGetTypeFlags,
7718     ITypeInfo2_fnGetFuncIndexOfMemId,
7719     ITypeInfo2_fnGetVarIndexOfMemId,
7720     ITypeInfo2_fnGetCustData,
7721     ITypeInfo2_fnGetFuncCustData,
7722     ITypeInfo2_fnGetParamCustData,
7723     ITypeInfo2_fnGetVarCustData,
7724     ITypeInfo2_fnGetImplTypeCustData,
7725     ITypeInfo2_fnGetDocumentation2,
7726     ITypeInfo2_fnGetAllCustData,
7727     ITypeInfo2_fnGetAllFuncCustData,
7728     ITypeInfo2_fnGetAllParamCustData,
7729     ITypeInfo2_fnGetAllVarCustData,
7730     ITypeInfo2_fnGetAllImplTypeCustData,
7731 };
7732
7733 /******************************************************************************
7734  * CreateDispTypeInfo [OLEAUT32.31]
7735  *
7736  * Build type information for an object so it can be called through an
7737  * IDispatch interface.
7738  *
7739  * RETURNS
7740  *  Success: S_OK. pptinfo contains the created ITypeInfo object.
7741  *  Failure: E_INVALIDARG, if one or more arguments is invalid.
7742  *
7743  * NOTES
7744  *  This call allows an objects methods to be accessed through IDispatch, by
7745  *  building an ITypeInfo object that IDispatch can use to call through.
7746  */
7747 HRESULT WINAPI CreateDispTypeInfo(
7748         INTERFACEDATA *pidata, /* [I] Description of the interface to build type info for */
7749         LCID lcid, /* [I] Locale Id */
7750         ITypeInfo **pptinfo) /* [O] Destination for created ITypeInfo object */
7751 {
7752     ITypeInfoImpl *pTIClass, *pTIIface;
7753     ITypeLibImpl *pTypeLibImpl;
7754     unsigned int param, func;
7755     TLBFuncDesc *pFuncDesc;
7756     TLBRefType *ref;
7757
7758     TRACE("\n");
7759     pTypeLibImpl = TypeLibImpl_Constructor();
7760     if (!pTypeLibImpl) return E_FAIL;
7761
7762     pTypeLibImpl->TypeInfoCount = 2;
7763     pTypeLibImpl->typeinfos = heap_alloc_zero(pTypeLibImpl->TypeInfoCount * sizeof(ITypeInfoImpl*));
7764
7765     pTIIface = pTypeLibImpl->typeinfos[0] = ITypeInfoImpl_Constructor();
7766     pTIIface->pTypeLib = pTypeLibImpl;
7767     pTIIface->index = 0;
7768     pTIIface->Name = NULL;
7769     pTIIface->dwHelpContext = -1;
7770     memset(&pTIIface->TypeAttr.guid, 0, sizeof(GUID));
7771     pTIIface->TypeAttr.lcid = lcid;
7772     pTIIface->TypeAttr.typekind = TKIND_INTERFACE;
7773     pTIIface->TypeAttr.wMajorVerNum = 0;
7774     pTIIface->TypeAttr.wMinorVerNum = 0;
7775     pTIIface->TypeAttr.cbAlignment = 2;
7776     pTIIface->TypeAttr.cbSizeInstance = -1;
7777     pTIIface->TypeAttr.cbSizeVft = -1;
7778     pTIIface->TypeAttr.cFuncs = 0;
7779     pTIIface->TypeAttr.cImplTypes = 0;
7780     pTIIface->TypeAttr.cVars = 0;
7781     pTIIface->TypeAttr.wTypeFlags = 0;
7782
7783     pTIIface->funcdescs = TLBFuncDesc_Constructor(pidata->cMembers);
7784     pFuncDesc = pTIIface->funcdescs;
7785     for(func = 0; func < pidata->cMembers; func++) {
7786         METHODDATA *md = pidata->pmethdata + func;
7787         pFuncDesc->Name = SysAllocString(md->szName);
7788         pFuncDesc->funcdesc.memid = md->dispid;
7789         pFuncDesc->funcdesc.lprgscode = NULL;
7790         pFuncDesc->funcdesc.funckind = FUNC_VIRTUAL;
7791         pFuncDesc->funcdesc.invkind = md->wFlags;
7792         pFuncDesc->funcdesc.callconv = md->cc;
7793         pFuncDesc->funcdesc.cParams = md->cArgs;
7794         pFuncDesc->funcdesc.cParamsOpt = 0;
7795         pFuncDesc->funcdesc.oVft = md->iMeth * sizeof(void *);
7796         pFuncDesc->funcdesc.cScodes = 0;
7797         pFuncDesc->funcdesc.wFuncFlags = 0;
7798         pFuncDesc->funcdesc.elemdescFunc.tdesc.vt = md->vtReturn;
7799         pFuncDesc->funcdesc.elemdescFunc.u.paramdesc.wParamFlags = PARAMFLAG_NONE;
7800         pFuncDesc->funcdesc.elemdescFunc.u.paramdesc.pparamdescex = NULL;
7801         pFuncDesc->funcdesc.lprgelemdescParam = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7802                                                               md->cArgs * sizeof(ELEMDESC));
7803         pFuncDesc->pParamDesc = TLBParDesc_Constructor(md->cArgs);
7804         for(param = 0; param < md->cArgs; param++) {
7805             pFuncDesc->funcdesc.lprgelemdescParam[param].tdesc.vt = md->ppdata[param].vt;
7806             pFuncDesc->pParamDesc[param].Name = SysAllocString(md->ppdata[param].szName);
7807         }
7808         pFuncDesc->helpcontext = 0;
7809         pFuncDesc->HelpStringContext = 0;
7810         pFuncDesc->HelpString = NULL;
7811         pFuncDesc->Entry = NULL;
7812         list_init(&pFuncDesc->custdata_list);
7813         pTIIface->TypeAttr.cFuncs++;
7814         ++pFuncDesc;
7815     }
7816
7817     dump_TypeInfo(pTIIface);
7818
7819     pTIClass = pTypeLibImpl->typeinfos[1] = ITypeInfoImpl_Constructor();
7820     pTIClass->pTypeLib = pTypeLibImpl;
7821     pTIClass->index = 1;
7822     pTIClass->Name = NULL;
7823     pTIClass->dwHelpContext = -1;
7824     memset(&pTIClass->TypeAttr.guid, 0, sizeof(GUID));
7825     pTIClass->TypeAttr.lcid = lcid;
7826     pTIClass->TypeAttr.typekind = TKIND_COCLASS;
7827     pTIClass->TypeAttr.wMajorVerNum = 0;
7828     pTIClass->TypeAttr.wMinorVerNum = 0;
7829     pTIClass->TypeAttr.cbAlignment = 2;
7830     pTIClass->TypeAttr.cbSizeInstance = -1;
7831     pTIClass->TypeAttr.cbSizeVft = -1;
7832     pTIClass->TypeAttr.cFuncs = 0;
7833     pTIClass->TypeAttr.cImplTypes = 1;
7834     pTIClass->TypeAttr.cVars = 0;
7835     pTIClass->TypeAttr.wTypeFlags = 0;
7836
7837     pTIClass->impltypes = TLBImplType_Constructor(1);
7838
7839     ref = heap_alloc_zero(sizeof(*ref));
7840     ref->pImpTLInfo = TLB_REF_INTERNAL;
7841     list_add_head(&pTypeLibImpl->ref_list, &ref->entry);
7842
7843     dump_TypeInfo(pTIClass);
7844
7845     *pptinfo = (ITypeInfo*)pTIClass;
7846
7847     ITypeInfo_AddRef(*pptinfo);
7848     ITypeLib2_Release(&pTypeLibImpl->ITypeLib2_iface);
7849
7850     return S_OK;
7851
7852 }
7853
7854 static HRESULT WINAPI ITypeComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
7855 {
7856     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7857
7858     return ITypeInfo_QueryInterface((ITypeInfo *)This, riid, ppv);
7859 }
7860
7861 static ULONG WINAPI ITypeComp_fnAddRef(ITypeComp * iface)
7862 {
7863     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7864
7865     return ITypeInfo_AddRef((ITypeInfo *)This);
7866 }
7867
7868 static ULONG WINAPI ITypeComp_fnRelease(ITypeComp * iface)
7869 {
7870     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7871
7872     return ITypeInfo_Release((ITypeInfo *)This);
7873 }
7874
7875 static HRESULT WINAPI ITypeComp_fnBind(
7876     ITypeComp * iface,
7877     OLECHAR * szName,
7878     ULONG lHash,
7879     WORD wFlags,
7880     ITypeInfo ** ppTInfo,
7881     DESCKIND * pDescKind,
7882     BINDPTR * pBindPtr)
7883 {
7884     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7885     const TLBFuncDesc *pFDesc;
7886     const TLBVarDesc *pVDesc;
7887     HRESULT hr = DISP_E_MEMBERNOTFOUND;
7888     UINT fdc;
7889
7890     TRACE("(%p)->(%s, %x, 0x%x, %p, %p, %p)\n", This, debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
7891
7892     *pDescKind = DESCKIND_NONE;
7893     pBindPtr->lpfuncdesc = NULL;
7894     *ppTInfo = NULL;
7895
7896     for(fdc = 0; fdc < This->TypeAttr.cFuncs; ++fdc){
7897         pFDesc = &This->funcdescs[fdc];
7898         if (!strcmpiW(pFDesc->Name, szName)) {
7899             if (!wFlags || (pFDesc->funcdesc.invkind & wFlags))
7900                 break;
7901             else
7902                 /* name found, but wrong flags */
7903                 hr = TYPE_E_TYPEMISMATCH;
7904         }
7905     }
7906
7907     if (fdc < This->TypeAttr.cFuncs)
7908     {
7909         HRESULT hr = TLB_AllocAndInitFuncDesc(
7910             &pFDesc->funcdesc,
7911             &pBindPtr->lpfuncdesc,
7912             This->TypeAttr.typekind == TKIND_DISPATCH);
7913         if (FAILED(hr))
7914             return hr;
7915         *pDescKind = DESCKIND_FUNCDESC;
7916         *ppTInfo = (ITypeInfo *)&This->lpVtbl;
7917         ITypeInfo_AddRef(*ppTInfo);
7918         return S_OK;
7919     } else {
7920         pVDesc = TLB_get_vardesc_by_name(This->vardescs, This->TypeAttr.cVars, szName);
7921         if(pVDesc){
7922             HRESULT hr = TLB_AllocAndInitVarDesc(&pVDesc->vardesc, &pBindPtr->lpvardesc);
7923             if (FAILED(hr))
7924                 return hr;
7925             *pDescKind = DESCKIND_VARDESC;
7926             *ppTInfo = (ITypeInfo *)&This->lpVtbl;
7927             ITypeInfo_AddRef(*ppTInfo);
7928             return S_OK;
7929         }
7930     }
7931     /* FIXME: search each inherited interface, not just the first */
7932     if (hr == DISP_E_MEMBERNOTFOUND && This->impltypes) {
7933         /* recursive search */
7934         ITypeInfo *pTInfo;
7935         ITypeComp *pTComp;
7936         HRESULT hr;
7937         hr=ITypeInfo_GetRefTypeInfo((ITypeInfo *)&This->lpVtbl, This->impltypes[0].hRef, &pTInfo);
7938         if (SUCCEEDED(hr))
7939         {
7940             hr = ITypeInfo_GetTypeComp(pTInfo,&pTComp);
7941             ITypeInfo_Release(pTInfo);
7942         }
7943         if (SUCCEEDED(hr))
7944         {
7945             hr = ITypeComp_Bind(pTComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
7946             ITypeComp_Release(pTComp);
7947             return hr;
7948         }
7949         WARN("Could not search inherited interface!\n");
7950     }
7951     if (hr == DISP_E_MEMBERNOTFOUND)
7952         hr = S_OK;
7953     TRACE("did not find member with name %s, flags 0x%x\n", debugstr_w(szName), wFlags);
7954     return hr;
7955 }
7956
7957 static HRESULT WINAPI ITypeComp_fnBindType(
7958     ITypeComp * iface,
7959     OLECHAR * szName,
7960     ULONG lHash,
7961     ITypeInfo ** ppTInfo,
7962     ITypeComp ** ppTComp)
7963 {
7964     TRACE("(%s, %x, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
7965
7966     /* strange behaviour (does nothing) but like the
7967      * original */
7968
7969     if (!ppTInfo || !ppTComp)
7970         return E_POINTER;
7971
7972     *ppTInfo = NULL;
7973     *ppTComp = NULL;
7974
7975     return S_OK;
7976 }
7977
7978 static const ITypeCompVtbl tcompvt =
7979 {
7980
7981     ITypeComp_fnQueryInterface,
7982     ITypeComp_fnAddRef,
7983     ITypeComp_fnRelease,
7984
7985     ITypeComp_fnBind,
7986     ITypeComp_fnBindType
7987 };