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