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