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