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