oleaut32: Fix the references in function descriptions returned for dual IDispatch...
[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(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])=L'\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(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(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(char *ptr, BSTR *pBstr)
2628 {
2629     WORD bytelen;
2630     DWORD len;
2631     WCHAR *nameW;
2632
2633     *pBstr = NULL;
2634     bytelen = *(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(char *ptr, char **str)
2645 {
2646     WORD bytelen;
2647
2648     *str = NULL;
2649     bytelen = *(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(sltg_ref_lookup_t *table, DWORD typeinfo_ref, HREFTYPE *typelib_ref)
2715 {
2716     if(typeinfo_ref < table->num)
2717     {
2718         *typelib_ref = table->refs[typeinfo_ref];
2719         return S_OK;
2720     }
2721
2722     ERR("Unable to find reference\n");
2723     *typelib_ref = -1;
2724     return E_FAIL;
2725 }
2726
2727 static WORD *SLTG_DoType(WORD *pType, char *pBlk, TYPEDESC *pTD, sltg_ref_lookup_t *ref_lookup)
2728 {
2729     BOOL done = FALSE;
2730
2731     while(!done) {
2732         if((*pType & 0xe00) == 0xe00) {
2733             pTD->vt = VT_PTR;
2734             pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2735                                        sizeof(TYPEDESC));
2736             pTD = pTD->u.lptdesc;
2737         }
2738         switch(*pType & 0x3f) {
2739         case VT_PTR:
2740             pTD->vt = VT_PTR;
2741             pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2742                                        sizeof(TYPEDESC));
2743             pTD = pTD->u.lptdesc;
2744             break;
2745
2746         case VT_USERDEFINED:
2747             pTD->vt = VT_USERDEFINED;
2748             sltg_get_typelib_ref(ref_lookup, *(++pType) / 4, &pTD->u.hreftype);
2749             done = TRUE;
2750             break;
2751
2752         case VT_CARRAY:
2753           {
2754             /* *(pType+1) is offset to a SAFEARRAY, *(pType+2) is type of
2755                array */
2756
2757             SAFEARRAY *pSA = (SAFEARRAY *)(pBlk + *(++pType));
2758
2759             pTD->vt = VT_CARRAY;
2760             pTD->u.lpadesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2761                                 sizeof(ARRAYDESC) +
2762                                 (pSA->cDims - 1) * sizeof(SAFEARRAYBOUND));
2763             pTD->u.lpadesc->cDims = pSA->cDims;
2764             memcpy(pTD->u.lpadesc->rgbounds, pSA->rgsabound,
2765                    pSA->cDims * sizeof(SAFEARRAYBOUND));
2766
2767             pTD = &pTD->u.lpadesc->tdescElem;
2768             break;
2769           }
2770
2771         case VT_SAFEARRAY:
2772           {
2773             /* FIXME: *(pType+1) gives an offset to SAFEARRAY, is this
2774                useful? */
2775
2776             pType++;
2777             pTD->vt = VT_SAFEARRAY;
2778             pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2779                                        sizeof(TYPEDESC));
2780             pTD = pTD->u.lptdesc;
2781             break;
2782           }
2783         default:
2784             pTD->vt = *pType & 0x3f;
2785             done = TRUE;
2786             break;
2787         }
2788         pType++;
2789     }
2790     return pType;
2791 }
2792
2793 static WORD *SLTG_DoElem(WORD *pType, char *pBlk, ELEMDESC *pElem, sltg_ref_lookup_t *ref_lookup)
2794 {
2795     /* Handle [in/out] first */
2796     if((*pType & 0xc000) == 0xc000)
2797         pElem->u.paramdesc.wParamFlags = PARAMFLAG_NONE;
2798     else if(*pType & 0x8000)
2799         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN | PARAMFLAG_FOUT;
2800     else if(*pType & 0x4000)
2801         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FOUT;
2802     else
2803         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN;
2804
2805     if(*pType & 0x2000)
2806         pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FLCID;
2807
2808     if(*pType & 0x80)
2809         pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FRETVAL;
2810
2811     return SLTG_DoType(pType, pBlk, &pElem->tdesc, ref_lookup);
2812 }
2813
2814
2815 static sltg_ref_lookup_t *SLTG_DoRefs(SLTG_RefInfo *pRef, ITypeLibImpl *pTL,
2816                         char *pNameTable)
2817 {
2818     int ref;
2819     char *name;
2820     TLBRefType *ref_type;
2821     sltg_ref_lookup_t *table;
2822     HREFTYPE typelib_ref;
2823
2824     if(pRef->magic != SLTG_REF_MAGIC) {
2825         FIXME("Ref magic = %x\n", pRef->magic);
2826         return NULL;
2827     }
2828     name = ( (char*)(&pRef->names) + pRef->number);
2829
2830     table = HeapAlloc(GetProcessHeap(), 0, sizeof(*table) + ((pRef->number >> 3) - 1) * sizeof(table->refs[0]));
2831     table->num = pRef->number >> 3;
2832
2833     /* FIXME should scan the existing list and reuse matching refs added by previous typeinfos */
2834
2835     /* We don't want the first href to be 0 */
2836     typelib_ref = (list_count(&pTL->ref_list) + 1) << 2;
2837
2838     for(ref = 0; ref < pRef->number >> 3; ref++) {
2839         char *refname;
2840         unsigned int lib_offs, type_num;
2841
2842         ref_type = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ref_type));
2843
2844         name += SLTG_ReadStringA(name, &refname);
2845         if(sscanf(refname, "*\\R%x*#%x", &lib_offs, &type_num) != 2)
2846             FIXME("Can't sscanf ref\n");
2847         if(lib_offs != 0xffff) {
2848             TLBImpLib **import = &pTL->pImpLibs;
2849
2850             while(*import) {
2851                 if((*import)->offset == lib_offs)
2852                     break;
2853                 import = &(*import)->next;
2854             }
2855             if(!*import) {
2856                 char fname[MAX_PATH+1];
2857                 int len;
2858
2859                 *import = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2860                                     sizeof(**import));
2861                 (*import)->offset = lib_offs;
2862                 TLB_GUIDFromString( pNameTable + lib_offs + 4,
2863                                     &(*import)->guid);
2864                 if(sscanf(pNameTable + lib_offs + 40, "}#%hd.%hd#%x#%s",
2865                           &(*import)->wVersionMajor,
2866                           &(*import)->wVersionMinor,
2867                           &(*import)->lcid, fname) != 4) {
2868                   FIXME("can't sscanf ref %s\n",
2869                         pNameTable + lib_offs + 40);
2870                 }
2871                 len = strlen(fname);
2872                 if(fname[len-1] != '#')
2873                     FIXME("fname = %s\n", fname);
2874                 fname[len-1] = '\0';
2875                 (*import)->name = TLB_MultiByteToBSTR(fname);
2876             }
2877             ref_type->pImpTLInfo = *import;
2878
2879             /* Store a reference to IDispatch */
2880             if(pTL->dispatch_href == -1 && IsEqualGUID(&(*import)->guid, &IID_StdOle) && type_num == 4)
2881                 pTL->dispatch_href = typelib_ref;
2882
2883         } else { /* internal ref */
2884           ref_type->pImpTLInfo = TLB_REF_INTERNAL;
2885         }
2886         ref_type->reference = typelib_ref;
2887         ref_type->index = type_num;
2888
2889         HeapFree(GetProcessHeap(), 0, refname);
2890         list_add_tail(&pTL->ref_list, &ref_type->entry);
2891
2892         table->refs[ref] = typelib_ref;
2893         typelib_ref += 4;
2894     }
2895     if((BYTE)*name != SLTG_REF_MAGIC)
2896       FIXME("End of ref block magic = %x\n", *name);
2897     dump_TLBRefType(pTL);
2898     return table;
2899 }
2900
2901 static char *SLTG_DoImpls(char *pBlk, ITypeInfoImpl *pTI,
2902                           BOOL OneOnly, sltg_ref_lookup_t *ref_lookup)
2903 {
2904     SLTG_ImplInfo *info;
2905     TLBImplType **ppImplType = &pTI->impltypelist;
2906     /* I don't really get this structure, usually it's 0x16 bytes
2907        long, but iuser.tlb contains some that are 0x18 bytes long.
2908        That's ok because we can use the next ptr to jump to the next
2909        one. But how do we know the length of the last one?  The WORD
2910        at offs 0x8 might be the clue.  For now I'm just assuming that
2911        the last one is the regular 0x16 bytes. */
2912
2913     info = (SLTG_ImplInfo*)pBlk;
2914     while(1) {
2915         *ppImplType = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2916                                 sizeof(**ppImplType));
2917         sltg_get_typelib_ref(ref_lookup, info->ref, &(*ppImplType)->hRef);
2918         (*ppImplType)->implflags = info->impltypeflags;
2919         pTI->TypeAttr.cImplTypes++;
2920         ppImplType = &(*ppImplType)->next;
2921
2922         if(info->next == 0xffff)
2923             break;
2924         if(OneOnly)
2925             FIXME("Interface inheriting more than one interface\n");
2926         info = (SLTG_ImplInfo*)(pBlk + info->next);
2927     }
2928     info++; /* see comment at top of function */
2929     return (char*)info;
2930 }
2931
2932 static void SLTG_DoVars(char *pBlk, char *pFirstItem, ITypeInfoImpl *pTI, unsigned short cVars, char *pNameTable, sltg_ref_lookup_t *ref_lookup)
2933 {
2934   TLBVarDesc **ppVarDesc = &pTI->varlist;
2935   BSTR bstrPrevName = NULL;
2936   SLTG_Variable *pItem;
2937   unsigned short i;
2938   WORD *pType;
2939   char buf[300];
2940
2941   for(pItem = (SLTG_Variable *)pFirstItem, i = 0; i < cVars;
2942       pItem = (SLTG_Variable *)(pBlk + pItem->next), i++) {
2943
2944       *ppVarDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2945                              sizeof(**ppVarDesc));
2946       (*ppVarDesc)->vardesc.memid = pItem->memid;
2947
2948       if (pItem->magic != SLTG_VAR_MAGIC &&
2949           pItem->magic != SLTG_VAR_WITH_FLAGS_MAGIC) {
2950           FIXME_(typelib)("var magic = %02x\n", pItem->magic);
2951           return;
2952       }
2953
2954       if (pItem->name == 0xfffe)
2955         (*ppVarDesc)->Name = SysAllocString(bstrPrevName);
2956       else
2957         (*ppVarDesc)->Name = TLB_MultiByteToBSTR(pItem->name + pNameTable);
2958
2959       TRACE_(typelib)("byte_offs = 0x%x\n", pItem->byte_offs);
2960       TRACE_(typelib)("memid = 0x%x\n", pItem->memid);
2961
2962       if (pItem->flags & 0x40) {
2963         TRACE_(typelib)("VAR_DISPATCH\n");
2964         (*ppVarDesc)->vardesc.varkind = VAR_DISPATCH;
2965       }
2966       else if (pItem->flags & 0x10) {
2967         TRACE_(typelib)("VAR_CONST\n");
2968         (*ppVarDesc)->vardesc.varkind = VAR_CONST;
2969         (*ppVarDesc)->vardesc.u.lpvarValue = HeapAlloc(GetProcessHeap(), 0,
2970                                                        sizeof(VARIANT));
2971         V_VT((*ppVarDesc)->vardesc.u.lpvarValue) = VT_INT;
2972         V_UNION((*ppVarDesc)->vardesc.u.lpvarValue, intVal) =
2973           *(INT*)(pBlk + pItem->byte_offs);
2974       }
2975       else {
2976         TRACE_(typelib)("VAR_PERINSTANCE\n");
2977         (*ppVarDesc)->vardesc.u.oInst = pItem->byte_offs;
2978         (*ppVarDesc)->vardesc.varkind = VAR_PERINSTANCE;
2979       }
2980
2981       if (pItem->magic == SLTG_VAR_WITH_FLAGS_MAGIC)
2982         (*ppVarDesc)->vardesc.wVarFlags = pItem->varflags;
2983
2984       if (pItem->flags & 0x80)
2985         (*ppVarDesc)->vardesc.wVarFlags |= VARFLAG_FREADONLY;
2986
2987       if(pItem->flags & 0x02)
2988           pType = &pItem->type;
2989       else
2990           pType = (WORD*)(pBlk + pItem->type);
2991
2992       if (pItem->flags & ~0xd2)
2993         FIXME_(typelib)("unhandled flags = %02x\n", pItem->flags & ~0xd2);
2994
2995       SLTG_DoElem(pType, pBlk,
2996                   &(*ppVarDesc)->vardesc.elemdescVar, ref_lookup);
2997
2998       dump_TypeDesc(&(*ppVarDesc)->vardesc.elemdescVar.tdesc, buf);
2999
3000       bstrPrevName = (*ppVarDesc)->Name;
3001       ppVarDesc = &((*ppVarDesc)->next);
3002   }
3003   pTI->TypeAttr.cVars = cVars;
3004 }
3005
3006 static void SLTG_DoFuncs(char *pBlk, char *pFirstItem, ITypeInfoImpl *pTI, unsigned short cFuncs, char *pNameTable, sltg_ref_lookup_t *ref_lookup)
3007 {
3008     SLTG_Function *pFunc;
3009     unsigned short i;
3010     TLBFuncDesc **ppFuncDesc = &pTI->funclist;
3011
3012     for(pFunc = (SLTG_Function*)pFirstItem, i = 0; i < cFuncs;
3013         pFunc = (SLTG_Function*)(pBlk + pFunc->next), i++) {
3014
3015         int param;
3016         WORD *pType, *pArg;
3017
3018         *ppFuncDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3019                                 sizeof(**ppFuncDesc));
3020
3021         switch (pFunc->magic & ~SLTG_FUNCTION_FLAGS_PRESENT) {
3022         case SLTG_FUNCTION_MAGIC:
3023             (*ppFuncDesc)->funcdesc.funckind = FUNC_PUREVIRTUAL;
3024             break;
3025         case SLTG_DISPATCH_FUNCTION_MAGIC:
3026             (*ppFuncDesc)->funcdesc.funckind = FUNC_DISPATCH;
3027             break;
3028         case SLTG_STATIC_FUNCTION_MAGIC:
3029             (*ppFuncDesc)->funcdesc.funckind = FUNC_STATIC;
3030             break;
3031         default:
3032             FIXME("unimplemented func magic = %02x\n", pFunc->magic & ~SLTG_FUNCTION_FLAGS_PRESENT);
3033             HeapFree(GetProcessHeap(), 0, *ppFuncDesc);
3034             *ppFuncDesc = NULL;
3035             return;
3036         }
3037         (*ppFuncDesc)->Name = TLB_MultiByteToBSTR(pFunc->name + pNameTable);
3038
3039         (*ppFuncDesc)->funcdesc.memid = pFunc->dispid;
3040         (*ppFuncDesc)->funcdesc.invkind = pFunc->inv >> 4;
3041         (*ppFuncDesc)->funcdesc.callconv = pFunc->nacc & 0x7;
3042         (*ppFuncDesc)->funcdesc.cParams = pFunc->nacc >> 3;
3043         (*ppFuncDesc)->funcdesc.cParamsOpt = (pFunc->retnextopt & 0x7e) >> 1;
3044         (*ppFuncDesc)->funcdesc.oVft = pFunc->vtblpos;
3045
3046         if(pFunc->magic & SLTG_FUNCTION_FLAGS_PRESENT)
3047             (*ppFuncDesc)->funcdesc.wFuncFlags = pFunc->funcflags;
3048
3049         if(pFunc->retnextopt & 0x80)
3050             pType = &pFunc->rettype;
3051         else
3052             pType = (WORD*)(pBlk + pFunc->rettype);
3053
3054         SLTG_DoElem(pType, pBlk, &(*ppFuncDesc)->funcdesc.elemdescFunc, ref_lookup);
3055
3056         (*ppFuncDesc)->funcdesc.lprgelemdescParam =
3057           HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3058                     (*ppFuncDesc)->funcdesc.cParams * sizeof(ELEMDESC));
3059         (*ppFuncDesc)->pParamDesc =
3060           HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3061                     (*ppFuncDesc)->funcdesc.cParams * sizeof(TLBParDesc));
3062
3063         pArg = (WORD*)(pBlk + pFunc->arg_off);
3064
3065         for(param = 0; param < (*ppFuncDesc)->funcdesc.cParams; param++) {
3066             char *paramName = pNameTable + *pArg;
3067             BOOL HaveOffs;
3068             /* If arg type follows then paramName points to the 2nd
3069                letter of the name, else the next WORD is an offset to
3070                the arg type and paramName points to the first letter.
3071                So let's take one char off paramName and see if we're
3072                pointing at an alpha-numeric char.  However if *pArg is
3073                0xffff or 0xfffe then the param has no name, the former
3074                meaning that the next WORD is the type, the latter
3075                meaning the the next WORD is an offset to the type. */
3076
3077             HaveOffs = FALSE;
3078             if(*pArg == 0xffff)
3079                 paramName = NULL;
3080             else if(*pArg == 0xfffe) {
3081                 paramName = NULL;
3082                 HaveOffs = TRUE;
3083             }
3084             else if(paramName[-1] && !isalnum(paramName[-1]))
3085                 HaveOffs = TRUE;
3086
3087             pArg++;
3088
3089             if(HaveOffs) { /* the next word is an offset to type */
3090                 pType = (WORD*)(pBlk + *pArg);
3091                 SLTG_DoElem(pType, pBlk,
3092                             &(*ppFuncDesc)->funcdesc.lprgelemdescParam[param], ref_lookup);
3093                 pArg++;
3094             } else {
3095                 if(paramName)
3096                   paramName--;
3097                 pArg = SLTG_DoElem(pArg, pBlk,
3098                                    &(*ppFuncDesc)->funcdesc.lprgelemdescParam[param], ref_lookup);
3099             }
3100
3101             /* Are we an optional param ? */
3102             if((*ppFuncDesc)->funcdesc.cParams - param <=
3103                (*ppFuncDesc)->funcdesc.cParamsOpt)
3104               (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].u.paramdesc.wParamFlags |= PARAMFLAG_FOPT;
3105
3106             if(paramName) {
3107                 (*ppFuncDesc)->pParamDesc[param].Name =
3108                   TLB_MultiByteToBSTR(paramName);
3109             }
3110         }
3111
3112         ppFuncDesc = &((*ppFuncDesc)->next);
3113         if(pFunc->next == 0xffff) break;
3114     }
3115     pTI->TypeAttr.cFuncs = cFuncs;
3116 }
3117
3118 static void SLTG_ProcessCoClass(char *pBlk, ITypeInfoImpl *pTI,
3119                                 char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3120                                 SLTG_TypeInfoTail *pTITail)
3121 {
3122     char *pFirstItem, *pNextItem;
3123     sltg_ref_lookup_t *ref_lookup = NULL;
3124
3125     if(pTIHeader->href_table != 0xffffffff) {
3126         ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3127                     pNameTable);
3128     }
3129
3130     pFirstItem = pNextItem = pBlk;
3131
3132     if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
3133         pNextItem = SLTG_DoImpls(pFirstItem, pTI, FALSE, ref_lookup);
3134     }
3135     HeapFree(GetProcessHeap(), 0, ref_lookup);
3136 }
3137
3138
3139 static void SLTG_ProcessInterface(char *pBlk, ITypeInfoImpl *pTI,
3140                                   char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3141                                   SLTG_TypeInfoTail *pTITail)
3142 {
3143     char *pFirstItem, *pNextItem;
3144     sltg_ref_lookup_t *ref_lookup = NULL;
3145
3146     if(pTIHeader->href_table != 0xffffffff) {
3147         ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3148                     pNameTable);
3149     }
3150
3151     pFirstItem = pNextItem = pBlk;
3152
3153     if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
3154         pNextItem = SLTG_DoImpls(pFirstItem, pTI, TRUE, ref_lookup);
3155     }
3156
3157     if (pTITail->funcs_off != 0xffff)
3158         SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup);
3159
3160     HeapFree(GetProcessHeap(), 0, ref_lookup);
3161
3162     if (TRACE_ON(typelib))
3163         dump_TLBFuncDesc(pTI->funclist);
3164 }
3165
3166 static void SLTG_ProcessRecord(char *pBlk, ITypeInfoImpl *pTI,
3167                                char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3168                                SLTG_TypeInfoTail *pTITail)
3169 {
3170   SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, NULL);
3171 }
3172
3173 static void SLTG_ProcessAlias(char *pBlk, ITypeInfoImpl *pTI,
3174                               char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3175                               SLTG_TypeInfoTail *pTITail)
3176 {
3177   WORD *pType;
3178   sltg_ref_lookup_t *ref_lookup = NULL;
3179
3180   if (pTITail->simple_alias) {
3181     /* if simple alias, no more processing required */
3182     pTI->TypeAttr.tdescAlias.vt = pTITail->tdescalias_vt;
3183     return;
3184   }
3185
3186   if(pTIHeader->href_table != 0xffffffff) {
3187       ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3188                   pNameTable);
3189   }
3190
3191   /* otherwise it is an offset to a type */
3192   pType = (WORD *)(pBlk + pTITail->tdescalias_vt);
3193
3194   SLTG_DoType(pType, pBlk, &pTI->TypeAttr.tdescAlias, ref_lookup);
3195
3196   HeapFree(GetProcessHeap(), 0, ref_lookup);
3197 }
3198
3199 static void SLTG_ProcessDispatch(char *pBlk, ITypeInfoImpl *pTI,
3200                                  char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3201                                  SLTG_TypeInfoTail *pTITail)
3202 {
3203   sltg_ref_lookup_t *ref_lookup = NULL;
3204   if (pTIHeader->href_table != 0xffffffff)
3205       ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3206                                   pNameTable);
3207
3208   if (pTITail->vars_off != 0xffff)
3209     SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, ref_lookup);
3210
3211   if (pTITail->funcs_off != 0xffff)
3212     SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup);
3213
3214   /* this is necessary to cope with MSFT typelibs that set cFuncs to the number
3215    * of dispinterface functons including the IDispatch ones, so
3216    * ITypeInfo::GetFuncDesc takes the real value for cFuncs from cbSizeVft */
3217   pTI->TypeAttr.cbSizeVft = pTI->TypeAttr.cFuncs * sizeof(void *);
3218
3219   HeapFree(GetProcessHeap(), 0, ref_lookup);
3220   if (TRACE_ON(typelib))
3221       dump_TLBFuncDesc(pTI->funclist);
3222 }
3223
3224 static void SLTG_ProcessEnum(char *pBlk, ITypeInfoImpl *pTI,
3225                              char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3226                              SLTG_TypeInfoTail *pTITail)
3227 {
3228   SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, NULL);
3229 }
3230
3231 static void SLTG_ProcessModule(char *pBlk, ITypeInfoImpl *pTI,
3232                                char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3233                                SLTG_TypeInfoTail *pTITail)
3234 {
3235   sltg_ref_lookup_t *ref_lookup = NULL;
3236   if (pTIHeader->href_table != 0xffffffff)
3237       ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3238                                   pNameTable);
3239
3240   if (pTITail->vars_off != 0xffff)
3241     SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, ref_lookup);
3242
3243   if (pTITail->funcs_off != 0xffff)
3244     SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup);
3245   HeapFree(GetProcessHeap(), 0, ref_lookup);
3246 }
3247
3248 /* Because SLTG_OtherTypeInfo is such a painful struct, we make a more
3249    managable copy of it into this */
3250 typedef struct {
3251   WORD small_no;
3252   char *index_name;
3253   char *other_name;
3254   WORD res1a;
3255   WORD name_offs;
3256   WORD more_bytes;
3257   char *extra;
3258   WORD res20;
3259   DWORD helpcontext;
3260   WORD res26;
3261   GUID uuid;
3262 } SLTG_InternalOtherTypeInfo;
3263
3264 /****************************************************************************
3265  *      ITypeLib2_Constructor_SLTG
3266  *
3267  * loading a SLTG typelib from an in-memory image
3268  */
3269 static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength)
3270 {
3271     ITypeLibImpl *pTypeLibImpl;
3272     SLTG_Header *pHeader;
3273     SLTG_BlkEntry *pBlkEntry;
3274     SLTG_Magic *pMagic;
3275     SLTG_Index *pIndex;
3276     SLTG_Pad9 *pPad9;
3277     LPVOID pBlk, pFirstBlk;
3278     SLTG_LibBlk *pLibBlk;
3279     SLTG_InternalOtherTypeInfo *pOtherTypeInfoBlks;
3280     char *pAfterOTIBlks = NULL;
3281     char *pNameTable, *ptr;
3282     int i;
3283     DWORD len, order;
3284     ITypeInfoImpl **ppTypeInfoImpl;
3285
3286     TRACE_(typelib)("%p, TLB length = %d\n", pLib, dwTLBLength);
3287
3288
3289     pTypeLibImpl = TypeLibImpl_Constructor();
3290     if (!pTypeLibImpl) return NULL;
3291
3292     pHeader = pLib;
3293
3294     TRACE_(typelib)("header:\n");
3295     TRACE_(typelib)("\tmagic=0x%08x, file blocks = %d\n", pHeader->SLTG_magic,
3296           pHeader->nrOfFileBlks );
3297     if (pHeader->SLTG_magic != SLTG_SIGNATURE) {
3298         FIXME("Header type magic 0x%08x not supported.\n",
3299               pHeader->SLTG_magic);
3300         return NULL;
3301     }
3302
3303     /* There are pHeader->nrOfFileBlks - 2 TypeInfo records in this typelib */
3304     pTypeLibImpl->TypeInfoCount = pHeader->nrOfFileBlks - 2;
3305
3306     /* This points to pHeader->nrOfFileBlks - 1 of SLTG_BlkEntry */
3307     pBlkEntry = (SLTG_BlkEntry*)(pHeader + 1);
3308
3309     /* Next we have a magic block */
3310     pMagic = (SLTG_Magic*)(pBlkEntry + pHeader->nrOfFileBlks - 1);
3311
3312     /* Let's see if we're still in sync */
3313     if(memcmp(pMagic->CompObj_magic, SLTG_COMPOBJ_MAGIC,
3314               sizeof(SLTG_COMPOBJ_MAGIC))) {
3315         FIXME("CompObj magic = %s\n", pMagic->CompObj_magic);
3316         return NULL;
3317     }
3318     if(memcmp(pMagic->dir_magic, SLTG_DIR_MAGIC,
3319               sizeof(SLTG_DIR_MAGIC))) {
3320         FIXME("dir magic = %s\n", pMagic->dir_magic);
3321         return NULL;
3322     }
3323
3324     pIndex = (SLTG_Index*)(pMagic+1);
3325
3326     pPad9 = (SLTG_Pad9*)(pIndex + pTypeLibImpl->TypeInfoCount);
3327
3328     pFirstBlk = (LPVOID)(pPad9 + 1);
3329
3330     /* We'll set up a ptr to the main library block, which is the last one. */
3331
3332     for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0;
3333           pBlkEntry[order].next != 0;
3334           order = pBlkEntry[order].next - 1, i++) {
3335        pBlk = (char*)pBlk + pBlkEntry[order].len;
3336     }
3337     pLibBlk = pBlk;
3338
3339     len = SLTG_ReadLibBlk(pLibBlk, pTypeLibImpl);
3340
3341     /* Now there's 0x40 bytes of 0xffff with the numbers 0 to TypeInfoCount
3342        interspersed */
3343
3344     len += 0x40;
3345
3346     /* And now TypeInfoCount of SLTG_OtherTypeInfo */
3347
3348     pOtherTypeInfoBlks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3349                                    sizeof(*pOtherTypeInfoBlks) *
3350                                    pTypeLibImpl->TypeInfoCount);
3351
3352
3353     ptr = (char*)pLibBlk + len;
3354
3355     for(i = 0; i < pTypeLibImpl->TypeInfoCount; i++) {
3356         WORD w, extra;
3357         len = 0;
3358
3359         pOtherTypeInfoBlks[i].small_no = *(WORD*)ptr;
3360
3361         w = *(WORD*)(ptr + 2);
3362         if(w != 0xffff) {
3363             len += w;
3364             pOtherTypeInfoBlks[i].index_name = HeapAlloc(GetProcessHeap(),0,
3365                                                          w+1);
3366             memcpy(pOtherTypeInfoBlks[i].index_name, ptr + 4, w);
3367             pOtherTypeInfoBlks[i].index_name[w] = '\0';
3368         }
3369         w = *(WORD*)(ptr + 4 + len);
3370         if(w != 0xffff) {
3371             TRACE_(typelib)("\twith %s\n", debugstr_an(ptr + 6 + len, w));
3372             len += w;
3373             pOtherTypeInfoBlks[i].other_name = HeapAlloc(GetProcessHeap(),0,
3374                                                          w+1);
3375             memcpy(pOtherTypeInfoBlks[i].other_name, ptr + 6 + len, w);
3376             pOtherTypeInfoBlks[i].other_name[w] = '\0';
3377         }
3378         pOtherTypeInfoBlks[i].res1a = *(WORD*)(ptr + len + 6);
3379         pOtherTypeInfoBlks[i].name_offs = *(WORD*)(ptr + len + 8);
3380         extra = pOtherTypeInfoBlks[i].more_bytes = *(WORD*)(ptr + 10 + len);
3381         if(extra) {
3382             pOtherTypeInfoBlks[i].extra = HeapAlloc(GetProcessHeap(),0,
3383                                                     extra);
3384             memcpy(pOtherTypeInfoBlks[i].extra, ptr + 12, extra);
3385             len += extra;
3386         }
3387         pOtherTypeInfoBlks[i].res20 = *(WORD*)(ptr + 12 + len);
3388         pOtherTypeInfoBlks[i].helpcontext = *(DWORD*)(ptr + 14 + len);
3389         pOtherTypeInfoBlks[i].res26 = *(WORD*)(ptr + 18 + len);
3390         memcpy(&pOtherTypeInfoBlks[i].uuid, ptr + 20 + len, sizeof(GUID));
3391         len += sizeof(SLTG_OtherTypeInfo);
3392         ptr += len;
3393     }
3394
3395     pAfterOTIBlks = ptr;
3396
3397     /* Skip this WORD and get the next DWORD */
3398     len = *(DWORD*)(pAfterOTIBlks + 2);
3399
3400     /* Now add this to pLibBLk look at what we're pointing at and
3401        possibly add 0x20, then add 0x216, sprinkle a bit a magic
3402        dust and we should be pointing at the beginning of the name
3403        table */
3404
3405     pNameTable = (char*)pLibBlk + len;
3406
3407    switch(*(WORD*)pNameTable) {
3408    case 0xffff:
3409        break;
3410    case 0x0200:
3411        pNameTable += 0x20;
3412        break;
3413    default:
3414        FIXME("pNameTable jump = %x\n", *(WORD*)pNameTable);
3415        break;
3416    }
3417
3418     pNameTable += 0x216;
3419
3420     pNameTable += 2;
3421
3422     TRACE("Library name is %s\n", pNameTable + pLibBlk->name);
3423
3424     pTypeLibImpl->Name = TLB_MultiByteToBSTR(pNameTable + pLibBlk->name);
3425
3426
3427     /* Hopefully we now have enough ptrs set up to actually read in
3428        some TypeInfos.  It's not clear which order to do them in, so
3429        I'll just follow the links along the BlkEntry chain and read
3430        them in the order in which they are in the file */
3431
3432     ppTypeInfoImpl = &(pTypeLibImpl->pTypeInfo);
3433
3434     for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0;
3435         pBlkEntry[order].next != 0;
3436         order = pBlkEntry[order].next - 1, i++) {
3437
3438       SLTG_TypeInfoHeader *pTIHeader;
3439       SLTG_TypeInfoTail *pTITail;
3440       SLTG_MemberHeader *pMemHeader;
3441
3442       if(strcmp(pBlkEntry[order].index_string + (char*)pMagic,
3443                 pOtherTypeInfoBlks[i].index_name)) {
3444         FIXME("Index strings don't match\n");
3445         return NULL;
3446       }
3447
3448       pTIHeader = pBlk;
3449       if(pTIHeader->magic != SLTG_TIHEADER_MAGIC) {
3450         FIXME("TypeInfoHeader magic = %04x\n", pTIHeader->magic);
3451         return NULL;
3452       }
3453       TRACE("pTIHeader->res06 = %x, pTIHeader->res0e = %x, pTIHeader->res16 = %x, pTIHeader->res1e = %x\n",
3454         pTIHeader->res06, pTIHeader->res0e, pTIHeader->res16, pTIHeader->res1e);
3455
3456       *ppTypeInfoImpl = (ITypeInfoImpl*)ITypeInfo_Constructor();
3457       (*ppTypeInfoImpl)->pTypeLib = pTypeLibImpl;
3458       (*ppTypeInfoImpl)->index = i;
3459       (*ppTypeInfoImpl)->Name = TLB_MultiByteToBSTR(
3460                                              pOtherTypeInfoBlks[i].name_offs +
3461                                              pNameTable);
3462       (*ppTypeInfoImpl)->dwHelpContext = pOtherTypeInfoBlks[i].helpcontext;
3463       memcpy(&((*ppTypeInfoImpl)->TypeAttr.guid), &pOtherTypeInfoBlks[i].uuid,
3464              sizeof(GUID));
3465       (*ppTypeInfoImpl)->TypeAttr.typekind = pTIHeader->typekind;
3466       (*ppTypeInfoImpl)->TypeAttr.wMajorVerNum = pTIHeader->major_version;
3467       (*ppTypeInfoImpl)->TypeAttr.wMinorVerNum = pTIHeader->minor_version;
3468       (*ppTypeInfoImpl)->TypeAttr.wTypeFlags =
3469         (pTIHeader->typeflags1 >> 3) | (pTIHeader->typeflags2 << 5);
3470
3471       if((pTIHeader->typeflags1 & 7) != 2)
3472         FIXME("typeflags1 = %02x\n", pTIHeader->typeflags1);
3473       if(pTIHeader->typeflags3 != 2)
3474         FIXME("typeflags3 = %02x\n", pTIHeader->typeflags3);
3475
3476       TRACE("TypeInfo %s of kind %s guid %s typeflags %04x\n",
3477             debugstr_w((*ppTypeInfoImpl)->Name),
3478             typekind_desc[pTIHeader->typekind],
3479             debugstr_guid(&(*ppTypeInfoImpl)->TypeAttr.guid),
3480             (*ppTypeInfoImpl)->TypeAttr.wTypeFlags);
3481
3482       pMemHeader = (SLTG_MemberHeader*)((char *)pBlk + pTIHeader->elem_table);
3483
3484       pTITail = (SLTG_TypeInfoTail*)((char *)(pMemHeader + 1) + pMemHeader->cbExtra);
3485
3486       (*ppTypeInfoImpl)->TypeAttr.cbAlignment = pTITail->cbAlignment;
3487       (*ppTypeInfoImpl)->TypeAttr.cbSizeInstance = pTITail->cbSizeInstance;
3488       (*ppTypeInfoImpl)->TypeAttr.cbSizeVft = pTITail->cbSizeVft;
3489
3490       switch(pTIHeader->typekind) {
3491       case TKIND_ENUM:
3492         SLTG_ProcessEnum((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
3493                          pTIHeader, pTITail);
3494         break;
3495
3496       case TKIND_RECORD:
3497         SLTG_ProcessRecord((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
3498                            pTIHeader, pTITail);
3499         break;
3500
3501       case TKIND_INTERFACE:
3502         SLTG_ProcessInterface((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
3503                               pTIHeader, pTITail);
3504         break;
3505
3506       case TKIND_COCLASS:
3507         SLTG_ProcessCoClass((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
3508                             pTIHeader, pTITail);
3509         break;
3510
3511       case TKIND_ALIAS:
3512         SLTG_ProcessAlias((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
3513                           pTIHeader, pTITail);
3514         break;
3515
3516       case TKIND_DISPATCH:
3517         SLTG_ProcessDispatch((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
3518                              pTIHeader, pTITail);
3519         break;
3520
3521       case TKIND_MODULE:
3522         SLTG_ProcessModule((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
3523                            pTIHeader, pTITail);
3524         break;
3525
3526       default:
3527         FIXME("Not processing typekind %d\n", pTIHeader->typekind);
3528         break;
3529
3530       }
3531
3532       if(pTITail) { /* could get cFuncs, cVars and cImplTypes from here
3533                        but we've already set those */
3534 #define X(x) TRACE_(typelib)("tt "#x": %x\n",pTITail->res##x);
3535           X(06);
3536           X(16);
3537           X(18);
3538           X(1a);
3539           X(1e);
3540           X(24);
3541           X(26);
3542           X(2a);
3543           X(2c);
3544           X(2e);
3545           X(30);
3546           X(32);
3547           X(34);
3548       }
3549       ppTypeInfoImpl = &((*ppTypeInfoImpl)->next);
3550       pBlk = (char*)pBlk + pBlkEntry[order].len;
3551     }
3552
3553     if(i != pTypeLibImpl->TypeInfoCount) {
3554       FIXME("Somehow processed %d TypeInfos\n", i);
3555       return NULL;
3556     }
3557
3558     HeapFree(GetProcessHeap(), 0, pOtherTypeInfoBlks);
3559     return (ITypeLib2*)pTypeLibImpl;
3560 }
3561
3562 /* ITypeLib::QueryInterface
3563  */
3564 static HRESULT WINAPI ITypeLib2_fnQueryInterface(
3565         ITypeLib2 * iface,
3566         REFIID riid,
3567         VOID **ppvObject)
3568 {
3569     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3570
3571     TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
3572
3573     *ppvObject=NULL;
3574     if(IsEqualIID(riid, &IID_IUnknown) ||
3575        IsEqualIID(riid,&IID_ITypeLib)||
3576        IsEqualIID(riid,&IID_ITypeLib2))
3577     {
3578         *ppvObject = This;
3579     }
3580
3581     if(*ppvObject)
3582     {
3583         ITypeLib2_AddRef(iface);
3584         TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
3585         return S_OK;
3586     }
3587     TRACE("-- Interface: E_NOINTERFACE\n");
3588     return E_NOINTERFACE;
3589 }
3590
3591 /* ITypeLib::AddRef
3592  */
3593 static ULONG WINAPI ITypeLib2_fnAddRef( ITypeLib2 *iface)
3594 {
3595     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3596     ULONG ref = InterlockedIncrement(&This->ref);
3597
3598     TRACE("(%p)->ref was %u\n",This, ref - 1);
3599
3600     return ref;
3601 }
3602
3603 /* ITypeLib::Release
3604  */
3605 static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface)
3606 {
3607     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3608     ULONG ref = InterlockedDecrement(&This->ref);
3609
3610     TRACE("(%p)->(%u)\n",This, ref);
3611
3612     if (!ref)
3613     {
3614       TLBImpLib *pImpLib, *pImpLibNext;
3615       TLBCustData *pCustData, *pCustDataNext;
3616       TLBRefType *ref_type;
3617       void *cursor2;
3618       int i;
3619
3620       /* remove cache entry */
3621       if(This->path)
3622       {
3623           TRACE("removing from cache list\n");
3624           EnterCriticalSection(&cache_section);
3625           if (This->next) This->next->prev = This->prev;
3626           if (This->prev) This->prev->next = This->next;
3627           else tlb_cache_first = This->next;
3628           LeaveCriticalSection(&cache_section);
3629           HeapFree(GetProcessHeap(), 0, This->path);
3630       }
3631       TRACE(" destroying ITypeLib(%p)\n",This);
3632
3633       if (This->Name)
3634       {
3635           SysFreeString(This->Name);
3636           This->Name = NULL;
3637       }
3638
3639       if (This->DocString)
3640       {
3641           SysFreeString(This->DocString);
3642           This->DocString = NULL;
3643       }
3644
3645       if (This->HelpFile)
3646       {
3647           SysFreeString(This->HelpFile);
3648           This->HelpFile = NULL;
3649       }
3650
3651       if (This->HelpStringDll)
3652       {
3653           SysFreeString(This->HelpStringDll);
3654           This->HelpStringDll = NULL;
3655       }
3656
3657       for (pCustData = This->pCustData; pCustData; pCustData = pCustDataNext)
3658       {
3659           VariantClear(&pCustData->data);
3660
3661           pCustDataNext = pCustData->next;
3662           TLB_Free(pCustData);
3663       }
3664
3665       for (i = 0; i < This->ctTypeDesc; i++)
3666           if (This->pTypeDesc[i].vt == VT_CARRAY)
3667               TLB_Free(This->pTypeDesc[i].u.lpadesc);
3668
3669       TLB_Free(This->pTypeDesc);
3670
3671       for (pImpLib = This->pImpLibs; pImpLib; pImpLib = pImpLibNext)
3672       {
3673           if (pImpLib->pImpTypeLib)
3674               ITypeLib_Release((ITypeLib *)pImpLib->pImpTypeLib);
3675           TLB_Free(pImpLib->name);
3676
3677           pImpLibNext = pImpLib->next;
3678           TLB_Free(pImpLib);
3679       }
3680
3681       LIST_FOR_EACH_ENTRY_SAFE(ref_type, cursor2, &This->ref_list, TLBRefType, entry)
3682       {
3683           list_remove(&ref_type->entry);
3684           TLB_Free(ref_type);
3685       }
3686
3687       if (This->pTypeInfo) /* can be NULL */
3688           ITypeInfo_Release((ITypeInfo*) This->pTypeInfo);
3689       HeapFree(GetProcessHeap(),0,This);
3690       return 0;
3691     }
3692
3693     return ref;
3694 }
3695
3696 /* ITypeLib::GetTypeInfoCount
3697  *
3698  * Returns the number of type descriptions in the type library
3699  */
3700 static UINT WINAPI ITypeLib2_fnGetTypeInfoCount( ITypeLib2 *iface)
3701 {
3702     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3703     TRACE("(%p)->count is %d\n",This, This->TypeInfoCount);
3704     return This->TypeInfoCount;
3705 }
3706
3707 /* ITypeLib::GetTypeInfo
3708  *
3709  * retrieves the specified type description in the library.
3710  */
3711 static HRESULT WINAPI ITypeLib2_fnGetTypeInfo(
3712     ITypeLib2 *iface,
3713     UINT index,
3714     ITypeInfo **ppTInfo)
3715 {
3716     int i;
3717
3718     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3719     ITypeInfoImpl *pTypeInfo = This->pTypeInfo;
3720
3721     TRACE("(%p)->(index=%d)\n", This, index);
3722
3723     if (!ppTInfo) return E_INVALIDARG;
3724
3725     /* search element n in list */
3726     for(i=0; i < index; i++)
3727     {
3728       pTypeInfo = pTypeInfo->next;
3729       if (!pTypeInfo)
3730       {
3731         TRACE("-- element not found\n");
3732         return TYPE_E_ELEMENTNOTFOUND;
3733       }
3734     }
3735
3736     *ppTInfo = (ITypeInfo *) pTypeInfo;
3737
3738     ITypeInfo_AddRef(*ppTInfo);
3739     TRACE("-- found (%p)\n",*ppTInfo);
3740     return S_OK;
3741 }
3742
3743
3744 /* ITypeLibs::GetTypeInfoType
3745  *
3746  * Retrieves the type of a type description.
3747  */
3748 static HRESULT WINAPI ITypeLib2_fnGetTypeInfoType(
3749     ITypeLib2 *iface,
3750     UINT index,
3751     TYPEKIND *pTKind)
3752 {
3753     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3754     int i;
3755     ITypeInfoImpl *pTInfo = This->pTypeInfo;
3756     
3757     if ((ITypeLib2_fnGetTypeInfoCount(iface) < index + 1) || (index < 0))
3758          return TYPE_E_ELEMENTNOTFOUND;
3759
3760     TRACE("(%p) index %d\n", This, index);
3761
3762     if(!pTKind) return E_INVALIDARG;
3763
3764     /* search element n in list */
3765     for(i=0; i < index; i++)
3766     {
3767       if(!pTInfo)
3768       {
3769         TRACE("-- element not found\n");
3770         return TYPE_E_ELEMENTNOTFOUND;
3771       }
3772       pTInfo = pTInfo->next;
3773     }
3774
3775     *pTKind = pTInfo->TypeAttr.typekind;
3776     TRACE("-- found Type (%d)\n", *pTKind);
3777     return S_OK;
3778 }
3779
3780 /* ITypeLib::GetTypeInfoOfGuid
3781  *
3782  * Retrieves the type description that corresponds to the specified GUID.
3783  *
3784  */
3785 static HRESULT WINAPI ITypeLib2_fnGetTypeInfoOfGuid(
3786     ITypeLib2 *iface,
3787     REFGUID guid,
3788     ITypeInfo **ppTInfo)
3789 {
3790     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3791     ITypeInfoImpl *pTypeInfo = This->pTypeInfo; /* head of list */
3792
3793     TRACE("(%p)\n\tguid:\t%s)\n",This,debugstr_guid(guid));
3794
3795     if (!pTypeInfo)
3796     {
3797         WARN("-- element not found\n");
3798         return TYPE_E_ELEMENTNOTFOUND;
3799     }
3800
3801     /* search linked list for guid */
3802     while( !IsEqualIID(guid,&pTypeInfo->TypeAttr.guid) )
3803     {
3804       pTypeInfo = pTypeInfo->next;
3805
3806       if (!pTypeInfo)
3807       {
3808         /* end of list reached */
3809         WARN("-- element not found\n");
3810         return TYPE_E_ELEMENTNOTFOUND;
3811       }
3812     }
3813
3814     TRACE("-- found (%p, %s)\n",
3815           pTypeInfo,
3816           debugstr_w(pTypeInfo->Name));
3817
3818     *ppTInfo = (ITypeInfo*)pTypeInfo;
3819     ITypeInfo_AddRef(*ppTInfo);
3820     return S_OK;
3821 }
3822
3823 /* ITypeLib::GetLibAttr
3824  *
3825  * Retrieves the structure that contains the library's attributes.
3826  *
3827  */
3828 static HRESULT WINAPI ITypeLib2_fnGetLibAttr(
3829         ITypeLib2 *iface,
3830         LPTLIBATTR *ppTLibAttr)
3831 {
3832     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3833     TRACE("(%p)\n",This);
3834     *ppTLibAttr = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppTLibAttr));
3835     memcpy(*ppTLibAttr, &This->LibAttr, sizeof(**ppTLibAttr));
3836     return S_OK;
3837 }
3838
3839 /* ITypeLib::GetTypeComp
3840  *
3841  * Enables a client compiler to bind to a library's types, variables,
3842  * constants, and global functions.
3843  *
3844  */
3845 static HRESULT WINAPI ITypeLib2_fnGetTypeComp(
3846         ITypeLib2 *iface,
3847         ITypeComp **ppTComp)
3848 {
3849     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3850
3851     TRACE("(%p)->(%p)\n",This,ppTComp);
3852     *ppTComp = (ITypeComp *)&This->lpVtblTypeComp;
3853     ITypeComp_AddRef(*ppTComp);
3854
3855     return S_OK;
3856 }
3857
3858 /* ITypeLib::GetDocumentation
3859  *
3860  * Retrieves the library's documentation string, the complete Help file name
3861  * and path, and the context identifier for the library Help topic in the Help
3862  * file.
3863  *
3864  * On a successful return all non-null BSTR pointers will have been set,
3865  * possibly to NULL.
3866  */
3867 static HRESULT WINAPI ITypeLib2_fnGetDocumentation(
3868     ITypeLib2 *iface,
3869     INT index,
3870     BSTR *pBstrName,
3871     BSTR *pBstrDocString,
3872     DWORD *pdwHelpContext,
3873     BSTR *pBstrHelpFile)
3874 {
3875     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3876
3877     HRESULT result = E_INVALIDARG;
3878
3879     ITypeInfo *pTInfo;
3880
3881
3882     TRACE("(%p) index %d Name(%p) DocString(%p) HelpContext(%p) HelpFile(%p)\n",
3883         This, index,
3884         pBstrName, pBstrDocString,
3885         pdwHelpContext, pBstrHelpFile);
3886
3887     if(index<0)
3888     {
3889         /* documentation for the typelib */
3890         if(pBstrName)
3891         {
3892             if (This->Name)
3893             {
3894                 if(!(*pBstrName = SysAllocString(This->Name)))
3895                     goto memerr1;
3896             }
3897             else
3898                 *pBstrName = NULL;
3899         }
3900         if(pBstrDocString)
3901         {
3902             if (This->DocString)
3903             {
3904                 if(!(*pBstrDocString = SysAllocString(This->DocString)))
3905                     goto memerr2;
3906             }
3907             else if (This->Name)
3908             {
3909                 if(!(*pBstrDocString = SysAllocString(This->Name)))
3910                     goto memerr2;
3911             }
3912             else
3913                 *pBstrDocString = NULL;
3914         }
3915         if(pdwHelpContext)
3916         {
3917             *pdwHelpContext = This->dwHelpContext;
3918         }
3919         if(pBstrHelpFile)
3920         {
3921             if (This->HelpFile)
3922             {
3923                 if(!(*pBstrHelpFile = SysAllocString(This->HelpFile)))
3924                     goto memerr3;
3925             }
3926             else
3927                 *pBstrHelpFile = NULL;
3928         }
3929
3930         result = S_OK;
3931     }
3932     else
3933     {
3934         /* for a typeinfo */
3935         result = ITypeLib2_fnGetTypeInfo(iface, index, &pTInfo);
3936
3937         if(SUCCEEDED(result))
3938         {
3939             result = ITypeInfo_GetDocumentation(pTInfo,
3940                                           MEMBERID_NIL,
3941                                           pBstrName,
3942                                           pBstrDocString,
3943                                           pdwHelpContext, pBstrHelpFile);
3944
3945             ITypeInfo_Release(pTInfo);
3946         }
3947     }
3948     return result;
3949 memerr3:
3950     if (pBstrDocString) SysFreeString (*pBstrDocString);
3951 memerr2:
3952     if (pBstrName) SysFreeString (*pBstrName);
3953 memerr1:
3954     return STG_E_INSUFFICIENTMEMORY;
3955 }
3956
3957 /* ITypeLib::IsName
3958  *
3959  * Indicates whether a passed-in string contains the name of a type or member
3960  * described in the library.
3961  *
3962  */
3963 static HRESULT WINAPI ITypeLib2_fnIsName(
3964         ITypeLib2 *iface,
3965         LPOLESTR szNameBuf,
3966         ULONG lHashVal,
3967         BOOL *pfName)
3968 {
3969     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3970     ITypeInfoImpl *pTInfo;
3971     TLBFuncDesc *pFInfo;
3972     TLBVarDesc *pVInfo;
3973     int i;
3974     UINT nNameBufLen = (lstrlenW(szNameBuf)+1)*sizeof(WCHAR);
3975
3976     TRACE("(%p)->(%s,%08x,%p)\n", This, debugstr_w(szNameBuf), lHashVal,
3977           pfName);
3978
3979     *pfName=TRUE;
3980     for(pTInfo=This->pTypeInfo;pTInfo;pTInfo=pTInfo->next){
3981         if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
3982         for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
3983             if(!memcmp(szNameBuf,pFInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
3984             for(i=0;i<pFInfo->funcdesc.cParams;i++)
3985                 if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name, nNameBufLen))
3986                     goto ITypeLib2_fnIsName_exit;
3987         }
3988         for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next)
3989             if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
3990
3991     }
3992     *pfName=FALSE;
3993
3994 ITypeLib2_fnIsName_exit:
3995     TRACE("(%p)slow! search for %s: %s found!\n", This,
3996           debugstr_w(szNameBuf), *pfName?"NOT":"");
3997
3998     return S_OK;
3999 }
4000
4001 /* ITypeLib::FindName
4002  *
4003  * Finds occurrences of a type description in a type library. This may be used
4004  * to quickly verify that a name exists in a type library.
4005  *
4006  */
4007 static HRESULT WINAPI ITypeLib2_fnFindName(
4008         ITypeLib2 *iface,
4009         LPOLESTR szNameBuf,
4010         ULONG lHashVal,
4011         ITypeInfo **ppTInfo,
4012         MEMBERID *rgMemId,
4013         UINT16 *pcFound)
4014 {
4015     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4016     ITypeInfoImpl *pTInfo;
4017     TLBFuncDesc *pFInfo;
4018     TLBVarDesc *pVInfo;
4019     int i,j = 0;
4020     UINT nNameBufLen = (lstrlenW(szNameBuf)+1)*sizeof(WCHAR);
4021
4022     for(pTInfo=This->pTypeInfo;pTInfo && j<*pcFound; pTInfo=pTInfo->next){
4023         if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit;
4024         for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
4025             if(!memcmp(szNameBuf,pFInfo->Name,nNameBufLen)) goto ITypeLib2_fnFindName_exit;
4026             for(i=0;i<pFInfo->funcdesc.cParams;i++) {
4027                 if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name,nNameBufLen))
4028                     goto ITypeLib2_fnFindName_exit;
4029             }
4030         }
4031         for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next)
4032             if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit;
4033         continue;
4034 ITypeLib2_fnFindName_exit:
4035         ITypeInfo_AddRef((ITypeInfo*)pTInfo);
4036         ppTInfo[j]=(LPTYPEINFO)pTInfo;
4037         j++;
4038     }
4039     TRACE("(%p)slow! search for %d with %s: found %d TypeInfo's!\n",
4040           This, *pcFound, debugstr_w(szNameBuf), j);
4041
4042     *pcFound=j;
4043
4044     return S_OK;
4045 }
4046
4047 /* ITypeLib::ReleaseTLibAttr
4048  *
4049  * Releases the TLIBATTR originally obtained from ITypeLib::GetLibAttr.
4050  *
4051  */
4052 static VOID WINAPI ITypeLib2_fnReleaseTLibAttr(
4053         ITypeLib2 *iface,
4054         TLIBATTR *pTLibAttr)
4055 {
4056     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4057     TRACE("freeing (%p)\n",This);
4058     HeapFree(GetProcessHeap(),0,pTLibAttr);
4059
4060 }
4061
4062 /* ITypeLib2::GetCustData
4063  *
4064  * gets the custom data
4065  */
4066 static HRESULT WINAPI ITypeLib2_fnGetCustData(
4067         ITypeLib2 * iface,
4068         REFGUID guid,
4069         VARIANT *pVarVal)
4070 {
4071     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4072     TLBCustData *pCData;
4073
4074     for(pCData=This->pCustData; pCData; pCData = pCData->next)
4075     {
4076       if( IsEqualIID(guid, &pCData->guid)) break;
4077     }
4078
4079     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
4080
4081     if(pCData)
4082     {
4083         VariantInit( pVarVal);
4084         VariantCopy( pVarVal, &pCData->data);
4085         return S_OK;
4086     }
4087     return E_INVALIDARG;  /* FIXME: correct? */
4088 }
4089
4090 /* ITypeLib2::GetLibStatistics
4091  *
4092  * Returns statistics about a type library that are required for efficient
4093  * sizing of hash tables.
4094  *
4095  */
4096 static HRESULT WINAPI ITypeLib2_fnGetLibStatistics(
4097         ITypeLib2 * iface,
4098         ULONG *pcUniqueNames,
4099         ULONG *pcchUniqueNames)
4100 {
4101     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4102
4103     FIXME("(%p): stub!\n", This);
4104
4105     if(pcUniqueNames) *pcUniqueNames=1;
4106     if(pcchUniqueNames) *pcchUniqueNames=1;
4107     return S_OK;
4108 }
4109
4110 /* ITypeLib2::GetDocumentation2
4111  *
4112  * Retrieves the library's documentation string, the complete Help file name
4113  * and path, the localization context to use, and the context ID for the
4114  * library Help topic in the Help file.
4115  *
4116  */
4117 static HRESULT WINAPI ITypeLib2_fnGetDocumentation2(
4118         ITypeLib2 * iface,
4119         INT index,
4120         LCID lcid,
4121         BSTR *pbstrHelpString,
4122         DWORD *pdwHelpStringContext,
4123         BSTR *pbstrHelpStringDll)
4124 {
4125     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4126     HRESULT result;
4127     ITypeInfo *pTInfo;
4128
4129     FIXME("(%p) index %d lcid %d half implemented stub!\n", This, index, lcid);
4130
4131     /* the help string should be obtained from the helpstringdll,
4132      * using the _DLLGetDocumentation function, based on the supplied
4133      * lcid. Nice to do sometime...
4134      */
4135     if(index<0)
4136     {
4137       /* documentation for the typelib */
4138       if(pbstrHelpString)
4139         *pbstrHelpString=SysAllocString(This->DocString);
4140       if(pdwHelpStringContext)
4141         *pdwHelpStringContext=This->dwHelpContext;
4142       if(pbstrHelpStringDll)
4143         *pbstrHelpStringDll=SysAllocString(This->HelpStringDll);
4144
4145       result = S_OK;
4146     }
4147     else
4148     {
4149       /* for a typeinfo */
4150       result=ITypeLib2_GetTypeInfo(iface, index, &pTInfo);
4151
4152       if(SUCCEEDED(result))
4153       {
4154         ITypeInfo2 * pTInfo2;
4155         result = ITypeInfo_QueryInterface(pTInfo,
4156                                           &IID_ITypeInfo2,
4157                                           (LPVOID*) &pTInfo2);
4158
4159         if(SUCCEEDED(result))
4160         {
4161           result = ITypeInfo2_GetDocumentation2(pTInfo2,
4162                                            MEMBERID_NIL,
4163                                            lcid,
4164                                            pbstrHelpString,
4165                                            pdwHelpStringContext,
4166                                            pbstrHelpStringDll);
4167
4168           ITypeInfo2_Release(pTInfo2);
4169         }
4170
4171         ITypeInfo_Release(pTInfo);
4172       }
4173     }
4174     return result;
4175 }
4176
4177 /* ITypeLib2::GetAllCustData
4178  *
4179  * Gets all custom data items for the library.
4180  *
4181  */
4182 static HRESULT WINAPI ITypeLib2_fnGetAllCustData(
4183         ITypeLib2 * iface,
4184         CUSTDATA *pCustData)
4185 {
4186     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4187     TLBCustData *pCData;
4188     int i;
4189     TRACE("(%p) returning %d items\n", This, This->ctCustData);
4190     pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
4191     if(pCustData->prgCustData ){
4192         pCustData->cCustData=This->ctCustData;
4193         for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
4194             pCustData->prgCustData[i].guid=pCData->guid;
4195             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
4196         }
4197     }else{
4198         ERR(" OUT OF MEMORY!\n");
4199         return E_OUTOFMEMORY;
4200     }
4201     return S_OK;
4202 }
4203
4204 static const ITypeLib2Vtbl tlbvt = {
4205     ITypeLib2_fnQueryInterface,
4206     ITypeLib2_fnAddRef,
4207     ITypeLib2_fnRelease,
4208     ITypeLib2_fnGetTypeInfoCount,
4209     ITypeLib2_fnGetTypeInfo,
4210     ITypeLib2_fnGetTypeInfoType,
4211     ITypeLib2_fnGetTypeInfoOfGuid,
4212     ITypeLib2_fnGetLibAttr,
4213     ITypeLib2_fnGetTypeComp,
4214     ITypeLib2_fnGetDocumentation,
4215     ITypeLib2_fnIsName,
4216     ITypeLib2_fnFindName,
4217     ITypeLib2_fnReleaseTLibAttr,
4218
4219     ITypeLib2_fnGetCustData,
4220     ITypeLib2_fnGetLibStatistics,
4221     ITypeLib2_fnGetDocumentation2,
4222     ITypeLib2_fnGetAllCustData
4223  };
4224
4225
4226 static HRESULT WINAPI ITypeLibComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
4227 {
4228     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4229
4230     return ITypeLib2_QueryInterface((ITypeLib *)This, riid, ppv);
4231 }
4232
4233 static ULONG WINAPI ITypeLibComp_fnAddRef(ITypeComp * iface)
4234 {
4235     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4236
4237     return ITypeLib2_AddRef((ITypeLib2 *)This);
4238 }
4239
4240 static ULONG WINAPI ITypeLibComp_fnRelease(ITypeComp * iface)
4241 {
4242     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4243
4244     return ITypeLib2_Release((ITypeLib2 *)This);
4245 }
4246
4247 static HRESULT WINAPI ITypeLibComp_fnBind(
4248     ITypeComp * iface,
4249     OLECHAR * szName,
4250     ULONG lHash,
4251     WORD wFlags,
4252     ITypeInfo ** ppTInfo,
4253     DESCKIND * pDescKind,
4254     BINDPTR * pBindPtr)
4255 {
4256     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4257     ITypeInfoImpl *pTypeInfo;
4258
4259     TRACE("(%s, 0x%x, 0x%x, %p, %p, %p)\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
4260
4261     *pDescKind = DESCKIND_NONE;
4262     pBindPtr->lptcomp = NULL;
4263     *ppTInfo = NULL;
4264
4265     for (pTypeInfo = This->pTypeInfo; pTypeInfo; pTypeInfo = pTypeInfo->next)
4266     {
4267         TRACE("testing %s\n", debugstr_w(pTypeInfo->Name));
4268
4269         /* FIXME: check wFlags here? */
4270         /* FIXME: we should use a hash table to look this info up using lHash
4271          * instead of an O(n) search */
4272         if ((pTypeInfo->TypeAttr.typekind == TKIND_ENUM) ||
4273             (pTypeInfo->TypeAttr.typekind == TKIND_MODULE))
4274         {
4275             if (pTypeInfo->Name && !strcmpW(pTypeInfo->Name, szName))
4276             {
4277                 *pDescKind = DESCKIND_TYPECOMP;
4278                 pBindPtr->lptcomp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4279                 ITypeComp_AddRef(pBindPtr->lptcomp);
4280                 TRACE("module or enum: %s\n", debugstr_w(szName));
4281                 return S_OK;
4282             }
4283         }
4284
4285         if ((pTypeInfo->TypeAttr.typekind == TKIND_MODULE) ||
4286             (pTypeInfo->TypeAttr.typekind == TKIND_ENUM))
4287         {
4288             ITypeComp *pSubTypeComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4289             HRESULT hr;
4290
4291             hr = ITypeComp_Bind(pSubTypeComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
4292             if (SUCCEEDED(hr) && (*pDescKind != DESCKIND_NONE))
4293             {
4294                 TRACE("found in module or in enum: %s\n", debugstr_w(szName));
4295                 return S_OK;
4296             }
4297         }
4298
4299         if ((pTypeInfo->TypeAttr.typekind == TKIND_COCLASS) &&
4300             (pTypeInfo->TypeAttr.wTypeFlags & TYPEFLAG_FAPPOBJECT))
4301         {
4302             ITypeComp *pSubTypeComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4303             HRESULT hr;
4304             ITypeInfo *subtypeinfo;
4305             BINDPTR subbindptr;
4306             DESCKIND subdesckind;
4307
4308             hr = ITypeComp_Bind(pSubTypeComp, szName, lHash, wFlags,
4309                 &subtypeinfo, &subdesckind, &subbindptr);
4310             if (SUCCEEDED(hr) && (subdesckind != DESCKIND_NONE))
4311             {
4312                 TYPEDESC tdesc_appobject =
4313                 {
4314                     {
4315                         (TYPEDESC *)pTypeInfo->hreftype
4316                     },
4317                     VT_USERDEFINED
4318                 };
4319                 const VARDESC vardesc_appobject =
4320                 {
4321                     -2,         /* memid */
4322                     NULL,       /* lpstrSchema */
4323                     {
4324                         0       /* oInst */
4325                     },
4326                     {
4327                                 /* ELEMDESC */
4328                         {
4329                                 /* TYPEDESC */
4330                                 {
4331                                     &tdesc_appobject
4332                                 },
4333                                 VT_PTR
4334                         },
4335                     },
4336                     0,          /* wVarFlags */
4337                     VAR_STATIC  /* varkind */
4338                 };
4339
4340                 TRACE("found in implicit app object: %s\n", debugstr_w(szName));
4341
4342                 /* cleanup things filled in by Bind call so we can put our
4343                  * application object data in there instead */
4344                 switch (subdesckind)
4345                 {
4346                 case DESCKIND_FUNCDESC:
4347                     ITypeInfo_ReleaseFuncDesc(subtypeinfo, subbindptr.lpfuncdesc);
4348                     break;
4349                 case DESCKIND_VARDESC:
4350                     ITypeInfo_ReleaseVarDesc(subtypeinfo, subbindptr.lpvardesc);
4351                     break;
4352                 default:
4353                     break;
4354                 }
4355                 if (subtypeinfo) ITypeInfo_Release(subtypeinfo);
4356
4357                 if (pTypeInfo->hreftype == -1)
4358                     FIXME("no hreftype for interface %p\n", pTypeInfo);
4359
4360                 hr = TLB_AllocAndInitVarDesc(&vardesc_appobject, &pBindPtr->lpvardesc);
4361                 if (FAILED(hr))
4362                     return hr;
4363
4364                 *pDescKind = DESCKIND_IMPLICITAPPOBJ;
4365                 *ppTInfo = (ITypeInfo *)pTypeInfo;
4366                 ITypeInfo_AddRef(*ppTInfo);
4367                 return S_OK;
4368             }
4369         }
4370     }
4371
4372     TRACE("name not found %s\n", debugstr_w(szName));
4373     return S_OK;
4374 }
4375
4376 static HRESULT WINAPI ITypeLibComp_fnBindType(
4377     ITypeComp * iface,
4378     OLECHAR * szName,
4379     ULONG lHash,
4380     ITypeInfo ** ppTInfo,
4381     ITypeComp ** ppTComp)
4382 {
4383     FIXME("(%s, %x, %p, %p): stub\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
4384     return E_NOTIMPL;
4385 }
4386
4387 static const ITypeCompVtbl tlbtcvt =
4388 {
4389
4390     ITypeLibComp_fnQueryInterface,
4391     ITypeLibComp_fnAddRef,
4392     ITypeLibComp_fnRelease,
4393
4394     ITypeLibComp_fnBind,
4395     ITypeLibComp_fnBindType
4396 };
4397
4398 /*================== ITypeInfo(2) Methods ===================================*/
4399 static ITypeInfo2 * WINAPI ITypeInfo_Constructor(void)
4400 {
4401     ITypeInfoImpl * pTypeInfoImpl;
4402
4403     pTypeInfoImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeInfoImpl));
4404     if (pTypeInfoImpl)
4405     {
4406       pTypeInfoImpl->lpVtbl = &tinfvt;
4407       pTypeInfoImpl->lpVtblTypeComp = &tcompvt;
4408       pTypeInfoImpl->ref=1;
4409       pTypeInfoImpl->hreftype = -1;
4410       pTypeInfoImpl->TypeAttr.memidConstructor = MEMBERID_NIL;
4411       pTypeInfoImpl->TypeAttr.memidDestructor = MEMBERID_NIL;
4412     }
4413     TRACE("(%p)\n", pTypeInfoImpl);
4414     return (ITypeInfo2*) pTypeInfoImpl;
4415 }
4416
4417 /* ITypeInfo::QueryInterface
4418  */
4419 static HRESULT WINAPI ITypeInfo_fnQueryInterface(
4420         ITypeInfo2 *iface,
4421         REFIID riid,
4422         VOID **ppvObject)
4423 {
4424     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4425
4426     TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
4427
4428     *ppvObject=NULL;
4429     if(IsEqualIID(riid, &IID_IUnknown) ||
4430             IsEqualIID(riid,&IID_ITypeInfo)||
4431             IsEqualIID(riid,&IID_ITypeInfo2))
4432         *ppvObject = This;
4433
4434     if(*ppvObject){
4435         ITypeInfo_AddRef(iface);
4436         TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
4437         return S_OK;
4438     }
4439     TRACE("-- Interface: E_NOINTERFACE\n");
4440     return E_NOINTERFACE;
4441 }
4442
4443 /* ITypeInfo::AddRef
4444  */
4445 static ULONG WINAPI ITypeInfo_fnAddRef( ITypeInfo2 *iface)
4446 {
4447     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4448     ULONG ref = InterlockedIncrement(&This->ref);
4449
4450     ITypeLib2_AddRef((ITypeLib2*)This->pTypeLib);
4451
4452     TRACE("(%p)->ref is %u\n",This, ref);
4453     return ref;
4454 }
4455
4456 /* ITypeInfo::Release
4457  */
4458 static ULONG WINAPI ITypeInfo_fnRelease(ITypeInfo2 *iface)
4459 {
4460     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4461     ULONG ref = InterlockedDecrement(&This->ref);
4462
4463     TRACE("(%p)->(%u)\n",This, ref);
4464
4465     if (ref)   {
4466       /* We don't release ITypeLib when ref=0 because
4467          it means that function is called by ITypeLib2_Release */
4468       ITypeLib2_Release((ITypeLib2*)This->pTypeLib);
4469     } else   {
4470       TLBFuncDesc *pFInfo, *pFInfoNext;
4471       TLBVarDesc *pVInfo, *pVInfoNext;
4472       TLBImplType *pImpl, *pImplNext;
4473       TLBCustData *pCustData, *pCustDataNext;
4474
4475       TRACE("destroying ITypeInfo(%p)\n",This);
4476
4477       if (This->no_free_data)
4478           goto finish_free;
4479
4480       if (This->Name)
4481       {
4482           SysFreeString(This->Name);
4483           This->Name = 0;
4484       }
4485
4486       if (This->DocString)
4487       {
4488           SysFreeString(This->DocString);
4489           This->DocString = 0;
4490       }
4491
4492       if (This->DllName)
4493       {
4494           SysFreeString(This->DllName);
4495           This->DllName = 0;
4496       }
4497
4498       for (pFInfo = This->funclist; pFInfo; pFInfo = pFInfoNext)
4499       {
4500           UINT i;
4501           for(i = 0;i < pFInfo->funcdesc.cParams; i++)
4502           {
4503               ELEMDESC *elemdesc = &pFInfo->funcdesc.lprgelemdescParam[i];
4504               if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
4505               {
4506                   VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue);
4507                   TLB_Free(elemdesc->u.paramdesc.pparamdescex);
4508               }
4509               SysFreeString(pFInfo->pParamDesc[i].Name);
4510           }
4511           TLB_Free(pFInfo->funcdesc.lprgelemdescParam);
4512           TLB_Free(pFInfo->pParamDesc);
4513           for (pCustData = This->pCustData; pCustData; pCustData = pCustDataNext)
4514           {
4515               VariantClear(&pCustData->data);
4516
4517               pCustDataNext = pCustData->next;
4518               TLB_Free(pCustData);
4519           }
4520           if (HIWORD(pFInfo->Entry) != 0 && pFInfo->Entry != (BSTR)-1) 
4521               SysFreeString(pFInfo->Entry);
4522           SysFreeString(pFInfo->HelpString);
4523           SysFreeString(pFInfo->Name);
4524
4525           pFInfoNext = pFInfo->next;
4526           TLB_Free(pFInfo);
4527       }
4528       for (pVInfo = This->varlist; pVInfo; pVInfo = pVInfoNext)
4529       {
4530           if (pVInfo->vardesc.varkind == VAR_CONST)
4531           {
4532               VariantClear(pVInfo->vardesc.u.lpvarValue);
4533               TLB_Free(pVInfo->vardesc.u.lpvarValue);
4534           }
4535           SysFreeString(pVInfo->Name);
4536           pVInfoNext = pVInfo->next;
4537           TLB_Free(pVInfo);
4538       }
4539       for(pImpl = This->impltypelist; pImpl; pImpl = pImplNext)
4540       {
4541           for (pCustData = pImpl->pCustData; pCustData; pCustData = pCustDataNext)
4542           {
4543               VariantClear(&pCustData->data);
4544
4545               pCustDataNext = pCustData->next;
4546               TLB_Free(pCustData);
4547           }
4548           pImplNext = pImpl->next;
4549           TLB_Free(pImpl);
4550       }
4551       TLB_Free(This->pCustData);
4552
4553 finish_free:
4554       if (This->next)
4555       {
4556         ITypeInfo_Release((ITypeInfo*)This->next);
4557       }
4558
4559       HeapFree(GetProcessHeap(),0,This);
4560       return 0;
4561     }
4562     return ref;
4563 }
4564
4565 /* ITypeInfo::GetTypeAttr
4566  *
4567  * Retrieves a TYPEATTR structure that contains the attributes of the type
4568  * description.
4569  *
4570  */
4571 static HRESULT WINAPI ITypeInfo_fnGetTypeAttr( ITypeInfo2 *iface,
4572         LPTYPEATTR  *ppTypeAttr)
4573 {
4574     const ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4575     SIZE_T size;
4576
4577     TRACE("(%p)\n",This);
4578
4579     size = sizeof(**ppTypeAttr);
4580     if (This->TypeAttr.typekind == TKIND_ALIAS)
4581         size += TLB_SizeTypeDesc(&This->TypeAttr.tdescAlias, FALSE);
4582
4583     *ppTypeAttr = HeapAlloc(GetProcessHeap(), 0, size);
4584     if (!*ppTypeAttr)
4585         return E_OUTOFMEMORY;
4586
4587     memcpy(*ppTypeAttr, &This->TypeAttr, sizeof(**ppTypeAttr));
4588
4589     if (This->TypeAttr.typekind == TKIND_ALIAS)
4590         TLB_CopyTypeDesc(&(*ppTypeAttr)->tdescAlias,
4591             &This->TypeAttr.tdescAlias, (void *)(*ppTypeAttr + 1));
4592
4593     if((*ppTypeAttr)->typekind == TKIND_DISPATCH) {
4594         (*ppTypeAttr)->cFuncs = (*ppTypeAttr)->cbSizeVft / 4; /* This should include all the inherited
4595                                                                  funcs */
4596         (*ppTypeAttr)->cbSizeVft = 28; /* This is always the size of IDispatch's vtbl */
4597         (*ppTypeAttr)->wTypeFlags &= ~TYPEFLAG_FOLEAUTOMATION;
4598     }
4599     return S_OK;
4600 }
4601
4602 /* ITypeInfo::GetTypeComp
4603  *
4604  * Retrieves the ITypeComp interface for the type description, which enables a
4605  * client compiler to bind to the type description's members.
4606  *
4607  */
4608 static HRESULT WINAPI ITypeInfo_fnGetTypeComp( ITypeInfo2 *iface,
4609         ITypeComp  * *ppTComp)
4610 {
4611     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4612
4613     TRACE("(%p)->(%p)\n", This, ppTComp);
4614
4615     *ppTComp = (ITypeComp *)&This->lpVtblTypeComp;
4616     ITypeComp_AddRef(*ppTComp);
4617     return S_OK;
4618 }
4619
4620 static SIZE_T TLB_SizeElemDesc( const ELEMDESC *elemdesc )
4621 {
4622     SIZE_T size = TLB_SizeTypeDesc(&elemdesc->tdesc, FALSE);
4623     if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
4624         size += sizeof(*elemdesc->u.paramdesc.pparamdescex);
4625     return size;
4626 }
4627
4628 static HRESULT TLB_CopyElemDesc( const ELEMDESC *src, ELEMDESC *dest, char **buffer )
4629 {
4630     memcpy(dest, src, sizeof(ELEMDESC));
4631     *buffer = TLB_CopyTypeDesc(&dest->tdesc, &src->tdesc, *buffer);
4632     if (src->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
4633     {
4634         const PARAMDESCEX *pparamdescex_src = src->u.paramdesc.pparamdescex;
4635         PARAMDESCEX *pparamdescex_dest = dest->u.paramdesc.pparamdescex = (PARAMDESCEX *)*buffer;
4636         *buffer += sizeof(PARAMDESCEX);
4637         memcpy(pparamdescex_dest, pparamdescex_src, sizeof(PARAMDESCEX));
4638         VariantInit(&pparamdescex_dest->varDefaultValue);
4639         return VariantCopy(&pparamdescex_dest->varDefaultValue, 
4640                            (VARIANTARG *)&pparamdescex_src->varDefaultValue);
4641     }
4642     else
4643         dest->u.paramdesc.pparamdescex = NULL;
4644     return S_OK;
4645 }
4646
4647 static void TLB_FreeElemDesc( ELEMDESC *elemdesc )
4648 {
4649     if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
4650         VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue);
4651 }
4652
4653 static HRESULT TLB_AllocAndInitFuncDesc( const FUNCDESC *src, FUNCDESC **dest_ptr, BOOL dispinterface )
4654 {
4655     FUNCDESC *dest;
4656     char *buffer;
4657     SIZE_T size = sizeof(*src);
4658     SHORT i;
4659     HRESULT hr;
4660
4661     size += sizeof(*src->lprgscode) * src->cScodes;
4662     size += TLB_SizeElemDesc(&src->elemdescFunc);
4663     for (i = 0; i < src->cParams; i++)
4664     {
4665         size += sizeof(ELEMDESC);
4666         size += TLB_SizeElemDesc(&src->lprgelemdescParam[i]);
4667     }
4668
4669     dest = (FUNCDESC *)SysAllocStringByteLen(NULL, size);
4670     if (!dest) return E_OUTOFMEMORY;
4671
4672     memcpy(dest, src, sizeof(FUNCDESC));
4673     buffer = (char *)(dest + 1);
4674
4675     dest->lprgscode = (SCODE *)buffer;
4676     memcpy(dest->lprgscode, src->lprgscode, sizeof(*src->lprgscode) * src->cScodes);
4677     buffer += sizeof(*src->lprgscode) * src->cScodes;
4678
4679     hr = TLB_CopyElemDesc(&src->elemdescFunc, &dest->elemdescFunc, &buffer);
4680     if (FAILED(hr))
4681     {
4682         SysFreeString((BSTR)dest);
4683         return hr;
4684     }
4685
4686     dest->lprgelemdescParam = (ELEMDESC *)buffer;
4687     buffer += sizeof(ELEMDESC) * src->cParams;
4688     for (i = 0; i < src->cParams; i++)
4689     {
4690         hr = TLB_CopyElemDesc(&src->lprgelemdescParam[i], &dest->lprgelemdescParam[i], &buffer);
4691         if (FAILED(hr))
4692             break;
4693     }
4694     if (FAILED(hr))
4695     {
4696         /* undo the above actions */
4697         for (i = i - 1; i >= 0; i--)
4698             TLB_FreeElemDesc(&dest->lprgelemdescParam[i]);
4699         TLB_FreeElemDesc(&dest->elemdescFunc);
4700         SysFreeString((BSTR)dest);
4701         return hr;
4702     }
4703
4704     /* special treatment for dispinterfaces: this makes functions appear
4705      * to return their [retval] value when it is really returning an
4706      * HRESULT */
4707     if (dispinterface && dest->elemdescFunc.tdesc.vt == VT_HRESULT)
4708     {
4709         if (dest->cParams &&
4710             (dest->lprgelemdescParam[dest->cParams - 1].u.paramdesc.wParamFlags & PARAMFLAG_FRETVAL))
4711         {
4712             ELEMDESC *elemdesc = &dest->lprgelemdescParam[dest->cParams - 1];
4713             if (elemdesc->tdesc.vt != VT_PTR)
4714             {
4715                 ERR("elemdesc should have started with VT_PTR instead of:\n");
4716                 if (ERR_ON(ole))
4717                     dump_ELEMDESC(elemdesc);
4718                 return E_UNEXPECTED;
4719             }
4720
4721             /* copy last parameter to the return value. we are using a flat
4722              * buffer so there is no danger of leaking memory in
4723              * elemdescFunc */
4724             dest->elemdescFunc.tdesc = *elemdesc->tdesc.u.lptdesc;
4725
4726             /* remove the last parameter */
4727             dest->cParams--;
4728         }
4729         else
4730             /* otherwise this function is made to appear to have no return
4731              * value */
4732             dest->elemdescFunc.tdesc.vt = VT_VOID;
4733
4734     }
4735
4736     *dest_ptr = dest;
4737     return S_OK;
4738 }
4739
4740 HRESULT ITypeInfoImpl_GetInternalFuncDesc( ITypeInfo *iface, UINT index, const FUNCDESC **ppFuncDesc )
4741 {
4742     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4743     const TLBFuncDesc *pFDesc;
4744     int i;
4745
4746     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++, pFDesc=pFDesc->next)
4747         ;
4748
4749     if (pFDesc)
4750     {
4751         *ppFuncDesc = &pFDesc->funcdesc;
4752         return S_OK;
4753     }
4754
4755     return TYPE_E_ELEMENTNOTFOUND;
4756 }
4757
4758 /* internal function to make the inherited interfaces' methods appear
4759  * part of the interface */
4760 static HRESULT ITypeInfoImpl_GetInternalDispatchFuncDesc( ITypeInfo *iface,
4761     UINT index, const FUNCDESC **ppFuncDesc, UINT *funcs, UINT *hrefoffset)
4762 {
4763     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4764     HRESULT hr;
4765     UINT implemented_funcs = 0;
4766
4767     if (funcs)
4768         *funcs = 0;
4769     else
4770         *hrefoffset = DISPATCH_HREF_OFFSET;
4771
4772     if(This->impltypelist)
4773     {
4774         ITypeInfo *pSubTypeInfo;
4775         UINT sub_funcs;
4776
4777         hr = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef, &pSubTypeInfo);
4778         if (FAILED(hr))
4779             return hr;
4780
4781         hr = ITypeInfoImpl_GetInternalDispatchFuncDesc(pSubTypeInfo,
4782                                                        index,
4783                                                        ppFuncDesc,
4784                                                        &sub_funcs, hrefoffset);
4785         implemented_funcs += sub_funcs;
4786         ITypeInfo_Release(pSubTypeInfo);
4787         if (SUCCEEDED(hr))
4788             return hr;
4789         *hrefoffset += DISPATCH_HREF_OFFSET;
4790     }
4791
4792     if (funcs)
4793         *funcs = implemented_funcs + This->TypeAttr.cFuncs;
4794     else
4795         *hrefoffset = 0;
4796     
4797     if (index < implemented_funcs)
4798         return E_INVALIDARG;
4799     return ITypeInfoImpl_GetInternalFuncDesc(iface, index - implemented_funcs,
4800                                              ppFuncDesc);
4801 }
4802
4803 static inline void ITypeInfoImpl_ElemDescAddHrefOffset( LPELEMDESC pElemDesc, UINT hrefoffset)
4804 {
4805     TYPEDESC *pTypeDesc = &pElemDesc->tdesc;
4806     while (TRUE)
4807     {
4808         switch (pTypeDesc->vt)
4809         {
4810         case VT_USERDEFINED:
4811             pTypeDesc->u.hreftype += hrefoffset;
4812             return;
4813         case VT_PTR:
4814         case VT_SAFEARRAY:
4815             pTypeDesc = pTypeDesc->u.lptdesc;
4816             break;
4817         case VT_CARRAY:
4818             pTypeDesc = &pTypeDesc->u.lpadesc->tdescElem;
4819             break;
4820         default:
4821             return;
4822         }
4823     }
4824 }
4825
4826 static inline void ITypeInfoImpl_FuncDescAddHrefOffset( LPFUNCDESC pFuncDesc, UINT hrefoffset)
4827 {
4828     SHORT i;
4829     for (i = 0; i < pFuncDesc->cParams; i++)
4830         ITypeInfoImpl_ElemDescAddHrefOffset(&pFuncDesc->lprgelemdescParam[i], hrefoffset);
4831     ITypeInfoImpl_ElemDescAddHrefOffset(&pFuncDesc->elemdescFunc, hrefoffset);
4832 }
4833
4834 /* ITypeInfo::GetFuncDesc
4835  *
4836  * Retrieves the FUNCDESC structure that contains information about a
4837  * specified function.
4838  *
4839  */
4840 static HRESULT WINAPI ITypeInfo_fnGetFuncDesc( ITypeInfo2 *iface, UINT index,
4841         LPFUNCDESC  *ppFuncDesc)
4842 {
4843     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4844     const FUNCDESC *internal_funcdesc;
4845     HRESULT hr;
4846     UINT hrefoffset = 0;
4847
4848     TRACE("(%p) index %d\n", This, index);
4849
4850     if (This->TypeAttr.typekind == TKIND_DISPATCH)
4851         hr = ITypeInfoImpl_GetInternalDispatchFuncDesc((ITypeInfo *)iface, index,
4852                                                        &internal_funcdesc, NULL,
4853                                                        &hrefoffset);
4854     else
4855         hr = ITypeInfoImpl_GetInternalFuncDesc((ITypeInfo *)iface, index,
4856                                                &internal_funcdesc);
4857     if (FAILED(hr))
4858     {
4859         WARN("description for function %d not found\n", index);
4860         return hr;
4861     }
4862
4863     hr = TLB_AllocAndInitFuncDesc(
4864         internal_funcdesc,
4865         ppFuncDesc,
4866         This->TypeAttr.typekind == TKIND_DISPATCH);
4867
4868     if ((This->TypeAttr.typekind == TKIND_DISPATCH) && hrefoffset)
4869         ITypeInfoImpl_FuncDescAddHrefOffset(*ppFuncDesc, hrefoffset);
4870
4871     TRACE("-- 0x%08x\n", hr);
4872     return hr;
4873 }
4874
4875 static HRESULT TLB_AllocAndInitVarDesc( const VARDESC *src, VARDESC **dest_ptr )
4876 {
4877     VARDESC *dest;
4878     char *buffer;
4879     SIZE_T size = sizeof(*src);
4880     HRESULT hr;
4881
4882     if (src->lpstrSchema) size += (strlenW(src->lpstrSchema) + 1) * sizeof(WCHAR);
4883     if (src->varkind == VAR_CONST)
4884         size += sizeof(VARIANT);
4885     size += TLB_SizeElemDesc(&src->elemdescVar);
4886
4887     dest = (VARDESC *)SysAllocStringByteLen(NULL, size);
4888     if (!dest) return E_OUTOFMEMORY;
4889
4890     *dest = *src;
4891     buffer = (char *)(dest + 1);
4892     if (src->lpstrSchema)
4893     {
4894         int len;
4895         dest->lpstrSchema = (LPOLESTR)buffer;
4896         len = strlenW(src->lpstrSchema);
4897         memcpy(dest->lpstrSchema, src->lpstrSchema, (len + 1) * sizeof(WCHAR));
4898         buffer += (len + 1) * sizeof(WCHAR);
4899     }
4900
4901     if (src->varkind == VAR_CONST)
4902     {
4903         HRESULT hr;
4904
4905         dest->u.lpvarValue = (VARIANT *)buffer;
4906         *dest->u.lpvarValue = *src->u.lpvarValue;
4907         buffer += sizeof(VARIANT);
4908         VariantInit(dest->u.lpvarValue);
4909         hr = VariantCopy(dest->u.lpvarValue, src->u.lpvarValue);
4910         if (FAILED(hr))
4911         {
4912             SysFreeString((BSTR)dest_ptr);
4913             return hr;
4914         }
4915     }
4916     hr = TLB_CopyElemDesc(&src->elemdescVar, &dest->elemdescVar, &buffer);
4917     if (FAILED(hr))
4918     {
4919         if (src->varkind == VAR_CONST)
4920             VariantClear(dest->u.lpvarValue);
4921         SysFreeString((BSTR)dest);
4922         return hr;
4923     }
4924     *dest_ptr = dest;
4925     return S_OK;
4926 }
4927
4928 /* ITypeInfo::GetVarDesc
4929  *
4930  * Retrieves a VARDESC structure that describes the specified variable.
4931  *
4932  */
4933 static HRESULT WINAPI ITypeInfo_fnGetVarDesc( ITypeInfo2 *iface, UINT index,
4934         LPVARDESC  *ppVarDesc)
4935 {
4936     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4937     int i;
4938     const TLBVarDesc *pVDesc;
4939
4940     TRACE("(%p) index %d\n", This, index);
4941
4942     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next)
4943         ;
4944
4945     if (pVDesc)
4946         return TLB_AllocAndInitVarDesc(&pVDesc->vardesc, ppVarDesc);
4947
4948     return E_INVALIDARG;
4949 }
4950
4951 /* ITypeInfo_GetNames
4952  *
4953  * Retrieves the variable with the specified member ID (or the name of the
4954  * property or method and its parameters) that correspond to the specified
4955  * function ID.
4956  */
4957 static HRESULT WINAPI ITypeInfo_fnGetNames( ITypeInfo2 *iface, MEMBERID memid,
4958         BSTR  *rgBstrNames, UINT cMaxNames, UINT  *pcNames)
4959 {
4960     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4961     const TLBFuncDesc *pFDesc;
4962     const TLBVarDesc *pVDesc;
4963     int i;
4964     TRACE("(%p) memid=0x%08x Maxname=%d\n", This, memid, cMaxNames);
4965     for(pFDesc=This->funclist; pFDesc && pFDesc->funcdesc.memid != memid; pFDesc=pFDesc->next);
4966     if(pFDesc)
4967     {
4968       /* function found, now return function and parameter names */
4969       for(i=0; i<cMaxNames && i <= pFDesc->funcdesc.cParams; i++)
4970       {
4971         if(!i)
4972           *rgBstrNames=SysAllocString(pFDesc->Name);
4973         else
4974           rgBstrNames[i]=SysAllocString(pFDesc->pParamDesc[i-1].Name);
4975       }
4976       *pcNames=i;
4977     }
4978     else
4979     {
4980       for(pVDesc=This->varlist; pVDesc && pVDesc->vardesc.memid != memid; pVDesc=pVDesc->next);
4981       if(pVDesc)
4982       {
4983         *rgBstrNames=SysAllocString(pVDesc->Name);
4984         *pcNames=1;
4985       }
4986       else
4987       {
4988         if(This->impltypelist &&
4989            (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
4990           /* recursive search */
4991           ITypeInfo *pTInfo;
4992           HRESULT result;
4993           result=ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef,
4994                                           &pTInfo);
4995           if(SUCCEEDED(result))
4996           {
4997             result=ITypeInfo_GetNames(pTInfo, memid, rgBstrNames, cMaxNames, pcNames);
4998             ITypeInfo_Release(pTInfo);
4999             return result;
5000           }
5001           WARN("Could not search inherited interface!\n");
5002         }
5003         else
5004         {
5005           WARN("no names found\n");
5006         }
5007         *pcNames=0;
5008         return TYPE_E_ELEMENTNOTFOUND;
5009       }
5010     }
5011     return S_OK;
5012 }
5013
5014
5015 /* ITypeInfo::GetRefTypeOfImplType
5016  *
5017  * If a type description describes a COM class, it retrieves the type
5018  * description of the implemented interface types. For an interface,
5019  * GetRefTypeOfImplType returns the type information for inherited interfaces,
5020  * if any exist.
5021  *
5022  */
5023 static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType(
5024         ITypeInfo2 *iface,
5025         UINT index,
5026         HREFTYPE  *pRefType)
5027 {
5028     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5029     int i;
5030     HRESULT hr = S_OK;
5031     const TLBImplType *pImpl = This->impltypelist;
5032
5033     TRACE("(%p) index %d\n", This, index);
5034     if (TRACE_ON(ole)) dump_TypeInfo(This);
5035
5036     if(index==(UINT)-1)
5037     {
5038       /* only valid on dual interfaces;
5039          retrieve the associated TKIND_INTERFACE handle for the current TKIND_DISPATCH
5040       */
5041       if( This->TypeAttr.typekind != TKIND_DISPATCH) return E_INVALIDARG;
5042
5043       if (This->TypeAttr.wTypeFlags & TYPEFLAG_FDISPATCHABLE &&
5044           This->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL )
5045       {
5046         *pRefType = -1;
5047       }
5048       else
5049       {
5050         hr = TYPE_E_ELEMENTNOTFOUND;
5051       }
5052     }
5053     else if(index == 0 && This->TypeAttr.typekind == TKIND_DISPATCH)
5054     {
5055       /* All TKIND_DISPATCHs are made to look like they inherit from IDispatch */
5056       *pRefType = This->pTypeLib->dispatch_href;
5057     }
5058     else
5059     {
5060       /* get element n from linked list */
5061       for(i=0; pImpl && i<index; i++)
5062       {
5063         pImpl = pImpl->next;
5064       }
5065
5066       if (pImpl)
5067         *pRefType = pImpl->hRef;
5068       else
5069         hr = TYPE_E_ELEMENTNOTFOUND;
5070     }
5071
5072     if(TRACE_ON(ole))
5073     {
5074         if(SUCCEEDED(hr))
5075             TRACE("SUCCESS -- hRef = 0x%08x\n", *pRefType );
5076         else
5077             TRACE("FAILURE -- hresult = 0x%08x\n", hr);
5078     }
5079
5080     return hr;
5081 }
5082
5083 /* ITypeInfo::GetImplTypeFlags
5084  *
5085  * Retrieves the IMPLTYPEFLAGS enumeration for one implemented interface
5086  * or base interface in a type description.
5087  */
5088 static HRESULT WINAPI ITypeInfo_fnGetImplTypeFlags( ITypeInfo2 *iface,
5089         UINT index, INT  *pImplTypeFlags)
5090 {
5091     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5092     int i;
5093     TLBImplType *pImpl;
5094
5095     TRACE("(%p) index %d\n", This, index);
5096     for(i=0, pImpl=This->impltypelist; i<index && pImpl;
5097         i++, pImpl=pImpl->next)
5098         ;
5099     if(i==index && pImpl){
5100         *pImplTypeFlags=pImpl->implflags;
5101         return S_OK;
5102     }
5103     *pImplTypeFlags=0;
5104     return TYPE_E_ELEMENTNOTFOUND;
5105 }
5106
5107 /* GetIDsOfNames
5108  * Maps between member names and member IDs, and parameter names and
5109  * parameter IDs.
5110  */
5111 static HRESULT WINAPI ITypeInfo_fnGetIDsOfNames( ITypeInfo2 *iface,
5112         LPOLESTR  *rgszNames, UINT cNames, MEMBERID  *pMemId)
5113 {
5114     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5115     const TLBFuncDesc *pFDesc;
5116     const TLBVarDesc *pVDesc;
5117     HRESULT ret=S_OK;
5118     int i;
5119
5120     TRACE("(%p) Name %s cNames %d\n", This, debugstr_w(*rgszNames),
5121             cNames);
5122
5123     /* init out parameters in case of failure */
5124     for (i = 0; i < cNames; i++)
5125         pMemId[i] = MEMBERID_NIL;
5126
5127     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next) {
5128         int j;
5129         if(!lstrcmpiW(*rgszNames, pFDesc->Name)) {
5130             if(cNames) *pMemId=pFDesc->funcdesc.memid;
5131             for(i=1; i < cNames; i++){
5132                 for(j=0; j<pFDesc->funcdesc.cParams; j++)
5133                     if(!lstrcmpiW(rgszNames[i],pFDesc->pParamDesc[j].Name))
5134                             break;
5135                 if( j<pFDesc->funcdesc.cParams)
5136                     pMemId[i]=j;
5137                 else
5138                    ret=DISP_E_UNKNOWNNAME;
5139             };
5140             TRACE("-- 0x%08x\n", ret);
5141             return ret;
5142         }
5143     }
5144     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) {
5145         if(!lstrcmpiW(*rgszNames, pVDesc->Name)) {
5146             if(cNames) *pMemId=pVDesc->vardesc.memid;
5147             return ret;
5148         }
5149     }
5150     /* not found, see if it can be found in an inherited interface */
5151     if(This->impltypelist) {
5152         /* recursive search */
5153         ITypeInfo *pTInfo;
5154         ret=ITypeInfo_GetRefTypeInfo(iface,
5155                 This->impltypelist->hRef, &pTInfo);
5156         if(SUCCEEDED(ret)){
5157             ret=ITypeInfo_GetIDsOfNames(pTInfo, rgszNames, cNames, pMemId );
5158             ITypeInfo_Release(pTInfo);
5159             return ret;
5160         }
5161         WARN("Could not search inherited interface!\n");
5162     } else
5163         WARN("no names found\n");
5164     return DISP_E_UNKNOWNNAME;
5165 }
5166
5167 /* ITypeInfo::Invoke
5168  *
5169  * Invokes a method, or accesses a property of an object, that implements the
5170  * interface described by the type description.
5171  */
5172 DWORD
5173 _invoke(FARPROC func,CALLCONV callconv, int nrargs, DWORD *args) {
5174     DWORD res;
5175
5176     if (TRACE_ON(ole)) {
5177         int i;
5178         TRACE("Calling %p(",func);
5179         for (i=0;i<nrargs;i++) TRACE("%08x,",args[i]);
5180         TRACE(")\n");
5181     }
5182
5183     switch (callconv) {
5184     case CC_STDCALL:
5185
5186         switch (nrargs) {
5187         case 0:
5188                 res = func();
5189                 break;
5190         case 1:
5191                 res = func(args[0]);
5192                 break;
5193         case 2:
5194                 res = func(args[0],args[1]);
5195                 break;
5196         case 3:
5197                 res = func(args[0],args[1],args[2]);
5198                 break;
5199         case 4:
5200                 res = func(args[0],args[1],args[2],args[3]);
5201                 break;
5202         case 5:
5203                 res = func(args[0],args[1],args[2],args[3],args[4]);
5204                 break;
5205         case 6:
5206                 res = func(args[0],args[1],args[2],args[3],args[4],args[5]);
5207                 break;
5208         case 7:
5209                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
5210                 break;
5211         case 8:
5212                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]);
5213                 break;
5214         case 9:
5215                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]);
5216                 break;
5217         case 10:
5218                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9]);
5219                 break;
5220         case 11:
5221                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10]);
5222                 break;
5223         case 12:
5224                 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]);
5225                 break;
5226         case 13:
5227                 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]);
5228                 break;
5229         case 14:
5230                 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]);
5231                 break;
5232         case 15:
5233                 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]);
5234                 break;
5235         case 16:
5236                 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]);
5237                 break;
5238         case 17:
5239                 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]);
5240                 break;
5241         case 18:
5242                 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]);
5243                 break;
5244         case 19:
5245                 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]);
5246                 break;
5247         case 20:
5248                 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]);
5249                 break;
5250         case 21:
5251                 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]);
5252                 break;
5253         case 22:
5254                 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]);
5255                 break;
5256         case 23:
5257                 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]);
5258                 break;
5259         default:
5260                 FIXME("unsupported number of arguments %d in stdcall\n",nrargs);
5261                 res = -1;
5262                 break;
5263         }
5264         break;
5265     default:
5266         FIXME("unsupported calling convention %d\n",callconv);
5267         res = -1;
5268         break;
5269     }
5270     TRACE("returns %08x\n",res);
5271     return res;
5272 }
5273
5274 extern int _argsize(DWORD vt);
5275
5276 static HRESULT userdefined_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
5277 {
5278     HRESULT hr = S_OK;
5279     ITypeInfo *tinfo2 = NULL;
5280     TYPEATTR *tattr = NULL;
5281
5282     hr = ITypeInfo_GetRefTypeInfo(tinfo, tdesc->u.hreftype, &tinfo2);
5283     if (hr)
5284     {
5285         ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED, "
5286             "hr = 0x%08x\n",
5287               tdesc->u.hreftype, hr);
5288         return hr;
5289     }
5290     hr = ITypeInfo_GetTypeAttr(tinfo2, &tattr);
5291     if (hr)
5292     {
5293         ERR("ITypeInfo_GetTypeAttr failed, hr = 0x%08x\n", hr);
5294         ITypeInfo_Release(tinfo2);
5295         return hr;
5296     }
5297
5298     switch (tattr->typekind)
5299     {
5300     case TKIND_ENUM:
5301         *vt |= VT_I4;
5302         break;
5303
5304     case TKIND_ALIAS:
5305         tdesc = &tattr->tdescAlias;
5306         hr = typedescvt_to_variantvt(tinfo2, &tattr->tdescAlias, vt);
5307         break;
5308
5309     case TKIND_INTERFACE:
5310         if (IsEqualIID(&IID_IDispatch, &tattr->guid))
5311            *vt |= VT_DISPATCH;
5312         else
5313            *vt |= VT_UNKNOWN;
5314         break;
5315
5316     case TKIND_DISPATCH:
5317         *vt |= VT_DISPATCH;
5318         break;
5319
5320     case TKIND_COCLASS:
5321         *vt |= VT_DISPATCH;
5322         break;
5323
5324     case TKIND_RECORD:
5325         FIXME("TKIND_RECORD unhandled.\n");
5326         hr = E_NOTIMPL;
5327         break;
5328
5329     case TKIND_UNION:
5330         FIXME("TKIND_UNION unhandled.\n");
5331         hr = E_NOTIMPL;
5332         break;
5333
5334     default:
5335         FIXME("TKIND %d unhandled.\n",tattr->typekind);
5336         hr = E_NOTIMPL;
5337         break;
5338     }
5339     ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
5340     ITypeInfo_Release(tinfo2);
5341     return hr;
5342 }
5343
5344 static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
5345 {
5346     HRESULT hr = S_OK;
5347
5348     /* enforce only one level of pointer indirection */
5349     if (!(*vt & VT_BYREF) && !(*vt & VT_ARRAY) && (tdesc->vt == VT_PTR))
5350     {
5351         tdesc = tdesc->u.lptdesc;
5352
5353         /* munch VT_PTR -> VT_USERDEFINED(interface) into VT_UNKNOWN or
5354          * VT_DISPATCH and VT_PTR -> VT_PTR -> VT_USERDEFINED(interface) into 
5355          * VT_BYREF|VT_DISPATCH or VT_BYREF|VT_UNKNOWN */
5356         if ((tdesc->vt == VT_USERDEFINED) ||
5357             ((tdesc->vt == VT_PTR) && (tdesc->u.lptdesc->vt == VT_USERDEFINED)))
5358         {
5359             VARTYPE vt_userdefined = 0;
5360             const TYPEDESC *tdesc_userdefined = tdesc;
5361             if (tdesc->vt == VT_PTR)
5362             {
5363                 vt_userdefined = VT_BYREF;
5364                 tdesc_userdefined = tdesc->u.lptdesc;
5365             }
5366             hr = userdefined_to_variantvt(tinfo, tdesc_userdefined, &vt_userdefined);
5367             if ((hr == S_OK) && 
5368                 (((vt_userdefined & VT_TYPEMASK) == VT_UNKNOWN) ||
5369                  ((vt_userdefined & VT_TYPEMASK) == VT_DISPATCH)))
5370             {
5371                 *vt |= vt_userdefined;
5372                 return S_OK;
5373             }
5374         }
5375         *vt = VT_BYREF;
5376     }
5377
5378     switch (tdesc->vt)
5379     {
5380     case VT_HRESULT:
5381         *vt |= VT_ERROR;
5382         break;
5383     case VT_USERDEFINED:
5384         hr = userdefined_to_variantvt(tinfo, tdesc, vt);
5385         break;
5386     case VT_VOID:
5387     case VT_CARRAY:
5388     case VT_PTR:
5389     case VT_LPSTR:
5390     case VT_LPWSTR:
5391         ERR("cannot convert type %d into variant VT\n", tdesc->vt);
5392         hr = DISP_E_BADVARTYPE;
5393         break;
5394     case VT_SAFEARRAY:
5395         *vt |= VT_ARRAY;
5396         hr = typedescvt_to_variantvt(tinfo, tdesc->u.lptdesc, vt);
5397         break;
5398     default:
5399         *vt |= tdesc->vt;
5400         break;
5401     }
5402     return hr;
5403 }
5404
5405 /***********************************************************************
5406  *              DispCallFunc (OLEAUT32.@)
5407  *
5408  * Invokes a function of the specifed calling convention, passing the
5409  * specified arguments and returns the result.
5410  *
5411  * PARAMS
5412  *  pvInstance  [I] Optional pointer to the instance whose function to invoke.
5413  *  oVft        [I] The offset in the vtable. See notes.
5414  *  cc          [I] Calling convention of the function to call.
5415  *  vtReturn    [I] The return type of the function.
5416  *  cActuals    [I] Number of parameters.
5417  *  prgvt       [I] The types of the parameters to pass. This is used for sizing only.
5418  *  prgpvarg    [I] The arguments to pass.
5419  *  pvargResult [O] The return value of the function. Can be NULL.
5420  *
5421  * RETURNS
5422  *  Success: S_OK.
5423  *  Failure: HRESULT code.
5424  *
5425  * NOTES
5426  *  The HRESULT return value of this function is not affected by the return
5427  *  value of the user supplied function, which is returned in pvargResult.
5428  *
5429  *  If pvInstance is NULL then a non-object function is to be called and oVft
5430  *  is the address of the function to call.
5431  *
5432  * The cc parameter can be one of the following values:
5433  *|CC_FASTCALL
5434  *|CC_CDECL
5435  *|CC_PASCAL
5436  *|CC_STDCALL
5437  *|CC_FPFASTCALL
5438  *|CC_SYSCALL
5439  *|CC_MPWCDECL
5440  *|CC_MPWPASCAL
5441  *
5442  */
5443 HRESULT WINAPI
5444 DispCallFunc(
5445     void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals,
5446     VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult)
5447 {
5448     int i, argsize, argspos;
5449     DWORD *args;
5450     HRESULT hres;
5451
5452     TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
5453         pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
5454         pvargResult, V_VT(pvargResult));
5455
5456     argsize = 0;
5457     if (pvInstance)
5458         argsize++; /* for This pointer */
5459
5460     for (i=0;i<cActuals;i++)
5461     {
5462         TRACE("arg %d: type %d, size %d\n",i,prgvt[i],_argsize(prgvt[i]));
5463         dump_Variant(prgpvarg[i]);
5464         argsize += _argsize(prgvt[i]);
5465     }
5466     args = HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*argsize);
5467
5468     argspos = 0;
5469     if (pvInstance)
5470     {
5471         args[0] = (DWORD)pvInstance; /* the This pointer is always the first parameter */
5472         argspos++;
5473     }
5474
5475     for (i=0;i<cActuals;i++)
5476     {
5477         VARIANT *arg = prgpvarg[i];
5478         TRACE("Storing arg %d (%d as %d)\n",i,V_VT(arg),prgvt[i]);
5479         if (prgvt[i] == VT_VARIANT)
5480             memcpy(&args[argspos], arg, _argsize(prgvt[i]) * sizeof(DWORD));
5481         else
5482             memcpy(&args[argspos], &V_NONE(arg), _argsize(prgvt[i]) * sizeof(DWORD));
5483         argspos += _argsize(prgvt[i]);
5484     }
5485
5486     if (pvInstance)
5487     {
5488         FARPROC *vtable = *(FARPROC**)pvInstance;
5489         hres = _invoke(vtable[oVft/sizeof(void *)], cc, argsize, args);
5490     }
5491     else
5492         /* if we aren't invoking an object then the function pointer is stored
5493          * in oVft */
5494         hres = _invoke((FARPROC)oVft, cc, argsize, args);
5495
5496     if (pvargResult && (vtReturn != VT_EMPTY))
5497     {
5498         TRACE("Method returned 0x%08x\n",hres);
5499         V_VT(pvargResult) = vtReturn;
5500         V_UI4(pvargResult) = hres;
5501     }
5502
5503     HeapFree(GetProcessHeap(),0,args);
5504     return S_OK;
5505 }
5506
5507 #define INVBUF_ELEMENT_SIZE \
5508     (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *) + sizeof(VARTYPE))
5509 #define INVBUF_GET_ARG_ARRAY(buffer, params) \
5510     ((VARIANTARG *)(buffer))
5511 #define INVBUF_GET_MISSING_ARG_ARRAY(buffer, params) \
5512     ((VARIANTARG *)((char *)(buffer) + sizeof(VARIANTARG) * (params)))
5513 #define INVBUF_GET_ARG_PTR_ARRAY(buffer, params) \
5514     ((VARIANTARG **)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG)) * (params)))
5515 #define INVBUF_GET_ARG_TYPE_ARRAY(buffer, params) \
5516     ((VARTYPE *)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *)) * (params)))
5517
5518 static HRESULT WINAPI ITypeInfo_fnInvoke(
5519     ITypeInfo2 *iface,
5520     VOID  *pIUnk,
5521     MEMBERID memid,
5522     UINT16 wFlags,
5523     DISPPARAMS  *pDispParams,
5524     VARIANT  *pVarResult,
5525     EXCEPINFO  *pExcepInfo,
5526     UINT  *pArgErr)
5527 {
5528     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5529     int i;
5530     unsigned int var_index;
5531     TYPEKIND type_kind;
5532     HRESULT hres;
5533     const TLBFuncDesc *pFuncInfo;
5534
5535     TRACE("(%p)(%p,id=%d,flags=0x%08x,%p,%p,%p,%p)\n",
5536       This,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr
5537     );
5538
5539     if (!pDispParams)
5540     {
5541         ERR("NULL pDispParams not allowed\n");
5542         return E_INVALIDARG;
5543     }
5544
5545     dump_DispParms(pDispParams);
5546
5547     if (pDispParams->cNamedArgs > pDispParams->cArgs)
5548     {
5549         ERR("named argument array cannot be bigger than argument array (%d/%d)\n",
5550             pDispParams->cNamedArgs, pDispParams->cArgs);
5551         return E_INVALIDARG;
5552     }
5553
5554     /* we do this instead of using GetFuncDesc since it will return a fake
5555      * FUNCDESC for dispinterfaces and we want the real function description */
5556     for (pFuncInfo = This->funclist; pFuncInfo; pFuncInfo=pFuncInfo->next)
5557         if ((memid == pFuncInfo->funcdesc.memid) &&
5558             (wFlags & pFuncInfo->funcdesc.invkind))
5559             break;
5560
5561     if (pFuncInfo) {
5562         const FUNCDESC *func_desc = &pFuncInfo->funcdesc;
5563
5564         if (TRACE_ON(ole))
5565         {
5566             TRACE("invoking:\n");
5567             dump_TLBFuncDescOne(pFuncInfo);
5568         }
5569         
5570         switch (func_desc->funckind) {
5571         case FUNC_PUREVIRTUAL:
5572         case FUNC_VIRTUAL: {
5573             void *buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INVBUF_ELEMENT_SIZE * func_desc->cParams);
5574             VARIANT varresult;
5575             VARIANT retval; /* pointer for storing byref retvals in */
5576             VARIANTARG **prgpvarg = INVBUF_GET_ARG_PTR_ARRAY(buffer, func_desc->cParams);
5577             VARIANTARG *rgvarg = INVBUF_GET_ARG_ARRAY(buffer, func_desc->cParams);
5578             VARTYPE *rgvt = INVBUF_GET_ARG_TYPE_ARRAY(buffer, func_desc->cParams);
5579             UINT cNamedArgs = pDispParams->cNamedArgs;
5580             DISPID *rgdispidNamedArgs = pDispParams->rgdispidNamedArgs;
5581
5582             hres = S_OK;
5583
5584             if (func_desc->invkind & (INVOKE_PROPERTYPUT|INVOKE_PROPERTYPUTREF))
5585             {
5586                 if (!cNamedArgs || (rgdispidNamedArgs[0] != DISPID_PROPERTYPUT))
5587                 {
5588                     ERR("first named arg for property put invocation must be DISPID_PROPERTYPUT\n");
5589                     hres = DISP_E_PARAMNOTFOUND;
5590                     goto func_fail;
5591                 }
5592                 /* ignore the DISPID_PROPERTYPUT named argument from now on */
5593                 cNamedArgs--;
5594                 rgdispidNamedArgs++;
5595             }
5596
5597             for (i = 0; i < func_desc->cParams; i++)
5598             {
5599                 TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc;
5600                 hres = typedescvt_to_variantvt((ITypeInfo *)iface, tdesc, &rgvt[i]);
5601                 if (FAILED(hres))
5602                     goto func_fail;
5603             }
5604
5605             TRACE("changing args\n");
5606             for (i = 0; i < func_desc->cParams; i++)
5607             {
5608                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
5609                 VARIANTARG *src_arg;
5610
5611                 if (cNamedArgs)
5612                 {
5613                     USHORT j;
5614                     src_arg = NULL;
5615                     for (j = 0; j < cNamedArgs; j++)
5616                         if (rgdispidNamedArgs[j] == i)
5617                         {
5618                             src_arg = &pDispParams->rgvarg[j];
5619                             break;
5620                         }
5621                 }
5622                 else
5623                     src_arg = i < pDispParams->cArgs ? &pDispParams->rgvarg[pDispParams->cArgs - 1 - i] : NULL;
5624
5625                 if (wParamFlags & PARAMFLAG_FRETVAL)
5626                 {
5627                     /* under most conditions the caller is not allowed to
5628                      * pass in a dispparam arg in the index of what would be
5629                      * the retval parameter. however, there is an exception
5630                      * where the extra parameter is used in an extra
5631                      * IDispatch::Invoke below */
5632                     if ((i < pDispParams->cArgs) &&
5633                         ((func_desc->cParams != 1) || !pVarResult ||
5634                          !(func_desc->invkind & INVOKE_PROPERTYGET)))
5635                     {
5636                         hres = DISP_E_BADPARAMCOUNT;
5637                         break;
5638                     }
5639
5640                     /* note: this check is placed so that if the caller passes
5641                      * in a VARIANTARG for the retval we just ignore it, like
5642                      * native does */
5643                     if (i == func_desc->cParams - 1)
5644                     {
5645                         VARIANTARG *arg;
5646                         arg = prgpvarg[i] = &rgvarg[i];
5647                         memset(arg, 0, sizeof(*arg));
5648                         V_VT(arg) = rgvt[i];
5649                         memset(&retval, 0, sizeof(retval));
5650                         V_BYREF(arg) = &retval;
5651                     }
5652                     else
5653                     {
5654                         ERR("[retval] parameter must be the last parameter of the method (%d/%d)\n", i, func_desc->cParams);
5655                         hres = E_UNEXPECTED;
5656                         break;
5657                     }
5658                 }
5659                 else if (src_arg)
5660                 {
5661                     dump_Variant(src_arg);
5662
5663                     if (rgvt[i] == VT_VARIANT)
5664                         hres = VariantCopy(&rgvarg[i], src_arg);
5665                     else if (rgvt[i] == (VT_VARIANT | VT_BYREF))
5666                     {
5667                         if (rgvt[i] == V_VT(src_arg))
5668                             V_VARIANTREF(&rgvarg[i]) = V_VARIANTREF(src_arg);
5669                         else
5670                         {
5671                             VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
5672                             hres = VariantCopy(&missing_arg[i], src_arg);
5673                             V_VARIANTREF(&rgvarg[i]) = &missing_arg[i];
5674                         }
5675                         V_VT(&rgvarg[i]) = rgvt[i];
5676                     }
5677                     else if ((rgvt[i] & VT_BYREF) && !V_ISBYREF(src_arg))
5678                     {
5679                         VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
5680                         V_VT(&missing_arg[i]) = V_VT(src_arg);
5681                         hres = VariantChangeType(&missing_arg[i], src_arg, 0, rgvt[i] & ~VT_BYREF);
5682                         V_BYREF(&rgvarg[i]) = &V_NONE(&missing_arg[i]);
5683                         V_VT(&rgvarg[i]) = rgvt[i];
5684                     }
5685                     else if ((rgvt[i] & VT_BYREF) && (rgvt[i] == V_VT(src_arg)))
5686                     {
5687                         V_BYREF(&rgvarg[i]) = V_BYREF(src_arg);
5688                         V_VT(&rgvarg[i]) = rgvt[i];
5689                     }
5690                     else
5691                     {
5692                         /* FIXME: this doesn't work for VT_BYREF arguments if
5693                          * they are not the same type as in the paramdesc */
5694                         V_VT(&rgvarg[i]) = V_VT(src_arg);
5695                         hres = VariantChangeType(&rgvarg[i], src_arg, 0, rgvt[i]);
5696                         V_VT(&rgvarg[i]) = rgvt[i];
5697                     }
5698
5699                     if (FAILED(hres))
5700                     {
5701                         ERR("failed to convert param %d to %s%s from %s%s\n", i,
5702                             debugstr_vt(rgvt[i]), debugstr_vf(rgvt[i]),
5703                             debugstr_VT(src_arg), debugstr_VF(src_arg));
5704                         break;
5705                     }
5706                     prgpvarg[i] = &rgvarg[i];
5707                 }
5708                 else if (wParamFlags & PARAMFLAG_FOPT)
5709                 {
5710                     VARIANTARG *arg;
5711                     arg = prgpvarg[i] = &rgvarg[i];
5712                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
5713                     {
5714                         hres = VariantCopy(arg, &func_desc->lprgelemdescParam[i].u.paramdesc.pparamdescex->varDefaultValue);
5715                         if (FAILED(hres))
5716                             break;
5717                     }
5718                     else
5719                     {
5720                         VARIANTARG *missing_arg;
5721                         /* if the function wants a pointer to a variant then
5722                          * set that up, otherwise just pass the VT_ERROR in
5723                          * the argument by value */
5724                         if (rgvt[i] & VT_BYREF)
5725                         {
5726                             missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams) + i;
5727                             V_VT(arg) = VT_VARIANT | VT_BYREF;
5728                             V_VARIANTREF(arg) = missing_arg;
5729                         }
5730                         else
5731                             missing_arg = arg;
5732                         V_VT(missing_arg) = VT_ERROR;
5733                         V_ERROR(missing_arg) = DISP_E_PARAMNOTFOUND;
5734                     }
5735                 }
5736                 else
5737                 {
5738                     hres = DISP_E_BADPARAMCOUNT;
5739                     break;
5740                 }
5741             }
5742             if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
5743             if (func_desc->cParamsOpt < 0)
5744             {
5745                 FIXME("Does not support safearray optional parameters\n");
5746                 hres = DISP_E_BADPARAMCOUNT;
5747                 goto func_fail; /* FIXME: we don't free changed types here */
5748             }
5749
5750             /* VT_VOID is a special case for return types, so it is not
5751              * handled in the general function */
5752             if (func_desc->elemdescFunc.tdesc.vt == VT_VOID)
5753                 V_VT(&varresult) = VT_EMPTY;
5754             else
5755             {
5756                 V_VT(&varresult) = 0;
5757                 hres = typedescvt_to_variantvt((ITypeInfo *)iface, &func_desc->elemdescFunc.tdesc, &V_VT(&varresult));
5758                 if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
5759             }
5760
5761             hres = DispCallFunc(pIUnk, func_desc->oVft, func_desc->callconv,
5762                                 V_VT(&varresult), func_desc->cParams, rgvt,
5763                                 prgpvarg, &varresult);
5764
5765             for (i = 0; i < func_desc->cParams; i++)
5766             {
5767                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
5768                 if (wParamFlags & PARAMFLAG_FRETVAL)
5769                 {
5770                     if (TRACE_ON(ole))
5771                     {
5772                         TRACE("[retval] value: ");
5773                         dump_Variant(prgpvarg[i]);
5774                     }
5775
5776                     if (pVarResult)
5777                     {
5778                         VariantInit(pVarResult);
5779                         /* deref return value */
5780                         hres = VariantCopyInd(pVarResult, prgpvarg[i]);
5781                     }
5782
5783                     /* free data stored in varresult. Note that
5784                      * VariantClear doesn't do what we want because we are
5785                      * working with byref types. */
5786                     /* FIXME: clear safearrays, bstrs, records and
5787                      * variants here too */
5788                     if ((V_VT(prgpvarg[i]) == (VT_UNKNOWN | VT_BYREF)) ||
5789                          (V_VT(prgpvarg[i]) == (VT_DISPATCH | VT_BYREF)))
5790                     {
5791                         if(*V_UNKNOWNREF(prgpvarg[i]))
5792                             IUnknown_Release(*V_UNKNOWNREF(prgpvarg[i]));
5793                     }
5794                     break;
5795                 }
5796                 else if (i < pDispParams->cArgs)
5797                 {
5798                     if (wParamFlags & PARAMFLAG_FOUT)
5799                     {
5800                         VARIANTARG *arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - i];
5801
5802                         if ((rgvt[i] == VT_BYREF) && (V_VT(arg) != VT_BYREF))
5803                             hres = VariantChangeType(arg, &rgvarg[i], 0, V_VT(arg));
5804
5805                         if (FAILED(hres))
5806                         {
5807                             ERR("failed to convert param %d to vt %d\n", i,
5808                                 V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1 - i]));
5809                             break;
5810                         }
5811                     }
5812                     VariantClear(&rgvarg[i]);
5813                 }
5814                 else if (wParamFlags & PARAMFLAG_FOPT)
5815                 {
5816                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
5817                         VariantClear(&rgvarg[i]);
5818                 }
5819             }
5820
5821             if ((V_VT(&varresult) == VT_ERROR) && FAILED(V_ERROR(&varresult)))
5822             {
5823                 WARN("invoked function failed with error 0x%08x\n", V_ERROR(&varresult));
5824                 hres = DISP_E_EXCEPTION;
5825                 if (pExcepInfo)
5826                 {
5827                     IErrorInfo *pErrorInfo;
5828                     pExcepInfo->scode = V_ERROR(&varresult);
5829                     if (GetErrorInfo(0, &pErrorInfo) == S_OK)
5830                     {
5831                         IErrorInfo_GetDescription(pErrorInfo, &pExcepInfo->bstrDescription);
5832                         IErrorInfo_GetHelpFile(pErrorInfo, &pExcepInfo->bstrHelpFile);
5833                         IErrorInfo_GetSource(pErrorInfo, &pExcepInfo->bstrSource);
5834                         IErrorInfo_GetHelpContext(pErrorInfo, &pExcepInfo->dwHelpContext);
5835
5836                         IErrorInfo_Release(pErrorInfo);
5837                     }
5838                 }
5839             }
5840             if (V_VT(&varresult) != VT_ERROR)
5841             {
5842                 TRACE("varresult value: ");
5843                 dump_Variant(&varresult);
5844
5845                 if (pVarResult)
5846                 {
5847                     VariantClear(pVarResult);
5848                     *pVarResult = varresult;
5849                 }
5850                 else
5851                     VariantClear(&varresult);
5852             }
5853
5854             if (SUCCEEDED(hres) && pVarResult && (func_desc->cParams == 1) &&
5855                 (func_desc->invkind & INVOKE_PROPERTYGET) &&
5856                 (func_desc->lprgelemdescParam[0].u.paramdesc.wParamFlags & PARAMFLAG_FRETVAL) &&
5857                 (pDispParams->cArgs != 0))
5858             {
5859                 if (V_VT(pVarResult) == VT_DISPATCH)
5860                 {
5861                     IDispatch *pDispatch = V_DISPATCH(pVarResult);
5862                     /* Note: not VariantClear; we still need the dispatch
5863                      * pointer to be valid */
5864                     VariantInit(pVarResult);
5865                     hres = IDispatch_Invoke(pDispatch, DISPID_VALUE, &IID_NULL,
5866                         GetSystemDefaultLCID(), INVOKE_PROPERTYGET,
5867                         pDispParams, pVarResult, pExcepInfo, pArgErr);
5868                     IDispatch_Release(pDispatch);
5869                 }
5870                 else
5871                 {
5872                     VariantClear(pVarResult);
5873                     hres = DISP_E_NOTACOLLECTION;
5874                 }
5875             }
5876
5877 func_fail:
5878             HeapFree(GetProcessHeap(), 0, buffer);
5879             break;
5880         }
5881         case FUNC_DISPATCH:  {
5882            IDispatch *disp;
5883
5884            hres = IUnknown_QueryInterface((LPUNKNOWN)pIUnk,&IID_IDispatch,(LPVOID*)&disp);
5885            if (SUCCEEDED(hres)) {
5886                FIXME("Calling Invoke in IDispatch iface. untested!\n");
5887                hres = IDispatch_Invoke(
5888                                      disp,memid,&IID_NULL,LOCALE_USER_DEFAULT,wFlags,pDispParams,
5889                                      pVarResult,pExcepInfo,pArgErr
5890                                      );
5891                if (FAILED(hres))
5892                    FIXME("IDispatch::Invoke failed with %08x. (Could be not a real error?)\n", hres);
5893                IDispatch_Release(disp);
5894            } else
5895                FIXME("FUNC_DISPATCH used on object without IDispatch iface?\n");
5896            break;
5897         }
5898         default:
5899             FIXME("Unknown function invocation type %d\n", func_desc->funckind);
5900             hres = E_FAIL;
5901             break;
5902         }
5903
5904         TRACE("-- 0x%08x\n", hres);
5905         return hres;
5906
5907     } else if(SUCCEEDED(hres = ITypeInfo2_GetVarIndexOfMemId(iface, memid, &var_index))) {
5908         VARDESC *var_desc;
5909
5910         hres = ITypeInfo2_GetVarDesc(iface, var_index, &var_desc);
5911         if(FAILED(hres)) return hres;
5912         
5913         FIXME("varseek: Found memid, but variable-based invoking not supported\n");
5914         dump_VARDESC(var_desc);
5915         ITypeInfo2_ReleaseVarDesc(iface, var_desc);
5916         return E_NOTIMPL;
5917     }
5918
5919     /* not found, look for it in inherited interfaces */
5920     ITypeInfo2_GetTypeKind(iface, &type_kind);
5921     if(type_kind == TKIND_INTERFACE || type_kind == TKIND_DISPATCH) {
5922         if(This->impltypelist) {
5923             /* recursive search */
5924             ITypeInfo *pTInfo;
5925             hres = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef, &pTInfo);
5926             if(SUCCEEDED(hres)){
5927                 hres = ITypeInfo_Invoke(pTInfo,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr);
5928                 ITypeInfo_Release(pTInfo);
5929                 return hres;
5930             }
5931             WARN("Could not search inherited interface!\n");
5932         }
5933     }
5934     ERR("did not find member id %d, flags 0x%x!\n", memid, wFlags);
5935     return DISP_E_MEMBERNOTFOUND;
5936 }
5937
5938 /* ITypeInfo::GetDocumentation
5939  *
5940  * Retrieves the documentation string, the complete Help file name and path,
5941  * and the context ID for the Help topic for a specified type description.
5942  *
5943  * (Can be tested by the Visual Basic Editor in Word for instance.)
5944  */
5945 static HRESULT WINAPI ITypeInfo_fnGetDocumentation( ITypeInfo2 *iface,
5946         MEMBERID memid, BSTR  *pBstrName, BSTR  *pBstrDocString,
5947         DWORD  *pdwHelpContext, BSTR  *pBstrHelpFile)
5948 {
5949     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5950     const TLBFuncDesc *pFDesc;
5951     const TLBVarDesc *pVDesc;
5952     TRACE("(%p) memid %d Name(%p) DocString(%p)"
5953           " HelpContext(%p) HelpFile(%p)\n",
5954         This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
5955     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
5956         if(pBstrName)
5957             *pBstrName=SysAllocString(This->Name);
5958         if(pBstrDocString)
5959             *pBstrDocString=SysAllocString(This->DocString);
5960         if(pdwHelpContext)
5961             *pdwHelpContext=This->dwHelpContext;
5962         if(pBstrHelpFile)
5963             *pBstrHelpFile=SysAllocString(This->DocString);/* FIXME */
5964         return S_OK;
5965     }else {/* for a member */
5966     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
5967         if(pFDesc->funcdesc.memid==memid){
5968           if(pBstrName)
5969             *pBstrName = SysAllocString(pFDesc->Name);
5970           if(pBstrDocString)
5971             *pBstrDocString=SysAllocString(pFDesc->HelpString);
5972           if(pdwHelpContext)
5973             *pdwHelpContext=pFDesc->helpcontext;
5974           return S_OK;
5975         }
5976     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
5977         if(pVDesc->vardesc.memid==memid){
5978             if(pBstrName)
5979               *pBstrName = SysAllocString(pVDesc->Name);
5980             if(pBstrDocString)
5981               *pBstrDocString=SysAllocString(pVDesc->HelpString);
5982             if(pdwHelpContext)
5983               *pdwHelpContext=pVDesc->HelpContext;
5984             return S_OK;
5985         }
5986     }
5987
5988     if(This->impltypelist &&
5989        (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
5990         /* recursive search */
5991         ITypeInfo *pTInfo;
5992         HRESULT result;
5993         result = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef,
5994                                         &pTInfo);
5995         if(SUCCEEDED(result)) {
5996             result = ITypeInfo_GetDocumentation(pTInfo, memid, pBstrName,
5997                 pBstrDocString, pdwHelpContext, pBstrHelpFile);
5998             ITypeInfo_Release(pTInfo);
5999             return result;
6000         }
6001         WARN("Could not search inherited interface!\n");
6002     }
6003
6004     WARN("member %d not found\n", memid);
6005     return TYPE_E_ELEMENTNOTFOUND;
6006 }
6007
6008 /*  ITypeInfo::GetDllEntry
6009  *
6010  * Retrieves a description or specification of an entry point for a function
6011  * in a DLL.
6012  */
6013 static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid,
6014         INVOKEKIND invKind, BSTR  *pBstrDllName, BSTR  *pBstrName,
6015         WORD  *pwOrdinal)
6016 {
6017     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6018     const TLBFuncDesc *pFDesc;
6019
6020     TRACE("(%p)->(memid %x, %d, %p, %p, %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
6021
6022     if (pBstrDllName) *pBstrDllName = NULL;
6023     if (pBstrName) *pBstrName = NULL;
6024     if (pwOrdinal) *pwOrdinal = 0;
6025
6026     if (This->TypeAttr.typekind != TKIND_MODULE)
6027         return TYPE_E_BADMODULEKIND;
6028
6029     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
6030         if(pFDesc->funcdesc.memid==memid){
6031             dump_TypeInfo(This);
6032             if (TRACE_ON(ole))
6033                 dump_TLBFuncDescOne(pFDesc);
6034
6035             if (pBstrDllName)
6036                 *pBstrDllName = SysAllocString(This->DllName);
6037
6038             if (HIWORD(pFDesc->Entry) && (pFDesc->Entry != (void*)-1)) {
6039                 if (pBstrName)
6040                     *pBstrName = SysAllocString(pFDesc->Entry);
6041                 if (pwOrdinal)
6042                     *pwOrdinal = -1;
6043                 return S_OK;
6044             }
6045             if (pBstrName)
6046                 *pBstrName = NULL;
6047             if (pwOrdinal)
6048                 *pwOrdinal = (DWORD)pFDesc->Entry;
6049             return S_OK;
6050         }
6051     return TYPE_E_ELEMENTNOTFOUND;
6052 }
6053
6054 /* internal function to make the inherited interfaces' methods appear
6055  * part of the interface */
6056 static HRESULT ITypeInfoImpl_GetDispatchRefTypeInfo( ITypeInfo *iface,
6057     HREFTYPE *hRefType, ITypeInfo  **ppTInfo)
6058 {
6059     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6060     HRESULT hr;
6061
6062     TRACE("%p, 0x%x\n", iface, *hRefType);
6063
6064     if (This->impltypelist && (*hRefType & DISPATCH_HREF_MASK))
6065     {
6066         ITypeInfo *pSubTypeInfo;
6067
6068         hr = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef, &pSubTypeInfo);
6069         if (FAILED(hr))
6070             return hr;
6071
6072         hr = ITypeInfoImpl_GetDispatchRefTypeInfo(pSubTypeInfo,
6073                                                   hRefType, ppTInfo);
6074         ITypeInfo_Release(pSubTypeInfo);
6075         if (SUCCEEDED(hr))
6076             return hr;
6077     }
6078     *hRefType -= DISPATCH_HREF_OFFSET;
6079
6080     if (!(*hRefType & DISPATCH_HREF_MASK))
6081         return ITypeInfo_GetRefTypeInfo(iface, *hRefType, ppTInfo);
6082     else
6083         return E_FAIL;
6084 }
6085
6086 /* ITypeInfo::GetRefTypeInfo
6087  *
6088  * If a type description references other type descriptions, it retrieves
6089  * the referenced type descriptions.
6090  */
6091 static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo(
6092         ITypeInfo2 *iface,
6093         HREFTYPE hRefType,
6094         ITypeInfo  **ppTInfo)
6095 {
6096     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6097     HRESULT result = E_FAIL;
6098
6099     if ((This->hreftype != -1) && (This->hreftype == hRefType))
6100     {
6101         *ppTInfo = (ITypeInfo *)&This->lpVtbl;
6102         ITypeInfo_AddRef(*ppTInfo);
6103         result = S_OK;
6104     }
6105     else if (hRefType == -1 &&
6106         (This->TypeAttr.typekind   == TKIND_DISPATCH) &&
6107         (This->TypeAttr.wTypeFlags &  TYPEFLAG_FDUAL))
6108     {
6109           /* when we meet a DUAL dispinterface, we must create the interface
6110           * version of it.
6111           */
6112           ITypeInfoImpl* pTypeInfoImpl = (ITypeInfoImpl*) ITypeInfo_Constructor();
6113
6114
6115           /* the interface version contains the same information as the dispinterface
6116            * copy the contents of the structs.
6117            */
6118           *pTypeInfoImpl = *This;
6119           pTypeInfoImpl->ref = 0;
6120
6121           /* change the type to interface */
6122           pTypeInfoImpl->TypeAttr.typekind = TKIND_INTERFACE;
6123
6124           *ppTInfo = (ITypeInfo*) pTypeInfoImpl;
6125
6126           /* we use data structures from This, so we need to keep a reference
6127            * to it to stop it being destroyed and signal to the new instance to
6128            * not free its data structures when it is destroyed */
6129           pTypeInfoImpl->no_free_data = TRUE;
6130           pTypeInfoImpl->next = This;
6131           ITypeInfo_AddRef((ITypeInfo*) This);
6132
6133           ITypeInfo_AddRef(*ppTInfo);
6134
6135           result = S_OK;
6136
6137     } else if ((hRefType != -1) && (hRefType & DISPATCH_HREF_MASK) &&
6138         (This->TypeAttr.typekind   == TKIND_DISPATCH) &&
6139         (This->TypeAttr.wTypeFlags &  TYPEFLAG_FDUAL))
6140     {
6141         HREFTYPE href_dispatch = hRefType;
6142         result = ITypeInfoImpl_GetDispatchRefTypeInfo((ITypeInfo *)iface, &href_dispatch, ppTInfo);
6143     } else {
6144         TLBRefType *ref_type;
6145         LIST_FOR_EACH_ENTRY(ref_type, &This->pTypeLib->ref_list, TLBRefType, entry)
6146         {
6147             if(ref_type->reference == hRefType)
6148                 break;
6149         }
6150         if(&ref_type->entry == &This->pTypeLib->ref_list)
6151         {
6152             FIXME("Can't find pRefType for ref %x\n", hRefType);
6153             goto end;
6154         }
6155         if(hRefType != -1) {
6156             ITypeLib *pTLib = NULL;
6157
6158             if(ref_type->pImpTLInfo == TLB_REF_INTERNAL) {
6159                 UINT Index;
6160                 result = ITypeInfo_GetContainingTypeLib(iface, &pTLib, &Index);
6161             } else {
6162                 if(ref_type->pImpTLInfo->pImpTypeLib) {
6163                     TRACE("typeinfo in imported typelib that is already loaded\n");
6164                     pTLib = (ITypeLib*)ref_type->pImpTLInfo->pImpTypeLib;
6165                     ITypeLib2_AddRef((ITypeLib*) pTLib);
6166                     result = S_OK;
6167                 } else {
6168                     TRACE("typeinfo in imported typelib that isn't already loaded\n");
6169                     result = LoadRegTypeLib( &ref_type->pImpTLInfo->guid,
6170                                              ref_type->pImpTLInfo->wVersionMajor,
6171                                              ref_type->pImpTLInfo->wVersionMinor,
6172                                              ref_type->pImpTLInfo->lcid,
6173                                              &pTLib);
6174
6175                     if(!SUCCEEDED(result)) {
6176                         BSTR libnam=SysAllocString(ref_type->pImpTLInfo->name);
6177                         result=LoadTypeLib(libnam, &pTLib);
6178                         SysFreeString(libnam);
6179                     }
6180                     if(SUCCEEDED(result)) {
6181                         ref_type->pImpTLInfo->pImpTypeLib = (ITypeLibImpl*)pTLib;
6182                         ITypeLib2_AddRef(pTLib);
6183                     }
6184                 }
6185             }
6186             if(SUCCEEDED(result)) {
6187                 if(ref_type->index == TLB_REF_USE_GUID)
6188                     result = ITypeLib2_GetTypeInfoOfGuid(pTLib,
6189                                                          &ref_type->guid,
6190                                                          ppTInfo);
6191                 else
6192                     result = ITypeLib2_GetTypeInfo(pTLib, ref_type->index,
6193                                                    ppTInfo);
6194             }
6195             if (pTLib != NULL)
6196                 ITypeLib2_Release(pTLib);
6197         }
6198     }
6199
6200 end:
6201     TRACE("(%p) hreftype 0x%04x loaded %s (%p)\n", This, hRefType,
6202           SUCCEEDED(result)? "SUCCESS":"FAILURE", *ppTInfo);
6203     return result;
6204 }
6205
6206 /* ITypeInfo::AddressOfMember
6207  *
6208  * Retrieves the addresses of static functions or variables, such as those
6209  * defined in a DLL.
6210  */
6211 static HRESULT WINAPI ITypeInfo_fnAddressOfMember( ITypeInfo2 *iface,
6212         MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
6213 {
6214     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6215     HRESULT hr;
6216     BSTR dll, entry;
6217     WORD ordinal;
6218     HMODULE module;
6219
6220     TRACE("(%p)->(0x%x, 0x%x, %p)\n", This, memid, invKind, ppv);
6221
6222     hr = ITypeInfo_GetDllEntry(iface, memid, invKind, &dll, &entry, &ordinal);
6223     if (FAILED(hr))
6224         return hr;
6225
6226     module = LoadLibraryW(dll);
6227     if (!module)
6228     {
6229         ERR("couldn't load %s\n", debugstr_w(dll));
6230         SysFreeString(dll);
6231         if (entry) SysFreeString(entry);
6232         return STG_E_FILENOTFOUND;
6233     }
6234     /* FIXME: store library somewhere where we can free it */
6235
6236     if (entry)
6237     {
6238         LPSTR entryA;
6239         INT len = WideCharToMultiByte(CP_ACP, 0, entry, -1, NULL, 0, NULL, NULL);
6240         entryA = HeapAlloc(GetProcessHeap(), 0, len);
6241         WideCharToMultiByte(CP_ACP, 0, entry, -1, entryA, len, NULL, NULL);
6242
6243         *ppv = GetProcAddress(module, entryA);
6244         if (!*ppv)
6245             ERR("function not found %s\n", debugstr_a(entryA));
6246
6247         HeapFree(GetProcessHeap(), 0, entryA);
6248     }
6249     else
6250     {
6251         *ppv = GetProcAddress(module, MAKEINTRESOURCEA(ordinal));
6252         if (!*ppv)
6253             ERR("function not found %d\n", ordinal);
6254     }
6255
6256     SysFreeString(dll);
6257     if (entry) SysFreeString(entry);
6258
6259     if (!*ppv)
6260         return TYPE_E_DLLFUNCTIONNOTFOUND;
6261
6262     return S_OK;
6263 }
6264
6265 /* ITypeInfo::CreateInstance
6266  *
6267  * Creates a new instance of a type that describes a component object class
6268  * (coclass).
6269  */
6270 static HRESULT WINAPI ITypeInfo_fnCreateInstance( ITypeInfo2 *iface,
6271         IUnknown *pOuterUnk, REFIID riid, VOID  **ppvObj)
6272 {
6273     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6274     HRESULT hr;
6275     TYPEATTR *pTA;
6276
6277     TRACE("(%p)->(%p, %s, %p)\n", This, pOuterUnk, debugstr_guid(riid), ppvObj);
6278
6279     *ppvObj = NULL;
6280
6281     if(pOuterUnk)
6282     {
6283         WARN("Not able to aggregate\n");
6284         return CLASS_E_NOAGGREGATION;
6285     }
6286
6287     hr = ITypeInfo_GetTypeAttr(iface, &pTA);
6288     if(FAILED(hr)) return hr;
6289
6290     if(pTA->typekind != TKIND_COCLASS)
6291     {
6292         WARN("CreateInstance on typeinfo of type %x\n", pTA->typekind);
6293         hr = E_INVALIDARG;
6294         goto end;
6295     }
6296
6297     hr = S_FALSE;
6298     if(pTA->wTypeFlags & TYPEFLAG_FAPPOBJECT)
6299     {
6300         IUnknown *pUnk;
6301         hr = GetActiveObject(&pTA->guid, NULL, &pUnk);
6302         TRACE("GetActiveObject rets %08x\n", hr);
6303         if(hr == S_OK)
6304         {
6305             hr = IUnknown_QueryInterface(pUnk, riid, ppvObj);
6306             IUnknown_Release(pUnk);
6307         }
6308     }
6309
6310     if(hr != S_OK)
6311         hr = CoCreateInstance(&pTA->guid, NULL,
6312                               CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
6313                               riid, ppvObj);
6314
6315 end:
6316     ITypeInfo_ReleaseTypeAttr(iface, pTA);
6317     return hr;
6318 }
6319
6320 /* ITypeInfo::GetMops
6321  *
6322  * Retrieves marshalling information.
6323  */
6324 static HRESULT WINAPI ITypeInfo_fnGetMops( ITypeInfo2 *iface, MEMBERID memid,
6325                                 BSTR  *pBstrMops)
6326 {
6327     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6328     FIXME("(%p) stub!\n", This);
6329     return S_OK;
6330 }
6331
6332 /* ITypeInfo::GetContainingTypeLib
6333  *
6334  * Retrieves the containing type library and the index of the type description
6335  * within that type library.
6336  */
6337 static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( ITypeInfo2 *iface,
6338         ITypeLib  * *ppTLib, UINT  *pIndex)
6339 {
6340     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6341     
6342     /* If a pointer is null, we simply ignore it, the ATL in particular passes pIndex as 0 */
6343     if (pIndex) {
6344       *pIndex=This->index;
6345       TRACE("returning pIndex=%d\n", *pIndex);
6346     }
6347     
6348     if (ppTLib) {
6349       *ppTLib=(LPTYPELIB )(This->pTypeLib);
6350       ITypeLib2_AddRef(*ppTLib);
6351       TRACE("returning ppTLib=%p\n", *ppTLib);
6352     }
6353     
6354     return S_OK;
6355 }
6356
6357 /* ITypeInfo::ReleaseTypeAttr
6358  *
6359  * Releases a TYPEATTR previously returned by GetTypeAttr.
6360  *
6361  */
6362 static void WINAPI ITypeInfo_fnReleaseTypeAttr( ITypeInfo2 *iface,
6363         TYPEATTR* pTypeAttr)
6364 {
6365     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6366     TRACE("(%p)->(%p)\n", This, pTypeAttr);
6367     HeapFree(GetProcessHeap(), 0, pTypeAttr);
6368 }
6369
6370 /* ITypeInfo::ReleaseFuncDesc
6371  *
6372  * Releases a FUNCDESC previously returned by GetFuncDesc. *
6373  */
6374 static void WINAPI ITypeInfo_fnReleaseFuncDesc(
6375         ITypeInfo2 *iface,
6376         FUNCDESC *pFuncDesc)
6377 {
6378     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6379     SHORT i;
6380
6381     TRACE("(%p)->(%p)\n", This, pFuncDesc);
6382
6383     for (i = 0; i < pFuncDesc->cParams; i++)
6384         TLB_FreeElemDesc(&pFuncDesc->lprgelemdescParam[i]);
6385     TLB_FreeElemDesc(&pFuncDesc->elemdescFunc);
6386
6387     SysFreeString((BSTR)pFuncDesc);
6388 }
6389
6390 /* ITypeInfo::ReleaseVarDesc
6391  *
6392  * Releases a VARDESC previously returned by GetVarDesc.
6393  */
6394 static void WINAPI ITypeInfo_fnReleaseVarDesc( ITypeInfo2 *iface,
6395         VARDESC *pVarDesc)
6396 {
6397     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6398     TRACE("(%p)->(%p)\n", This, pVarDesc);
6399
6400     TLB_FreeElemDesc(&pVarDesc->elemdescVar);
6401     if (pVarDesc->varkind == VAR_CONST)
6402         VariantClear(pVarDesc->u.lpvarValue);
6403     SysFreeString((BSTR)pVarDesc);
6404 }
6405
6406 /* ITypeInfo2::GetTypeKind
6407  *
6408  * Returns the TYPEKIND enumeration quickly, without doing any allocations.
6409  *
6410  */
6411 static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo2 * iface,
6412     TYPEKIND *pTypeKind)
6413 {
6414     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6415     *pTypeKind=This->TypeAttr.typekind;
6416     TRACE("(%p) type 0x%0x\n", This,*pTypeKind);
6417     return S_OK;
6418 }
6419
6420 /* ITypeInfo2::GetTypeFlags
6421  *
6422  * Returns the type flags without any allocations. This returns a DWORD type
6423  * flag, which expands the type flags without growing the TYPEATTR (type
6424  * attribute).
6425  *
6426  */
6427 static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo2 *iface, ULONG *pTypeFlags)
6428 {
6429     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6430     *pTypeFlags=This->TypeAttr.wTypeFlags;
6431     TRACE("(%p) flags 0x%x\n", This,*pTypeFlags);
6432     return S_OK;
6433 }
6434
6435 /* ITypeInfo2::GetFuncIndexOfMemId
6436  * Binds to a specific member based on a known DISPID, where the member name
6437  * is not known (for example, when binding to a default member).
6438  *
6439  */
6440 static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo2 * iface,
6441     MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex)
6442 {
6443     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6444     const TLBFuncDesc *pFuncInfo;
6445     int i;
6446     HRESULT result;
6447
6448     for(i = 0, pFuncInfo = This->funclist; pFuncInfo; i++, pFuncInfo=pFuncInfo->next)
6449         if(memid == pFuncInfo->funcdesc.memid && (invKind & pFuncInfo->funcdesc.invkind))
6450             break;
6451     if(pFuncInfo) {
6452         *pFuncIndex = i;
6453         result = S_OK;
6454     } else
6455         result = TYPE_E_ELEMENTNOTFOUND;
6456
6457     TRACE("(%p) memid 0x%08x invKind 0x%04x -> %s\n", This,
6458           memid, invKind, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
6459     return result;
6460 }
6461
6462 /* TypeInfo2::GetVarIndexOfMemId
6463  *
6464  * Binds to a specific member based on a known DISPID, where the member name
6465  * is not known (for example, when binding to a default member).
6466  *
6467  */
6468 static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( ITypeInfo2 * iface,
6469     MEMBERID memid, UINT *pVarIndex)
6470 {
6471     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6472     TLBVarDesc *pVarInfo;
6473     int i;
6474     HRESULT result;
6475     for(i=0, pVarInfo=This->varlist; pVarInfo &&
6476             memid != pVarInfo->vardesc.memid; i++, pVarInfo=pVarInfo->next)
6477         ;
6478     if(pVarInfo) {
6479         *pVarIndex = i;
6480         result = S_OK;
6481     } else
6482         result = TYPE_E_ELEMENTNOTFOUND;
6483
6484     TRACE("(%p) memid 0x%08x -> %s\n", This,
6485           memid, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
6486     return result;
6487 }
6488
6489 /* ITypeInfo2::GetCustData
6490  *
6491  * Gets the custom data
6492  */
6493 static HRESULT WINAPI ITypeInfo2_fnGetCustData(
6494         ITypeInfo2 * iface,
6495         REFGUID guid,
6496         VARIANT *pVarVal)
6497 {
6498     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6499     TLBCustData *pCData;
6500
6501     for(pCData=This->pCustData; pCData; pCData = pCData->next)
6502         if( IsEqualIID(guid, &pCData->guid)) break;
6503
6504     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
6505
6506     if(pCData)
6507     {
6508         VariantInit( pVarVal);
6509         VariantCopy( pVarVal, &pCData->data);
6510         return S_OK;
6511     }
6512     return E_INVALIDARG;  /* FIXME: correct? */
6513 }
6514
6515 /* ITypeInfo2::GetFuncCustData
6516  *
6517  * Gets the custom data
6518  */
6519 static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData(
6520         ITypeInfo2 * iface,
6521         UINT index,
6522         REFGUID guid,
6523         VARIANT *pVarVal)
6524 {
6525     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6526     TLBCustData *pCData=NULL;
6527     TLBFuncDesc * pFDesc;
6528     int i;
6529     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
6530             pFDesc=pFDesc->next);
6531
6532     if(pFDesc)
6533         for(pCData=pFDesc->pCustData; pCData; pCData = pCData->next)
6534             if( IsEqualIID(guid, &pCData->guid)) break;
6535
6536     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
6537
6538     if(pCData){
6539         VariantInit( pVarVal);
6540         VariantCopy( pVarVal, &pCData->data);
6541         return S_OK;
6542     }
6543     return E_INVALIDARG;  /* FIXME: correct? */
6544 }
6545
6546 /* ITypeInfo2::GetParamCustData
6547  *
6548  * Gets the custom data
6549  */
6550 static HRESULT WINAPI ITypeInfo2_fnGetParamCustData(
6551         ITypeInfo2 * iface,
6552         UINT indexFunc,
6553         UINT indexParam,
6554         REFGUID guid,
6555         VARIANT *pVarVal)
6556 {
6557     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6558     TLBCustData *pCData=NULL;
6559     TLBFuncDesc * pFDesc;
6560     int i;
6561
6562     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,pFDesc=pFDesc->next);
6563
6564     if(pFDesc && indexParam >=0 && indexParam<pFDesc->funcdesc.cParams)
6565         for(pCData=pFDesc->pParamDesc[indexParam].pCustData; pCData;
6566                 pCData = pCData->next)
6567             if( IsEqualIID(guid, &pCData->guid)) break;
6568
6569     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
6570
6571     if(pCData)
6572     {
6573         VariantInit( pVarVal);
6574         VariantCopy( pVarVal, &pCData->data);
6575         return S_OK;
6576     }
6577     return E_INVALIDARG;  /* FIXME: correct? */
6578 }
6579
6580 /* ITypeInfo2::GetVarCustData
6581  *
6582  * Gets the custom data
6583  */
6584 static HRESULT WINAPI ITypeInfo2_fnGetVarCustData(
6585         ITypeInfo2 * iface,
6586         UINT index,
6587         REFGUID guid,
6588         VARIANT *pVarVal)
6589 {
6590     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6591     TLBCustData *pCData=NULL;
6592     TLBVarDesc * pVDesc;
6593     int i;
6594
6595     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next);
6596
6597     if(pVDesc)
6598     {
6599       for(pCData=pVDesc->pCustData; pCData; pCData = pCData->next)
6600       {
6601         if( IsEqualIID(guid, &pCData->guid)) break;
6602       }
6603     }
6604
6605     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
6606
6607     if(pCData)
6608     {
6609         VariantInit( pVarVal);
6610         VariantCopy( pVarVal, &pCData->data);
6611         return S_OK;
6612     }
6613     return E_INVALIDARG;  /* FIXME: correct? */
6614 }
6615
6616 /* ITypeInfo2::GetImplCustData
6617  *
6618  * Gets the custom data
6619  */
6620 static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData(
6621         ITypeInfo2 * iface,
6622         UINT index,
6623         REFGUID guid,
6624         VARIANT *pVarVal)
6625 {
6626     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6627     TLBCustData *pCData=NULL;
6628     TLBImplType * pRDesc;
6629     int i;
6630
6631     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++, pRDesc=pRDesc->next);
6632
6633     if(pRDesc)
6634     {
6635       for(pCData=pRDesc->pCustData; pCData; pCData = pCData->next)
6636       {
6637         if( IsEqualIID(guid, &pCData->guid)) break;
6638       }
6639     }
6640
6641     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
6642
6643     if(pCData)
6644     {
6645         VariantInit( pVarVal);
6646         VariantCopy( pVarVal, &pCData->data);
6647         return S_OK;
6648     }
6649     return E_INVALIDARG;  /* FIXME: correct? */
6650 }
6651
6652 /* ITypeInfo2::GetDocumentation2
6653  *
6654  * Retrieves the documentation string, the complete Help file name and path,
6655  * the localization context to use, and the context ID for the library Help
6656  * topic in the Help file.
6657  *
6658  */
6659 static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2(
6660         ITypeInfo2 * iface,
6661         MEMBERID memid,
6662         LCID lcid,
6663         BSTR *pbstrHelpString,
6664         DWORD *pdwHelpStringContext,
6665         BSTR *pbstrHelpStringDll)
6666 {
6667     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6668     const TLBFuncDesc *pFDesc;
6669     const TLBVarDesc *pVDesc;
6670     TRACE("(%p) memid %d lcid(0x%x)  HelpString(%p) "
6671           "HelpStringContext(%p) HelpStringDll(%p)\n",
6672           This, memid, lcid, pbstrHelpString, pdwHelpStringContext,
6673           pbstrHelpStringDll );
6674     /* the help string should be obtained from the helpstringdll,
6675      * using the _DLLGetDocumentation function, based on the supplied
6676      * lcid. Nice to do sometime...
6677      */
6678     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
6679         if(pbstrHelpString)
6680             *pbstrHelpString=SysAllocString(This->Name);
6681         if(pdwHelpStringContext)
6682             *pdwHelpStringContext=This->dwHelpStringContext;
6683         if(pbstrHelpStringDll)
6684             *pbstrHelpStringDll=
6685                 SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
6686         return S_OK;
6687     }else {/* for a member */
6688     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
6689         if(pFDesc->funcdesc.memid==memid){
6690              if(pbstrHelpString)
6691                 *pbstrHelpString=SysAllocString(pFDesc->HelpString);
6692             if(pdwHelpStringContext)
6693                 *pdwHelpStringContext=pFDesc->HelpStringContext;
6694             if(pbstrHelpStringDll)
6695                 *pbstrHelpStringDll=
6696                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
6697         return S_OK;
6698     }
6699     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
6700         if(pVDesc->vardesc.memid==memid){
6701              if(pbstrHelpString)
6702                 *pbstrHelpString=SysAllocString(pVDesc->HelpString);
6703             if(pdwHelpStringContext)
6704                 *pdwHelpStringContext=pVDesc->HelpStringContext;
6705             if(pbstrHelpStringDll)
6706                 *pbstrHelpStringDll=
6707                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
6708             return S_OK;
6709         }
6710     }
6711     return TYPE_E_ELEMENTNOTFOUND;
6712 }
6713
6714 /* ITypeInfo2::GetAllCustData
6715  *
6716  * Gets all custom data items for the Type info.
6717  *
6718  */
6719 static HRESULT WINAPI ITypeInfo2_fnGetAllCustData(
6720         ITypeInfo2 * iface,
6721         CUSTDATA *pCustData)
6722 {
6723     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6724     TLBCustData *pCData;
6725     int i;
6726
6727     TRACE("(%p) returning %d items\n", This, This->ctCustData);
6728
6729     pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
6730     if(pCustData->prgCustData ){
6731         pCustData->cCustData=This->ctCustData;
6732         for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
6733             pCustData->prgCustData[i].guid=pCData->guid;
6734             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
6735         }
6736     }else{
6737         ERR(" OUT OF MEMORY!\n");
6738         return E_OUTOFMEMORY;
6739     }
6740     return S_OK;
6741 }
6742
6743 /* ITypeInfo2::GetAllFuncCustData
6744  *
6745  * Gets all custom data items for the specified Function
6746  *
6747  */
6748 static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData(
6749         ITypeInfo2 * iface,
6750         UINT index,
6751         CUSTDATA *pCustData)
6752 {
6753     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6754     TLBCustData *pCData;
6755     TLBFuncDesc * pFDesc;
6756     int i;
6757     TRACE("(%p) index %d\n", This, index);
6758     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
6759             pFDesc=pFDesc->next)
6760         ;
6761     if(pFDesc){
6762         pCustData->prgCustData =
6763             TLB_Alloc(pFDesc->ctCustData * sizeof(CUSTDATAITEM));
6764         if(pCustData->prgCustData ){
6765             pCustData->cCustData=pFDesc->ctCustData;
6766             for(i=0, pCData=pFDesc->pCustData; pCData; i++,
6767                     pCData = pCData->next){
6768                 pCustData->prgCustData[i].guid=pCData->guid;
6769                 VariantCopy(& pCustData->prgCustData[i].varValue,
6770                         & pCData->data);
6771             }
6772         }else{
6773             ERR(" OUT OF MEMORY!\n");
6774             return E_OUTOFMEMORY;
6775         }
6776         return S_OK;
6777     }
6778     return TYPE_E_ELEMENTNOTFOUND;
6779 }
6780
6781 /* ITypeInfo2::GetAllParamCustData
6782  *
6783  * Gets all custom data items for the Functions
6784  *
6785  */
6786 static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo2 * iface,
6787     UINT indexFunc, UINT indexParam, CUSTDATA *pCustData)
6788 {
6789     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6790     TLBCustData *pCData=NULL;
6791     TLBFuncDesc * pFDesc;
6792     int i;
6793     TRACE("(%p) index %d\n", This, indexFunc);
6794     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,
6795             pFDesc=pFDesc->next)
6796         ;
6797     if(pFDesc && indexParam >=0 && indexParam<pFDesc->funcdesc.cParams){
6798         pCustData->prgCustData =
6799             TLB_Alloc(pFDesc->pParamDesc[indexParam].ctCustData *
6800                     sizeof(CUSTDATAITEM));
6801         if(pCustData->prgCustData ){
6802             pCustData->cCustData=pFDesc->pParamDesc[indexParam].ctCustData;
6803             for(i=0, pCData=pFDesc->pParamDesc[indexParam].pCustData;
6804                     pCData; i++, pCData = pCData->next){
6805                 pCustData->prgCustData[i].guid=pCData->guid;
6806                 VariantCopy(& pCustData->prgCustData[i].varValue,
6807                         & pCData->data);
6808             }
6809         }else{
6810             ERR(" OUT OF MEMORY!\n");
6811             return E_OUTOFMEMORY;
6812         }
6813         return S_OK;
6814     }
6815     return TYPE_E_ELEMENTNOTFOUND;
6816 }
6817
6818 /* ITypeInfo2::GetAllVarCustData
6819  *
6820  * Gets all custom data items for the specified Variable
6821  *
6822  */
6823 static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo2 * iface,
6824     UINT index, CUSTDATA *pCustData)
6825 {
6826     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6827     TLBCustData *pCData;
6828     TLBVarDesc * pVDesc;
6829     int i;
6830     TRACE("(%p) index %d\n", This, index);
6831     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++,
6832             pVDesc=pVDesc->next)
6833         ;
6834     if(pVDesc){
6835         pCustData->prgCustData =
6836             TLB_Alloc(pVDesc->ctCustData * sizeof(CUSTDATAITEM));
6837         if(pCustData->prgCustData ){
6838             pCustData->cCustData=pVDesc->ctCustData;
6839             for(i=0, pCData=pVDesc->pCustData; pCData; i++,
6840                     pCData = pCData->next){
6841                 pCustData->prgCustData[i].guid=pCData->guid;
6842                 VariantCopy(& pCustData->prgCustData[i].varValue,
6843                         & pCData->data);
6844             }
6845         }else{
6846             ERR(" OUT OF MEMORY!\n");
6847             return E_OUTOFMEMORY;
6848         }
6849         return S_OK;
6850     }
6851     return TYPE_E_ELEMENTNOTFOUND;
6852 }
6853
6854 /* ITypeInfo2::GetAllImplCustData
6855  *
6856  * Gets all custom data items for the specified implementation type
6857  *
6858  */
6859 static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData(
6860         ITypeInfo2 * iface,
6861         UINT index,
6862         CUSTDATA *pCustData)
6863 {
6864     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6865     TLBCustData *pCData;
6866     TLBImplType * pRDesc;
6867     int i;
6868     TRACE("(%p) index %d\n", This, index);
6869     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++,
6870             pRDesc=pRDesc->next)
6871         ;
6872     if(pRDesc){
6873         pCustData->prgCustData =
6874             TLB_Alloc(pRDesc->ctCustData * sizeof(CUSTDATAITEM));
6875         if(pCustData->prgCustData ){
6876             pCustData->cCustData=pRDesc->ctCustData;
6877             for(i=0, pCData=pRDesc->pCustData; pCData; i++,
6878                     pCData = pCData->next){
6879                 pCustData->prgCustData[i].guid=pCData->guid;
6880                 VariantCopy(& pCustData->prgCustData[i].varValue,
6881                         & pCData->data);
6882             }
6883         }else{
6884             ERR(" OUT OF MEMORY!\n");
6885             return E_OUTOFMEMORY;
6886         }
6887         return S_OK;
6888     }
6889     return TYPE_E_ELEMENTNOTFOUND;
6890 }
6891
6892 static const ITypeInfo2Vtbl tinfvt =
6893 {
6894
6895     ITypeInfo_fnQueryInterface,
6896     ITypeInfo_fnAddRef,
6897     ITypeInfo_fnRelease,
6898
6899     ITypeInfo_fnGetTypeAttr,
6900     ITypeInfo_fnGetTypeComp,
6901     ITypeInfo_fnGetFuncDesc,
6902     ITypeInfo_fnGetVarDesc,
6903     ITypeInfo_fnGetNames,
6904     ITypeInfo_fnGetRefTypeOfImplType,
6905     ITypeInfo_fnGetImplTypeFlags,
6906     ITypeInfo_fnGetIDsOfNames,
6907     ITypeInfo_fnInvoke,
6908     ITypeInfo_fnGetDocumentation,
6909     ITypeInfo_fnGetDllEntry,
6910     ITypeInfo_fnGetRefTypeInfo,
6911     ITypeInfo_fnAddressOfMember,
6912     ITypeInfo_fnCreateInstance,
6913     ITypeInfo_fnGetMops,
6914     ITypeInfo_fnGetContainingTypeLib,
6915     ITypeInfo_fnReleaseTypeAttr,
6916     ITypeInfo_fnReleaseFuncDesc,
6917     ITypeInfo_fnReleaseVarDesc,
6918
6919     ITypeInfo2_fnGetTypeKind,
6920     ITypeInfo2_fnGetTypeFlags,
6921     ITypeInfo2_fnGetFuncIndexOfMemId,
6922     ITypeInfo2_fnGetVarIndexOfMemId,
6923     ITypeInfo2_fnGetCustData,
6924     ITypeInfo2_fnGetFuncCustData,
6925     ITypeInfo2_fnGetParamCustData,
6926     ITypeInfo2_fnGetVarCustData,
6927     ITypeInfo2_fnGetImplTypeCustData,
6928     ITypeInfo2_fnGetDocumentation2,
6929     ITypeInfo2_fnGetAllCustData,
6930     ITypeInfo2_fnGetAllFuncCustData,
6931     ITypeInfo2_fnGetAllParamCustData,
6932     ITypeInfo2_fnGetAllVarCustData,
6933     ITypeInfo2_fnGetAllImplTypeCustData,
6934 };
6935
6936 /******************************************************************************
6937  * CreateDispTypeInfo [OLEAUT32.31]
6938  *
6939  * Build type information for an object so it can be called through an
6940  * IDispatch interface.
6941  *
6942  * RETURNS
6943  *  Success: S_OK. pptinfo contains the created ITypeInfo object.
6944  *  Failure: E_INVALIDARG, if one or more arguments is invalid.
6945  *
6946  * NOTES
6947  *  This call allows an objects methods to be accessed through IDispatch, by
6948  *  building an ITypeInfo object that IDispatch can use to call through.
6949  */
6950 HRESULT WINAPI CreateDispTypeInfo(
6951         INTERFACEDATA *pidata, /* [I] Description of the interface to build type info for */
6952         LCID lcid, /* [I] Locale Id */
6953         ITypeInfo **pptinfo) /* [O] Destination for created ITypeInfo object */
6954 {
6955     ITypeInfoImpl *pTIClass, *pTIIface;
6956     ITypeLibImpl *pTypeLibImpl;
6957     int param, func;
6958     TLBFuncDesc **ppFuncDesc;
6959     TLBRefType *ref;
6960
6961     TRACE("\n");
6962     pTypeLibImpl = TypeLibImpl_Constructor();
6963     if (!pTypeLibImpl) return E_FAIL;
6964
6965     pTIIface = (ITypeInfoImpl*)ITypeInfo_Constructor();
6966     pTIIface->pTypeLib = pTypeLibImpl;
6967     pTIIface->index = 0;
6968     pTIIface->Name = NULL;
6969     pTIIface->dwHelpContext = -1;
6970     memset(&pTIIface->TypeAttr.guid, 0, sizeof(GUID));
6971     pTIIface->TypeAttr.lcid = lcid;
6972     pTIIface->TypeAttr.typekind = TKIND_INTERFACE;
6973     pTIIface->TypeAttr.wMajorVerNum = 0;
6974     pTIIface->TypeAttr.wMinorVerNum = 0;
6975     pTIIface->TypeAttr.cbAlignment = 2;
6976     pTIIface->TypeAttr.cbSizeInstance = -1;
6977     pTIIface->TypeAttr.cbSizeVft = -1;
6978     pTIIface->TypeAttr.cFuncs = 0;
6979     pTIIface->TypeAttr.cImplTypes = 0;
6980     pTIIface->TypeAttr.cVars = 0;
6981     pTIIface->TypeAttr.wTypeFlags = 0;
6982
6983     ppFuncDesc = &pTIIface->funclist;
6984     for(func = 0; func < pidata->cMembers; func++) {
6985         METHODDATA *md = pidata->pmethdata + func;
6986         *ppFuncDesc = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppFuncDesc));
6987         (*ppFuncDesc)->Name = SysAllocString(md->szName);
6988         (*ppFuncDesc)->funcdesc.memid = md->dispid;
6989         (*ppFuncDesc)->funcdesc.lprgscode = NULL;
6990         (*ppFuncDesc)->funcdesc.funckind = FUNC_VIRTUAL;
6991         (*ppFuncDesc)->funcdesc.invkind = md->wFlags;
6992         (*ppFuncDesc)->funcdesc.callconv = md->cc;
6993         (*ppFuncDesc)->funcdesc.cParams = md->cArgs;
6994         (*ppFuncDesc)->funcdesc.cParamsOpt = 0;
6995         (*ppFuncDesc)->funcdesc.oVft = md->iMeth << 2;
6996         (*ppFuncDesc)->funcdesc.cScodes = 0;
6997         (*ppFuncDesc)->funcdesc.wFuncFlags = 0;
6998         (*ppFuncDesc)->funcdesc.elemdescFunc.tdesc.vt = md->vtReturn;
6999         (*ppFuncDesc)->funcdesc.elemdescFunc.u.paramdesc.wParamFlags = PARAMFLAG_NONE;
7000         (*ppFuncDesc)->funcdesc.elemdescFunc.u.paramdesc.pparamdescex = NULL;
7001         (*ppFuncDesc)->funcdesc.lprgelemdescParam = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7002                                                               md->cArgs * sizeof(ELEMDESC));
7003         (*ppFuncDesc)->pParamDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7004                                               md->cArgs * sizeof(TLBParDesc));
7005         for(param = 0; param < md->cArgs; param++) {
7006             (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].tdesc.vt = md->ppdata[param].vt;
7007             (*ppFuncDesc)->pParamDesc[param].Name = SysAllocString(md->ppdata[param].szName);
7008         }
7009         (*ppFuncDesc)->helpcontext = 0;
7010         (*ppFuncDesc)->HelpStringContext = 0;
7011         (*ppFuncDesc)->HelpString = NULL;
7012         (*ppFuncDesc)->Entry = NULL;
7013         (*ppFuncDesc)->ctCustData = 0;
7014         (*ppFuncDesc)->pCustData = NULL;
7015         (*ppFuncDesc)->next = NULL;
7016         pTIIface->TypeAttr.cFuncs++;
7017         ppFuncDesc = &(*ppFuncDesc)->next;
7018     }
7019
7020     dump_TypeInfo(pTIIface);
7021
7022     pTypeLibImpl->pTypeInfo = pTIIface;
7023     pTypeLibImpl->TypeInfoCount++;
7024
7025     pTIClass = (ITypeInfoImpl*)ITypeInfo_Constructor();
7026     pTIClass->pTypeLib = pTypeLibImpl;
7027     pTIClass->index = 1;
7028     pTIClass->Name = NULL;
7029     pTIClass->dwHelpContext = -1;
7030     memset(&pTIClass->TypeAttr.guid, 0, sizeof(GUID));
7031     pTIClass->TypeAttr.lcid = lcid;
7032     pTIClass->TypeAttr.typekind = TKIND_COCLASS;
7033     pTIClass->TypeAttr.wMajorVerNum = 0;
7034     pTIClass->TypeAttr.wMinorVerNum = 0;
7035     pTIClass->TypeAttr.cbAlignment = 2;
7036     pTIClass->TypeAttr.cbSizeInstance = -1;
7037     pTIClass->TypeAttr.cbSizeVft = -1;
7038     pTIClass->TypeAttr.cFuncs = 0;
7039     pTIClass->TypeAttr.cImplTypes = 1;
7040     pTIClass->TypeAttr.cVars = 0;
7041     pTIClass->TypeAttr.wTypeFlags = 0;
7042
7043     pTIClass->impltypelist = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pTIClass->impltypelist));
7044     pTIClass->impltypelist->hRef = 0;
7045
7046     ref = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ref));
7047     ref->index = 0;
7048     ref->reference = 0;
7049     ref->pImpTLInfo = TLB_REF_INTERNAL;
7050     list_add_head(&pTypeLibImpl->ref_list, &ref->entry);
7051
7052     dump_TypeInfo(pTIClass);
7053
7054     pTIIface->next = pTIClass;
7055     pTypeLibImpl->TypeInfoCount++;
7056
7057     *pptinfo = (ITypeInfo*)pTIClass;
7058
7059     ITypeInfo_AddRef(*pptinfo);
7060     ITypeLib_Release((ITypeLib *)&pTypeLibImpl->lpVtbl);
7061
7062     return S_OK;
7063
7064 }
7065
7066 static HRESULT WINAPI ITypeComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
7067 {
7068     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7069
7070     return ITypeInfo_QueryInterface((ITypeInfo *)This, riid, ppv);
7071 }
7072
7073 static ULONG WINAPI ITypeComp_fnAddRef(ITypeComp * iface)
7074 {
7075     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7076
7077     return ITypeInfo_AddRef((ITypeInfo *)This);
7078 }
7079
7080 static ULONG WINAPI ITypeComp_fnRelease(ITypeComp * iface)
7081 {
7082     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7083
7084     return ITypeInfo_Release((ITypeInfo *)This);
7085 }
7086
7087 static HRESULT WINAPI ITypeComp_fnBind(
7088     ITypeComp * iface,
7089     OLECHAR * szName,
7090     ULONG lHash,
7091     WORD wFlags,
7092     ITypeInfo ** ppTInfo,
7093     DESCKIND * pDescKind,
7094     BINDPTR * pBindPtr)
7095 {
7096     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7097     const TLBFuncDesc *pFDesc;
7098     const TLBVarDesc *pVDesc;
7099     HRESULT hr = DISP_E_MEMBERNOTFOUND;
7100
7101     TRACE("(%s, %x, 0x%x, %p, %p, %p)\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
7102
7103     *pDescKind = DESCKIND_NONE;
7104     pBindPtr->lpfuncdesc = NULL;
7105     *ppTInfo = NULL;
7106
7107     for(pFDesc = This->funclist; pFDesc; pFDesc = pFDesc->next)
7108         if (!strcmpiW(pFDesc->Name, szName)) {
7109             if (!wFlags || (pFDesc->funcdesc.invkind & wFlags))
7110                 break;
7111             else
7112                 /* name found, but wrong flags */
7113                 hr = TYPE_E_TYPEMISMATCH;
7114         }
7115
7116     if (pFDesc)
7117     {
7118         HRESULT hr = TLB_AllocAndInitFuncDesc(
7119             &pFDesc->funcdesc,
7120             &pBindPtr->lpfuncdesc,
7121             This->TypeAttr.typekind == TKIND_DISPATCH);
7122         if (FAILED(hr))
7123             return hr;
7124         *pDescKind = DESCKIND_FUNCDESC;
7125         *ppTInfo = (ITypeInfo *)&This->lpVtbl;
7126         ITypeInfo_AddRef(*ppTInfo);
7127         return S_OK;
7128     } else {
7129         for(pVDesc = This->varlist; pVDesc; pVDesc = pVDesc->next) {
7130             if (!strcmpiW(pVDesc->Name, szName)) {
7131                 HRESULT hr = TLB_AllocAndInitVarDesc(&pVDesc->vardesc, &pBindPtr->lpvardesc);
7132                 if (FAILED(hr))
7133                     return hr;
7134                 *pDescKind = DESCKIND_VARDESC;
7135                 *ppTInfo = (ITypeInfo *)&This->lpVtbl;
7136                 ITypeInfo_AddRef(*ppTInfo);
7137                 return S_OK;
7138             }
7139         }
7140     }
7141     /* FIXME: search each inherited interface, not just the first */
7142     if (hr == DISP_E_MEMBERNOTFOUND && This->impltypelist) {
7143         /* recursive search */
7144         ITypeInfo *pTInfo;
7145         ITypeComp *pTComp;
7146         HRESULT hr;
7147         hr=ITypeInfo_GetRefTypeInfo((ITypeInfo *)&This->lpVtbl, This->impltypelist->hRef, &pTInfo);
7148         if (SUCCEEDED(hr))
7149         {
7150             hr = ITypeInfo_GetTypeComp(pTInfo,&pTComp);
7151             ITypeInfo_Release(pTInfo);
7152         }
7153         if (SUCCEEDED(hr))
7154         {
7155             hr = ITypeComp_Bind(pTComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
7156             ITypeComp_Release(pTComp);
7157             return hr;
7158         }
7159         WARN("Could not search inherited interface!\n");
7160     }
7161     WARN("did not find member with name %s, flags 0x%x!\n", debugstr_w(szName), wFlags);
7162     return hr;
7163 }
7164
7165 static HRESULT WINAPI ITypeComp_fnBindType(
7166     ITypeComp * iface,
7167     OLECHAR * szName,
7168     ULONG lHash,
7169     ITypeInfo ** ppTInfo,
7170     ITypeComp ** ppTComp)
7171 {
7172     TRACE("(%s, %x, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
7173
7174     /* strange behaviour (does nothing) but like the
7175      * original */
7176
7177     if (!ppTInfo || !ppTComp)
7178         return E_POINTER;
7179
7180     *ppTInfo = NULL;
7181     *ppTComp = NULL;
7182
7183     return S_OK;
7184 }
7185
7186 static const ITypeCompVtbl tcompvt =
7187 {
7188
7189     ITypeComp_fnQueryInterface,
7190     ITypeComp_fnAddRef,
7191     ITypeComp_fnRelease,
7192
7193     ITypeComp_fnBind,
7194     ITypeComp_fnBindType
7195 };