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