Annotate with allocation size attribute.
[wine] / dlls / oleaut32 / typelib.c
1 /*
2  *      TYPELIB
3  *
4  *      Copyright 1997  Marcus Meissner
5  *                    1999  Rein Klazes
6  *                    2000  Francois Jacques
7  *                    2001  Huw D M Davies for CodeWeavers
8  *                    2005  Robert Shearman, for CodeWeavers
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23  *
24  * --------------------------------------------------------------------------------------
25  * Known problems (2000, Francois Jacques)
26  *
27  * - Tested using OLEVIEW (Platform SDK tool) only.
28  *
29  * - dual interface dispinterfaces. vtable-interface ITypeInfo instances are
30  *   creating by doing a straight copy of the dispinterface instance and just changing
31  *   its typekind. Pointed structures aren't copied - only the address of the pointers.
32  *
33  * - locale stuff is partially implemented but hasn't been tested.
34  *
35  * - typelib file is still read in its entirety, but it is released now.
36  *
37  * --------------------------------------------------------------------------------------
38  *  Known problems left from previous implementation (1999, Rein Klazes) :
39  *
40  * -. Data structures are straightforward, but slow for look-ups.
41  * -. (related) nothing is hashed
42  * -. Most error return values are just guessed not checked with windows
43  *      behaviour.
44  * -. lousy fatal error handling
45  *
46  */
47
48 #include "config.h"
49 #include "wine/port.h"
50
51 #include <stdlib.h>
52 #include <string.h>
53 #include <stdarg.h>
54 #include <stdio.h>
55 #include <ctype.h>
56
57 #define COBJMACROS
58 #define NONAMELESSUNION
59 #define NONAMELESSSTRUCT
60
61 #include "winerror.h"
62 #include "windef.h"
63 #include "winbase.h"
64 #include "winnls.h"
65 #include "winreg.h"
66 #include "winuser.h"
67
68 #include "wine/unicode.h"
69 #include "objbase.h"
70 #include "typelib.h"
71 #include "wine/debug.h"
72 #include "variant.h"
73 #include "wine/list.h"
74
75 WINE_DEFAULT_DEBUG_CHANNEL(ole);
76 WINE_DECLARE_DEBUG_CHANNEL(typelib);
77
78 static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt);
79 static HRESULT TLB_AllocAndInitVarDesc(const VARDESC *src, VARDESC **dest_ptr);
80
81 /****************************************************************************
82  *              FromLExxx
83  *
84  * Takes p_iVal (which is in little endian) and returns it
85  *   in the host machine's byte order.
86  */
87 #ifdef WORDS_BIGENDIAN
88 static WORD FromLEWord(WORD p_iVal)
89 {
90   return (((p_iVal & 0x00FF) << 8) |
91           ((p_iVal & 0xFF00) >> 8));
92 }
93
94
95 static DWORD FromLEDWord(DWORD p_iVal)
96 {
97   return (((p_iVal & 0x000000FF) << 24) |
98           ((p_iVal & 0x0000FF00) <<  8) |
99           ((p_iVal & 0x00FF0000) >>  8) |
100           ((p_iVal & 0xFF000000) >> 24));
101 }
102 #else
103 #define FromLEWord(X)  (X)
104 #define FromLEDWord(X) (X)
105 #endif
106
107 #define DISPATCH_HREF_OFFSET 0x01000000
108 #define DISPATCH_HREF_MASK   0xff000000
109
110 /****************************************************************************
111  *              FromLExxx
112  *
113  * Fix byte order in any structure if necessary
114  */
115 #ifdef WORDS_BIGENDIAN
116 static void FromLEWords(void *p_Val, int p_iSize)
117 {
118   WORD *Val = p_Val;
119
120   p_iSize /= sizeof(WORD);
121
122   while (p_iSize) {
123     *Val = FromLEWord(*Val);
124     Val++;
125     p_iSize--;
126   }
127 }
128
129
130 static void FromLEDWords(void *p_Val, int p_iSize)
131 {
132   DWORD *Val = p_Val;
133
134   p_iSize /= sizeof(DWORD);
135
136   while (p_iSize) {
137     *Val = FromLEDWord(*Val);
138     Val++;
139     p_iSize--;
140   }
141 }
142 #else
143 #define FromLEWords(X,Y) /*nothing*/
144 #define FromLEDWords(X,Y) /*nothing*/
145 #endif
146
147 /*
148  * Find a typelib key which matches a requested maj.min version.
149  */
150 static BOOL find_typelib_key( REFGUID guid, WORD wMaj, WORD *wMin )
151 {
152     static const WCHAR typelibW[] = {'T','y','p','e','l','i','b','\\',0};
153     WCHAR buffer[60];
154     char key_name[16];
155     DWORD len, i;
156     INT best_min = -1;
157     HKEY hkey;
158
159     memcpy( buffer, typelibW, sizeof(typelibW) );
160     StringFromGUID2( guid, buffer + strlenW(buffer), 40 );
161
162     if (RegOpenKeyExW( HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hkey ) != ERROR_SUCCESS)
163         return FALSE;
164
165     len = sizeof(key_name);
166     i = 0;
167     while (RegEnumKeyExA(hkey, i++, key_name, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
168     {
169         INT v_maj, v_min;
170
171         if (sscanf(key_name, "%x.%x", &v_maj, &v_min) == 2)
172         {
173             TRACE("found %s: %x.%x\n", debugstr_w(buffer), v_maj, v_min);
174
175             if (wMaj == v_maj)
176             {
177                 if (*wMin == v_min)
178                 {
179                     best_min = v_min;
180                     break; /* exact match */
181                 }
182                 if (v_min > best_min) best_min = v_min;
183             }
184         }
185         len = sizeof(key_name);
186     }
187     RegCloseKey( hkey );
188     if (best_min >= 0)
189     {
190         *wMin = best_min;
191         return TRUE;
192     }
193     return FALSE;
194 }
195
196 /* get the path of a typelib key, in the form "Typelib\\<guid>\\<maj>.<min>" */
197 /* buffer must be at least 60 characters long */
198 static WCHAR *get_typelib_key( REFGUID guid, WORD wMaj, WORD wMin, WCHAR *buffer )
199 {
200     static const WCHAR TypelibW[] = {'T','y','p','e','l','i','b','\\',0};
201     static const WCHAR VersionFormatW[] = {'\\','%','x','.','%','x',0};
202
203     memcpy( buffer, TypelibW, sizeof(TypelibW) );
204     StringFromGUID2( guid, buffer + strlenW(buffer), 40 );
205     sprintfW( buffer + strlenW(buffer), VersionFormatW, wMaj, wMin );
206     return buffer;
207 }
208
209 /* get the path of an interface key, in the form "Interface\\<guid>" */
210 /* buffer must be at least 50 characters long */
211 static WCHAR *get_interface_key( REFGUID guid, WCHAR *buffer )
212 {
213     static const WCHAR InterfaceW[] = {'I','n','t','e','r','f','a','c','e','\\',0};
214
215     memcpy( buffer, InterfaceW, sizeof(InterfaceW) );
216     StringFromGUID2( guid, buffer + strlenW(buffer), 40 );
217     return buffer;
218 }
219
220 /* get the lcid subkey for a typelib, in the form "<lcid>\\<syskind>" */
221 /* buffer must be at least 16 characters long */
222 static WCHAR *get_lcid_subkey( LCID lcid, SYSKIND syskind, WCHAR *buffer )
223 {
224     static const WCHAR LcidFormatW[] = {'%','l','x','\\',0};
225     static const WCHAR win16W[] = {'w','i','n','1','6',0};
226     static const WCHAR win32W[] = {'w','i','n','3','2',0};
227
228     sprintfW( buffer, LcidFormatW, lcid );
229     switch(syskind)
230     {
231     case SYS_WIN16: strcatW( buffer, win16W ); break;
232     case SYS_WIN32: strcatW( buffer, win32W ); break;
233     default:
234         TRACE("Typelib is for unsupported syskind %i\n", syskind);
235         return NULL;
236     }
237     return buffer;
238 }
239
240 static HRESULT TLB_ReadTypeLib(LPCWSTR pszFileName, LPWSTR pszPath, UINT cchPath, ITypeLib2 **ppTypeLib);
241
242
243 /****************************************************************************
244  *              QueryPathOfRegTypeLib   [OLEAUT32.164]
245  *
246  * Gets the path to a registered type library.
247  *
248  * PARAMS
249  *  guid [I] referenced guid
250  *  wMaj [I] major version
251  *  wMin [I] minor version
252  *  lcid [I] locale id
253  *  path [O] path of typelib
254  *
255  * RETURNS
256  *  Success: S_OK.
257  *  Failure: If the type library is not registered then TYPE_E_LIBNOTREGISTERED
258  *  or TYPE_E_REGISTRYACCESS if the type library registration key couldn't be
259  *  opened.
260  */
261 HRESULT WINAPI QueryPathOfRegTypeLib(
262         REFGUID guid,
263         WORD wMaj,
264         WORD wMin,
265         LCID lcid,
266         LPBSTR path )
267 {
268     HRESULT hr = TYPE_E_LIBNOTREGISTERED;
269     LCID myLCID = lcid;
270     HKEY hkey;
271     WCHAR buffer[60];
272     WCHAR Path[MAX_PATH];
273     LONG res;
274
275     TRACE_(typelib)("(%s, %x.%x, 0x%x, %p)\n", debugstr_guid(guid), wMaj, wMin, lcid, path);
276
277     if (!find_typelib_key( guid, wMaj, &wMin )) return TYPE_E_LIBNOTREGISTERED;
278     get_typelib_key( guid, wMaj, wMin, buffer );
279
280     res = RegOpenKeyExW( HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hkey );
281     if (res == ERROR_FILE_NOT_FOUND)
282     {
283         TRACE_(typelib)("%s not found\n", debugstr_w(buffer));
284         return TYPE_E_LIBNOTREGISTERED;
285     }
286     else if (res != ERROR_SUCCESS)
287     {
288         TRACE_(typelib)("failed to open %s for read access\n", debugstr_w(buffer));
289         return TYPE_E_REGISTRYACCESS;
290     }
291
292     while (hr != S_OK)
293     {
294         LONG dwPathLen = sizeof(Path);
295
296         get_lcid_subkey( myLCID, SYS_WIN32, buffer );
297
298         if (RegQueryValueW(hkey, buffer, Path, &dwPathLen))
299         {
300             if (!lcid)
301                 break;
302             else if (myLCID == lcid)
303             {
304                 /* try with sub-langid */
305                 myLCID = SUBLANGID(lcid);
306             }
307             else if ((myLCID == SUBLANGID(lcid)) && myLCID)
308             {
309                 /* try with system langid */
310                 myLCID = 0;
311             }
312             else
313             {
314                 break;
315             }
316         }
317         else
318         {
319             *path = SysAllocString( Path );
320             hr = S_OK;
321         }
322     }
323     RegCloseKey( hkey );
324     TRACE_(typelib)("-- 0x%08x\n", hr);
325     return hr;
326 }
327
328 /******************************************************************************
329  * CreateTypeLib [OLEAUT32.160]  creates a typelib
330  *
331  * RETURNS
332  *    Success: S_OK
333  *    Failure: Status
334  */
335 HRESULT WINAPI CreateTypeLib(
336         SYSKIND syskind, LPCOLESTR szFile, ICreateTypeLib** ppctlib
337 ) {
338     FIXME("(%d,%s,%p), stub!\n",syskind,debugstr_w(szFile),ppctlib);
339     return E_FAIL;
340 }
341
342 /******************************************************************************
343  *              LoadTypeLib     [OLEAUT32.161]
344  *
345  * Loads a type library
346  *
347  * PARAMS
348  *  szFile [I] Name of file to load from.
349  *  pptLib [O] Pointer that receives ITypeLib object on success.
350  *
351  * RETURNS
352  *    Success: S_OK
353  *    Failure: Status
354  *
355  * SEE
356  *  LoadTypeLibEx, LoadRegTypeLib, CreateTypeLib.
357  */
358 HRESULT WINAPI LoadTypeLib(const OLECHAR *szFile, ITypeLib * *pptLib)
359 {
360     TRACE("(%s,%p)\n",debugstr_w(szFile), pptLib);
361     return LoadTypeLibEx(szFile, REGKIND_DEFAULT, pptLib);
362 }
363
364 /******************************************************************************
365  *              LoadTypeLibEx   [OLEAUT32.183]
366  *
367  * Loads and optionally registers a type library
368  *
369  * RETURNS
370  *    Success: S_OK
371  *    Failure: Status
372  */
373 HRESULT WINAPI LoadTypeLibEx(
374     LPCOLESTR szFile,  /* [in] Name of file to load from */
375     REGKIND  regkind,  /* [in] Specify kind of registration */
376     ITypeLib **pptLib) /* [out] Pointer to pointer to loaded type library */
377 {
378     WCHAR szPath[MAX_PATH+1];
379     HRESULT res;
380
381     TRACE("(%s,%d,%p)\n",debugstr_w(szFile), regkind, pptLib);
382
383     *pptLib = NULL;
384
385     res = TLB_ReadTypeLib(szFile, szPath, MAX_PATH + 1, (ITypeLib2**)pptLib);
386
387     if (SUCCEEDED(res))
388         switch(regkind)
389         {
390             case REGKIND_DEFAULT:
391                 /* don't register typelibs supplied with full path. Experimentation confirms the following */
392                 if (((szFile[0] == '\\') && (szFile[1] == '\\')) ||
393                     (szFile[0] && (szFile[1] == ':'))) break;
394                 /* else fall-through */
395
396             case REGKIND_REGISTER:
397                 if (!SUCCEEDED(res = RegisterTypeLib(*pptLib, (LPOLESTR)szPath, NULL)))
398                 {
399                     IUnknown_Release(*pptLib);
400                     *pptLib = 0;
401                 }
402                 break;
403             case REGKIND_NONE:
404                 break;
405         }
406
407     TRACE(" returns %08x\n",res);
408     return res;
409 }
410
411 /******************************************************************************
412  *              LoadRegTypeLib  [OLEAUT32.162]
413  *
414  * Loads a registered type library.
415  *
416  * PARAMS
417  *  rguid     [I] GUID of the registered type library.
418  *  wVerMajor [I] major version.
419  *  wVerMinor [I] minor version.
420  *  lcid      [I] locale ID.
421  *  ppTLib    [O] pointer that receives an ITypeLib object on success.
422  *
423  * RETURNS
424  *  Success: S_OK.
425  *  Failure: Any HRESULT code returned from QueryPathOfRegTypeLib or
426  *  LoadTypeLib.
427  */
428 HRESULT WINAPI LoadRegTypeLib(
429         REFGUID rguid,
430         WORD wVerMajor,
431         WORD wVerMinor,
432         LCID lcid,
433         ITypeLib **ppTLib)
434 {
435     BSTR bstr=NULL;
436     HRESULT res;
437
438     *ppTLib = NULL;
439
440     res = QueryPathOfRegTypeLib( rguid, wVerMajor, wVerMinor, lcid, &bstr);
441
442     if(SUCCEEDED(res))
443     {
444         res= LoadTypeLib(bstr, ppTLib);
445         SysFreeString(bstr);
446     }
447
448     TRACE("(IID: %s) load %s (%p)\n",debugstr_guid(rguid), SUCCEEDED(res)? "SUCCESS":"FAILED", *ppTLib);
449
450     return res;
451 }
452
453
454 /* some string constants shared between RegisterTypeLib and UnRegisterTypeLib */
455 static const WCHAR TypeLibW[] = {'T','y','p','e','L','i','b',0};
456 static const WCHAR FLAGSW[] = {'F','L','A','G','S',0};
457 static const WCHAR HELPDIRW[] = {'H','E','L','P','D','I','R',0};
458 static const WCHAR ProxyStubClsidW[] = {'P','r','o','x','y','S','t','u','b','C','l','s','i','d',0};
459 static const WCHAR ProxyStubClsid32W[] = {'P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
460
461 /******************************************************************************
462  *              RegisterTypeLib [OLEAUT32.163]
463  * Adds information about a type library to the System Registry
464  * NOTES
465  *    Docs: ITypeLib FAR * ptlib
466  *    Docs: OLECHAR FAR* szFullPath
467  *    Docs: OLECHAR FAR* szHelpDir
468  *
469  * RETURNS
470  *    Success: S_OK
471  *    Failure: Status
472  */
473 HRESULT WINAPI RegisterTypeLib(
474      ITypeLib * ptlib,     /* [in] Pointer to the library*/
475      OLECHAR * szFullPath, /* [in] full Path of the library*/
476      OLECHAR * szHelpDir)  /* [in] dir to the helpfile for the library,
477                                                          may be NULL*/
478 {
479     static const WCHAR PSOA[] = {'{','0','0','0','2','0','4','2','4','-',
480                                  '0','0','0','0','-','0','0','0','0','-','C','0','0','0','-',
481                                  '0','0','0','0','0','0','0','0','0','0','4','6','}',0};
482     HRESULT res;
483     TLIBATTR *attr;
484     WCHAR keyName[60];
485     WCHAR tmp[16];
486     HKEY key, subKey;
487     UINT types, tidx;
488     TYPEKIND kind;
489     DWORD disposition;
490
491     if (ptlib == NULL || szFullPath == NULL)
492         return E_INVALIDARG;
493
494     if (!SUCCEEDED(ITypeLib_GetLibAttr(ptlib, &attr)))
495         return E_FAIL;
496
497     get_typelib_key( &attr->guid, attr->wMajorVerNum, attr->wMinorVerNum, keyName );
498
499     res = S_OK;
500     if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0,
501         KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS)
502     {
503         LPOLESTR doc;
504
505         /* Set the human-readable name of the typelib */
506         if (SUCCEEDED(ITypeLib_GetDocumentation(ptlib, -1, NULL, &doc, NULL, NULL)))
507         {
508             if (RegSetValueExW(key, NULL, 0, REG_SZ,
509                 (BYTE *)doc, (lstrlenW(doc)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS)
510                 res = E_FAIL;
511
512             SysFreeString(doc);
513         }
514         else
515             res = E_FAIL;
516
517         /* Make up the name of the typelib path subkey */
518         if (!get_lcid_subkey( attr->lcid, attr->syskind, tmp )) res = E_FAIL;
519
520         /* Create the typelib path subkey */
521         if (res == S_OK && RegCreateKeyExW(key, tmp, 0, NULL, 0,
522             KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
523         {
524             if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
525                 (BYTE *)szFullPath, (lstrlenW(szFullPath)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS)
526                 res = E_FAIL;
527
528             RegCloseKey(subKey);
529         }
530         else
531             res = E_FAIL;
532
533         /* Create the flags subkey */
534         if (res == S_OK && RegCreateKeyExW(key, FLAGSW, 0, NULL, 0,
535             KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
536         {
537             /* FIXME: is %u correct? */
538             static const WCHAR formatW[] = {'%','u',0};
539             WCHAR buf[20];
540             sprintfW(buf, formatW, attr->wLibFlags);
541             if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
542                                (BYTE *)buf, (strlenW(buf) + 1)*sizeof(WCHAR) ) != ERROR_SUCCESS)
543                 res = E_FAIL;
544
545             RegCloseKey(subKey);
546         }
547         else
548             res = E_FAIL;
549
550         /* create the helpdir subkey */
551         if (res == S_OK && RegCreateKeyExW(key, HELPDIRW, 0, NULL, 0,
552             KEY_WRITE, NULL, &subKey, &disposition) == ERROR_SUCCESS)
553         {
554             BOOL freeHelpDir = FALSE;
555             OLECHAR* pIndexStr;
556
557             /* if we created a new key, and helpDir was null, set the helpdir
558                to the directory which contains the typelib. However,
559                if we just opened an existing key, we leave the helpdir alone */
560             if ((disposition == REG_CREATED_NEW_KEY) && (szHelpDir == NULL)) {
561                 szHelpDir = SysAllocString(szFullPath);
562                 pIndexStr = strrchrW(szHelpDir, '\\');
563                 if (pIndexStr) {
564                     *pIndexStr = 0;
565                 }
566                 freeHelpDir = TRUE;
567             }
568
569             /* if we have an szHelpDir, set it! */
570             if (szHelpDir != NULL) {
571                 if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
572                     (BYTE *)szHelpDir, (lstrlenW(szHelpDir)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS) {
573                     res = E_FAIL;
574                 }
575             }
576
577             /* tidy up */
578             if (freeHelpDir) SysFreeString(szHelpDir);
579             RegCloseKey(subKey);
580
581         } else {
582             res = E_FAIL;
583         }
584
585         RegCloseKey(key);
586     }
587     else
588         res = E_FAIL;
589
590     /* register OLE Automation-compatible interfaces for this typelib */
591     types = ITypeLib_GetTypeInfoCount(ptlib);
592     for (tidx=0; tidx<types; tidx++) {
593         if (SUCCEEDED(ITypeLib_GetTypeInfoType(ptlib, tidx, &kind))) {
594             LPOLESTR name = NULL;
595             ITypeInfo *tinfo = NULL;
596
597             ITypeLib_GetDocumentation(ptlib, tidx, &name, NULL, NULL, NULL);
598
599             switch (kind) {
600             case TKIND_INTERFACE:
601                 TRACE_(typelib)("%d: interface %s\n", tidx, debugstr_w(name));
602                 ITypeLib_GetTypeInfo(ptlib, tidx, &tinfo);
603                 break;
604
605             case TKIND_DISPATCH:
606                 TRACE_(typelib)("%d: dispinterface %s\n", tidx, debugstr_w(name));
607                 ITypeLib_GetTypeInfo(ptlib, tidx, &tinfo);
608                 break;
609
610             default:
611                 TRACE_(typelib)("%d: %s\n", tidx, debugstr_w(name));
612                 break;
613             }
614
615             if (tinfo) {
616                 TYPEATTR *tattr = NULL;
617                 ITypeInfo_GetTypeAttr(tinfo, &tattr);
618
619                 if (tattr) {
620                     TRACE_(typelib)("guid=%s, flags=%04x (",
621                                     debugstr_guid(&tattr->guid),
622                                     tattr->wTypeFlags);
623
624                     if (TRACE_ON(typelib)) {
625 #define XX(x) if (TYPEFLAG_##x & tattr->wTypeFlags) MESSAGE(#x"|");
626                         XX(FAPPOBJECT);
627                         XX(FCANCREATE);
628                         XX(FLICENSED);
629                         XX(FPREDECLID);
630                         XX(FHIDDEN);
631                         XX(FCONTROL);
632                         XX(FDUAL);
633                         XX(FNONEXTENSIBLE);
634                         XX(FOLEAUTOMATION);
635                         XX(FRESTRICTED);
636                         XX(FAGGREGATABLE);
637                         XX(FREPLACEABLE);
638                         XX(FDISPATCHABLE);
639                         XX(FREVERSEBIND);
640                         XX(FPROXY);
641 #undef XX
642                         MESSAGE("\n");
643                     }
644
645                     if (tattr->wTypeFlags & (TYPEFLAG_FOLEAUTOMATION|TYPEFLAG_FDUAL|TYPEFLAG_FDISPATCHABLE))
646                     {
647                         /* register interface<->typelib coupling */
648                         get_interface_key( &tattr->guid, keyName );
649                         if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0,
650                                             KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS)
651                         {
652                             if (name)
653                                 RegSetValueExW(key, NULL, 0, REG_SZ,
654                                                (BYTE *)name, (strlenW(name)+1) * sizeof(OLECHAR));
655
656                             if (RegCreateKeyExW(key, ProxyStubClsidW, 0, NULL, 0,
657                                 KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) {
658                                 RegSetValueExW(subKey, NULL, 0, REG_SZ,
659                                                (const BYTE *)PSOA, sizeof PSOA);
660                                 RegCloseKey(subKey);
661                             }
662
663                             if (RegCreateKeyExW(key, ProxyStubClsid32W, 0, NULL, 0,
664                                 KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) {
665                                 RegSetValueExW(subKey, NULL, 0, REG_SZ,
666                                                (const BYTE *)PSOA, sizeof PSOA);
667                                 RegCloseKey(subKey);
668                             }
669
670                             if (RegCreateKeyExW(key, TypeLibW, 0, NULL, 0,
671                                 KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
672                             {
673                                 WCHAR buffer[40];
674                                 static const WCHAR fmtver[] = {'%','x','.','%','x',0 };
675                                 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
676
677                                 StringFromGUID2(&attr->guid, buffer, 40);
678                                 RegSetValueExW(subKey, NULL, 0, REG_SZ,
679                                                (BYTE *)buffer, (strlenW(buffer)+1) * sizeof(WCHAR));
680                                 sprintfW(buffer, fmtver, attr->wMajorVerNum, attr->wMinorVerNum);
681                                 RegSetValueExW(subKey, VersionW, 0, REG_SZ,
682                                                (BYTE*)buffer, (strlenW(buffer)+1) * sizeof(WCHAR));
683                                 RegCloseKey(subKey);
684                             }
685
686                             RegCloseKey(key);
687                         }
688                     }
689
690                     ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
691                 }
692
693                 ITypeInfo_Release(tinfo);
694             }
695
696             SysFreeString(name);
697         }
698     }
699
700     ITypeLib_ReleaseTLibAttr(ptlib, attr);
701
702     return res;
703 }
704
705
706 /******************************************************************************
707  *      UnRegisterTypeLib       [OLEAUT32.186]
708  * Removes information about a type library from the System Registry
709  * NOTES
710  *
711  * RETURNS
712  *    Success: S_OK
713  *    Failure: Status
714  */
715 HRESULT WINAPI UnRegisterTypeLib(
716     REFGUID libid,      /* [in] Guid of the library */
717         WORD wVerMajor, /* [in] major version */
718         WORD wVerMinor, /* [in] minor version */
719         LCID lcid,      /* [in] locale id */
720         SYSKIND syskind)
721 {
722     BSTR tlibPath = NULL;
723     DWORD tmpLength;
724     WCHAR keyName[60];
725     WCHAR subKeyName[50];
726     int result = S_OK;
727     DWORD i = 0;
728     BOOL deleteOtherStuff;
729     HKEY key = NULL;
730     HKEY subKey = NULL;
731     TYPEATTR* typeAttr = NULL;
732     TYPEKIND kind;
733     ITypeInfo* typeInfo = NULL;
734     ITypeLib* typeLib = NULL;
735     int numTypes;
736
737     TRACE("(IID: %s)\n",debugstr_guid(libid));
738
739     /* Create the path to the key */
740     get_typelib_key( libid, wVerMajor, wVerMinor, keyName );
741
742     if (syskind != SYS_WIN16 && syskind != SYS_WIN32)
743     {
744         TRACE("Unsupported syskind %i\n", syskind);
745         result = E_INVALIDARG;
746         goto end;
747     }
748
749     /* get the path to the typelib on disk */
750     if (QueryPathOfRegTypeLib(libid, wVerMajor, wVerMinor, lcid, &tlibPath) != S_OK) {
751         result = E_INVALIDARG;
752         goto end;
753     }
754
755     /* Try and open the key to the type library. */
756     if (RegOpenKeyExW(HKEY_CLASSES_ROOT, keyName, 0, KEY_READ | KEY_WRITE, &key) != ERROR_SUCCESS) {
757         result = E_INVALIDARG;
758         goto end;
759     }
760
761     /* Try and load the type library */
762     if (LoadTypeLibEx(tlibPath, REGKIND_NONE, &typeLib)) {
763         result = TYPE_E_INVALIDSTATE;
764         goto end;
765     }
766
767     /* remove any types registered with this typelib */
768     numTypes = ITypeLib_GetTypeInfoCount(typeLib);
769     for (i=0; i<numTypes; i++) {
770         /* get the kind of type */
771         if (ITypeLib_GetTypeInfoType(typeLib, i, &kind) != S_OK) {
772             goto enddeleteloop;
773         }
774
775         /* skip non-interfaces, and get type info for the type */
776         if ((kind != TKIND_INTERFACE) && (kind != TKIND_DISPATCH)) {
777             goto enddeleteloop;
778         }
779         if (ITypeLib_GetTypeInfo(typeLib, i, &typeInfo) != S_OK) {
780             goto enddeleteloop;
781         }
782         if (ITypeInfo_GetTypeAttr(typeInfo, &typeAttr) != S_OK) {
783             goto enddeleteloop;
784         }
785
786         /* the path to the type */
787         get_interface_key( &typeAttr->guid, subKeyName );
788
789         /* Delete its bits */
790         if (RegOpenKeyExW(HKEY_CLASSES_ROOT, subKeyName, 0, KEY_WRITE, &subKey) != ERROR_SUCCESS) {
791             goto enddeleteloop;
792         }
793         RegDeleteKeyW(subKey, ProxyStubClsidW);
794         RegDeleteKeyW(subKey, ProxyStubClsid32W);
795         RegDeleteKeyW(subKey, TypeLibW);
796         RegCloseKey(subKey);
797         subKey = NULL;
798         RegDeleteKeyW(HKEY_CLASSES_ROOT, subKeyName);
799
800 enddeleteloop:
801         if (typeAttr) ITypeInfo_ReleaseTypeAttr(typeInfo, typeAttr);
802         typeAttr = NULL;
803         if (typeInfo) ITypeInfo_Release(typeInfo);
804         typeInfo = NULL;
805     }
806
807     /* Now, delete the type library path subkey */
808     get_lcid_subkey( lcid, syskind, subKeyName );
809     RegDeleteKeyW(key, subKeyName);
810     *strrchrW( subKeyName, '\\' ) = 0;  /* remove last path component */
811     RegDeleteKeyW(key, subKeyName);
812
813     /* check if there is anything besides the FLAGS/HELPDIR keys.
814        If there is, we don't delete them */
815     tmpLength = sizeof(subKeyName)/sizeof(WCHAR);
816     deleteOtherStuff = TRUE;
817     i = 0;
818     while(RegEnumKeyExW(key, i++, subKeyName, &tmpLength, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
819         tmpLength = sizeof(subKeyName)/sizeof(WCHAR);
820
821         /* if its not FLAGS or HELPDIR, then we must keep the rest of the key */
822         if (!strcmpW(subKeyName, FLAGSW)) continue;
823         if (!strcmpW(subKeyName, HELPDIRW)) continue;
824         deleteOtherStuff = FALSE;
825         break;
826     }
827
828     /* only delete the other parts of the key if we're absolutely sure */
829     if (deleteOtherStuff) {
830         RegDeleteKeyW(key, FLAGSW);
831         RegDeleteKeyW(key, HELPDIRW);
832         RegCloseKey(key);
833         key = NULL;
834
835         RegDeleteKeyW(HKEY_CLASSES_ROOT, keyName);
836         *strrchrW( keyName, '\\' ) = 0;  /* remove last path component */
837         RegDeleteKeyW(HKEY_CLASSES_ROOT, keyName);
838     }
839
840 end:
841     if (tlibPath) SysFreeString(tlibPath);
842     if (typeLib) ITypeLib_Release(typeLib);
843     if (subKey) RegCloseKey(subKey);
844     if (key) RegCloseKey(key);
845     return result;
846 }
847
848 /*======================= ITypeLib implementation =======================*/
849
850 typedef struct tagTLBCustData
851 {
852     GUID guid;
853     VARIANT data;
854     struct tagTLBCustData* next;
855 } TLBCustData;
856
857 /* data structure for import typelibs */
858 typedef struct tagTLBImpLib
859 {
860     int offset;                 /* offset in the file (MSFT)
861                                    offset in nametable (SLTG)
862                                    just used to identify library while reading
863                                    data from file */
864     GUID guid;                  /* libid */
865     BSTR name;                  /* name */
866
867     LCID lcid;                  /* lcid of imported typelib */
868
869     WORD wVersionMajor;         /* major version number */
870     WORD wVersionMinor;         /* minor version number */
871
872     struct tagITypeLibImpl *pImpTypeLib; /* pointer to loaded typelib, or
873                                             NULL if not yet loaded */
874     struct tagTLBImpLib * next;
875 } TLBImpLib;
876
877 /* internal ITypeLib data */
878 typedef struct tagITypeLibImpl
879 {
880     const ITypeLib2Vtbl *lpVtbl;
881     const ITypeCompVtbl *lpVtblTypeComp;
882     LONG ref;
883     TLIBATTR LibAttr;            /* guid,lcid,syskind,version,flags */
884
885     /* strings can be stored in tlb as multibyte strings BUT they are *always*
886      * exported to the application as a UNICODE string.
887      */
888     BSTR Name;
889     BSTR DocString;
890     BSTR HelpFile;
891     BSTR HelpStringDll;
892     unsigned long  dwHelpContext;
893     int TypeInfoCount;          /* nr of typeinfo's in librarry */
894     struct tagITypeInfoImpl *pTypeInfo;   /* linked list of type info data */
895     int ctCustData;             /* number of items in cust data list */
896     TLBCustData * pCustData;    /* linked list to cust data */
897     TLBImpLib   * pImpLibs;     /* linked list to all imported typelibs */
898     int ctTypeDesc;             /* number of items in type desc array */
899     TYPEDESC * pTypeDesc;       /* array of TypeDescriptions found in the
900                                    library. Only used while reading MSFT
901                                    typelibs */
902     struct list ref_list;       /* list of ref types in this typelib */
903     HREFTYPE dispatch_href;     /* reference to IDispatch, -1 if unused */
904
905
906     /* typelibs are cached, keyed by path and index, so store the linked list info within them */
907     struct tagITypeLibImpl *next, *prev;
908     WCHAR *path;
909     INT index;
910 } ITypeLibImpl;
911
912 static const ITypeLib2Vtbl tlbvt;
913 static const ITypeCompVtbl tlbtcvt;
914
915 static inline ITypeLibImpl *impl_from_ITypeComp( ITypeComp *iface )
916 {
917     return (ITypeLibImpl *)((char*)iface - FIELD_OFFSET(ITypeLibImpl, lpVtblTypeComp));
918 }
919
920 /* ITypeLib methods */
921 static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength);
922 static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength);
923
924 /*======================= ITypeInfo implementation =======================*/
925
926 /* data for referenced types */
927 typedef struct tagTLBRefType
928 {
929     INT index;              /* Type index for internal ref or for external ref
930                                it the format is SLTG.  -2 indicates to
931                                use guid */
932
933     GUID guid;              /* guid of the referenced type */
934                             /* if index == TLB_REF_USE_GUID */
935
936     HREFTYPE reference;     /* The href of this ref */
937     TLBImpLib *pImpTLInfo;  /* If ref is external ptr to library data
938                                TLB_REF_INTERNAL for internal refs
939                                TLB_REF_NOT_FOUND for broken refs */
940
941     struct list entry;
942 } TLBRefType;
943
944 #define TLB_REF_USE_GUID -2
945
946 #define TLB_REF_INTERNAL (void*)-2
947 #define TLB_REF_NOT_FOUND (void*)-1
948
949 /* internal Parameter data */
950 typedef struct tagTLBParDesc
951 {
952     BSTR Name;
953     int ctCustData;
954     TLBCustData * pCustData;        /* linked list to cust data */
955 } TLBParDesc;
956
957 /* internal Function data */
958 typedef struct tagTLBFuncDesc
959 {
960     FUNCDESC funcdesc;      /* lots of info on the function and its attributes. */
961     BSTR Name;             /* the name of this function */
962     TLBParDesc *pParamDesc; /* array with param names and custom data */
963     int helpcontext;
964     int HelpStringContext;
965     BSTR HelpString;
966     BSTR Entry;            /* if its Hiword==0, it numeric; -1 is not present*/
967     int ctCustData;
968     TLBCustData * pCustData;        /* linked list to cust data; */
969     struct tagTLBFuncDesc * next;
970 } TLBFuncDesc;
971
972 /* internal Variable data */
973 typedef struct tagTLBVarDesc
974 {
975     VARDESC vardesc;        /* lots of info on the variable and its attributes. */
976     BSTR Name;             /* the name of this variable */
977     int HelpContext;
978     int HelpStringContext;  /* FIXME: where? */
979     BSTR HelpString;
980     int ctCustData;
981     TLBCustData * pCustData;/* linked list to cust data; */
982     struct tagTLBVarDesc * next;
983 } TLBVarDesc;
984
985 /* internal implemented interface data */
986 typedef struct tagTLBImplType
987 {
988     HREFTYPE hRef;          /* hRef of interface */
989     int implflags;          /* IMPLFLAG_*s */
990     int ctCustData;
991     TLBCustData * pCustData;/* linked list to custom data; */
992     struct tagTLBImplType *next;
993 } TLBImplType;
994
995 /* internal TypeInfo data */
996 typedef struct tagITypeInfoImpl
997 {
998     const ITypeInfo2Vtbl *lpVtbl;
999     const ITypeCompVtbl  *lpVtblTypeComp;
1000     LONG ref;
1001     BOOL no_free_data; /* don't free data structures */
1002     TYPEATTR TypeAttr ;         /* _lots_ of type information. */
1003     ITypeLibImpl * pTypeLib;        /* back pointer to typelib */
1004     int index;                  /* index in this typelib; */
1005     HREFTYPE hreftype;          /* hreftype for app object binding */
1006     /* type libs seem to store the doc strings in ascii
1007      * so why should we do it in unicode?
1008      */
1009     BSTR Name;
1010     BSTR DocString;
1011     BSTR DllName;
1012     unsigned long  dwHelpContext;
1013     unsigned long  dwHelpStringContext;
1014
1015     /* functions  */
1016     TLBFuncDesc * funclist;     /* linked list with function descriptions */
1017
1018     /* variables  */
1019     TLBVarDesc * varlist;       /* linked list with variable descriptions */
1020
1021     /* Implemented Interfaces  */
1022     TLBImplType * impltypelist;
1023
1024     int ctCustData;
1025     TLBCustData * pCustData;        /* linked list to cust data; */
1026     struct tagITypeInfoImpl * next;
1027 } ITypeInfoImpl;
1028
1029 static inline ITypeInfoImpl *info_impl_from_ITypeComp( ITypeComp *iface )
1030 {
1031     return (ITypeInfoImpl *)((char*)iface - FIELD_OFFSET(ITypeInfoImpl, lpVtblTypeComp));
1032 }
1033
1034 static const ITypeInfo2Vtbl tinfvt;
1035 static const ITypeCompVtbl  tcompvt;
1036
1037 static ITypeInfo2 * WINAPI ITypeInfo_Constructor(void);
1038
1039 typedef struct tagTLBContext
1040 {
1041         unsigned int oStart;  /* start of TLB in file */
1042         unsigned int pos;     /* current pos */
1043         unsigned int length;  /* total length */
1044         void *mapping;        /* memory mapping */
1045         MSFT_SegDir * pTblDir;
1046         ITypeLibImpl* pLibInfo;
1047 } TLBContext;
1048
1049
1050 static void MSFT_DoRefType(TLBContext *pcx, ITypeLibImpl *pTL, int offset);
1051
1052 /*
1053  debug
1054 */
1055 static void dump_TypeDesc(const TYPEDESC *pTD,char *szVarType) {
1056     if (pTD->vt & VT_RESERVED)
1057         szVarType += strlen(strcpy(szVarType, "reserved | "));
1058     if (pTD->vt & VT_BYREF)
1059         szVarType += strlen(strcpy(szVarType, "ref to "));
1060     if (pTD->vt & VT_ARRAY)
1061         szVarType += strlen(strcpy(szVarType, "array of "));
1062     if (pTD->vt & VT_VECTOR)
1063         szVarType += strlen(strcpy(szVarType, "vector of "));
1064     switch(pTD->vt & VT_TYPEMASK) {
1065     case VT_UI1: sprintf(szVarType, "VT_UI1"); break;
1066     case VT_I2: sprintf(szVarType, "VT_I2"); break;
1067     case VT_I4: sprintf(szVarType, "VT_I4"); break;
1068     case VT_R4: sprintf(szVarType, "VT_R4"); break;
1069     case VT_R8: sprintf(szVarType, "VT_R8"); break;
1070     case VT_BOOL: sprintf(szVarType, "VT_BOOL"); break;
1071     case VT_ERROR: sprintf(szVarType, "VT_ERROR"); break;
1072     case VT_CY: sprintf(szVarType, "VT_CY"); break;
1073     case VT_DATE: sprintf(szVarType, "VT_DATE"); break;
1074     case VT_BSTR: sprintf(szVarType, "VT_BSTR"); break;
1075     case VT_UNKNOWN: sprintf(szVarType, "VT_UNKNOWN"); break;
1076     case VT_DISPATCH: sprintf(szVarType, "VT_DISPATCH"); break;
1077     case VT_I1: sprintf(szVarType, "VT_I1"); break;
1078     case VT_UI2: sprintf(szVarType, "VT_UI2"); break;
1079     case VT_UI4: sprintf(szVarType, "VT_UI4"); break;
1080     case VT_INT: sprintf(szVarType, "VT_INT"); break;
1081     case VT_UINT: sprintf(szVarType, "VT_UINT"); break;
1082     case VT_VARIANT: sprintf(szVarType, "VT_VARIANT"); break;
1083     case VT_VOID: sprintf(szVarType, "VT_VOID"); break;
1084     case VT_HRESULT: sprintf(szVarType, "VT_HRESULT"); break;
1085     case VT_USERDEFINED: sprintf(szVarType, "VT_USERDEFINED ref = %x",
1086                                  pTD->u.hreftype); break;
1087     case VT_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_UNION((*ppVarDesc)->vardesc.u.lpvarValue, intVal) = 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               V_UNION((*ppVarDesc)->vardesc.u.lpvarValue, intVal) =
3176                 *(INT*)(pBlk + pItem->byte_offs);
3177               break;
3178             default:
3179               FIXME_(typelib)("VAR_CONST unimplemented for type %d\n", (*ppVarDesc)->vardesc.elemdescVar.tdesc.vt);
3180           }
3181         }
3182       }
3183       else {
3184         TRACE_(typelib)("VAR_PERINSTANCE\n");
3185         (*ppVarDesc)->vardesc.u.oInst = pItem->byte_offs;
3186         (*ppVarDesc)->vardesc.varkind = VAR_PERINSTANCE;
3187       }
3188
3189       if (pItem->magic == SLTG_VAR_WITH_FLAGS_MAGIC)
3190         (*ppVarDesc)->vardesc.wVarFlags = pItem->varflags;
3191
3192       if (pItem->flags & 0x80)
3193         (*ppVarDesc)->vardesc.wVarFlags |= VARFLAG_FREADONLY;
3194
3195       bstrPrevName = (*ppVarDesc)->Name;
3196       ppVarDesc = &((*ppVarDesc)->next);
3197   }
3198   pTI->TypeAttr.cVars = cVars;
3199 }
3200
3201 static void SLTG_DoFuncs(char *pBlk, char *pFirstItem, ITypeInfoImpl *pTI,
3202                          unsigned short cFuncs, char *pNameTable, const sltg_ref_lookup_t *ref_lookup)
3203 {
3204     SLTG_Function *pFunc;
3205     unsigned short i;
3206     TLBFuncDesc **ppFuncDesc = &pTI->funclist;
3207
3208     for(pFunc = (SLTG_Function*)pFirstItem, i = 0; i < cFuncs;
3209         pFunc = (SLTG_Function*)(pBlk + pFunc->next), i++) {
3210
3211         int param;
3212         WORD *pType, *pArg;
3213
3214         *ppFuncDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3215                                 sizeof(**ppFuncDesc));
3216
3217         switch (pFunc->magic & ~SLTG_FUNCTION_FLAGS_PRESENT) {
3218         case SLTG_FUNCTION_MAGIC:
3219             (*ppFuncDesc)->funcdesc.funckind = FUNC_PUREVIRTUAL;
3220             break;
3221         case SLTG_DISPATCH_FUNCTION_MAGIC:
3222             (*ppFuncDesc)->funcdesc.funckind = FUNC_DISPATCH;
3223             break;
3224         case SLTG_STATIC_FUNCTION_MAGIC:
3225             (*ppFuncDesc)->funcdesc.funckind = FUNC_STATIC;
3226             break;
3227         default:
3228             FIXME("unimplemented func magic = %02x\n", pFunc->magic & ~SLTG_FUNCTION_FLAGS_PRESENT);
3229             HeapFree(GetProcessHeap(), 0, *ppFuncDesc);
3230             *ppFuncDesc = NULL;
3231             return;
3232         }
3233         (*ppFuncDesc)->Name = TLB_MultiByteToBSTR(pFunc->name + pNameTable);
3234
3235         (*ppFuncDesc)->funcdesc.memid = pFunc->dispid;
3236         (*ppFuncDesc)->funcdesc.invkind = pFunc->inv >> 4;
3237         (*ppFuncDesc)->funcdesc.callconv = pFunc->nacc & 0x7;
3238         (*ppFuncDesc)->funcdesc.cParams = pFunc->nacc >> 3;
3239         (*ppFuncDesc)->funcdesc.cParamsOpt = (pFunc->retnextopt & 0x7e) >> 1;
3240         (*ppFuncDesc)->funcdesc.oVft = pFunc->vtblpos;
3241
3242         if(pFunc->magic & SLTG_FUNCTION_FLAGS_PRESENT)
3243             (*ppFuncDesc)->funcdesc.wFuncFlags = pFunc->funcflags;
3244
3245         if(pFunc->retnextopt & 0x80)
3246             pType = &pFunc->rettype;
3247         else
3248             pType = (WORD*)(pBlk + pFunc->rettype);
3249
3250         SLTG_DoElem(pType, pBlk, &(*ppFuncDesc)->funcdesc.elemdescFunc, ref_lookup);
3251
3252         (*ppFuncDesc)->funcdesc.lprgelemdescParam =
3253           HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3254                     (*ppFuncDesc)->funcdesc.cParams * sizeof(ELEMDESC));
3255         (*ppFuncDesc)->pParamDesc =
3256           HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3257                     (*ppFuncDesc)->funcdesc.cParams * sizeof(TLBParDesc));
3258
3259         pArg = (WORD*)(pBlk + pFunc->arg_off);
3260
3261         for(param = 0; param < (*ppFuncDesc)->funcdesc.cParams; param++) {
3262             char *paramName = pNameTable + *pArg;
3263             BOOL HaveOffs;
3264             /* If arg type follows then paramName points to the 2nd
3265                letter of the name, else the next WORD is an offset to
3266                the arg type and paramName points to the first letter.
3267                So let's take one char off paramName and see if we're
3268                pointing at an alpha-numeric char.  However if *pArg is
3269                0xffff or 0xfffe then the param has no name, the former
3270                meaning that the next WORD is the type, the latter
3271                meaning that the next WORD is an offset to the type. */
3272
3273             HaveOffs = FALSE;
3274             if(*pArg == 0xffff)
3275                 paramName = NULL;
3276             else if(*pArg == 0xfffe) {
3277                 paramName = NULL;
3278                 HaveOffs = TRUE;
3279             }
3280             else if(paramName[-1] && !isalnum(paramName[-1]))
3281                 HaveOffs = TRUE;
3282
3283             pArg++;
3284
3285             if(HaveOffs) { /* the next word is an offset to type */
3286                 pType = (WORD*)(pBlk + *pArg);
3287                 SLTG_DoElem(pType, pBlk,
3288                             &(*ppFuncDesc)->funcdesc.lprgelemdescParam[param], ref_lookup);
3289                 pArg++;
3290             } else {
3291                 if(paramName)
3292                   paramName--;
3293                 pArg = SLTG_DoElem(pArg, pBlk,
3294                                    &(*ppFuncDesc)->funcdesc.lprgelemdescParam[param], ref_lookup);
3295             }
3296
3297             /* Are we an optional param ? */
3298             if((*ppFuncDesc)->funcdesc.cParams - param <=
3299                (*ppFuncDesc)->funcdesc.cParamsOpt)
3300               (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].u.paramdesc.wParamFlags |= PARAMFLAG_FOPT;
3301
3302             if(paramName) {
3303                 (*ppFuncDesc)->pParamDesc[param].Name =
3304                   TLB_MultiByteToBSTR(paramName);
3305             } else {
3306                 (*ppFuncDesc)->pParamDesc[param].Name =
3307                   SysAllocString((*ppFuncDesc)->Name);
3308             }
3309         }
3310
3311         ppFuncDesc = &((*ppFuncDesc)->next);
3312         if(pFunc->next == 0xffff) break;
3313     }
3314     pTI->TypeAttr.cFuncs = cFuncs;
3315 }
3316
3317 static void SLTG_ProcessCoClass(char *pBlk, ITypeInfoImpl *pTI,
3318                                 char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3319                                 SLTG_TypeInfoTail *pTITail)
3320 {
3321     char *pFirstItem;
3322     sltg_ref_lookup_t *ref_lookup = NULL;
3323
3324     if(pTIHeader->href_table != 0xffffffff) {
3325         ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3326                     pNameTable);
3327     }
3328
3329     pFirstItem = pBlk;
3330
3331     if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
3332         SLTG_DoImpls(pFirstItem, pTI, FALSE, ref_lookup);
3333     }
3334     HeapFree(GetProcessHeap(), 0, ref_lookup);
3335 }
3336
3337
3338 static void SLTG_ProcessInterface(char *pBlk, ITypeInfoImpl *pTI,
3339                                   char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3340                                   const SLTG_TypeInfoTail *pTITail)
3341 {
3342     char *pFirstItem;
3343     sltg_ref_lookup_t *ref_lookup = NULL;
3344
3345     if(pTIHeader->href_table != 0xffffffff) {
3346         ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3347                     pNameTable);
3348     }
3349
3350     pFirstItem = pBlk;
3351
3352     if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
3353         SLTG_DoImpls(pFirstItem, pTI, TRUE, ref_lookup);
3354     }
3355
3356     if (pTITail->funcs_off != 0xffff)
3357         SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup);
3358
3359     HeapFree(GetProcessHeap(), 0, ref_lookup);
3360
3361     if (TRACE_ON(typelib))
3362         dump_TLBFuncDesc(pTI->funclist);
3363 }
3364
3365 static void SLTG_ProcessRecord(char *pBlk, ITypeInfoImpl *pTI,
3366                                const char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3367                                const SLTG_TypeInfoTail *pTITail)
3368 {
3369   SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, NULL);
3370 }
3371
3372 static void SLTG_ProcessAlias(char *pBlk, ITypeInfoImpl *pTI,
3373                               char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3374                               const SLTG_TypeInfoTail *pTITail)
3375 {
3376   WORD *pType;
3377   sltg_ref_lookup_t *ref_lookup = NULL;
3378
3379   if (pTITail->simple_alias) {
3380     /* if simple alias, no more processing required */
3381     pTI->TypeAttr.tdescAlias.vt = pTITail->tdescalias_vt;
3382     return;
3383   }
3384
3385   if(pTIHeader->href_table != 0xffffffff) {
3386       ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3387                   pNameTable);
3388   }
3389
3390   /* otherwise it is an offset to a type */
3391   pType = (WORD *)(pBlk + pTITail->tdescalias_vt);
3392
3393   SLTG_DoType(pType, pBlk, &pTI->TypeAttr.tdescAlias, ref_lookup);
3394
3395   HeapFree(GetProcessHeap(), 0, ref_lookup);
3396 }
3397
3398 static void SLTG_ProcessDispatch(char *pBlk, ITypeInfoImpl *pTI,
3399                                  char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3400                                  const SLTG_TypeInfoTail *pTITail)
3401 {
3402   sltg_ref_lookup_t *ref_lookup = NULL;
3403   if (pTIHeader->href_table != 0xffffffff)
3404       ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3405                                   pNameTable);
3406
3407   if (pTITail->vars_off != 0xffff)
3408     SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, ref_lookup);
3409
3410   if (pTITail->funcs_off != 0xffff)
3411     SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup);
3412
3413   /* this is necessary to cope with MSFT typelibs that set cFuncs to the number
3414    * of dispinterface functions including the IDispatch ones, so
3415    * ITypeInfo::GetFuncDesc takes the real value for cFuncs from cbSizeVft */
3416   pTI->TypeAttr.cbSizeVft = pTI->TypeAttr.cFuncs * sizeof(void *);
3417
3418   HeapFree(GetProcessHeap(), 0, ref_lookup);
3419   if (TRACE_ON(typelib))
3420       dump_TLBFuncDesc(pTI->funclist);
3421 }
3422
3423 static void SLTG_ProcessEnum(char *pBlk, ITypeInfoImpl *pTI,
3424                              const char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3425                              const SLTG_TypeInfoTail *pTITail)
3426 {
3427   SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, NULL);
3428 }
3429
3430 static void SLTG_ProcessModule(char *pBlk, ITypeInfoImpl *pTI,
3431                                char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3432                                const SLTG_TypeInfoTail *pTITail)
3433 {
3434   sltg_ref_lookup_t *ref_lookup = NULL;
3435   if (pTIHeader->href_table != 0xffffffff)
3436       ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3437                                   pNameTable);
3438
3439   if (pTITail->vars_off != 0xffff)
3440     SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, ref_lookup);
3441
3442   if (pTITail->funcs_off != 0xffff)
3443     SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup);
3444   HeapFree(GetProcessHeap(), 0, ref_lookup);
3445   if (TRACE_ON(typelib))
3446     dump_TypeInfo(pTI);
3447 }
3448
3449 /* Because SLTG_OtherTypeInfo is such a painful struct, we make a more
3450    managable copy of it into this */
3451 typedef struct {
3452   WORD small_no;
3453   char *index_name;
3454   char *other_name;
3455   WORD res1a;
3456   WORD name_offs;
3457   WORD more_bytes;
3458   char *extra;
3459   WORD res20;
3460   DWORD helpcontext;
3461   WORD res26;
3462   GUID uuid;
3463 } SLTG_InternalOtherTypeInfo;
3464
3465 /****************************************************************************
3466  *      ITypeLib2_Constructor_SLTG
3467  *
3468  * loading a SLTG typelib from an in-memory image
3469  */
3470 static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength)
3471 {
3472     ITypeLibImpl *pTypeLibImpl;
3473     SLTG_Header *pHeader;
3474     SLTG_BlkEntry *pBlkEntry;
3475     SLTG_Magic *pMagic;
3476     SLTG_Index *pIndex;
3477     SLTG_Pad9 *pPad9;
3478     LPVOID pBlk, pFirstBlk;
3479     SLTG_LibBlk *pLibBlk;
3480     SLTG_InternalOtherTypeInfo *pOtherTypeInfoBlks;
3481     char *pAfterOTIBlks = NULL;
3482     char *pNameTable, *ptr;
3483     int i;
3484     DWORD len, order;
3485     ITypeInfoImpl **ppTypeInfoImpl;
3486
3487     TRACE_(typelib)("%p, TLB length = %d\n", pLib, dwTLBLength);
3488
3489
3490     pTypeLibImpl = TypeLibImpl_Constructor();
3491     if (!pTypeLibImpl) return NULL;
3492
3493     pHeader = pLib;
3494
3495     TRACE_(typelib)("header:\n");
3496     TRACE_(typelib)("\tmagic=0x%08x, file blocks = %d\n", pHeader->SLTG_magic,
3497           pHeader->nrOfFileBlks );
3498     if (pHeader->SLTG_magic != SLTG_SIGNATURE) {
3499         FIXME_(typelib)("Header type magic 0x%08x not supported.\n",
3500               pHeader->SLTG_magic);
3501         return NULL;
3502     }
3503
3504     /* There are pHeader->nrOfFileBlks - 2 TypeInfo records in this typelib */
3505     pTypeLibImpl->TypeInfoCount = pHeader->nrOfFileBlks - 2;
3506
3507     /* This points to pHeader->nrOfFileBlks - 1 of SLTG_BlkEntry */
3508     pBlkEntry = (SLTG_BlkEntry*)(pHeader + 1);
3509
3510     /* Next we have a magic block */
3511     pMagic = (SLTG_Magic*)(pBlkEntry + pHeader->nrOfFileBlks - 1);
3512
3513     /* Let's see if we're still in sync */
3514     if(memcmp(pMagic->CompObj_magic, SLTG_COMPOBJ_MAGIC,
3515               sizeof(SLTG_COMPOBJ_MAGIC))) {
3516         FIXME_(typelib)("CompObj magic = %s\n", pMagic->CompObj_magic);
3517         return NULL;
3518     }
3519     if(memcmp(pMagic->dir_magic, SLTG_DIR_MAGIC,
3520               sizeof(SLTG_DIR_MAGIC))) {
3521         FIXME_(typelib)("dir magic = %s\n", pMagic->dir_magic);
3522         return NULL;
3523     }
3524
3525     pIndex = (SLTG_Index*)(pMagic+1);
3526
3527     pPad9 = (SLTG_Pad9*)(pIndex + pTypeLibImpl->TypeInfoCount);
3528
3529     pFirstBlk = (LPVOID)(pPad9 + 1);
3530
3531     /* We'll set up a ptr to the main library block, which is the last one. */
3532
3533     for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0;
3534           pBlkEntry[order].next != 0;
3535           order = pBlkEntry[order].next - 1, i++) {
3536        pBlk = (char*)pBlk + pBlkEntry[order].len;
3537     }
3538     pLibBlk = pBlk;
3539
3540     len = SLTG_ReadLibBlk(pLibBlk, pTypeLibImpl);
3541
3542     /* Now there's 0x40 bytes of 0xffff with the numbers 0 to TypeInfoCount
3543        interspersed */
3544
3545     len += 0x40;
3546
3547     /* And now TypeInfoCount of SLTG_OtherTypeInfo */
3548
3549     pOtherTypeInfoBlks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3550                                    sizeof(*pOtherTypeInfoBlks) *
3551                                    pTypeLibImpl->TypeInfoCount);
3552
3553
3554     ptr = (char*)pLibBlk + len;
3555
3556     for(i = 0; i < pTypeLibImpl->TypeInfoCount; i++) {
3557         WORD w, extra;
3558         len = 0;
3559
3560         pOtherTypeInfoBlks[i].small_no = *(WORD*)ptr;
3561
3562         w = *(WORD*)(ptr + 2);
3563         if(w != 0xffff) {
3564             len += w;
3565             pOtherTypeInfoBlks[i].index_name = HeapAlloc(GetProcessHeap(),0,
3566                                                          w+1);
3567             memcpy(pOtherTypeInfoBlks[i].index_name, ptr + 4, w);
3568             pOtherTypeInfoBlks[i].index_name[w] = '\0';
3569         }
3570         w = *(WORD*)(ptr + 4 + len);
3571         if(w != 0xffff) {
3572             TRACE_(typelib)("\twith %s\n", debugstr_an(ptr + 6 + len, w));
3573             len += w;
3574             pOtherTypeInfoBlks[i].other_name = HeapAlloc(GetProcessHeap(),0,
3575                                                          w+1);
3576             memcpy(pOtherTypeInfoBlks[i].other_name, ptr + 6 + len, w);
3577             pOtherTypeInfoBlks[i].other_name[w] = '\0';
3578         }
3579         pOtherTypeInfoBlks[i].res1a = *(WORD*)(ptr + len + 6);
3580         pOtherTypeInfoBlks[i].name_offs = *(WORD*)(ptr + len + 8);
3581         extra = pOtherTypeInfoBlks[i].more_bytes = *(WORD*)(ptr + 10 + len);
3582         if(extra) {
3583             pOtherTypeInfoBlks[i].extra = HeapAlloc(GetProcessHeap(),0,
3584                                                     extra);
3585             memcpy(pOtherTypeInfoBlks[i].extra, ptr + 12, extra);
3586             len += extra;
3587         }
3588         pOtherTypeInfoBlks[i].res20 = *(WORD*)(ptr + 12 + len);
3589         pOtherTypeInfoBlks[i].helpcontext = *(DWORD*)(ptr + 14 + len);
3590         pOtherTypeInfoBlks[i].res26 = *(WORD*)(ptr + 18 + len);
3591         memcpy(&pOtherTypeInfoBlks[i].uuid, ptr + 20 + len, sizeof(GUID));
3592         len += sizeof(SLTG_OtherTypeInfo);
3593         ptr += len;
3594     }
3595
3596     pAfterOTIBlks = ptr;
3597
3598     /* Skip this WORD and get the next DWORD */
3599     len = *(DWORD*)(pAfterOTIBlks + 2);
3600
3601     /* Now add this to pLibBLk look at what we're pointing at and
3602        possibly add 0x20, then add 0x216, sprinkle a bit a magic
3603        dust and we should be pointing at the beginning of the name
3604        table */
3605
3606     pNameTable = (char*)pLibBlk + len;
3607
3608    switch(*(WORD*)pNameTable) {
3609    case 0xffff:
3610        break;
3611    case 0x0200:
3612        pNameTable += 0x20;
3613        break;
3614    default:
3615        FIXME_(typelib)("pNameTable jump = %x\n", *(WORD*)pNameTable);
3616        break;
3617    }
3618
3619     pNameTable += 0x216;
3620
3621     pNameTable += 2;
3622
3623     TRACE_(typelib)("Library name is %s\n", pNameTable + pLibBlk->name);
3624
3625     pTypeLibImpl->Name = TLB_MultiByteToBSTR(pNameTable + pLibBlk->name);
3626
3627
3628     /* Hopefully we now have enough ptrs set up to actually read in
3629        some TypeInfos.  It's not clear which order to do them in, so
3630        I'll just follow the links along the BlkEntry chain and read
3631        them in the order in which they are in the file */
3632
3633     ppTypeInfoImpl = &(pTypeLibImpl->pTypeInfo);
3634
3635     for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0;
3636         pBlkEntry[order].next != 0;
3637         order = pBlkEntry[order].next - 1, i++) {
3638
3639       SLTG_TypeInfoHeader *pTIHeader;
3640       SLTG_TypeInfoTail *pTITail;
3641       SLTG_MemberHeader *pMemHeader;
3642
3643       if(strcmp(pBlkEntry[order].index_string + (char*)pMagic,
3644                 pOtherTypeInfoBlks[i].index_name)) {
3645         FIXME_(typelib)("Index strings don't match\n");
3646         return NULL;
3647       }
3648
3649       pTIHeader = pBlk;
3650       if(pTIHeader->magic != SLTG_TIHEADER_MAGIC) {
3651         FIXME_(typelib)("TypeInfoHeader magic = %04x\n", pTIHeader->magic);
3652         return NULL;
3653       }
3654       TRACE_(typelib)("pTIHeader->res06 = %x, pTIHeader->res0e = %x, "
3655         "pTIHeader->res16 = %x, pTIHeader->res1e = %x\n",
3656         pTIHeader->res06, pTIHeader->res0e, pTIHeader->res16, pTIHeader->res1e);
3657
3658       *ppTypeInfoImpl = (ITypeInfoImpl*)ITypeInfo_Constructor();
3659       (*ppTypeInfoImpl)->pTypeLib = pTypeLibImpl;
3660       (*ppTypeInfoImpl)->index = i;
3661       (*ppTypeInfoImpl)->Name = TLB_MultiByteToBSTR(
3662                                              pOtherTypeInfoBlks[i].name_offs +
3663                                              pNameTable);
3664       (*ppTypeInfoImpl)->dwHelpContext = pOtherTypeInfoBlks[i].helpcontext;
3665       (*ppTypeInfoImpl)->TypeAttr.guid = pOtherTypeInfoBlks[i].uuid;
3666       (*ppTypeInfoImpl)->TypeAttr.typekind = pTIHeader->typekind;
3667       (*ppTypeInfoImpl)->TypeAttr.wMajorVerNum = pTIHeader->major_version;
3668       (*ppTypeInfoImpl)->TypeAttr.wMinorVerNum = pTIHeader->minor_version;
3669       (*ppTypeInfoImpl)->TypeAttr.wTypeFlags =
3670         (pTIHeader->typeflags1 >> 3) | (pTIHeader->typeflags2 << 5);
3671
3672       if((pTIHeader->typeflags1 & 7) != 2)
3673         FIXME_(typelib)("typeflags1 = %02x\n", pTIHeader->typeflags1);
3674       if(pTIHeader->typeflags3 != 2)
3675         FIXME_(typelib)("typeflags3 = %02x\n", pTIHeader->typeflags3);
3676
3677       TRACE_(typelib)("TypeInfo %s of kind %s guid %s typeflags %04x\n",
3678             debugstr_w((*ppTypeInfoImpl)->Name),
3679             typekind_desc[pTIHeader->typekind],
3680             debugstr_guid(&(*ppTypeInfoImpl)->TypeAttr.guid),
3681             (*ppTypeInfoImpl)->TypeAttr.wTypeFlags);
3682
3683       pMemHeader = (SLTG_MemberHeader*)((char *)pBlk + pTIHeader->elem_table);
3684
3685       pTITail = (SLTG_TypeInfoTail*)((char *)(pMemHeader + 1) + pMemHeader->cbExtra);
3686
3687       (*ppTypeInfoImpl)->TypeAttr.cbAlignment = pTITail->cbAlignment;
3688       (*ppTypeInfoImpl)->TypeAttr.cbSizeInstance = pTITail->cbSizeInstance;
3689       (*ppTypeInfoImpl)->TypeAttr.cbSizeVft = pTITail->cbSizeVft;
3690
3691       switch(pTIHeader->typekind) {
3692       case TKIND_ENUM:
3693         SLTG_ProcessEnum((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
3694                          pTIHeader, pTITail);
3695         break;
3696
3697       case TKIND_RECORD:
3698         SLTG_ProcessRecord((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
3699                            pTIHeader, pTITail);
3700         break;
3701
3702       case TKIND_INTERFACE:
3703         SLTG_ProcessInterface((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
3704                               pTIHeader, pTITail);
3705         break;
3706
3707       case TKIND_COCLASS:
3708         SLTG_ProcessCoClass((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
3709                             pTIHeader, pTITail);
3710         break;
3711
3712       case TKIND_ALIAS:
3713         SLTG_ProcessAlias((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
3714                           pTIHeader, pTITail);
3715         break;
3716
3717       case TKIND_DISPATCH:
3718         SLTG_ProcessDispatch((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
3719                              pTIHeader, pTITail);
3720         break;
3721
3722       case TKIND_MODULE:
3723         SLTG_ProcessModule((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
3724                            pTIHeader, pTITail);
3725         break;
3726
3727       default:
3728         FIXME("Not processing typekind %d\n", pTIHeader->typekind);
3729         break;
3730
3731       }
3732
3733       if(pTITail) { /* could get cFuncs, cVars and cImplTypes from here
3734                        but we've already set those */
3735 #define X(x) TRACE_(typelib)("tt "#x": %x\n",pTITail->res##x);
3736           X(06);
3737           X(16);
3738           X(18);
3739           X(1a);
3740           X(1e);
3741           X(24);
3742           X(26);
3743           X(2a);
3744           X(2c);
3745           X(2e);
3746           X(30);
3747           X(32);
3748           X(34);
3749       }
3750       ppTypeInfoImpl = &((*ppTypeInfoImpl)->next);
3751       pBlk = (char*)pBlk + pBlkEntry[order].len;
3752     }
3753
3754     if(i != pTypeLibImpl->TypeInfoCount) {
3755       FIXME("Somehow processed %d TypeInfos\n", i);
3756       return NULL;
3757     }
3758
3759     HeapFree(GetProcessHeap(), 0, pOtherTypeInfoBlks);
3760     return (ITypeLib2*)pTypeLibImpl;
3761 }
3762
3763 /* ITypeLib::QueryInterface
3764  */
3765 static HRESULT WINAPI ITypeLib2_fnQueryInterface(
3766         ITypeLib2 * iface,
3767         REFIID riid,
3768         VOID **ppvObject)
3769 {
3770     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3771
3772     TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
3773
3774     *ppvObject=NULL;
3775     if(IsEqualIID(riid, &IID_IUnknown) ||
3776        IsEqualIID(riid,&IID_ITypeLib)||
3777        IsEqualIID(riid,&IID_ITypeLib2))
3778     {
3779         *ppvObject = This;
3780     }
3781
3782     if(*ppvObject)
3783     {
3784         ITypeLib2_AddRef(iface);
3785         TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
3786         return S_OK;
3787     }
3788     TRACE("-- Interface: E_NOINTERFACE\n");
3789     return E_NOINTERFACE;
3790 }
3791
3792 /* ITypeLib::AddRef
3793  */
3794 static ULONG WINAPI ITypeLib2_fnAddRef( ITypeLib2 *iface)
3795 {
3796     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3797     ULONG ref = InterlockedIncrement(&This->ref);
3798
3799     TRACE("(%p)->ref was %u\n",This, ref - 1);
3800
3801     return ref;
3802 }
3803
3804 /* ITypeLib::Release
3805  */
3806 static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface)
3807 {
3808     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3809     ULONG ref = InterlockedDecrement(&This->ref);
3810
3811     TRACE("(%p)->(%u)\n",This, ref);
3812
3813     if (!ref)
3814     {
3815       TLBImpLib *pImpLib, *pImpLibNext;
3816       TLBCustData *pCustData, *pCustDataNext;
3817       TLBRefType *ref_type;
3818       void *cursor2;
3819       int i;
3820
3821       /* remove cache entry */
3822       if(This->path)
3823       {
3824           TRACE("removing from cache list\n");
3825           EnterCriticalSection(&cache_section);
3826           if (This->next) This->next->prev = This->prev;
3827           if (This->prev) This->prev->next = This->next;
3828           else tlb_cache_first = This->next;
3829           LeaveCriticalSection(&cache_section);
3830           HeapFree(GetProcessHeap(), 0, This->path);
3831       }
3832       TRACE(" destroying ITypeLib(%p)\n",This);
3833
3834       if (This->Name)
3835       {
3836           SysFreeString(This->Name);
3837           This->Name = NULL;
3838       }
3839
3840       if (This->DocString)
3841       {
3842           SysFreeString(This->DocString);
3843           This->DocString = NULL;
3844       }
3845
3846       if (This->HelpFile)
3847       {
3848           SysFreeString(This->HelpFile);
3849           This->HelpFile = NULL;
3850       }
3851
3852       if (This->HelpStringDll)
3853       {
3854           SysFreeString(This->HelpStringDll);
3855           This->HelpStringDll = NULL;
3856       }
3857
3858       for (pCustData = This->pCustData; pCustData; pCustData = pCustDataNext)
3859       {
3860           VariantClear(&pCustData->data);
3861
3862           pCustDataNext = pCustData->next;
3863           TLB_Free(pCustData);
3864       }
3865
3866       for (i = 0; i < This->ctTypeDesc; i++)
3867           if (This->pTypeDesc[i].vt == VT_CARRAY)
3868               TLB_Free(This->pTypeDesc[i].u.lpadesc);
3869
3870       TLB_Free(This->pTypeDesc);
3871
3872       for (pImpLib = This->pImpLibs; pImpLib; pImpLib = pImpLibNext)
3873       {
3874           if (pImpLib->pImpTypeLib)
3875               ITypeLib_Release((ITypeLib *)pImpLib->pImpTypeLib);
3876           SysFreeString(pImpLib->name);
3877
3878           pImpLibNext = pImpLib->next;
3879           TLB_Free(pImpLib);
3880       }
3881
3882       LIST_FOR_EACH_ENTRY_SAFE(ref_type, cursor2, &This->ref_list, TLBRefType, entry)
3883       {
3884           list_remove(&ref_type->entry);
3885           TLB_Free(ref_type);
3886       }
3887
3888       if (This->pTypeInfo) /* can be NULL */
3889           ITypeInfo_Release((ITypeInfo*) This->pTypeInfo);
3890       HeapFree(GetProcessHeap(),0,This);
3891       return 0;
3892     }
3893
3894     return ref;
3895 }
3896
3897 /* ITypeLib::GetTypeInfoCount
3898  *
3899  * Returns the number of type descriptions in the type library
3900  */
3901 static UINT WINAPI ITypeLib2_fnGetTypeInfoCount( ITypeLib2 *iface)
3902 {
3903     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3904     TRACE("(%p)->count is %d\n",This, This->TypeInfoCount);
3905     return This->TypeInfoCount;
3906 }
3907
3908 /* ITypeLib::GetTypeInfo
3909  *
3910  * retrieves the specified type description in the library.
3911  */
3912 static HRESULT WINAPI ITypeLib2_fnGetTypeInfo(
3913     ITypeLib2 *iface,
3914     UINT index,
3915     ITypeInfo **ppTInfo)
3916 {
3917     int i;
3918
3919     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3920     ITypeInfoImpl *pTypeInfo = This->pTypeInfo;
3921
3922     TRACE("(%p)->(index=%d)\n", This, index);
3923
3924     if (!ppTInfo) return E_INVALIDARG;
3925
3926     /* search element n in list */
3927     for(i=0; i < index; i++)
3928     {
3929       pTypeInfo = pTypeInfo->next;
3930       if (!pTypeInfo)
3931       {
3932         TRACE("-- element not found\n");
3933         return TYPE_E_ELEMENTNOTFOUND;
3934       }
3935     }
3936
3937     *ppTInfo = (ITypeInfo *) pTypeInfo;
3938
3939     ITypeInfo_AddRef(*ppTInfo);
3940     TRACE("-- found (%p)\n",*ppTInfo);
3941     return S_OK;
3942 }
3943
3944
3945 /* ITypeLibs::GetTypeInfoType
3946  *
3947  * Retrieves the type of a type description.
3948  */
3949 static HRESULT WINAPI ITypeLib2_fnGetTypeInfoType(
3950     ITypeLib2 *iface,
3951     UINT index,
3952     TYPEKIND *pTKind)
3953 {
3954     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3955     int i;
3956     ITypeInfoImpl *pTInfo = This->pTypeInfo;
3957     
3958     if (ITypeLib2_fnGetTypeInfoCount(iface) < index + 1)
3959          return TYPE_E_ELEMENTNOTFOUND;
3960
3961     TRACE("(%p) index %d\n", This, index);
3962
3963     if(!pTKind) return E_INVALIDARG;
3964
3965     /* search element n in list */
3966     for(i=0; i < index; i++)
3967     {
3968       if(!pTInfo)
3969       {
3970         TRACE("-- element not found\n");
3971         return TYPE_E_ELEMENTNOTFOUND;
3972       }
3973       pTInfo = pTInfo->next;
3974     }
3975
3976     *pTKind = pTInfo->TypeAttr.typekind;
3977     TRACE("-- found Type (%d)\n", *pTKind);
3978     return S_OK;
3979 }
3980
3981 /* ITypeLib::GetTypeInfoOfGuid
3982  *
3983  * Retrieves the type description that corresponds to the specified GUID.
3984  *
3985  */
3986 static HRESULT WINAPI ITypeLib2_fnGetTypeInfoOfGuid(
3987     ITypeLib2 *iface,
3988     REFGUID guid,
3989     ITypeInfo **ppTInfo)
3990 {
3991     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3992     ITypeInfoImpl *pTypeInfo = This->pTypeInfo; /* head of list */
3993
3994     TRACE("(%p)\n\tguid:\t%s)\n",This,debugstr_guid(guid));
3995
3996     if (!pTypeInfo)
3997     {
3998         WARN("-- element not found\n");
3999         return TYPE_E_ELEMENTNOTFOUND;
4000     }
4001
4002     /* search linked list for guid */
4003     while( !IsEqualIID(guid,&pTypeInfo->TypeAttr.guid) )
4004     {
4005       pTypeInfo = pTypeInfo->next;
4006
4007       if (!pTypeInfo)
4008       {
4009         /* end of list reached */
4010         WARN("-- element not found\n");
4011         return TYPE_E_ELEMENTNOTFOUND;
4012       }
4013     }
4014
4015     TRACE("-- found (%p, %s)\n",
4016           pTypeInfo,
4017           debugstr_w(pTypeInfo->Name));
4018
4019     *ppTInfo = (ITypeInfo*)pTypeInfo;
4020     ITypeInfo_AddRef(*ppTInfo);
4021     return S_OK;
4022 }
4023
4024 /* ITypeLib::GetLibAttr
4025  *
4026  * Retrieves the structure that contains the library's attributes.
4027  *
4028  */
4029 static HRESULT WINAPI ITypeLib2_fnGetLibAttr(
4030         ITypeLib2 *iface,
4031         LPTLIBATTR *ppTLibAttr)
4032 {
4033     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4034     TRACE("(%p)\n",This);
4035     *ppTLibAttr = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppTLibAttr));
4036     **ppTLibAttr = This->LibAttr;
4037     return S_OK;
4038 }
4039
4040 /* ITypeLib::GetTypeComp
4041  *
4042  * Enables a client compiler to bind to a library's types, variables,
4043  * constants, and global functions.
4044  *
4045  */
4046 static HRESULT WINAPI ITypeLib2_fnGetTypeComp(
4047         ITypeLib2 *iface,
4048         ITypeComp **ppTComp)
4049 {
4050     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4051
4052     TRACE("(%p)->(%p)\n",This,ppTComp);
4053     *ppTComp = (ITypeComp *)&This->lpVtblTypeComp;
4054     ITypeComp_AddRef(*ppTComp);
4055
4056     return S_OK;
4057 }
4058
4059 /* ITypeLib::GetDocumentation
4060  *
4061  * Retrieves the library's documentation string, the complete Help file name
4062  * and path, and the context identifier for the library Help topic in the Help
4063  * file.
4064  *
4065  * On a successful return all non-null BSTR pointers will have been set,
4066  * possibly to NULL.
4067  */
4068 static HRESULT WINAPI ITypeLib2_fnGetDocumentation(
4069     ITypeLib2 *iface,
4070     INT index,
4071     BSTR *pBstrName,
4072     BSTR *pBstrDocString,
4073     DWORD *pdwHelpContext,
4074     BSTR *pBstrHelpFile)
4075 {
4076     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4077
4078     HRESULT result = E_INVALIDARG;
4079
4080     ITypeInfo *pTInfo;
4081
4082
4083     TRACE("(%p) index %d Name(%p) DocString(%p) HelpContext(%p) HelpFile(%p)\n",
4084         This, index,
4085         pBstrName, pBstrDocString,
4086         pdwHelpContext, pBstrHelpFile);
4087
4088     if(index<0)
4089     {
4090         /* documentation for the typelib */
4091         if(pBstrName)
4092         {
4093             if (This->Name)
4094             {
4095                 if(!(*pBstrName = SysAllocString(This->Name)))
4096                     goto memerr1;
4097             }
4098             else
4099                 *pBstrName = NULL;
4100         }
4101         if(pBstrDocString)
4102         {
4103             if (This->DocString)
4104             {
4105                 if(!(*pBstrDocString = SysAllocString(This->DocString)))
4106                     goto memerr2;
4107             }
4108             else if (This->Name)
4109             {
4110                 if(!(*pBstrDocString = SysAllocString(This->Name)))
4111                     goto memerr2;
4112             }
4113             else
4114                 *pBstrDocString = NULL;
4115         }
4116         if(pdwHelpContext)
4117         {
4118             *pdwHelpContext = This->dwHelpContext;
4119         }
4120         if(pBstrHelpFile)
4121         {
4122             if (This->HelpFile)
4123             {
4124                 if(!(*pBstrHelpFile = SysAllocString(This->HelpFile)))
4125                     goto memerr3;
4126             }
4127             else
4128                 *pBstrHelpFile = NULL;
4129         }
4130
4131         result = S_OK;
4132     }
4133     else
4134     {
4135         /* for a typeinfo */
4136         result = ITypeLib2_fnGetTypeInfo(iface, index, &pTInfo);
4137
4138         if(SUCCEEDED(result))
4139         {
4140             result = ITypeInfo_GetDocumentation(pTInfo,
4141                                           MEMBERID_NIL,
4142                                           pBstrName,
4143                                           pBstrDocString,
4144                                           pdwHelpContext, pBstrHelpFile);
4145
4146             ITypeInfo_Release(pTInfo);
4147         }
4148     }
4149     return result;
4150 memerr3:
4151     if (pBstrDocString) SysFreeString (*pBstrDocString);
4152 memerr2:
4153     if (pBstrName) SysFreeString (*pBstrName);
4154 memerr1:
4155     return STG_E_INSUFFICIENTMEMORY;
4156 }
4157
4158 /* ITypeLib::IsName
4159  *
4160  * Indicates whether a passed-in string contains the name of a type or member
4161  * described in the library.
4162  *
4163  */
4164 static HRESULT WINAPI ITypeLib2_fnIsName(
4165         ITypeLib2 *iface,
4166         LPOLESTR szNameBuf,
4167         ULONG lHashVal,
4168         BOOL *pfName)
4169 {
4170     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4171     ITypeInfoImpl *pTInfo;
4172     TLBFuncDesc *pFInfo;
4173     TLBVarDesc *pVInfo;
4174     int i;
4175     UINT nNameBufLen = (lstrlenW(szNameBuf)+1)*sizeof(WCHAR);
4176
4177     TRACE("(%p)->(%s,%08x,%p)\n", This, debugstr_w(szNameBuf), lHashVal,
4178           pfName);
4179
4180     *pfName=TRUE;
4181     for(pTInfo=This->pTypeInfo;pTInfo;pTInfo=pTInfo->next){
4182         if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
4183         for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
4184             if(!memcmp(szNameBuf,pFInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
4185             for(i=0;i<pFInfo->funcdesc.cParams;i++)
4186                 if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name, nNameBufLen))
4187                     goto ITypeLib2_fnIsName_exit;
4188         }
4189         for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next)
4190             if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
4191
4192     }
4193     *pfName=FALSE;
4194
4195 ITypeLib2_fnIsName_exit:
4196     TRACE("(%p)slow! search for %s: %s found!\n", This,
4197           debugstr_w(szNameBuf), *pfName?"NOT":"");
4198
4199     return S_OK;
4200 }
4201
4202 /* ITypeLib::FindName
4203  *
4204  * Finds occurrences of a type description in a type library. This may be used
4205  * to quickly verify that a name exists in a type library.
4206  *
4207  */
4208 static HRESULT WINAPI ITypeLib2_fnFindName(
4209         ITypeLib2 *iface,
4210         LPOLESTR szNameBuf,
4211         ULONG lHashVal,
4212         ITypeInfo **ppTInfo,
4213         MEMBERID *rgMemId,
4214         UINT16 *pcFound)
4215 {
4216     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4217     ITypeInfoImpl *pTInfo;
4218     TLBFuncDesc *pFInfo;
4219     TLBVarDesc *pVInfo;
4220     int i,j = 0;
4221     UINT nNameBufLen = (lstrlenW(szNameBuf)+1)*sizeof(WCHAR);
4222
4223     for(pTInfo=This->pTypeInfo;pTInfo && j<*pcFound; pTInfo=pTInfo->next){
4224         if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit;
4225         for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
4226             if(!memcmp(szNameBuf,pFInfo->Name,nNameBufLen)) goto ITypeLib2_fnFindName_exit;
4227             for(i=0;i<pFInfo->funcdesc.cParams;i++) {
4228                 if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name,nNameBufLen))
4229                     goto ITypeLib2_fnFindName_exit;
4230             }
4231         }
4232         for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next)
4233             if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit;
4234         continue;
4235 ITypeLib2_fnFindName_exit:
4236         ITypeInfo_AddRef((ITypeInfo*)pTInfo);
4237         ppTInfo[j]=(LPTYPEINFO)pTInfo;
4238         j++;
4239     }
4240     TRACE("(%p)slow! search for %d with %s: found %d TypeInfo's!\n",
4241           This, *pcFound, debugstr_w(szNameBuf), j);
4242
4243     *pcFound=j;
4244
4245     return S_OK;
4246 }
4247
4248 /* ITypeLib::ReleaseTLibAttr
4249  *
4250  * Releases the TLIBATTR originally obtained from ITypeLib::GetLibAttr.
4251  *
4252  */
4253 static VOID WINAPI ITypeLib2_fnReleaseTLibAttr(
4254         ITypeLib2 *iface,
4255         TLIBATTR *pTLibAttr)
4256 {
4257     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4258     TRACE("freeing (%p)\n",This);
4259     HeapFree(GetProcessHeap(),0,pTLibAttr);
4260
4261 }
4262
4263 /* ITypeLib2::GetCustData
4264  *
4265  * gets the custom data
4266  */
4267 static HRESULT WINAPI ITypeLib2_fnGetCustData(
4268         ITypeLib2 * iface,
4269         REFGUID guid,
4270         VARIANT *pVarVal)
4271 {
4272     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4273     TLBCustData *pCData;
4274
4275     for(pCData=This->pCustData; pCData; pCData = pCData->next)
4276     {
4277       if( IsEqualIID(guid, &pCData->guid)) break;
4278     }
4279
4280     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
4281
4282     if(pCData)
4283     {
4284         VariantInit( pVarVal);
4285         VariantCopy( pVarVal, &pCData->data);
4286         return S_OK;
4287     }
4288     return E_INVALIDARG;  /* FIXME: correct? */
4289 }
4290
4291 /* ITypeLib2::GetLibStatistics
4292  *
4293  * Returns statistics about a type library that are required for efficient
4294  * sizing of hash tables.
4295  *
4296  */
4297 static HRESULT WINAPI ITypeLib2_fnGetLibStatistics(
4298         ITypeLib2 * iface,
4299         ULONG *pcUniqueNames,
4300         ULONG *pcchUniqueNames)
4301 {
4302     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4303
4304     FIXME("(%p): stub!\n", This);
4305
4306     if(pcUniqueNames) *pcUniqueNames=1;
4307     if(pcchUniqueNames) *pcchUniqueNames=1;
4308     return S_OK;
4309 }
4310
4311 /* ITypeLib2::GetDocumentation2
4312  *
4313  * Retrieves the library's documentation string, the complete Help file name
4314  * and path, the localization context to use, and the context ID for the
4315  * library Help topic in the Help file.
4316  *
4317  */
4318 static HRESULT WINAPI ITypeLib2_fnGetDocumentation2(
4319         ITypeLib2 * iface,
4320         INT index,
4321         LCID lcid,
4322         BSTR *pbstrHelpString,
4323         DWORD *pdwHelpStringContext,
4324         BSTR *pbstrHelpStringDll)
4325 {
4326     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4327     HRESULT result;
4328     ITypeInfo *pTInfo;
4329
4330     FIXME("(%p) index %d lcid %d half implemented stub!\n", This, index, lcid);
4331
4332     /* the help string should be obtained from the helpstringdll,
4333      * using the _DLLGetDocumentation function, based on the supplied
4334      * lcid. Nice to do sometime...
4335      */
4336     if(index<0)
4337     {
4338       /* documentation for the typelib */
4339       if(pbstrHelpString)
4340         *pbstrHelpString=SysAllocString(This->DocString);
4341       if(pdwHelpStringContext)
4342         *pdwHelpStringContext=This->dwHelpContext;
4343       if(pbstrHelpStringDll)
4344         *pbstrHelpStringDll=SysAllocString(This->HelpStringDll);
4345
4346       result = S_OK;
4347     }
4348     else
4349     {
4350       /* for a typeinfo */
4351       result=ITypeLib2_GetTypeInfo(iface, index, &pTInfo);
4352
4353       if(SUCCEEDED(result))
4354       {
4355         ITypeInfo2 * pTInfo2;
4356         result = ITypeInfo_QueryInterface(pTInfo,
4357                                           &IID_ITypeInfo2,
4358                                           (LPVOID*) &pTInfo2);
4359
4360         if(SUCCEEDED(result))
4361         {
4362           result = ITypeInfo2_GetDocumentation2(pTInfo2,
4363                                            MEMBERID_NIL,
4364                                            lcid,
4365                                            pbstrHelpString,
4366                                            pdwHelpStringContext,
4367                                            pbstrHelpStringDll);
4368
4369           ITypeInfo2_Release(pTInfo2);
4370         }
4371
4372         ITypeInfo_Release(pTInfo);
4373       }
4374     }
4375     return result;
4376 }
4377
4378 /* ITypeLib2::GetAllCustData
4379  *
4380  * Gets all custom data items for the library.
4381  *
4382  */
4383 static HRESULT WINAPI ITypeLib2_fnGetAllCustData(
4384         ITypeLib2 * iface,
4385         CUSTDATA *pCustData)
4386 {
4387     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4388     TLBCustData *pCData;
4389     int i;
4390     TRACE("(%p) returning %d items\n", This, This->ctCustData);
4391     pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
4392     if(pCustData->prgCustData ){
4393         pCustData->cCustData=This->ctCustData;
4394         for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
4395             pCustData->prgCustData[i].guid=pCData->guid;
4396             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
4397         }
4398     }else{
4399         ERR(" OUT OF MEMORY!\n");
4400         return E_OUTOFMEMORY;
4401     }
4402     return S_OK;
4403 }
4404
4405 static const ITypeLib2Vtbl tlbvt = {
4406     ITypeLib2_fnQueryInterface,
4407     ITypeLib2_fnAddRef,
4408     ITypeLib2_fnRelease,
4409     ITypeLib2_fnGetTypeInfoCount,
4410     ITypeLib2_fnGetTypeInfo,
4411     ITypeLib2_fnGetTypeInfoType,
4412     ITypeLib2_fnGetTypeInfoOfGuid,
4413     ITypeLib2_fnGetLibAttr,
4414     ITypeLib2_fnGetTypeComp,
4415     ITypeLib2_fnGetDocumentation,
4416     ITypeLib2_fnIsName,
4417     ITypeLib2_fnFindName,
4418     ITypeLib2_fnReleaseTLibAttr,
4419
4420     ITypeLib2_fnGetCustData,
4421     ITypeLib2_fnGetLibStatistics,
4422     ITypeLib2_fnGetDocumentation2,
4423     ITypeLib2_fnGetAllCustData
4424  };
4425
4426
4427 static HRESULT WINAPI ITypeLibComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
4428 {
4429     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4430
4431     return ITypeLib2_QueryInterface((ITypeLib *)This, riid, ppv);
4432 }
4433
4434 static ULONG WINAPI ITypeLibComp_fnAddRef(ITypeComp * iface)
4435 {
4436     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4437
4438     return ITypeLib2_AddRef((ITypeLib2 *)This);
4439 }
4440
4441 static ULONG WINAPI ITypeLibComp_fnRelease(ITypeComp * iface)
4442 {
4443     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4444
4445     return ITypeLib2_Release((ITypeLib2 *)This);
4446 }
4447
4448 static HRESULT WINAPI ITypeLibComp_fnBind(
4449     ITypeComp * iface,
4450     OLECHAR * szName,
4451     ULONG lHash,
4452     WORD wFlags,
4453     ITypeInfo ** ppTInfo,
4454     DESCKIND * pDescKind,
4455     BINDPTR * pBindPtr)
4456 {
4457     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4458     ITypeInfoImpl *pTypeInfo;
4459
4460     TRACE("(%s, 0x%x, 0x%x, %p, %p, %p)\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
4461
4462     *pDescKind = DESCKIND_NONE;
4463     pBindPtr->lptcomp = NULL;
4464     *ppTInfo = NULL;
4465
4466     for (pTypeInfo = This->pTypeInfo; pTypeInfo; pTypeInfo = pTypeInfo->next)
4467     {
4468         TRACE("testing %s\n", debugstr_w(pTypeInfo->Name));
4469
4470         /* FIXME: check wFlags here? */
4471         /* FIXME: we should use a hash table to look this info up using lHash
4472          * instead of an O(n) search */
4473         if ((pTypeInfo->TypeAttr.typekind == TKIND_ENUM) ||
4474             (pTypeInfo->TypeAttr.typekind == TKIND_MODULE))
4475         {
4476             if (pTypeInfo->Name && !strcmpW(pTypeInfo->Name, szName))
4477             {
4478                 *pDescKind = DESCKIND_TYPECOMP;
4479                 pBindPtr->lptcomp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4480                 ITypeComp_AddRef(pBindPtr->lptcomp);
4481                 TRACE("module or enum: %s\n", debugstr_w(szName));
4482                 return S_OK;
4483             }
4484         }
4485
4486         if ((pTypeInfo->TypeAttr.typekind == TKIND_MODULE) ||
4487             (pTypeInfo->TypeAttr.typekind == TKIND_ENUM))
4488         {
4489             ITypeComp *pSubTypeComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4490             HRESULT hr;
4491
4492             hr = ITypeComp_Bind(pSubTypeComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
4493             if (SUCCEEDED(hr) && (*pDescKind != DESCKIND_NONE))
4494             {
4495                 TRACE("found in module or in enum: %s\n", debugstr_w(szName));
4496                 return S_OK;
4497             }
4498         }
4499
4500         if ((pTypeInfo->TypeAttr.typekind == TKIND_COCLASS) &&
4501             (pTypeInfo->TypeAttr.wTypeFlags & TYPEFLAG_FAPPOBJECT))
4502         {
4503             ITypeComp *pSubTypeComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4504             HRESULT hr;
4505             ITypeInfo *subtypeinfo;
4506             BINDPTR subbindptr;
4507             DESCKIND subdesckind;
4508
4509             hr = ITypeComp_Bind(pSubTypeComp, szName, lHash, wFlags,
4510                 &subtypeinfo, &subdesckind, &subbindptr);
4511             if (SUCCEEDED(hr) && (subdesckind != DESCKIND_NONE))
4512             {
4513                 TYPEDESC tdesc_appobject =
4514                 {
4515                     {
4516                         (TYPEDESC *)pTypeInfo->hreftype
4517                     },
4518                     VT_USERDEFINED
4519                 };
4520                 const VARDESC vardesc_appobject =
4521                 {
4522                     -2,         /* memid */
4523                     NULL,       /* lpstrSchema */
4524                     {
4525                         0       /* oInst */
4526                     },
4527                     {
4528                                 /* ELEMDESC */
4529                         {
4530                                 /* TYPEDESC */
4531                                 {
4532                                     &tdesc_appobject
4533                                 },
4534                                 VT_PTR
4535                         },
4536                     },
4537                     0,          /* wVarFlags */
4538                     VAR_STATIC  /* varkind */
4539                 };
4540
4541                 TRACE("found in implicit app object: %s\n", debugstr_w(szName));
4542
4543                 /* cleanup things filled in by Bind call so we can put our
4544                  * application object data in there instead */
4545                 switch (subdesckind)
4546                 {
4547                 case DESCKIND_FUNCDESC:
4548                     ITypeInfo_ReleaseFuncDesc(subtypeinfo, subbindptr.lpfuncdesc);
4549                     break;
4550                 case DESCKIND_VARDESC:
4551                     ITypeInfo_ReleaseVarDesc(subtypeinfo, subbindptr.lpvardesc);
4552                     break;
4553                 default:
4554                     break;
4555                 }
4556                 if (subtypeinfo) ITypeInfo_Release(subtypeinfo);
4557
4558                 if (pTypeInfo->hreftype == -1)
4559                     FIXME("no hreftype for interface %p\n", pTypeInfo);
4560
4561                 hr = TLB_AllocAndInitVarDesc(&vardesc_appobject, &pBindPtr->lpvardesc);
4562                 if (FAILED(hr))
4563                     return hr;
4564
4565                 *pDescKind = DESCKIND_IMPLICITAPPOBJ;
4566                 *ppTInfo = (ITypeInfo *)pTypeInfo;
4567                 ITypeInfo_AddRef(*ppTInfo);
4568                 return S_OK;
4569             }
4570         }
4571     }
4572
4573     TRACE("name not found %s\n", debugstr_w(szName));
4574     return S_OK;
4575 }
4576
4577 static HRESULT WINAPI ITypeLibComp_fnBindType(
4578     ITypeComp * iface,
4579     OLECHAR * szName,
4580     ULONG lHash,
4581     ITypeInfo ** ppTInfo,
4582     ITypeComp ** ppTComp)
4583 {
4584     FIXME("(%s, %x, %p, %p): stub\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
4585     return E_NOTIMPL;
4586 }
4587
4588 static const ITypeCompVtbl tlbtcvt =
4589 {
4590
4591     ITypeLibComp_fnQueryInterface,
4592     ITypeLibComp_fnAddRef,
4593     ITypeLibComp_fnRelease,
4594
4595     ITypeLibComp_fnBind,
4596     ITypeLibComp_fnBindType
4597 };
4598
4599 /*================== ITypeInfo(2) Methods ===================================*/
4600 static ITypeInfo2 * WINAPI ITypeInfo_Constructor(void)
4601 {
4602     ITypeInfoImpl * pTypeInfoImpl;
4603
4604     pTypeInfoImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeInfoImpl));
4605     if (pTypeInfoImpl)
4606     {
4607       pTypeInfoImpl->lpVtbl = &tinfvt;
4608       pTypeInfoImpl->lpVtblTypeComp = &tcompvt;
4609       pTypeInfoImpl->ref=1;
4610       pTypeInfoImpl->hreftype = -1;
4611       pTypeInfoImpl->TypeAttr.memidConstructor = MEMBERID_NIL;
4612       pTypeInfoImpl->TypeAttr.memidDestructor = MEMBERID_NIL;
4613     }
4614     TRACE("(%p)\n", pTypeInfoImpl);
4615     return (ITypeInfo2*) pTypeInfoImpl;
4616 }
4617
4618 /* ITypeInfo::QueryInterface
4619  */
4620 static HRESULT WINAPI ITypeInfo_fnQueryInterface(
4621         ITypeInfo2 *iface,
4622         REFIID riid,
4623         VOID **ppvObject)
4624 {
4625     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4626
4627     TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
4628
4629     *ppvObject=NULL;
4630     if(IsEqualIID(riid, &IID_IUnknown) ||
4631             IsEqualIID(riid,&IID_ITypeInfo)||
4632             IsEqualIID(riid,&IID_ITypeInfo2))
4633         *ppvObject = This;
4634
4635     if(*ppvObject){
4636         ITypeInfo_AddRef(iface);
4637         TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
4638         return S_OK;
4639     }
4640     TRACE("-- Interface: E_NOINTERFACE\n");
4641     return E_NOINTERFACE;
4642 }
4643
4644 /* ITypeInfo::AddRef
4645  */
4646 static ULONG WINAPI ITypeInfo_fnAddRef( ITypeInfo2 *iface)
4647 {
4648     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4649     ULONG ref = InterlockedIncrement(&This->ref);
4650
4651     ITypeLib2_AddRef((ITypeLib2*)This->pTypeLib);
4652
4653     TRACE("(%p)->ref is %u\n",This, ref);
4654     return ref;
4655 }
4656
4657 /* ITypeInfo::Release
4658  */
4659 static ULONG WINAPI ITypeInfo_fnRelease(ITypeInfo2 *iface)
4660 {
4661     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4662     ULONG ref = InterlockedDecrement(&This->ref);
4663
4664     TRACE("(%p)->(%u)\n",This, ref);
4665
4666     if (ref)   {
4667       /* We don't release ITypeLib when ref=0 because
4668          it means that function is called by ITypeLib2_Release */
4669       ITypeLib2_Release((ITypeLib2*)This->pTypeLib);
4670     } else   {
4671       TLBFuncDesc *pFInfo, *pFInfoNext;
4672       TLBVarDesc *pVInfo, *pVInfoNext;
4673       TLBImplType *pImpl, *pImplNext;
4674
4675       TRACE("destroying ITypeInfo(%p)\n",This);
4676
4677       if (This->no_free_data)
4678           goto finish_free;
4679
4680       if (This->Name)
4681       {
4682           SysFreeString(This->Name);
4683           This->Name = 0;
4684       }
4685
4686       if (This->DocString)
4687       {
4688           SysFreeString(This->DocString);
4689           This->DocString = 0;
4690       }
4691
4692       if (This->DllName)
4693       {
4694           SysFreeString(This->DllName);
4695           This->DllName = 0;
4696       }
4697
4698       for (pFInfo = This->funclist; pFInfo; pFInfo = pFInfoNext)
4699       {
4700           UINT i;
4701           for(i = 0;i < pFInfo->funcdesc.cParams; i++)
4702           {
4703               ELEMDESC *elemdesc = &pFInfo->funcdesc.lprgelemdescParam[i];
4704               if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
4705               {
4706                   VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue);
4707                   TLB_Free(elemdesc->u.paramdesc.pparamdescex);
4708               }
4709               SysFreeString(pFInfo->pParamDesc[i].Name);
4710           }
4711           TLB_Free(pFInfo->funcdesc.lprgelemdescParam);
4712           TLB_Free(pFInfo->pParamDesc);
4713           TLB_FreeCustData(pFInfo->pCustData);
4714           if (HIWORD(pFInfo->Entry) != 0 && pFInfo->Entry != (BSTR)-1) 
4715               SysFreeString(pFInfo->Entry);
4716           SysFreeString(pFInfo->HelpString);
4717           SysFreeString(pFInfo->Name);
4718
4719           pFInfoNext = pFInfo->next;
4720           TLB_Free(pFInfo);
4721       }
4722       for (pVInfo = This->varlist; pVInfo; pVInfo = pVInfoNext)
4723       {
4724           if (pVInfo->vardesc.varkind == VAR_CONST)
4725           {
4726               VariantClear(pVInfo->vardesc.u.lpvarValue);
4727               TLB_Free(pVInfo->vardesc.u.lpvarValue);
4728           }
4729           TLB_FreeCustData(pVInfo->pCustData);
4730           SysFreeString(pVInfo->Name);
4731           pVInfoNext = pVInfo->next;
4732           TLB_Free(pVInfo);
4733       }
4734       for(pImpl = This->impltypelist; pImpl; pImpl = pImplNext)
4735       {
4736           TLB_FreeCustData(pImpl->pCustData);
4737           pImplNext = pImpl->next;
4738           TLB_Free(pImpl);
4739       }
4740       TLB_FreeCustData(This->pCustData);
4741
4742 finish_free:
4743       if (This->next)
4744       {
4745         ITypeInfo_Release((ITypeInfo*)This->next);
4746       }
4747
4748       HeapFree(GetProcessHeap(),0,This);
4749       return 0;
4750     }
4751     return ref;
4752 }
4753
4754 /* ITypeInfo::GetTypeAttr
4755  *
4756  * Retrieves a TYPEATTR structure that contains the attributes of the type
4757  * description.
4758  *
4759  */
4760 static HRESULT WINAPI ITypeInfo_fnGetTypeAttr( ITypeInfo2 *iface,
4761         LPTYPEATTR  *ppTypeAttr)
4762 {
4763     const ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4764     SIZE_T size;
4765
4766     TRACE("(%p)\n",This);
4767
4768     size = sizeof(**ppTypeAttr);
4769     if (This->TypeAttr.typekind == TKIND_ALIAS)
4770         size += TLB_SizeTypeDesc(&This->TypeAttr.tdescAlias, FALSE);
4771
4772     *ppTypeAttr = HeapAlloc(GetProcessHeap(), 0, size);
4773     if (!*ppTypeAttr)
4774         return E_OUTOFMEMORY;
4775
4776     **ppTypeAttr = This->TypeAttr;
4777
4778     if (This->TypeAttr.typekind == TKIND_ALIAS)
4779         TLB_CopyTypeDesc(&(*ppTypeAttr)->tdescAlias,
4780             &This->TypeAttr.tdescAlias, (void *)(*ppTypeAttr + 1));
4781
4782     if((*ppTypeAttr)->typekind == TKIND_DISPATCH) {
4783         (*ppTypeAttr)->cFuncs = (*ppTypeAttr)->cbSizeVft / 4; /* This should include all the inherited
4784                                                                  funcs */
4785         (*ppTypeAttr)->cbSizeVft = 28; /* This is always the size of IDispatch's vtbl */
4786         (*ppTypeAttr)->wTypeFlags &= ~TYPEFLAG_FOLEAUTOMATION;
4787     }
4788     return S_OK;
4789 }
4790
4791 /* ITypeInfo::GetTypeComp
4792  *
4793  * Retrieves the ITypeComp interface for the type description, which enables a
4794  * client compiler to bind to the type description's members.
4795  *
4796  */
4797 static HRESULT WINAPI ITypeInfo_fnGetTypeComp( ITypeInfo2 *iface,
4798         ITypeComp  * *ppTComp)
4799 {
4800     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4801
4802     TRACE("(%p)->(%p)\n", This, ppTComp);
4803
4804     *ppTComp = (ITypeComp *)&This->lpVtblTypeComp;
4805     ITypeComp_AddRef(*ppTComp);
4806     return S_OK;
4807 }
4808
4809 static SIZE_T TLB_SizeElemDesc( const ELEMDESC *elemdesc )
4810 {
4811     SIZE_T size = TLB_SizeTypeDesc(&elemdesc->tdesc, FALSE);
4812     if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
4813         size += sizeof(*elemdesc->u.paramdesc.pparamdescex);
4814     return size;
4815 }
4816
4817 static HRESULT TLB_CopyElemDesc( const ELEMDESC *src, ELEMDESC *dest, char **buffer )
4818 {
4819     *dest = *src;
4820     *buffer = TLB_CopyTypeDesc(&dest->tdesc, &src->tdesc, *buffer);
4821     if (src->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
4822     {
4823         const PARAMDESCEX *pparamdescex_src = src->u.paramdesc.pparamdescex;
4824         PARAMDESCEX *pparamdescex_dest = dest->u.paramdesc.pparamdescex = (PARAMDESCEX *)*buffer;
4825         *buffer += sizeof(PARAMDESCEX);
4826         *pparamdescex_dest = *pparamdescex_src;
4827         VariantInit(&pparamdescex_dest->varDefaultValue);
4828         return VariantCopy(&pparamdescex_dest->varDefaultValue, 
4829                            (VARIANTARG *)&pparamdescex_src->varDefaultValue);
4830     }
4831     else
4832         dest->u.paramdesc.pparamdescex = NULL;
4833     return S_OK;
4834 }
4835
4836 static void TLB_FreeElemDesc( ELEMDESC *elemdesc )
4837 {
4838     if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
4839         VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue);
4840 }
4841
4842 static HRESULT TLB_AllocAndInitFuncDesc( const FUNCDESC *src, FUNCDESC **dest_ptr, BOOL dispinterface )
4843 {
4844     FUNCDESC *dest;
4845     char *buffer;
4846     SIZE_T size = sizeof(*src);
4847     SHORT i;
4848     HRESULT hr;
4849
4850     size += sizeof(*src->lprgscode) * src->cScodes;
4851     size += TLB_SizeElemDesc(&src->elemdescFunc);
4852     for (i = 0; i < src->cParams; i++)
4853     {
4854         size += sizeof(ELEMDESC);
4855         size += TLB_SizeElemDesc(&src->lprgelemdescParam[i]);
4856     }
4857
4858     dest = (FUNCDESC *)SysAllocStringByteLen(NULL, size);
4859     if (!dest) return E_OUTOFMEMORY;
4860
4861     *dest = *src;
4862     if (dispinterface)    /* overwrite funckind */
4863         dest->funckind = FUNC_DISPATCH;
4864     buffer = (char *)(dest + 1);
4865
4866     dest->lprgscode = (SCODE *)buffer;
4867     memcpy(dest->lprgscode, src->lprgscode, sizeof(*src->lprgscode) * src->cScodes);
4868     buffer += sizeof(*src->lprgscode) * src->cScodes;
4869
4870     hr = TLB_CopyElemDesc(&src->elemdescFunc, &dest->elemdescFunc, &buffer);
4871     if (FAILED(hr))
4872     {
4873         SysFreeString((BSTR)dest);
4874         return hr;
4875     }
4876
4877     dest->lprgelemdescParam = (ELEMDESC *)buffer;
4878     buffer += sizeof(ELEMDESC) * src->cParams;
4879     for (i = 0; i < src->cParams; i++)
4880     {
4881         hr = TLB_CopyElemDesc(&src->lprgelemdescParam[i], &dest->lprgelemdescParam[i], &buffer);
4882         if (FAILED(hr))
4883             break;
4884     }
4885     if (FAILED(hr))
4886     {
4887         /* undo the above actions */
4888         for (i = i - 1; i >= 0; i--)
4889             TLB_FreeElemDesc(&dest->lprgelemdescParam[i]);
4890         TLB_FreeElemDesc(&dest->elemdescFunc);
4891         SysFreeString((BSTR)dest);
4892         return hr;
4893     }
4894
4895     /* special treatment for dispinterfaces: this makes functions appear
4896      * to return their [retval] value when it is really returning an
4897      * HRESULT */
4898     if (dispinterface && dest->elemdescFunc.tdesc.vt == VT_HRESULT)
4899     {
4900         if (dest->cParams &&
4901             (dest->lprgelemdescParam[dest->cParams - 1].u.paramdesc.wParamFlags & PARAMFLAG_FRETVAL))
4902         {
4903             ELEMDESC *elemdesc = &dest->lprgelemdescParam[dest->cParams - 1];
4904             if (elemdesc->tdesc.vt != VT_PTR)
4905             {
4906                 ERR("elemdesc should have started with VT_PTR instead of:\n");
4907                 if (ERR_ON(ole))
4908                     dump_ELEMDESC(elemdesc);
4909                 return E_UNEXPECTED;
4910             }
4911
4912             /* copy last parameter to the return value. we are using a flat
4913              * buffer so there is no danger of leaking memory in
4914              * elemdescFunc */
4915             dest->elemdescFunc.tdesc = *elemdesc->tdesc.u.lptdesc;
4916
4917             /* remove the last parameter */
4918             dest->cParams--;
4919         }
4920         else
4921             /* otherwise this function is made to appear to have no return
4922              * value */
4923             dest->elemdescFunc.tdesc.vt = VT_VOID;
4924
4925     }
4926
4927     *dest_ptr = dest;
4928     return S_OK;
4929 }
4930
4931 HRESULT ITypeInfoImpl_GetInternalFuncDesc( ITypeInfo *iface, UINT index, const FUNCDESC **ppFuncDesc )
4932 {
4933     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4934     const TLBFuncDesc *pFDesc;
4935     int i;
4936
4937     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++, pFDesc=pFDesc->next)
4938         ;
4939
4940     if (pFDesc)
4941     {
4942         *ppFuncDesc = &pFDesc->funcdesc;
4943         return S_OK;
4944     }
4945
4946     return TYPE_E_ELEMENTNOTFOUND;
4947 }
4948
4949 /* internal function to make the inherited interfaces' methods appear
4950  * part of the interface */
4951 static HRESULT ITypeInfoImpl_GetInternalDispatchFuncDesc( ITypeInfo *iface,
4952     UINT index, const FUNCDESC **ppFuncDesc, UINT *funcs, UINT *hrefoffset)
4953 {
4954     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4955     HRESULT hr;
4956     UINT implemented_funcs = 0;
4957
4958     if (funcs)
4959         *funcs = 0;
4960     else
4961         *hrefoffset = DISPATCH_HREF_OFFSET;
4962
4963     if(This->impltypelist)
4964     {
4965         ITypeInfo *pSubTypeInfo;
4966         UINT sub_funcs;
4967
4968         hr = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef, &pSubTypeInfo);
4969         if (FAILED(hr))
4970             return hr;
4971
4972         hr = ITypeInfoImpl_GetInternalDispatchFuncDesc(pSubTypeInfo,
4973                                                        index,
4974                                                        ppFuncDesc,
4975                                                        &sub_funcs, hrefoffset);
4976         implemented_funcs += sub_funcs;
4977         ITypeInfo_Release(pSubTypeInfo);
4978         if (SUCCEEDED(hr))
4979             return hr;
4980         *hrefoffset += DISPATCH_HREF_OFFSET;
4981     }
4982
4983     if (funcs)
4984         *funcs = implemented_funcs + This->TypeAttr.cFuncs;
4985     else
4986         *hrefoffset = 0;
4987     
4988     if (index < implemented_funcs)
4989         return E_INVALIDARG;
4990     return ITypeInfoImpl_GetInternalFuncDesc(iface, index - implemented_funcs,
4991                                              ppFuncDesc);
4992 }
4993
4994 static inline void ITypeInfoImpl_ElemDescAddHrefOffset( LPELEMDESC pElemDesc, UINT hrefoffset)
4995 {
4996     TYPEDESC *pTypeDesc = &pElemDesc->tdesc;
4997     while (TRUE)
4998     {
4999         switch (pTypeDesc->vt)
5000         {
5001         case VT_USERDEFINED:
5002             pTypeDesc->u.hreftype += hrefoffset;
5003             return;
5004         case VT_PTR:
5005         case VT_SAFEARRAY:
5006             pTypeDesc = pTypeDesc->u.lptdesc;
5007             break;
5008         case VT_CARRAY:
5009             pTypeDesc = &pTypeDesc->u.lpadesc->tdescElem;
5010             break;
5011         default:
5012             return;
5013         }
5014     }
5015 }
5016
5017 static inline void ITypeInfoImpl_FuncDescAddHrefOffset( LPFUNCDESC pFuncDesc, UINT hrefoffset)
5018 {
5019     SHORT i;
5020     for (i = 0; i < pFuncDesc->cParams; i++)
5021         ITypeInfoImpl_ElemDescAddHrefOffset(&pFuncDesc->lprgelemdescParam[i], hrefoffset);
5022     ITypeInfoImpl_ElemDescAddHrefOffset(&pFuncDesc->elemdescFunc, hrefoffset);
5023 }
5024
5025 /* ITypeInfo::GetFuncDesc
5026  *
5027  * Retrieves the FUNCDESC structure that contains information about a
5028  * specified function.
5029  *
5030  */
5031 static HRESULT WINAPI ITypeInfo_fnGetFuncDesc( ITypeInfo2 *iface, UINT index,
5032         LPFUNCDESC  *ppFuncDesc)
5033 {
5034     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5035     const FUNCDESC *internal_funcdesc;
5036     HRESULT hr;
5037     UINT hrefoffset = 0;
5038
5039     TRACE("(%p) index %d\n", This, index);
5040
5041     if (This->TypeAttr.typekind == TKIND_DISPATCH)
5042         hr = ITypeInfoImpl_GetInternalDispatchFuncDesc((ITypeInfo *)iface, index,
5043                                                        &internal_funcdesc, NULL,
5044                                                        &hrefoffset);
5045     else
5046         hr = ITypeInfoImpl_GetInternalFuncDesc((ITypeInfo *)iface, index,
5047                                                &internal_funcdesc);
5048     if (FAILED(hr))
5049     {
5050         WARN("description for function %d not found\n", index);
5051         return hr;
5052     }
5053
5054     hr = TLB_AllocAndInitFuncDesc(
5055         internal_funcdesc,
5056         ppFuncDesc,
5057         This->TypeAttr.typekind == TKIND_DISPATCH);
5058
5059     if ((This->TypeAttr.typekind == TKIND_DISPATCH) && hrefoffset)
5060         ITypeInfoImpl_FuncDescAddHrefOffset(*ppFuncDesc, hrefoffset);
5061
5062     TRACE("-- 0x%08x\n", hr);
5063     return hr;
5064 }
5065
5066 static HRESULT TLB_AllocAndInitVarDesc( const VARDESC *src, VARDESC **dest_ptr )
5067 {
5068     VARDESC *dest;
5069     char *buffer;
5070     SIZE_T size = sizeof(*src);
5071     HRESULT hr;
5072
5073     if (src->lpstrSchema) size += (strlenW(src->lpstrSchema) + 1) * sizeof(WCHAR);
5074     if (src->varkind == VAR_CONST)
5075         size += sizeof(VARIANT);
5076     size += TLB_SizeElemDesc(&src->elemdescVar);
5077
5078     dest = (VARDESC *)SysAllocStringByteLen(NULL, size);
5079     if (!dest) return E_OUTOFMEMORY;
5080
5081     *dest = *src;
5082     buffer = (char *)(dest + 1);
5083     if (src->lpstrSchema)
5084     {
5085         int len;
5086         dest->lpstrSchema = (LPOLESTR)buffer;
5087         len = strlenW(src->lpstrSchema);
5088         memcpy(dest->lpstrSchema, src->lpstrSchema, (len + 1) * sizeof(WCHAR));
5089         buffer += (len + 1) * sizeof(WCHAR);
5090     }
5091
5092     if (src->varkind == VAR_CONST)
5093     {
5094         HRESULT hr;
5095
5096         dest->u.lpvarValue = (VARIANT *)buffer;
5097         *dest->u.lpvarValue = *src->u.lpvarValue;
5098         buffer += sizeof(VARIANT);
5099         VariantInit(dest->u.lpvarValue);
5100         hr = VariantCopy(dest->u.lpvarValue, src->u.lpvarValue);
5101         if (FAILED(hr))
5102         {
5103             SysFreeString((BSTR)dest_ptr);
5104             return hr;
5105         }
5106     }
5107     hr = TLB_CopyElemDesc(&src->elemdescVar, &dest->elemdescVar, &buffer);
5108     if (FAILED(hr))
5109     {
5110         if (src->varkind == VAR_CONST)
5111             VariantClear(dest->u.lpvarValue);
5112         SysFreeString((BSTR)dest);
5113         return hr;
5114     }
5115     *dest_ptr = dest;
5116     return S_OK;
5117 }
5118
5119 /* ITypeInfo::GetVarDesc
5120  *
5121  * Retrieves a VARDESC structure that describes the specified variable.
5122  *
5123  */
5124 static HRESULT WINAPI ITypeInfo_fnGetVarDesc( ITypeInfo2 *iface, UINT index,
5125         LPVARDESC  *ppVarDesc)
5126 {
5127     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5128     int i;
5129     const TLBVarDesc *pVDesc;
5130
5131     TRACE("(%p) index %d\n", This, index);
5132
5133     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next)
5134         ;
5135
5136     if (pVDesc)
5137         return TLB_AllocAndInitVarDesc(&pVDesc->vardesc, ppVarDesc);
5138
5139     return E_INVALIDARG;
5140 }
5141
5142 /* ITypeInfo_GetNames
5143  *
5144  * Retrieves the variable with the specified member ID (or the name of the
5145  * property or method and its parameters) that correspond to the specified
5146  * function ID.
5147  */
5148 static HRESULT WINAPI ITypeInfo_fnGetNames( ITypeInfo2 *iface, MEMBERID memid,
5149         BSTR  *rgBstrNames, UINT cMaxNames, UINT  *pcNames)
5150 {
5151     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5152     const TLBFuncDesc *pFDesc;
5153     const TLBVarDesc *pVDesc;
5154     int i;
5155     TRACE("(%p) memid=0x%08x Maxname=%d\n", This, memid, cMaxNames);
5156     for(pFDesc=This->funclist; pFDesc && pFDesc->funcdesc.memid != memid; pFDesc=pFDesc->next);
5157     if(pFDesc)
5158     {
5159       /* function found, now return function and parameter names */
5160       for(i=0; i<cMaxNames && i <= pFDesc->funcdesc.cParams; i++)
5161       {
5162         if(!i)
5163           *rgBstrNames=SysAllocString(pFDesc->Name);
5164         else
5165           rgBstrNames[i]=SysAllocString(pFDesc->pParamDesc[i-1].Name);
5166       }
5167       *pcNames=i;
5168     }
5169     else
5170     {
5171       for(pVDesc=This->varlist; pVDesc && pVDesc->vardesc.memid != memid; pVDesc=pVDesc->next);
5172       if(pVDesc)
5173       {
5174         *rgBstrNames=SysAllocString(pVDesc->Name);
5175         *pcNames=1;
5176       }
5177       else
5178       {
5179         if(This->impltypelist &&
5180            (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
5181           /* recursive search */
5182           ITypeInfo *pTInfo;
5183           HRESULT result;
5184           result=ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef,
5185                                           &pTInfo);
5186           if(SUCCEEDED(result))
5187           {
5188             result=ITypeInfo_GetNames(pTInfo, memid, rgBstrNames, cMaxNames, pcNames);
5189             ITypeInfo_Release(pTInfo);
5190             return result;
5191           }
5192           WARN("Could not search inherited interface!\n");
5193         }
5194         else
5195         {
5196           WARN("no names found\n");
5197         }
5198         *pcNames=0;
5199         return TYPE_E_ELEMENTNOTFOUND;
5200       }
5201     }
5202     return S_OK;
5203 }
5204
5205
5206 /* ITypeInfo::GetRefTypeOfImplType
5207  *
5208  * If a type description describes a COM class, it retrieves the type
5209  * description of the implemented interface types. For an interface,
5210  * GetRefTypeOfImplType returns the type information for inherited interfaces,
5211  * if any exist.
5212  *
5213  */
5214 static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType(
5215         ITypeInfo2 *iface,
5216         UINT index,
5217         HREFTYPE  *pRefType)
5218 {
5219     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5220     int i;
5221     HRESULT hr = S_OK;
5222     const TLBImplType *pImpl = This->impltypelist;
5223
5224     TRACE("(%p) index %d\n", This, index);
5225     if (TRACE_ON(ole)) dump_TypeInfo(This);
5226
5227     if(index==(UINT)-1)
5228     {
5229       /* only valid on dual interfaces;
5230          retrieve the associated TKIND_INTERFACE handle for the current TKIND_DISPATCH
5231       */
5232       if( This->TypeAttr.typekind != TKIND_DISPATCH) return E_INVALIDARG;
5233
5234       if (This->TypeAttr.wTypeFlags & TYPEFLAG_FDISPATCHABLE &&
5235           This->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL )
5236       {
5237         *pRefType = -1;
5238       }
5239       else
5240       {
5241         hr = TYPE_E_ELEMENTNOTFOUND;
5242       }
5243     }
5244     else if(index == 0 && This->TypeAttr.typekind == TKIND_DISPATCH)
5245     {
5246       /* All TKIND_DISPATCHs are made to look like they inherit from IDispatch */
5247       *pRefType = This->pTypeLib->dispatch_href;
5248     }
5249     else
5250     {
5251       /* get element n from linked list */
5252       for(i=0; pImpl && i<index; i++)
5253       {
5254         pImpl = pImpl->next;
5255       }
5256
5257       if (pImpl)
5258         *pRefType = pImpl->hRef;
5259       else
5260         hr = TYPE_E_ELEMENTNOTFOUND;
5261     }
5262
5263     if(TRACE_ON(ole))
5264     {
5265         if(SUCCEEDED(hr))
5266             TRACE("SUCCESS -- hRef = 0x%08x\n", *pRefType );
5267         else
5268             TRACE("FAILURE -- hresult = 0x%08x\n", hr);
5269     }
5270
5271     return hr;
5272 }
5273
5274 /* ITypeInfo::GetImplTypeFlags
5275  *
5276  * Retrieves the IMPLTYPEFLAGS enumeration for one implemented interface
5277  * or base interface in a type description.
5278  */
5279 static HRESULT WINAPI ITypeInfo_fnGetImplTypeFlags( ITypeInfo2 *iface,
5280         UINT index, INT  *pImplTypeFlags)
5281 {
5282     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5283     int i;
5284     TLBImplType *pImpl;
5285
5286     TRACE("(%p) index %d\n", This, index);
5287     for(i=0, pImpl=This->impltypelist; i<index && pImpl;
5288         i++, pImpl=pImpl->next)
5289         ;
5290     if(i==index && pImpl){
5291         *pImplTypeFlags=pImpl->implflags;
5292         return S_OK;
5293     }
5294     *pImplTypeFlags=0;
5295     return TYPE_E_ELEMENTNOTFOUND;
5296 }
5297
5298 /* GetIDsOfNames
5299  * Maps between member names and member IDs, and parameter names and
5300  * parameter IDs.
5301  */
5302 static HRESULT WINAPI ITypeInfo_fnGetIDsOfNames( ITypeInfo2 *iface,
5303         LPOLESTR  *rgszNames, UINT cNames, MEMBERID  *pMemId)
5304 {
5305     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5306     const TLBFuncDesc *pFDesc;
5307     const TLBVarDesc *pVDesc;
5308     HRESULT ret=S_OK;
5309     int i;
5310
5311     TRACE("(%p) Name %s cNames %d\n", This, debugstr_w(*rgszNames),
5312             cNames);
5313
5314     /* init out parameters in case of failure */
5315     for (i = 0; i < cNames; i++)
5316         pMemId[i] = MEMBERID_NIL;
5317
5318     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next) {
5319         int j;
5320         if(!lstrcmpiW(*rgszNames, pFDesc->Name)) {
5321             if(cNames) *pMemId=pFDesc->funcdesc.memid;
5322             for(i=1; i < cNames; i++){
5323                 for(j=0; j<pFDesc->funcdesc.cParams; j++)
5324                     if(!lstrcmpiW(rgszNames[i],pFDesc->pParamDesc[j].Name))
5325                             break;
5326                 if( j<pFDesc->funcdesc.cParams)
5327                     pMemId[i]=j;
5328                 else
5329                    ret=DISP_E_UNKNOWNNAME;
5330             };
5331             TRACE("-- 0x%08x\n", ret);
5332             return ret;
5333         }
5334     }
5335     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) {
5336         if(!lstrcmpiW(*rgszNames, pVDesc->Name)) {
5337             if(cNames) *pMemId=pVDesc->vardesc.memid;
5338             return ret;
5339         }
5340     }
5341     /* not found, see if it can be found in an inherited interface */
5342     if(This->impltypelist) {
5343         /* recursive search */
5344         ITypeInfo *pTInfo;
5345         ret=ITypeInfo_GetRefTypeInfo(iface,
5346                 This->impltypelist->hRef, &pTInfo);
5347         if(SUCCEEDED(ret)){
5348             ret=ITypeInfo_GetIDsOfNames(pTInfo, rgszNames, cNames, pMemId );
5349             ITypeInfo_Release(pTInfo);
5350             return ret;
5351         }
5352         WARN("Could not search inherited interface!\n");
5353     } else
5354         WARN("no names found\n");
5355     return DISP_E_UNKNOWNNAME;
5356 }
5357
5358 /* ITypeInfo::Invoke
5359  *
5360  * Invokes a method, or accesses a property of an object, that implements the
5361  * interface described by the type description.
5362  */
5363 DWORD
5364 _invoke(FARPROC func,CALLCONV callconv, int nrargs, DWORD *args) {
5365     DWORD res;
5366
5367     if (TRACE_ON(ole)) {
5368         int i;
5369         TRACE("Calling %p(",func);
5370         for (i=0;i<nrargs;i++) TRACE("%08x,",args[i]);
5371         TRACE(")\n");
5372     }
5373
5374     switch (callconv) {
5375     case CC_STDCALL:
5376
5377         switch (nrargs) {
5378         case 0:
5379                 res = func();
5380                 break;
5381         case 1:
5382                 res = func(args[0]);
5383                 break;
5384         case 2:
5385                 res = func(args[0],args[1]);
5386                 break;
5387         case 3:
5388                 res = func(args[0],args[1],args[2]);
5389                 break;
5390         case 4:
5391                 res = func(args[0],args[1],args[2],args[3]);
5392                 break;
5393         case 5:
5394                 res = func(args[0],args[1],args[2],args[3],args[4]);
5395                 break;
5396         case 6:
5397                 res = func(args[0],args[1],args[2],args[3],args[4],args[5]);
5398                 break;
5399         case 7:
5400                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
5401                 break;
5402         case 8:
5403                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]);
5404                 break;
5405         case 9:
5406                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]);
5407                 break;
5408         case 10:
5409                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9]);
5410                 break;
5411         case 11:
5412                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10]);
5413                 break;
5414         case 12:
5415                 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]);
5416                 break;
5417         case 13:
5418                 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]);
5419                 break;
5420         case 14:
5421                 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]);
5422                 break;
5423         case 15:
5424                 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]);
5425                 break;
5426         case 16:
5427                 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]);
5428                 break;
5429         case 17:
5430                 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]);
5431                 break;
5432         case 18:
5433                 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]);
5434                 break;
5435         case 19:
5436                 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]);
5437                 break;
5438         case 20:
5439                 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]);
5440                 break;
5441         case 21:
5442                 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]);
5443                 break;
5444         case 22:
5445                 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]);
5446                 break;
5447         case 23:
5448                 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]);
5449                 break;
5450         case 24:
5451                 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]);
5452                 break;
5453         case 25:
5454                 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]);
5455                 break;
5456         case 26:
5457                 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]);
5458                 break;
5459         case 27:
5460                 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]);
5461                 break;
5462         case 28:
5463                 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]);
5464                 break;
5465         case 29:
5466                 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]);
5467                 break;
5468         case 30:
5469                 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]);
5470                 break;
5471         default:
5472                 FIXME("unsupported number of arguments %d in stdcall\n",nrargs);
5473                 res = -1;
5474                 break;
5475         }
5476         break;
5477     default:
5478         FIXME("unsupported calling convention %d\n",callconv);
5479         res = -1;
5480         break;
5481     }
5482     TRACE("returns %08x\n",res);
5483     return res;
5484 }
5485
5486 extern int _argsize(DWORD vt);
5487
5488 static HRESULT userdefined_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
5489 {
5490     HRESULT hr = S_OK;
5491     ITypeInfo *tinfo2 = NULL;
5492     TYPEATTR *tattr = NULL;
5493
5494     hr = ITypeInfo_GetRefTypeInfo(tinfo, tdesc->u.hreftype, &tinfo2);
5495     if (hr)
5496     {
5497         ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED, "
5498             "hr = 0x%08x\n",
5499               tdesc->u.hreftype, hr);
5500         return hr;
5501     }
5502     hr = ITypeInfo_GetTypeAttr(tinfo2, &tattr);
5503     if (hr)
5504     {
5505         ERR("ITypeInfo_GetTypeAttr failed, hr = 0x%08x\n", hr);
5506         ITypeInfo_Release(tinfo2);
5507         return hr;
5508     }
5509
5510     switch (tattr->typekind)
5511     {
5512     case TKIND_ENUM:
5513         *vt |= VT_I4;
5514         break;
5515
5516     case TKIND_ALIAS:
5517         tdesc = &tattr->tdescAlias;
5518         hr = typedescvt_to_variantvt(tinfo2, &tattr->tdescAlias, vt);
5519         break;
5520
5521     case TKIND_INTERFACE:
5522         if (tattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE)
5523            *vt |= VT_DISPATCH;
5524         else
5525            *vt |= VT_UNKNOWN;
5526         break;
5527
5528     case TKIND_DISPATCH:
5529         *vt |= VT_DISPATCH;
5530         break;
5531
5532     case TKIND_COCLASS:
5533         *vt |= VT_DISPATCH;
5534         break;
5535
5536     case TKIND_RECORD:
5537         FIXME("TKIND_RECORD unhandled.\n");
5538         hr = E_NOTIMPL;
5539         break;
5540
5541     case TKIND_UNION:
5542         FIXME("TKIND_UNION unhandled.\n");
5543         hr = E_NOTIMPL;
5544         break;
5545
5546     default:
5547         FIXME("TKIND %d unhandled.\n",tattr->typekind);
5548         hr = E_NOTIMPL;
5549         break;
5550     }
5551     ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
5552     ITypeInfo_Release(tinfo2);
5553     return hr;
5554 }
5555
5556 static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
5557 {
5558     HRESULT hr = S_OK;
5559
5560     /* enforce only one level of pointer indirection */
5561     if (!(*vt & VT_BYREF) && !(*vt & VT_ARRAY) && (tdesc->vt == VT_PTR))
5562     {
5563         tdesc = tdesc->u.lptdesc;
5564
5565         /* munch VT_PTR -> VT_USERDEFINED(interface) into VT_UNKNOWN or
5566          * VT_DISPATCH and VT_PTR -> VT_PTR -> VT_USERDEFINED(interface) into 
5567          * VT_BYREF|VT_DISPATCH or VT_BYREF|VT_UNKNOWN */
5568         if ((tdesc->vt == VT_USERDEFINED) ||
5569             ((tdesc->vt == VT_PTR) && (tdesc->u.lptdesc->vt == VT_USERDEFINED)))
5570         {
5571             VARTYPE vt_userdefined = 0;
5572             const TYPEDESC *tdesc_userdefined = tdesc;
5573             if (tdesc->vt == VT_PTR)
5574             {
5575                 vt_userdefined = VT_BYREF;
5576                 tdesc_userdefined = tdesc->u.lptdesc;
5577             }
5578             hr = userdefined_to_variantvt(tinfo, tdesc_userdefined, &vt_userdefined);
5579             if ((hr == S_OK) && 
5580                 (((vt_userdefined & VT_TYPEMASK) == VT_UNKNOWN) ||
5581                  ((vt_userdefined & VT_TYPEMASK) == VT_DISPATCH)))
5582             {
5583                 *vt |= vt_userdefined;
5584                 return S_OK;
5585             }
5586         }
5587         *vt = VT_BYREF;
5588     }
5589
5590     switch (tdesc->vt)
5591     {
5592     case VT_HRESULT:
5593         *vt |= VT_ERROR;
5594         break;
5595     case VT_USERDEFINED:
5596         hr = userdefined_to_variantvt(tinfo, tdesc, vt);
5597         break;
5598     case VT_VOID:
5599     case VT_CARRAY:
5600     case VT_PTR:
5601     case VT_LPSTR:
5602     case VT_LPWSTR:
5603         ERR("cannot convert type %d into variant VT\n", tdesc->vt);
5604         hr = DISP_E_BADVARTYPE;
5605         break;
5606     case VT_SAFEARRAY:
5607         *vt |= VT_ARRAY;
5608         hr = typedescvt_to_variantvt(tinfo, tdesc->u.lptdesc, vt);
5609         break;
5610     default:
5611         *vt |= tdesc->vt;
5612         break;
5613     }
5614     return hr;
5615 }
5616
5617 /***********************************************************************
5618  *              DispCallFunc (OLEAUT32.@)
5619  *
5620  * Invokes a function of the specified calling convention, passing the
5621  * specified arguments and returns the result.
5622  *
5623  * PARAMS
5624  *  pvInstance  [I] Optional pointer to the instance whose function to invoke.
5625  *  oVft        [I] The offset in the vtable. See notes.
5626  *  cc          [I] Calling convention of the function to call.
5627  *  vtReturn    [I] The return type of the function.
5628  *  cActuals    [I] Number of parameters.
5629  *  prgvt       [I] The types of the parameters to pass. This is used for sizing only.
5630  *  prgpvarg    [I] The arguments to pass.
5631  *  pvargResult [O] The return value of the function. Can be NULL.
5632  *
5633  * RETURNS
5634  *  Success: S_OK.
5635  *  Failure: HRESULT code.
5636  *
5637  * NOTES
5638  *  The HRESULT return value of this function is not affected by the return
5639  *  value of the user supplied function, which is returned in pvargResult.
5640  *
5641  *  If pvInstance is NULL then a non-object function is to be called and oVft
5642  *  is the address of the function to call.
5643  *
5644  * The cc parameter can be one of the following values:
5645  *|CC_FASTCALL
5646  *|CC_CDECL
5647  *|CC_PASCAL
5648  *|CC_STDCALL
5649  *|CC_FPFASTCALL
5650  *|CC_SYSCALL
5651  *|CC_MPWCDECL
5652  *|CC_MPWPASCAL
5653  *
5654  */
5655 HRESULT WINAPI
5656 DispCallFunc(
5657     void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals,
5658     VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult)
5659 {
5660     int i, argsize, argspos;
5661     DWORD *args;
5662     HRESULT hres;
5663
5664     TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
5665         pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
5666         pvargResult, V_VT(pvargResult));
5667
5668     argsize = 0;
5669     if (pvInstance)
5670         argsize++; /* for This pointer */
5671
5672     for (i=0;i<cActuals;i++)
5673     {
5674         TRACE("arg %d: type %d, size %d\n",i,prgvt[i],_argsize(prgvt[i]));
5675         dump_Variant(prgpvarg[i]);
5676         argsize += _argsize(prgvt[i]);
5677     }
5678     args = HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*argsize);
5679
5680     argspos = 0;
5681     if (pvInstance)
5682     {
5683         args[0] = (DWORD)pvInstance; /* the This pointer is always the first parameter */
5684         argspos++;
5685     }
5686
5687     for (i=0;i<cActuals;i++)
5688     {
5689         VARIANT *arg = prgpvarg[i];
5690         TRACE("Storing arg %d (%d as %d)\n",i,V_VT(arg),prgvt[i]);
5691         if (prgvt[i] == VT_VARIANT)
5692             memcpy(&args[argspos], arg, _argsize(prgvt[i]) * sizeof(DWORD));
5693         else
5694             memcpy(&args[argspos], &V_NONE(arg), _argsize(prgvt[i]) * sizeof(DWORD));
5695         argspos += _argsize(prgvt[i]);
5696     }
5697
5698     if (pvInstance)
5699     {
5700         FARPROC *vtable = *(FARPROC**)pvInstance;
5701         hres = _invoke(vtable[oVft/sizeof(void *)], cc, argsize, args);
5702     }
5703     else
5704         /* if we aren't invoking an object then the function pointer is stored
5705          * in oVft */
5706         hres = _invoke((FARPROC)oVft, cc, argsize, args);
5707
5708     if (pvargResult && (vtReturn != VT_EMPTY))
5709     {
5710         TRACE("Method returned 0x%08x\n",hres);
5711         V_VT(pvargResult) = vtReturn;
5712         V_UI4(pvargResult) = hres;
5713     }
5714
5715     HeapFree(GetProcessHeap(),0,args);
5716     return S_OK;
5717 }
5718
5719 #define INVBUF_ELEMENT_SIZE \
5720     (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *) + sizeof(VARTYPE))
5721 #define INVBUF_GET_ARG_ARRAY(buffer, params) \
5722     ((VARIANTARG *)(buffer))
5723 #define INVBUF_GET_MISSING_ARG_ARRAY(buffer, params) \
5724     ((VARIANTARG *)((char *)(buffer) + sizeof(VARIANTARG) * (params)))
5725 #define INVBUF_GET_ARG_PTR_ARRAY(buffer, params) \
5726     ((VARIANTARG **)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG)) * (params)))
5727 #define INVBUF_GET_ARG_TYPE_ARRAY(buffer, params) \
5728     ((VARTYPE *)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *)) * (params)))
5729
5730 static HRESULT WINAPI ITypeInfo_fnInvoke(
5731     ITypeInfo2 *iface,
5732     VOID  *pIUnk,
5733     MEMBERID memid,
5734     UINT16 wFlags,
5735     DISPPARAMS  *pDispParams,
5736     VARIANT  *pVarResult,
5737     EXCEPINFO  *pExcepInfo,
5738     UINT  *pArgErr)
5739 {
5740     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5741     int i;
5742     unsigned int var_index;
5743     TYPEKIND type_kind;
5744     HRESULT hres;
5745     const TLBFuncDesc *pFuncInfo;
5746
5747     TRACE("(%p)(%p,id=%d,flags=0x%08x,%p,%p,%p,%p)\n",
5748       This,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr
5749     );
5750
5751     if (!pDispParams)
5752     {
5753         ERR("NULL pDispParams not allowed\n");
5754         return E_INVALIDARG;
5755     }
5756
5757     dump_DispParms(pDispParams);
5758
5759     if (pDispParams->cNamedArgs > pDispParams->cArgs)
5760     {
5761         ERR("named argument array cannot be bigger than argument array (%d/%d)\n",
5762             pDispParams->cNamedArgs, pDispParams->cArgs);
5763         return E_INVALIDARG;
5764     }
5765
5766     /* we do this instead of using GetFuncDesc since it will return a fake
5767      * FUNCDESC for dispinterfaces and we want the real function description */
5768     for (pFuncInfo = This->funclist; pFuncInfo; pFuncInfo=pFuncInfo->next)
5769         if ((memid == pFuncInfo->funcdesc.memid) &&
5770             (wFlags & pFuncInfo->funcdesc.invkind))
5771             break;
5772
5773     if (pFuncInfo) {
5774         const FUNCDESC *func_desc = &pFuncInfo->funcdesc;
5775
5776         if (TRACE_ON(ole))
5777         {
5778             TRACE("invoking:\n");
5779             dump_TLBFuncDescOne(pFuncInfo);
5780         }
5781         
5782         switch (func_desc->funckind) {
5783         case FUNC_PUREVIRTUAL:
5784         case FUNC_VIRTUAL: {
5785             void *buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INVBUF_ELEMENT_SIZE * func_desc->cParams);
5786             VARIANT varresult;
5787             VARIANT retval; /* pointer for storing byref retvals in */
5788             VARIANTARG **prgpvarg = INVBUF_GET_ARG_PTR_ARRAY(buffer, func_desc->cParams);
5789             VARIANTARG *rgvarg = INVBUF_GET_ARG_ARRAY(buffer, func_desc->cParams);
5790             VARTYPE *rgvt = INVBUF_GET_ARG_TYPE_ARRAY(buffer, func_desc->cParams);
5791             UINT cNamedArgs = pDispParams->cNamedArgs;
5792             DISPID *rgdispidNamedArgs = pDispParams->rgdispidNamedArgs;
5793
5794             hres = S_OK;
5795
5796             if (func_desc->invkind & (INVOKE_PROPERTYPUT|INVOKE_PROPERTYPUTREF))
5797             {
5798                 if (!cNamedArgs || (rgdispidNamedArgs[0] != DISPID_PROPERTYPUT))
5799                 {
5800                     ERR("first named arg for property put invocation must be DISPID_PROPERTYPUT\n");
5801                     hres = DISP_E_PARAMNOTFOUND;
5802                     goto func_fail;
5803                 }
5804                 /* ignore the DISPID_PROPERTYPUT named argument from now on */
5805                 cNamedArgs--;
5806                 rgdispidNamedArgs++;
5807             }
5808
5809             if (func_desc->cParamsOpt < 0 && cNamedArgs)
5810             {
5811                 ERR("functions with the vararg attribute do not support named arguments\n");
5812                 hres = DISP_E_NONAMEDARGS;
5813                 goto func_fail;
5814             }
5815
5816             for (i = 0; i < func_desc->cParams; i++)
5817             {
5818                 TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc;
5819                 hres = typedescvt_to_variantvt((ITypeInfo *)iface, tdesc, &rgvt[i]);
5820                 if (FAILED(hres))
5821                     goto func_fail;
5822             }
5823
5824             TRACE("changing args\n");
5825             for (i = 0; i < func_desc->cParams; i++)
5826             {
5827                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
5828                 VARIANTARG *src_arg;
5829
5830                 if (cNamedArgs)
5831                 {
5832                     USHORT j;
5833                     src_arg = NULL;
5834                     for (j = 0; j < cNamedArgs; j++)
5835                         if (rgdispidNamedArgs[j] == i)
5836                         {
5837                             src_arg = &pDispParams->rgvarg[j];
5838                             break;
5839                         }
5840                 }
5841                 else
5842                     src_arg = i < pDispParams->cArgs ? &pDispParams->rgvarg[pDispParams->cArgs - 1 - i] : NULL;
5843
5844                 if (wParamFlags & PARAMFLAG_FRETVAL)
5845                 {
5846                     /* under most conditions the caller is not allowed to
5847                      * pass in a dispparam arg in the index of what would be
5848                      * the retval parameter. however, there is an exception
5849                      * where the extra parameter is used in an extra
5850                      * IDispatch::Invoke below */
5851                     if ((i < pDispParams->cArgs) &&
5852                         ((func_desc->cParams != 1) || !pVarResult ||
5853                          !(func_desc->invkind & INVOKE_PROPERTYGET)))
5854                     {
5855                         hres = DISP_E_BADPARAMCOUNT;
5856                         break;
5857                     }
5858
5859                     /* note: this check is placed so that if the caller passes
5860                      * in a VARIANTARG for the retval we just ignore it, like
5861                      * native does */
5862                     if (i == func_desc->cParams - 1)
5863                     {
5864                         VARIANTARG *arg;
5865                         arg = prgpvarg[i] = &rgvarg[i];
5866                         memset(arg, 0, sizeof(*arg));
5867                         V_VT(arg) = rgvt[i];
5868                         memset(&retval, 0, sizeof(retval));
5869                         V_BYREF(arg) = &retval;
5870                     }
5871                     else
5872                     {
5873                         ERR("[retval] parameter must be the last parameter of the method (%d/%d)\n", i, func_desc->cParams);
5874                         hres = E_UNEXPECTED;
5875                         break;
5876                     }
5877                 }
5878                 else if (src_arg)
5879                 {
5880                     dump_Variant(src_arg);
5881
5882                     if (rgvt[i] == VT_VARIANT)
5883                         hres = VariantCopy(&rgvarg[i], src_arg);
5884                     else if (rgvt[i] == (VT_VARIANT | VT_BYREF))
5885                     {
5886                         if (rgvt[i] == V_VT(src_arg))
5887                             V_VARIANTREF(&rgvarg[i]) = V_VARIANTREF(src_arg);
5888                         else
5889                         {
5890                             VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
5891                             hres = VariantCopy(&missing_arg[i], src_arg);
5892                             V_VARIANTREF(&rgvarg[i]) = &missing_arg[i];
5893                         }
5894                         V_VT(&rgvarg[i]) = rgvt[i];
5895                     }
5896                     else if (rgvt[i] == (VT_VARIANT | VT_ARRAY) && func_desc->cParamsOpt < 0 && i == func_desc->cParams-1)
5897                     {
5898                         SAFEARRAY *a;
5899                         SAFEARRAYBOUND bound;
5900                         VARIANT *v;
5901                         LONG j;
5902                         bound.lLbound = 0;
5903                         bound.cElements = pDispParams->cArgs-i;
5904                         if (!(a = SafeArrayCreate(VT_VARIANT, 1, &bound)))
5905                         {
5906                             ERR("SafeArrayCreate failed\n");
5907                             break;
5908                         }
5909                         hres = SafeArrayAccessData(a, (LPVOID)&v);
5910                         if (hres != S_OK)
5911                         {
5912                             ERR("SafeArrayAccessData failed with %x\n", hres);
5913                             break;
5914                         }
5915                         for (j = 0; j < bound.cElements; j++)
5916                             VariantCopy(&v[j], &pDispParams->rgvarg[pDispParams->cArgs - 1 - i - j]);
5917                         hres = SafeArrayUnaccessData(a);
5918                         if (hres != S_OK)
5919                         {
5920                             ERR("SafeArrayUnaccessData failed with %x\n", hres);
5921                             break;
5922                         }
5923                         V_ARRAY(&rgvarg[i]) = a;
5924                         V_VT(&rgvarg[i]) = rgvt[i];
5925                     }
5926                     else if ((rgvt[i] & VT_BYREF) && !V_ISBYREF(src_arg))
5927                     {
5928                         VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
5929                         V_VT(&missing_arg[i]) = V_VT(src_arg);
5930                         hres = VariantChangeType(&missing_arg[i], src_arg, 0, rgvt[i] & ~VT_BYREF);
5931                         V_BYREF(&rgvarg[i]) = &V_NONE(&missing_arg[i]);
5932                         V_VT(&rgvarg[i]) = rgvt[i];
5933                     }
5934                     else if ((rgvt[i] & VT_BYREF) && (rgvt[i] == V_VT(src_arg)))
5935                     {
5936                         V_BYREF(&rgvarg[i]) = V_BYREF(src_arg);
5937                         V_VT(&rgvarg[i]) = rgvt[i];
5938                     }
5939                     else
5940                     {
5941                         /* FIXME: this doesn't work for VT_BYREF arguments if
5942                          * they are not the same type as in the paramdesc */
5943                         V_VT(&rgvarg[i]) = V_VT(src_arg);
5944                         hres = VariantChangeType(&rgvarg[i], src_arg, 0, rgvt[i]);
5945                         V_VT(&rgvarg[i]) = rgvt[i];
5946                     }
5947
5948                     if (FAILED(hres))
5949                     {
5950                         ERR("failed to convert param %d to %s%s from %s%s\n", i,
5951                             debugstr_vt(rgvt[i]), debugstr_vf(rgvt[i]),
5952                             debugstr_VT(src_arg), debugstr_VF(src_arg));
5953                         break;
5954                     }
5955                     prgpvarg[i] = &rgvarg[i];
5956                 }
5957                 else if (wParamFlags & PARAMFLAG_FOPT)
5958                 {
5959                     VARIANTARG *arg;
5960                     arg = prgpvarg[i] = &rgvarg[i];
5961                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
5962                     {
5963                         hres = VariantCopy(arg, &func_desc->lprgelemdescParam[i].u.paramdesc.pparamdescex->varDefaultValue);
5964                         if (FAILED(hres))
5965                             break;
5966                     }
5967                     else
5968                     {
5969                         VARIANTARG *missing_arg;
5970                         /* if the function wants a pointer to a variant then
5971                          * set that up, otherwise just pass the VT_ERROR in
5972                          * the argument by value */
5973                         if (rgvt[i] & VT_BYREF)
5974                         {
5975                             missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams) + i;
5976                             V_VT(arg) = VT_VARIANT | VT_BYREF;
5977                             V_VARIANTREF(arg) = missing_arg;
5978                         }
5979                         else
5980                             missing_arg = arg;
5981                         V_VT(missing_arg) = VT_ERROR;
5982                         V_ERROR(missing_arg) = DISP_E_PARAMNOTFOUND;
5983                     }
5984                 }
5985                 else
5986                 {
5987                     hres = DISP_E_BADPARAMCOUNT;
5988                     break;
5989                 }
5990             }
5991             if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
5992
5993             /* VT_VOID is a special case for return types, so it is not
5994              * handled in the general function */
5995             if (func_desc->elemdescFunc.tdesc.vt == VT_VOID)
5996                 V_VT(&varresult) = VT_EMPTY;
5997             else
5998             {
5999                 V_VT(&varresult) = 0;
6000                 hres = typedescvt_to_variantvt((ITypeInfo *)iface, &func_desc->elemdescFunc.tdesc, &V_VT(&varresult));
6001                 if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
6002             }
6003
6004             hres = DispCallFunc(pIUnk, func_desc->oVft, func_desc->callconv,
6005                                 V_VT(&varresult), func_desc->cParams, rgvt,
6006                                 prgpvarg, &varresult);
6007
6008             for (i = 0; i < func_desc->cParams; i++)
6009             {
6010                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
6011                 if (wParamFlags & PARAMFLAG_FRETVAL)
6012                 {
6013                     if (TRACE_ON(ole))
6014                     {
6015                         TRACE("[retval] value: ");
6016                         dump_Variant(prgpvarg[i]);
6017                     }
6018
6019                     if (pVarResult)
6020                     {
6021                         VariantInit(pVarResult);
6022                         /* deref return value */
6023                         hres = VariantCopyInd(pVarResult, prgpvarg[i]);
6024                     }
6025
6026                     /* free data stored in varresult. Note that
6027                      * VariantClear doesn't do what we want because we are
6028                      * working with byref types. */
6029                     /* FIXME: clear safearrays, bstrs, records and
6030                      * variants here too */
6031                     if ((V_VT(prgpvarg[i]) == (VT_UNKNOWN | VT_BYREF)) ||
6032                          (V_VT(prgpvarg[i]) == (VT_DISPATCH | VT_BYREF)))
6033                     {
6034                         if(*V_UNKNOWNREF(prgpvarg[i]))
6035                             IUnknown_Release(*V_UNKNOWNREF(prgpvarg[i]));
6036                     }
6037                     break;
6038                 }
6039                 else if (i < pDispParams->cArgs)
6040                 {
6041                     if (wParamFlags & PARAMFLAG_FOUT)
6042                     {
6043                         VARIANTARG *arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - i];
6044
6045                         if ((rgvt[i] == VT_BYREF) && (V_VT(arg) != VT_BYREF))
6046                             hres = VariantChangeType(arg, &rgvarg[i], 0, V_VT(arg));
6047
6048                         if (FAILED(hres))
6049                         {
6050                             ERR("failed to convert param %d to vt %d\n", i,
6051                                 V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1 - i]));
6052                             break;
6053                         }
6054                     }
6055                     else if (V_VT(prgpvarg[i]) == (VT_VARIANT | VT_ARRAY) &&
6056                              func_desc->cParamsOpt < 0 &&
6057                              i == func_desc->cParams-1)
6058                     {
6059                         SAFEARRAY *a = V_ARRAY(prgpvarg[i]);
6060                         LONG j, ubound;
6061                         VARIANT *v;
6062                         hres = SafeArrayGetUBound(a, 1, &ubound);
6063                         if (hres != S_OK)
6064                         {
6065                             ERR("SafeArrayGetUBound failed with %x\n", hres);
6066                             break;
6067                         }
6068                         hres = SafeArrayAccessData(a, (LPVOID)&v);
6069                         if (hres != S_OK)
6070                         {
6071                             ERR("SafeArrayAccessData failed with %x\n", hres);
6072                             break;
6073                         }
6074                         for (j = 0; j <= ubound; j++)
6075                             VariantClear(&v[j]);
6076                         hres = SafeArrayUnaccessData(a);
6077                         if (hres != S_OK)
6078                         {
6079                             ERR("SafeArrayUnaccessData failed with %x\n", hres);
6080                             break;
6081                         }
6082                     }
6083                     VariantClear(&rgvarg[i]);
6084                 }
6085                 else if (wParamFlags & PARAMFLAG_FOPT)
6086                 {
6087                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
6088                         VariantClear(&rgvarg[i]);
6089                 }
6090             }
6091
6092             if ((V_VT(&varresult) == VT_ERROR) && FAILED(V_ERROR(&varresult)))
6093             {
6094                 WARN("invoked function failed with error 0x%08x\n", V_ERROR(&varresult));
6095                 hres = DISP_E_EXCEPTION;
6096                 if (pExcepInfo)
6097                 {
6098                     IErrorInfo *pErrorInfo;
6099                     pExcepInfo->scode = V_ERROR(&varresult);
6100                     if (GetErrorInfo(0, &pErrorInfo) == S_OK)
6101                     {
6102                         IErrorInfo_GetDescription(pErrorInfo, &pExcepInfo->bstrDescription);
6103                         IErrorInfo_GetHelpFile(pErrorInfo, &pExcepInfo->bstrHelpFile);
6104                         IErrorInfo_GetSource(pErrorInfo, &pExcepInfo->bstrSource);
6105                         IErrorInfo_GetHelpContext(pErrorInfo, &pExcepInfo->dwHelpContext);
6106
6107                         IErrorInfo_Release(pErrorInfo);
6108                     }
6109                 }
6110             }
6111             if (V_VT(&varresult) != VT_ERROR)
6112             {
6113                 TRACE("varresult value: ");
6114                 dump_Variant(&varresult);
6115
6116                 if (pVarResult)
6117                 {
6118                     VariantClear(pVarResult);
6119                     *pVarResult = varresult;
6120                 }
6121                 else
6122                     VariantClear(&varresult);
6123             }
6124
6125             if (SUCCEEDED(hres) && pVarResult && (func_desc->cParams == 1) &&
6126                 (func_desc->invkind & INVOKE_PROPERTYGET) &&
6127                 (func_desc->lprgelemdescParam[0].u.paramdesc.wParamFlags & PARAMFLAG_FRETVAL) &&
6128                 (pDispParams->cArgs != 0))
6129             {
6130                 if (V_VT(pVarResult) == VT_DISPATCH)
6131                 {
6132                     IDispatch *pDispatch = V_DISPATCH(pVarResult);
6133                     /* Note: not VariantClear; we still need the dispatch
6134                      * pointer to be valid */
6135                     VariantInit(pVarResult);
6136                     hres = IDispatch_Invoke(pDispatch, DISPID_VALUE, &IID_NULL,
6137                         GetSystemDefaultLCID(), INVOKE_PROPERTYGET,
6138                         pDispParams, pVarResult, pExcepInfo, pArgErr);
6139                     IDispatch_Release(pDispatch);
6140                 }
6141                 else
6142                 {
6143                     VariantClear(pVarResult);
6144                     hres = DISP_E_NOTACOLLECTION;
6145                 }
6146             }
6147
6148 func_fail:
6149             HeapFree(GetProcessHeap(), 0, buffer);
6150             break;
6151         }
6152         case FUNC_DISPATCH:  {
6153            IDispatch *disp;
6154
6155            hres = IUnknown_QueryInterface((LPUNKNOWN)pIUnk,&IID_IDispatch,(LPVOID*)&disp);
6156            if (SUCCEEDED(hres)) {
6157                FIXME("Calling Invoke in IDispatch iface. untested!\n");
6158                hres = IDispatch_Invoke(
6159                                      disp,memid,&IID_NULL,LOCALE_USER_DEFAULT,wFlags,pDispParams,
6160                                      pVarResult,pExcepInfo,pArgErr
6161                                      );
6162                if (FAILED(hres))
6163                    FIXME("IDispatch::Invoke failed with %08x. (Could be not a real error?)\n", hres);
6164                IDispatch_Release(disp);
6165            } else
6166                FIXME("FUNC_DISPATCH used on object without IDispatch iface?\n");
6167            break;
6168         }
6169         default:
6170             FIXME("Unknown function invocation type %d\n", func_desc->funckind);
6171             hres = E_FAIL;
6172             break;
6173         }
6174
6175         TRACE("-- 0x%08x\n", hres);
6176         return hres;
6177
6178     } else if(SUCCEEDED(hres = ITypeInfo2_GetVarIndexOfMemId(iface, memid, &var_index))) {
6179         VARDESC *var_desc;
6180
6181         hres = ITypeInfo2_GetVarDesc(iface, var_index, &var_desc);
6182         if(FAILED(hres)) return hres;
6183         
6184         FIXME("varseek: Found memid, but variable-based invoking not supported\n");
6185         dump_VARDESC(var_desc);
6186         ITypeInfo2_ReleaseVarDesc(iface, var_desc);
6187         return E_NOTIMPL;
6188     }
6189
6190     /* not found, look for it in inherited interfaces */
6191     ITypeInfo2_GetTypeKind(iface, &type_kind);
6192     if(type_kind == TKIND_INTERFACE || type_kind == TKIND_DISPATCH) {
6193         if(This->impltypelist) {
6194             /* recursive search */
6195             ITypeInfo *pTInfo;
6196             hres = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef, &pTInfo);
6197             if(SUCCEEDED(hres)){
6198                 hres = ITypeInfo_Invoke(pTInfo,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr);
6199                 ITypeInfo_Release(pTInfo);
6200                 return hres;
6201             }
6202             WARN("Could not search inherited interface!\n");
6203         }
6204     }
6205     ERR("did not find member id %d, flags 0x%x!\n", memid, wFlags);
6206     return DISP_E_MEMBERNOTFOUND;
6207 }
6208
6209 /* ITypeInfo::GetDocumentation
6210  *
6211  * Retrieves the documentation string, the complete Help file name and path,
6212  * and the context ID for the Help topic for a specified type description.
6213  *
6214  * (Can be tested by the Visual Basic Editor in Word for instance.)
6215  */
6216 static HRESULT WINAPI ITypeInfo_fnGetDocumentation( ITypeInfo2 *iface,
6217         MEMBERID memid, BSTR  *pBstrName, BSTR  *pBstrDocString,
6218         DWORD  *pdwHelpContext, BSTR  *pBstrHelpFile)
6219 {
6220     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6221     const TLBFuncDesc *pFDesc;
6222     const TLBVarDesc *pVDesc;
6223     TRACE("(%p) memid %d Name(%p) DocString(%p)"
6224           " HelpContext(%p) HelpFile(%p)\n",
6225         This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
6226     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
6227         if(pBstrName)
6228             *pBstrName=SysAllocString(This->Name);
6229         if(pBstrDocString)
6230             *pBstrDocString=SysAllocString(This->DocString);
6231         if(pdwHelpContext)
6232             *pdwHelpContext=This->dwHelpContext;
6233         if(pBstrHelpFile)
6234             *pBstrHelpFile=SysAllocString(This->DocString);/* FIXME */
6235         return S_OK;
6236     }else {/* for a member */
6237     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
6238         if(pFDesc->funcdesc.memid==memid){
6239           if(pBstrName)
6240             *pBstrName = SysAllocString(pFDesc->Name);
6241           if(pBstrDocString)
6242             *pBstrDocString=SysAllocString(pFDesc->HelpString);
6243           if(pdwHelpContext)
6244             *pdwHelpContext=pFDesc->helpcontext;
6245           return S_OK;
6246         }
6247     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
6248         if(pVDesc->vardesc.memid==memid){
6249             if(pBstrName)
6250               *pBstrName = SysAllocString(pVDesc->Name);
6251             if(pBstrDocString)
6252               *pBstrDocString=SysAllocString(pVDesc->HelpString);
6253             if(pdwHelpContext)
6254               *pdwHelpContext=pVDesc->HelpContext;
6255             return S_OK;
6256         }
6257     }
6258
6259     if(This->impltypelist &&
6260        (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
6261         /* recursive search */
6262         ITypeInfo *pTInfo;
6263         HRESULT result;
6264         result = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef,
6265                                         &pTInfo);
6266         if(SUCCEEDED(result)) {
6267             result = ITypeInfo_GetDocumentation(pTInfo, memid, pBstrName,
6268                 pBstrDocString, pdwHelpContext, pBstrHelpFile);
6269             ITypeInfo_Release(pTInfo);
6270             return result;
6271         }
6272         WARN("Could not search inherited interface!\n");
6273     }
6274
6275     WARN("member %d not found\n", memid);
6276     return TYPE_E_ELEMENTNOTFOUND;
6277 }
6278
6279 /*  ITypeInfo::GetDllEntry
6280  *
6281  * Retrieves a description or specification of an entry point for a function
6282  * in a DLL.
6283  */
6284 static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid,
6285         INVOKEKIND invKind, BSTR  *pBstrDllName, BSTR  *pBstrName,
6286         WORD  *pwOrdinal)
6287 {
6288     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6289     const TLBFuncDesc *pFDesc;
6290
6291     TRACE("(%p)->(memid %x, %d, %p, %p, %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
6292
6293     if (pBstrDllName) *pBstrDllName = NULL;
6294     if (pBstrName) *pBstrName = NULL;
6295     if (pwOrdinal) *pwOrdinal = 0;
6296
6297     if (This->TypeAttr.typekind != TKIND_MODULE)
6298         return TYPE_E_BADMODULEKIND;
6299
6300     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
6301         if(pFDesc->funcdesc.memid==memid){
6302             dump_TypeInfo(This);
6303             if (TRACE_ON(ole))
6304                 dump_TLBFuncDescOne(pFDesc);
6305
6306             if (pBstrDllName)
6307                 *pBstrDllName = SysAllocString(This->DllName);
6308
6309             if (HIWORD(pFDesc->Entry) && (pFDesc->Entry != (void*)-1)) {
6310                 if (pBstrName)
6311                     *pBstrName = SysAllocString(pFDesc->Entry);
6312                 if (pwOrdinal)
6313                     *pwOrdinal = -1;
6314                 return S_OK;
6315             }
6316             if (pBstrName)
6317                 *pBstrName = NULL;
6318             if (pwOrdinal)
6319                 *pwOrdinal = (DWORD)pFDesc->Entry;
6320             return S_OK;
6321         }
6322     return TYPE_E_ELEMENTNOTFOUND;
6323 }
6324
6325 /* internal function to make the inherited interfaces' methods appear
6326  * part of the interface */
6327 static HRESULT ITypeInfoImpl_GetDispatchRefTypeInfo( ITypeInfo *iface,
6328     HREFTYPE *hRefType, ITypeInfo  **ppTInfo)
6329 {
6330     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6331     HRESULT hr;
6332
6333     TRACE("%p, 0x%x\n", iface, *hRefType);
6334
6335     if (This->impltypelist && (*hRefType & DISPATCH_HREF_MASK))
6336     {
6337         ITypeInfo *pSubTypeInfo;
6338
6339         hr = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef, &pSubTypeInfo);
6340         if (FAILED(hr))
6341             return hr;
6342
6343         hr = ITypeInfoImpl_GetDispatchRefTypeInfo(pSubTypeInfo,
6344                                                   hRefType, ppTInfo);
6345         ITypeInfo_Release(pSubTypeInfo);
6346         if (SUCCEEDED(hr))
6347             return hr;
6348     }
6349     *hRefType -= DISPATCH_HREF_OFFSET;
6350
6351     if (!(*hRefType & DISPATCH_HREF_MASK))
6352         return ITypeInfo_GetRefTypeInfo(iface, *hRefType, ppTInfo);
6353     else
6354         return E_FAIL;
6355 }
6356
6357 /* ITypeInfo::GetRefTypeInfo
6358  *
6359  * If a type description references other type descriptions, it retrieves
6360  * the referenced type descriptions.
6361  */
6362 static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo(
6363         ITypeInfo2 *iface,
6364         HREFTYPE hRefType,
6365         ITypeInfo  **ppTInfo)
6366 {
6367     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6368     HRESULT result = E_FAIL;
6369
6370     if ((This->hreftype != -1) && (This->hreftype == hRefType))
6371     {
6372         *ppTInfo = (ITypeInfo *)&This->lpVtbl;
6373         ITypeInfo_AddRef(*ppTInfo);
6374         result = S_OK;
6375     }
6376     else if (hRefType == -1 &&
6377         (This->TypeAttr.typekind   == TKIND_DISPATCH) &&
6378         (This->TypeAttr.wTypeFlags &  TYPEFLAG_FDUAL))
6379     {
6380           /* when we meet a DUAL dispinterface, we must create the interface
6381           * version of it.
6382           */
6383           ITypeInfoImpl* pTypeInfoImpl = (ITypeInfoImpl*) ITypeInfo_Constructor();
6384
6385
6386           /* the interface version contains the same information as the dispinterface
6387            * copy the contents of the structs.
6388            */
6389           *pTypeInfoImpl = *This;
6390           pTypeInfoImpl->ref = 0;
6391
6392           /* change the type to interface */
6393           pTypeInfoImpl->TypeAttr.typekind = TKIND_INTERFACE;
6394
6395           *ppTInfo = (ITypeInfo*) pTypeInfoImpl;
6396
6397           /* we use data structures from This, so we need to keep a reference
6398            * to it to stop it being destroyed and signal to the new instance to
6399            * not free its data structures when it is destroyed */
6400           pTypeInfoImpl->no_free_data = TRUE;
6401           pTypeInfoImpl->next = This;
6402           ITypeInfo_AddRef((ITypeInfo*) This);
6403
6404           ITypeInfo_AddRef(*ppTInfo);
6405
6406           result = S_OK;
6407
6408     } else if ((hRefType != -1) && (hRefType & DISPATCH_HREF_MASK) &&
6409         (This->TypeAttr.typekind   == TKIND_DISPATCH) &&
6410         (This->TypeAttr.wTypeFlags &  TYPEFLAG_FDUAL))
6411     {
6412         HREFTYPE href_dispatch = hRefType;
6413         result = ITypeInfoImpl_GetDispatchRefTypeInfo((ITypeInfo *)iface, &href_dispatch, ppTInfo);
6414     } else {
6415         TLBRefType *ref_type;
6416         LIST_FOR_EACH_ENTRY(ref_type, &This->pTypeLib->ref_list, TLBRefType, entry)
6417         {
6418             if(ref_type->reference == hRefType)
6419                 break;
6420         }
6421         if(&ref_type->entry == &This->pTypeLib->ref_list)
6422         {
6423             FIXME("Can't find pRefType for ref %x\n", hRefType);
6424             goto end;
6425         }
6426         if(hRefType != -1) {
6427             ITypeLib *pTLib = NULL;
6428
6429             if(ref_type->pImpTLInfo == TLB_REF_INTERNAL) {
6430                 UINT Index;
6431                 result = ITypeInfo_GetContainingTypeLib(iface, &pTLib, &Index);
6432             } else {
6433                 if(ref_type->pImpTLInfo->pImpTypeLib) {
6434                     TRACE("typeinfo in imported typelib that is already loaded\n");
6435                     pTLib = (ITypeLib*)ref_type->pImpTLInfo->pImpTypeLib;
6436                     ITypeLib2_AddRef(pTLib);
6437                     result = S_OK;
6438                 } else {
6439                     TRACE("typeinfo in imported typelib that isn't already loaded\n");
6440                     result = LoadRegTypeLib( &ref_type->pImpTLInfo->guid,
6441                                              ref_type->pImpTLInfo->wVersionMajor,
6442                                              ref_type->pImpTLInfo->wVersionMinor,
6443                                              ref_type->pImpTLInfo->lcid,
6444                                              &pTLib);
6445
6446                     if(!SUCCEEDED(result)) {
6447                         BSTR libnam=SysAllocString(ref_type->pImpTLInfo->name);
6448                         result=LoadTypeLib(libnam, &pTLib);
6449                         SysFreeString(libnam);
6450                     }
6451                     if(SUCCEEDED(result)) {
6452                         ref_type->pImpTLInfo->pImpTypeLib = (ITypeLibImpl*)pTLib;
6453                         ITypeLib2_AddRef(pTLib);
6454                     }
6455                 }
6456             }
6457             if(SUCCEEDED(result)) {
6458                 if(ref_type->index == TLB_REF_USE_GUID)
6459                     result = ITypeLib2_GetTypeInfoOfGuid(pTLib,
6460                                                          &ref_type->guid,
6461                                                          ppTInfo);
6462                 else
6463                     result = ITypeLib2_GetTypeInfo(pTLib, ref_type->index,
6464                                                    ppTInfo);
6465             }
6466             if (pTLib != NULL)
6467                 ITypeLib2_Release(pTLib);
6468         }
6469     }
6470
6471 end:
6472     TRACE("(%p) hreftype 0x%04x loaded %s (%p)\n", This, hRefType,
6473           SUCCEEDED(result)? "SUCCESS":"FAILURE", *ppTInfo);
6474     return result;
6475 }
6476
6477 /* ITypeInfo::AddressOfMember
6478  *
6479  * Retrieves the addresses of static functions or variables, such as those
6480  * defined in a DLL.
6481  */
6482 static HRESULT WINAPI ITypeInfo_fnAddressOfMember( ITypeInfo2 *iface,
6483         MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
6484 {
6485     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6486     HRESULT hr;
6487     BSTR dll, entry;
6488     WORD ordinal;
6489     HMODULE module;
6490
6491     TRACE("(%p)->(0x%x, 0x%x, %p)\n", This, memid, invKind, ppv);
6492
6493     hr = ITypeInfo_GetDllEntry(iface, memid, invKind, &dll, &entry, &ordinal);
6494     if (FAILED(hr))
6495         return hr;
6496
6497     module = LoadLibraryW(dll);
6498     if (!module)
6499     {
6500         ERR("couldn't load %s\n", debugstr_w(dll));
6501         SysFreeString(dll);
6502         if (entry) SysFreeString(entry);
6503         return STG_E_FILENOTFOUND;
6504     }
6505     /* FIXME: store library somewhere where we can free it */
6506
6507     if (entry)
6508     {
6509         LPSTR entryA;
6510         INT len = WideCharToMultiByte(CP_ACP, 0, entry, -1, NULL, 0, NULL, NULL);
6511         entryA = HeapAlloc(GetProcessHeap(), 0, len);
6512         WideCharToMultiByte(CP_ACP, 0, entry, -1, entryA, len, NULL, NULL);
6513
6514         *ppv = GetProcAddress(module, entryA);
6515         if (!*ppv)
6516             ERR("function not found %s\n", debugstr_a(entryA));
6517
6518         HeapFree(GetProcessHeap(), 0, entryA);
6519     }
6520     else
6521     {
6522         *ppv = GetProcAddress(module, MAKEINTRESOURCEA(ordinal));
6523         if (!*ppv)
6524             ERR("function not found %d\n", ordinal);
6525     }
6526
6527     SysFreeString(dll);
6528     if (entry) SysFreeString(entry);
6529
6530     if (!*ppv)
6531         return TYPE_E_DLLFUNCTIONNOTFOUND;
6532
6533     return S_OK;
6534 }
6535
6536 /* ITypeInfo::CreateInstance
6537  *
6538  * Creates a new instance of a type that describes a component object class
6539  * (coclass).
6540  */
6541 static HRESULT WINAPI ITypeInfo_fnCreateInstance( ITypeInfo2 *iface,
6542         IUnknown *pOuterUnk, REFIID riid, VOID  **ppvObj)
6543 {
6544     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6545     HRESULT hr;
6546     TYPEATTR *pTA;
6547
6548     TRACE("(%p)->(%p, %s, %p)\n", This, pOuterUnk, debugstr_guid(riid), ppvObj);
6549
6550     *ppvObj = NULL;
6551
6552     if(pOuterUnk)
6553     {
6554         WARN("Not able to aggregate\n");
6555         return CLASS_E_NOAGGREGATION;
6556     }
6557
6558     hr = ITypeInfo_GetTypeAttr(iface, &pTA);
6559     if(FAILED(hr)) return hr;
6560
6561     if(pTA->typekind != TKIND_COCLASS)
6562     {
6563         WARN("CreateInstance on typeinfo of type %x\n", pTA->typekind);
6564         hr = E_INVALIDARG;
6565         goto end;
6566     }
6567
6568     hr = S_FALSE;
6569     if(pTA->wTypeFlags & TYPEFLAG_FAPPOBJECT)
6570     {
6571         IUnknown *pUnk;
6572         hr = GetActiveObject(&pTA->guid, NULL, &pUnk);
6573         TRACE("GetActiveObject rets %08x\n", hr);
6574         if(hr == S_OK)
6575         {
6576             hr = IUnknown_QueryInterface(pUnk, riid, ppvObj);
6577             IUnknown_Release(pUnk);
6578         }
6579     }
6580
6581     if(hr != S_OK)
6582         hr = CoCreateInstance(&pTA->guid, NULL,
6583                               CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
6584                               riid, ppvObj);
6585
6586 end:
6587     ITypeInfo_ReleaseTypeAttr(iface, pTA);
6588     return hr;
6589 }
6590
6591 /* ITypeInfo::GetMops
6592  *
6593  * Retrieves marshalling information.
6594  */
6595 static HRESULT WINAPI ITypeInfo_fnGetMops( ITypeInfo2 *iface, MEMBERID memid,
6596                                 BSTR  *pBstrMops)
6597 {
6598     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6599     FIXME("(%p) stub!\n", This);
6600     return S_OK;
6601 }
6602
6603 /* ITypeInfo::GetContainingTypeLib
6604  *
6605  * Retrieves the containing type library and the index of the type description
6606  * within that type library.
6607  */
6608 static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( ITypeInfo2 *iface,
6609         ITypeLib  * *ppTLib, UINT  *pIndex)
6610 {
6611     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6612     
6613     /* If a pointer is null, we simply ignore it, the ATL in particular passes pIndex as 0 */
6614     if (pIndex) {
6615       *pIndex=This->index;
6616       TRACE("returning pIndex=%d\n", *pIndex);
6617     }
6618     
6619     if (ppTLib) {
6620       *ppTLib=(LPTYPELIB )(This->pTypeLib);
6621       ITypeLib2_AddRef(*ppTLib);
6622       TRACE("returning ppTLib=%p\n", *ppTLib);
6623     }
6624     
6625     return S_OK;
6626 }
6627
6628 /* ITypeInfo::ReleaseTypeAttr
6629  *
6630  * Releases a TYPEATTR previously returned by GetTypeAttr.
6631  *
6632  */
6633 static void WINAPI ITypeInfo_fnReleaseTypeAttr( ITypeInfo2 *iface,
6634         TYPEATTR* pTypeAttr)
6635 {
6636     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6637     TRACE("(%p)->(%p)\n", This, pTypeAttr);
6638     HeapFree(GetProcessHeap(), 0, pTypeAttr);
6639 }
6640
6641 /* ITypeInfo::ReleaseFuncDesc
6642  *
6643  * Releases a FUNCDESC previously returned by GetFuncDesc. *
6644  */
6645 static void WINAPI ITypeInfo_fnReleaseFuncDesc(
6646         ITypeInfo2 *iface,
6647         FUNCDESC *pFuncDesc)
6648 {
6649     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6650     SHORT i;
6651
6652     TRACE("(%p)->(%p)\n", This, pFuncDesc);
6653
6654     for (i = 0; i < pFuncDesc->cParams; i++)
6655         TLB_FreeElemDesc(&pFuncDesc->lprgelemdescParam[i]);
6656     TLB_FreeElemDesc(&pFuncDesc->elemdescFunc);
6657
6658     SysFreeString((BSTR)pFuncDesc);
6659 }
6660
6661 /* ITypeInfo::ReleaseVarDesc
6662  *
6663  * Releases a VARDESC previously returned by GetVarDesc.
6664  */
6665 static void WINAPI ITypeInfo_fnReleaseVarDesc( ITypeInfo2 *iface,
6666         VARDESC *pVarDesc)
6667 {
6668     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6669     TRACE("(%p)->(%p)\n", This, pVarDesc);
6670
6671     TLB_FreeElemDesc(&pVarDesc->elemdescVar);
6672     if (pVarDesc->varkind == VAR_CONST)
6673         VariantClear(pVarDesc->u.lpvarValue);
6674     SysFreeString((BSTR)pVarDesc);
6675 }
6676
6677 /* ITypeInfo2::GetTypeKind
6678  *
6679  * Returns the TYPEKIND enumeration quickly, without doing any allocations.
6680  *
6681  */
6682 static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo2 * iface,
6683     TYPEKIND *pTypeKind)
6684 {
6685     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6686     *pTypeKind=This->TypeAttr.typekind;
6687     TRACE("(%p) type 0x%0x\n", This,*pTypeKind);
6688     return S_OK;
6689 }
6690
6691 /* ITypeInfo2::GetTypeFlags
6692  *
6693  * Returns the type flags without any allocations. This returns a DWORD type
6694  * flag, which expands the type flags without growing the TYPEATTR (type
6695  * attribute).
6696  *
6697  */
6698 static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo2 *iface, ULONG *pTypeFlags)
6699 {
6700     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6701     *pTypeFlags=This->TypeAttr.wTypeFlags;
6702     TRACE("(%p) flags 0x%x\n", This,*pTypeFlags);
6703     return S_OK;
6704 }
6705
6706 /* ITypeInfo2::GetFuncIndexOfMemId
6707  * Binds to a specific member based on a known DISPID, where the member name
6708  * is not known (for example, when binding to a default member).
6709  *
6710  */
6711 static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo2 * iface,
6712     MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex)
6713 {
6714     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6715     const TLBFuncDesc *pFuncInfo;
6716     int i;
6717     HRESULT result;
6718
6719     for(i = 0, pFuncInfo = This->funclist; pFuncInfo; i++, pFuncInfo=pFuncInfo->next)
6720         if(memid == pFuncInfo->funcdesc.memid && (invKind & pFuncInfo->funcdesc.invkind))
6721             break;
6722     if(pFuncInfo) {
6723         *pFuncIndex = i;
6724         result = S_OK;
6725     } else
6726         result = TYPE_E_ELEMENTNOTFOUND;
6727
6728     TRACE("(%p) memid 0x%08x invKind 0x%04x -> %s\n", This,
6729           memid, invKind, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
6730     return result;
6731 }
6732
6733 /* TypeInfo2::GetVarIndexOfMemId
6734  *
6735  * Binds to a specific member based on a known DISPID, where the member name
6736  * is not known (for example, when binding to a default member).
6737  *
6738  */
6739 static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( ITypeInfo2 * iface,
6740     MEMBERID memid, UINT *pVarIndex)
6741 {
6742     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6743     TLBVarDesc *pVarInfo;
6744     int i;
6745     HRESULT result;
6746     for(i=0, pVarInfo=This->varlist; pVarInfo &&
6747             memid != pVarInfo->vardesc.memid; i++, pVarInfo=pVarInfo->next)
6748         ;
6749     if(pVarInfo) {
6750         *pVarIndex = i;
6751         result = S_OK;
6752     } else
6753         result = TYPE_E_ELEMENTNOTFOUND;
6754
6755     TRACE("(%p) memid 0x%08x -> %s\n", This,
6756           memid, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
6757     return result;
6758 }
6759
6760 /* ITypeInfo2::GetCustData
6761  *
6762  * Gets the custom data
6763  */
6764 static HRESULT WINAPI ITypeInfo2_fnGetCustData(
6765         ITypeInfo2 * iface,
6766         REFGUID guid,
6767         VARIANT *pVarVal)
6768 {
6769     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6770     TLBCustData *pCData;
6771
6772     for(pCData=This->pCustData; pCData; pCData = pCData->next)
6773         if( IsEqualIID(guid, &pCData->guid)) break;
6774
6775     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
6776
6777     if(pCData)
6778     {
6779         VariantInit( pVarVal);
6780         VariantCopy( pVarVal, &pCData->data);
6781         return S_OK;
6782     }
6783     return E_INVALIDARG;  /* FIXME: correct? */
6784 }
6785
6786 /* ITypeInfo2::GetFuncCustData
6787  *
6788  * Gets the custom data
6789  */
6790 static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData(
6791         ITypeInfo2 * iface,
6792         UINT index,
6793         REFGUID guid,
6794         VARIANT *pVarVal)
6795 {
6796     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6797     TLBCustData *pCData=NULL;
6798     TLBFuncDesc * pFDesc;
6799     int i;
6800     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
6801             pFDesc=pFDesc->next);
6802
6803     if(pFDesc)
6804         for(pCData=pFDesc->pCustData; pCData; pCData = pCData->next)
6805             if( IsEqualIID(guid, &pCData->guid)) break;
6806
6807     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
6808
6809     if(pCData){
6810         VariantInit( pVarVal);
6811         VariantCopy( pVarVal, &pCData->data);
6812         return S_OK;
6813     }
6814     return E_INVALIDARG;  /* FIXME: correct? */
6815 }
6816
6817 /* ITypeInfo2::GetParamCustData
6818  *
6819  * Gets the custom data
6820  */
6821 static HRESULT WINAPI ITypeInfo2_fnGetParamCustData(
6822         ITypeInfo2 * iface,
6823         UINT indexFunc,
6824         UINT indexParam,
6825         REFGUID guid,
6826         VARIANT *pVarVal)
6827 {
6828     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6829     TLBCustData *pCData=NULL;
6830     TLBFuncDesc * pFDesc;
6831     int i;
6832
6833     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,pFDesc=pFDesc->next);
6834
6835     if(pFDesc && indexParam<pFDesc->funcdesc.cParams)
6836         for(pCData=pFDesc->pParamDesc[indexParam].pCustData; pCData;
6837                 pCData = pCData->next)
6838             if( IsEqualIID(guid, &pCData->guid)) break;
6839
6840     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
6841
6842     if(pCData)
6843     {
6844         VariantInit( pVarVal);
6845         VariantCopy( pVarVal, &pCData->data);
6846         return S_OK;
6847     }
6848     return E_INVALIDARG;  /* FIXME: correct? */
6849 }
6850
6851 /* ITypeInfo2::GetVarCustData
6852  *
6853  * Gets the custom data
6854  */
6855 static HRESULT WINAPI ITypeInfo2_fnGetVarCustData(
6856         ITypeInfo2 * iface,
6857         UINT index,
6858         REFGUID guid,
6859         VARIANT *pVarVal)
6860 {
6861     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6862     TLBCustData *pCData=NULL;
6863     TLBVarDesc * pVDesc;
6864     int i;
6865
6866     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next);
6867
6868     if(pVDesc)
6869     {
6870       for(pCData=pVDesc->pCustData; pCData; pCData = pCData->next)
6871       {
6872         if( IsEqualIID(guid, &pCData->guid)) break;
6873       }
6874     }
6875
6876     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
6877
6878     if(pCData)
6879     {
6880         VariantInit( pVarVal);
6881         VariantCopy( pVarVal, &pCData->data);
6882         return S_OK;
6883     }
6884     return E_INVALIDARG;  /* FIXME: correct? */
6885 }
6886
6887 /* ITypeInfo2::GetImplCustData
6888  *
6889  * Gets the custom data
6890  */
6891 static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData(
6892         ITypeInfo2 * iface,
6893         UINT index,
6894         REFGUID guid,
6895         VARIANT *pVarVal)
6896 {
6897     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6898     TLBCustData *pCData=NULL;
6899     TLBImplType * pRDesc;
6900     int i;
6901
6902     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++, pRDesc=pRDesc->next);
6903
6904     if(pRDesc)
6905     {
6906       for(pCData=pRDesc->pCustData; pCData; pCData = pCData->next)
6907       {
6908         if( IsEqualIID(guid, &pCData->guid)) break;
6909       }
6910     }
6911
6912     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
6913
6914     if(pCData)
6915     {
6916         VariantInit( pVarVal);
6917         VariantCopy( pVarVal, &pCData->data);
6918         return S_OK;
6919     }
6920     return E_INVALIDARG;  /* FIXME: correct? */
6921 }
6922
6923 /* ITypeInfo2::GetDocumentation2
6924  *
6925  * Retrieves the documentation string, the complete Help file name and path,
6926  * the localization context to use, and the context ID for the library Help
6927  * topic in the Help file.
6928  *
6929  */
6930 static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2(
6931         ITypeInfo2 * iface,
6932         MEMBERID memid,
6933         LCID lcid,
6934         BSTR *pbstrHelpString,
6935         DWORD *pdwHelpStringContext,
6936         BSTR *pbstrHelpStringDll)
6937 {
6938     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6939     const TLBFuncDesc *pFDesc;
6940     const TLBVarDesc *pVDesc;
6941     TRACE("(%p) memid %d lcid(0x%x)  HelpString(%p) "
6942           "HelpStringContext(%p) HelpStringDll(%p)\n",
6943           This, memid, lcid, pbstrHelpString, pdwHelpStringContext,
6944           pbstrHelpStringDll );
6945     /* the help string should be obtained from the helpstringdll,
6946      * using the _DLLGetDocumentation function, based on the supplied
6947      * lcid. Nice to do sometime...
6948      */
6949     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
6950         if(pbstrHelpString)
6951             *pbstrHelpString=SysAllocString(This->Name);
6952         if(pdwHelpStringContext)
6953             *pdwHelpStringContext=This->dwHelpStringContext;
6954         if(pbstrHelpStringDll)
6955             *pbstrHelpStringDll=
6956                 SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
6957         return S_OK;
6958     }else {/* for a member */
6959     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
6960         if(pFDesc->funcdesc.memid==memid){
6961              if(pbstrHelpString)
6962                 *pbstrHelpString=SysAllocString(pFDesc->HelpString);
6963             if(pdwHelpStringContext)
6964                 *pdwHelpStringContext=pFDesc->HelpStringContext;
6965             if(pbstrHelpStringDll)
6966                 *pbstrHelpStringDll=
6967                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
6968         return S_OK;
6969     }
6970     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
6971         if(pVDesc->vardesc.memid==memid){
6972              if(pbstrHelpString)
6973                 *pbstrHelpString=SysAllocString(pVDesc->HelpString);
6974             if(pdwHelpStringContext)
6975                 *pdwHelpStringContext=pVDesc->HelpStringContext;
6976             if(pbstrHelpStringDll)
6977                 *pbstrHelpStringDll=
6978                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
6979             return S_OK;
6980         }
6981     }
6982     return TYPE_E_ELEMENTNOTFOUND;
6983 }
6984
6985 /* ITypeInfo2::GetAllCustData
6986  *
6987  * Gets all custom data items for the Type info.
6988  *
6989  */
6990 static HRESULT WINAPI ITypeInfo2_fnGetAllCustData(
6991         ITypeInfo2 * iface,
6992         CUSTDATA *pCustData)
6993 {
6994     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6995     TLBCustData *pCData;
6996     int i;
6997
6998     TRACE("(%p) returning %d items\n", This, This->ctCustData);
6999
7000     pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
7001     if(pCustData->prgCustData ){
7002         pCustData->cCustData=This->ctCustData;
7003         for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
7004             pCustData->prgCustData[i].guid=pCData->guid;
7005             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
7006         }
7007     }else{
7008         ERR(" OUT OF MEMORY!\n");
7009         return E_OUTOFMEMORY;
7010     }
7011     return S_OK;
7012 }
7013
7014 /* ITypeInfo2::GetAllFuncCustData
7015  *
7016  * Gets all custom data items for the specified Function
7017  *
7018  */
7019 static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData(
7020         ITypeInfo2 * iface,
7021         UINT index,
7022         CUSTDATA *pCustData)
7023 {
7024     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7025     TLBCustData *pCData;
7026     TLBFuncDesc * pFDesc;
7027     int i;
7028     TRACE("(%p) index %d\n", This, index);
7029     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
7030             pFDesc=pFDesc->next)
7031         ;
7032     if(pFDesc){
7033         pCustData->prgCustData =
7034             TLB_Alloc(pFDesc->ctCustData * sizeof(CUSTDATAITEM));
7035         if(pCustData->prgCustData ){
7036             pCustData->cCustData=pFDesc->ctCustData;
7037             for(i=0, pCData=pFDesc->pCustData; pCData; i++,
7038                     pCData = pCData->next){
7039                 pCustData->prgCustData[i].guid=pCData->guid;
7040                 VariantCopy(& pCustData->prgCustData[i].varValue,
7041                         & pCData->data);
7042             }
7043         }else{
7044             ERR(" OUT OF MEMORY!\n");
7045             return E_OUTOFMEMORY;
7046         }
7047         return S_OK;
7048     }
7049     return TYPE_E_ELEMENTNOTFOUND;
7050 }
7051
7052 /* ITypeInfo2::GetAllParamCustData
7053  *
7054  * Gets all custom data items for the Functions
7055  *
7056  */
7057 static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo2 * iface,
7058     UINT indexFunc, UINT indexParam, CUSTDATA *pCustData)
7059 {
7060     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7061     TLBCustData *pCData=NULL;
7062     TLBFuncDesc * pFDesc;
7063     int i;
7064     TRACE("(%p) index %d\n", This, indexFunc);
7065     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,
7066             pFDesc=pFDesc->next)
7067         ;
7068     if(pFDesc && indexParam<pFDesc->funcdesc.cParams){
7069         pCustData->prgCustData =
7070             TLB_Alloc(pFDesc->pParamDesc[indexParam].ctCustData *
7071                     sizeof(CUSTDATAITEM));
7072         if(pCustData->prgCustData ){
7073             pCustData->cCustData=pFDesc->pParamDesc[indexParam].ctCustData;
7074             for(i=0, pCData=pFDesc->pParamDesc[indexParam].pCustData;
7075                     pCData; i++, pCData = pCData->next){
7076                 pCustData->prgCustData[i].guid=pCData->guid;
7077                 VariantCopy(& pCustData->prgCustData[i].varValue,
7078                         & pCData->data);
7079             }
7080         }else{
7081             ERR(" OUT OF MEMORY!\n");
7082             return E_OUTOFMEMORY;
7083         }
7084         return S_OK;
7085     }
7086     return TYPE_E_ELEMENTNOTFOUND;
7087 }
7088
7089 /* ITypeInfo2::GetAllVarCustData
7090  *
7091  * Gets all custom data items for the specified Variable
7092  *
7093  */
7094 static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo2 * iface,
7095     UINT index, CUSTDATA *pCustData)
7096 {
7097     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7098     TLBCustData *pCData;
7099     TLBVarDesc * pVDesc;
7100     int i;
7101     TRACE("(%p) index %d\n", This, index);
7102     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++,
7103             pVDesc=pVDesc->next)
7104         ;
7105     if(pVDesc){
7106         pCustData->prgCustData =
7107             TLB_Alloc(pVDesc->ctCustData * sizeof(CUSTDATAITEM));
7108         if(pCustData->prgCustData ){
7109             pCustData->cCustData=pVDesc->ctCustData;
7110             for(i=0, pCData=pVDesc->pCustData; pCData; i++,
7111                     pCData = pCData->next){
7112                 pCustData->prgCustData[i].guid=pCData->guid;
7113                 VariantCopy(& pCustData->prgCustData[i].varValue,
7114                         & pCData->data);
7115             }
7116         }else{
7117             ERR(" OUT OF MEMORY!\n");
7118             return E_OUTOFMEMORY;
7119         }
7120         return S_OK;
7121     }
7122     return TYPE_E_ELEMENTNOTFOUND;
7123 }
7124
7125 /* ITypeInfo2::GetAllImplCustData
7126  *
7127  * Gets all custom data items for the specified implementation type
7128  *
7129  */
7130 static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData(
7131         ITypeInfo2 * iface,
7132         UINT index,
7133         CUSTDATA *pCustData)
7134 {
7135     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7136     TLBCustData *pCData;
7137     TLBImplType * pRDesc;
7138     int i;
7139     TRACE("(%p) index %d\n", This, index);
7140     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++,
7141             pRDesc=pRDesc->next)
7142         ;
7143     if(pRDesc){
7144         pCustData->prgCustData =
7145             TLB_Alloc(pRDesc->ctCustData * sizeof(CUSTDATAITEM));
7146         if(pCustData->prgCustData ){
7147             pCustData->cCustData=pRDesc->ctCustData;
7148             for(i=0, pCData=pRDesc->pCustData; pCData; i++,
7149                     pCData = pCData->next){
7150                 pCustData->prgCustData[i].guid=pCData->guid;
7151                 VariantCopy(& pCustData->prgCustData[i].varValue,
7152                         & pCData->data);
7153             }
7154         }else{
7155             ERR(" OUT OF MEMORY!\n");
7156             return E_OUTOFMEMORY;
7157         }
7158         return S_OK;
7159     }
7160     return TYPE_E_ELEMENTNOTFOUND;
7161 }
7162
7163 static const ITypeInfo2Vtbl tinfvt =
7164 {
7165
7166     ITypeInfo_fnQueryInterface,
7167     ITypeInfo_fnAddRef,
7168     ITypeInfo_fnRelease,
7169
7170     ITypeInfo_fnGetTypeAttr,
7171     ITypeInfo_fnGetTypeComp,
7172     ITypeInfo_fnGetFuncDesc,
7173     ITypeInfo_fnGetVarDesc,
7174     ITypeInfo_fnGetNames,
7175     ITypeInfo_fnGetRefTypeOfImplType,
7176     ITypeInfo_fnGetImplTypeFlags,
7177     ITypeInfo_fnGetIDsOfNames,
7178     ITypeInfo_fnInvoke,
7179     ITypeInfo_fnGetDocumentation,
7180     ITypeInfo_fnGetDllEntry,
7181     ITypeInfo_fnGetRefTypeInfo,
7182     ITypeInfo_fnAddressOfMember,
7183     ITypeInfo_fnCreateInstance,
7184     ITypeInfo_fnGetMops,
7185     ITypeInfo_fnGetContainingTypeLib,
7186     ITypeInfo_fnReleaseTypeAttr,
7187     ITypeInfo_fnReleaseFuncDesc,
7188     ITypeInfo_fnReleaseVarDesc,
7189
7190     ITypeInfo2_fnGetTypeKind,
7191     ITypeInfo2_fnGetTypeFlags,
7192     ITypeInfo2_fnGetFuncIndexOfMemId,
7193     ITypeInfo2_fnGetVarIndexOfMemId,
7194     ITypeInfo2_fnGetCustData,
7195     ITypeInfo2_fnGetFuncCustData,
7196     ITypeInfo2_fnGetParamCustData,
7197     ITypeInfo2_fnGetVarCustData,
7198     ITypeInfo2_fnGetImplTypeCustData,
7199     ITypeInfo2_fnGetDocumentation2,
7200     ITypeInfo2_fnGetAllCustData,
7201     ITypeInfo2_fnGetAllFuncCustData,
7202     ITypeInfo2_fnGetAllParamCustData,
7203     ITypeInfo2_fnGetAllVarCustData,
7204     ITypeInfo2_fnGetAllImplTypeCustData,
7205 };
7206
7207 /******************************************************************************
7208  * CreateDispTypeInfo [OLEAUT32.31]
7209  *
7210  * Build type information for an object so it can be called through an
7211  * IDispatch interface.
7212  *
7213  * RETURNS
7214  *  Success: S_OK. pptinfo contains the created ITypeInfo object.
7215  *  Failure: E_INVALIDARG, if one or more arguments is invalid.
7216  *
7217  * NOTES
7218  *  This call allows an objects methods to be accessed through IDispatch, by
7219  *  building an ITypeInfo object that IDispatch can use to call through.
7220  */
7221 HRESULT WINAPI CreateDispTypeInfo(
7222         INTERFACEDATA *pidata, /* [I] Description of the interface to build type info for */
7223         LCID lcid, /* [I] Locale Id */
7224         ITypeInfo **pptinfo) /* [O] Destination for created ITypeInfo object */
7225 {
7226     ITypeInfoImpl *pTIClass, *pTIIface;
7227     ITypeLibImpl *pTypeLibImpl;
7228     int param, func;
7229     TLBFuncDesc **ppFuncDesc;
7230     TLBRefType *ref;
7231
7232     TRACE("\n");
7233     pTypeLibImpl = TypeLibImpl_Constructor();
7234     if (!pTypeLibImpl) return E_FAIL;
7235
7236     pTIIface = (ITypeInfoImpl*)ITypeInfo_Constructor();
7237     pTIIface->pTypeLib = pTypeLibImpl;
7238     pTIIface->index = 0;
7239     pTIIface->Name = NULL;
7240     pTIIface->dwHelpContext = -1;
7241     memset(&pTIIface->TypeAttr.guid, 0, sizeof(GUID));
7242     pTIIface->TypeAttr.lcid = lcid;
7243     pTIIface->TypeAttr.typekind = TKIND_INTERFACE;
7244     pTIIface->TypeAttr.wMajorVerNum = 0;
7245     pTIIface->TypeAttr.wMinorVerNum = 0;
7246     pTIIface->TypeAttr.cbAlignment = 2;
7247     pTIIface->TypeAttr.cbSizeInstance = -1;
7248     pTIIface->TypeAttr.cbSizeVft = -1;
7249     pTIIface->TypeAttr.cFuncs = 0;
7250     pTIIface->TypeAttr.cImplTypes = 0;
7251     pTIIface->TypeAttr.cVars = 0;
7252     pTIIface->TypeAttr.wTypeFlags = 0;
7253
7254     ppFuncDesc = &pTIIface->funclist;
7255     for(func = 0; func < pidata->cMembers; func++) {
7256         METHODDATA *md = pidata->pmethdata + func;
7257         *ppFuncDesc = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppFuncDesc));
7258         (*ppFuncDesc)->Name = SysAllocString(md->szName);
7259         (*ppFuncDesc)->funcdesc.memid = md->dispid;
7260         (*ppFuncDesc)->funcdesc.lprgscode = NULL;
7261         (*ppFuncDesc)->funcdesc.funckind = FUNC_VIRTUAL;
7262         (*ppFuncDesc)->funcdesc.invkind = md->wFlags;
7263         (*ppFuncDesc)->funcdesc.callconv = md->cc;
7264         (*ppFuncDesc)->funcdesc.cParams = md->cArgs;
7265         (*ppFuncDesc)->funcdesc.cParamsOpt = 0;
7266         (*ppFuncDesc)->funcdesc.oVft = md->iMeth << 2;
7267         (*ppFuncDesc)->funcdesc.cScodes = 0;
7268         (*ppFuncDesc)->funcdesc.wFuncFlags = 0;
7269         (*ppFuncDesc)->funcdesc.elemdescFunc.tdesc.vt = md->vtReturn;
7270         (*ppFuncDesc)->funcdesc.elemdescFunc.u.paramdesc.wParamFlags = PARAMFLAG_NONE;
7271         (*ppFuncDesc)->funcdesc.elemdescFunc.u.paramdesc.pparamdescex = NULL;
7272         (*ppFuncDesc)->funcdesc.lprgelemdescParam = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7273                                                               md->cArgs * sizeof(ELEMDESC));
7274         (*ppFuncDesc)->pParamDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7275                                               md->cArgs * sizeof(TLBParDesc));
7276         for(param = 0; param < md->cArgs; param++) {
7277             (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].tdesc.vt = md->ppdata[param].vt;
7278             (*ppFuncDesc)->pParamDesc[param].Name = SysAllocString(md->ppdata[param].szName);
7279         }
7280         (*ppFuncDesc)->helpcontext = 0;
7281         (*ppFuncDesc)->HelpStringContext = 0;
7282         (*ppFuncDesc)->HelpString = NULL;
7283         (*ppFuncDesc)->Entry = NULL;
7284         (*ppFuncDesc)->ctCustData = 0;
7285         (*ppFuncDesc)->pCustData = NULL;
7286         (*ppFuncDesc)->next = NULL;
7287         pTIIface->TypeAttr.cFuncs++;
7288         ppFuncDesc = &(*ppFuncDesc)->next;
7289     }
7290
7291     dump_TypeInfo(pTIIface);
7292
7293     pTypeLibImpl->pTypeInfo = pTIIface;
7294     pTypeLibImpl->TypeInfoCount++;
7295
7296     pTIClass = (ITypeInfoImpl*)ITypeInfo_Constructor();
7297     pTIClass->pTypeLib = pTypeLibImpl;
7298     pTIClass->index = 1;
7299     pTIClass->Name = NULL;
7300     pTIClass->dwHelpContext = -1;
7301     memset(&pTIClass->TypeAttr.guid, 0, sizeof(GUID));
7302     pTIClass->TypeAttr.lcid = lcid;
7303     pTIClass->TypeAttr.typekind = TKIND_COCLASS;
7304     pTIClass->TypeAttr.wMajorVerNum = 0;
7305     pTIClass->TypeAttr.wMinorVerNum = 0;
7306     pTIClass->TypeAttr.cbAlignment = 2;
7307     pTIClass->TypeAttr.cbSizeInstance = -1;
7308     pTIClass->TypeAttr.cbSizeVft = -1;
7309     pTIClass->TypeAttr.cFuncs = 0;
7310     pTIClass->TypeAttr.cImplTypes = 1;
7311     pTIClass->TypeAttr.cVars = 0;
7312     pTIClass->TypeAttr.wTypeFlags = 0;
7313
7314     pTIClass->impltypelist = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pTIClass->impltypelist));
7315     pTIClass->impltypelist->hRef = 0;
7316
7317     ref = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ref));
7318     ref->index = 0;
7319     ref->reference = 0;
7320     ref->pImpTLInfo = TLB_REF_INTERNAL;
7321     list_add_head(&pTypeLibImpl->ref_list, &ref->entry);
7322
7323     dump_TypeInfo(pTIClass);
7324
7325     pTIIface->next = pTIClass;
7326     pTypeLibImpl->TypeInfoCount++;
7327
7328     *pptinfo = (ITypeInfo*)pTIClass;
7329
7330     ITypeInfo_AddRef(*pptinfo);
7331     ITypeLib_Release((ITypeLib *)&pTypeLibImpl->lpVtbl);
7332
7333     return S_OK;
7334
7335 }
7336
7337 static HRESULT WINAPI ITypeComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
7338 {
7339     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7340
7341     return ITypeInfo_QueryInterface((ITypeInfo *)This, riid, ppv);
7342 }
7343
7344 static ULONG WINAPI ITypeComp_fnAddRef(ITypeComp * iface)
7345 {
7346     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7347
7348     return ITypeInfo_AddRef((ITypeInfo *)This);
7349 }
7350
7351 static ULONG WINAPI ITypeComp_fnRelease(ITypeComp * iface)
7352 {
7353     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7354
7355     return ITypeInfo_Release((ITypeInfo *)This);
7356 }
7357
7358 static HRESULT WINAPI ITypeComp_fnBind(
7359     ITypeComp * iface,
7360     OLECHAR * szName,
7361     ULONG lHash,
7362     WORD wFlags,
7363     ITypeInfo ** ppTInfo,
7364     DESCKIND * pDescKind,
7365     BINDPTR * pBindPtr)
7366 {
7367     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7368     const TLBFuncDesc *pFDesc;
7369     const TLBVarDesc *pVDesc;
7370     HRESULT hr = DISP_E_MEMBERNOTFOUND;
7371
7372     TRACE("(%s, %x, 0x%x, %p, %p, %p)\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
7373
7374     *pDescKind = DESCKIND_NONE;
7375     pBindPtr->lpfuncdesc = NULL;
7376     *ppTInfo = NULL;
7377
7378     for(pFDesc = This->funclist; pFDesc; pFDesc = pFDesc->next)
7379         if (!strcmpiW(pFDesc->Name, szName)) {
7380             if (!wFlags || (pFDesc->funcdesc.invkind & wFlags))
7381                 break;
7382             else
7383                 /* name found, but wrong flags */
7384                 hr = TYPE_E_TYPEMISMATCH;
7385         }
7386
7387     if (pFDesc)
7388     {
7389         HRESULT hr = TLB_AllocAndInitFuncDesc(
7390             &pFDesc->funcdesc,
7391             &pBindPtr->lpfuncdesc,
7392             This->TypeAttr.typekind == TKIND_DISPATCH);
7393         if (FAILED(hr))
7394             return hr;
7395         *pDescKind = DESCKIND_FUNCDESC;
7396         *ppTInfo = (ITypeInfo *)&This->lpVtbl;
7397         ITypeInfo_AddRef(*ppTInfo);
7398         return S_OK;
7399     } else {
7400         for(pVDesc = This->varlist; pVDesc; pVDesc = pVDesc->next) {
7401             if (!strcmpiW(pVDesc->Name, szName)) {
7402                 HRESULT hr = TLB_AllocAndInitVarDesc(&pVDesc->vardesc, &pBindPtr->lpvardesc);
7403                 if (FAILED(hr))
7404                     return hr;
7405                 *pDescKind = DESCKIND_VARDESC;
7406                 *ppTInfo = (ITypeInfo *)&This->lpVtbl;
7407                 ITypeInfo_AddRef(*ppTInfo);
7408                 return S_OK;
7409             }
7410         }
7411     }
7412     /* FIXME: search each inherited interface, not just the first */
7413     if (hr == DISP_E_MEMBERNOTFOUND && This->impltypelist) {
7414         /* recursive search */
7415         ITypeInfo *pTInfo;
7416         ITypeComp *pTComp;
7417         HRESULT hr;
7418         hr=ITypeInfo_GetRefTypeInfo((ITypeInfo *)&This->lpVtbl, This->impltypelist->hRef, &pTInfo);
7419         if (SUCCEEDED(hr))
7420         {
7421             hr = ITypeInfo_GetTypeComp(pTInfo,&pTComp);
7422             ITypeInfo_Release(pTInfo);
7423         }
7424         if (SUCCEEDED(hr))
7425         {
7426             hr = ITypeComp_Bind(pTComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
7427             ITypeComp_Release(pTComp);
7428             return hr;
7429         }
7430         WARN("Could not search inherited interface!\n");
7431     }
7432     WARN("did not find member with name %s, flags 0x%x!\n", debugstr_w(szName), wFlags);
7433     return hr;
7434 }
7435
7436 static HRESULT WINAPI ITypeComp_fnBindType(
7437     ITypeComp * iface,
7438     OLECHAR * szName,
7439     ULONG lHash,
7440     ITypeInfo ** ppTInfo,
7441     ITypeComp ** ppTComp)
7442 {
7443     TRACE("(%s, %x, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
7444
7445     /* strange behaviour (does nothing) but like the
7446      * original */
7447
7448     if (!ppTInfo || !ppTComp)
7449         return E_POINTER;
7450
7451     *ppTInfo = NULL;
7452     *ppTComp = NULL;
7453
7454     return S_OK;
7455 }
7456
7457 static const ITypeCompVtbl tcompvt =
7458 {
7459
7460     ITypeComp_fnQueryInterface,
7461     ITypeComp_fnAddRef,
7462     ITypeComp_fnRelease,
7463
7464     ITypeComp_fnBind,
7465     ITypeComp_fnBindType
7466 };