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