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