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