oleaut32: Improve TKIND_COCLASS handling while creating typelib.
[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
4726     TRACE("(%s, 0x%x, 0x%x, %p, %p, %p)\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
4727
4728     *pDescKind = DESCKIND_NONE;
4729     pBindPtr->lptcomp = NULL;
4730     *ppTInfo = NULL;
4731
4732     for (pTypeInfo = This->pTypeInfo; pTypeInfo; pTypeInfo = pTypeInfo->next)
4733     {
4734         TRACE("testing %s\n", debugstr_w(pTypeInfo->Name));
4735
4736         /* FIXME: check wFlags here? */
4737         /* FIXME: we should use a hash table to look this info up using lHash
4738          * instead of an O(n) search */
4739         if ((pTypeInfo->TypeAttr.typekind == TKIND_ENUM) ||
4740             (pTypeInfo->TypeAttr.typekind == TKIND_MODULE))
4741         {
4742             if (pTypeInfo->Name && !strcmpW(pTypeInfo->Name, szName))
4743             {
4744                 *pDescKind = DESCKIND_TYPECOMP;
4745                 pBindPtr->lptcomp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4746                 ITypeComp_AddRef(pBindPtr->lptcomp);
4747                 TRACE("module or enum: %s\n", debugstr_w(szName));
4748                 return S_OK;
4749             }
4750         }
4751
4752         if ((pTypeInfo->TypeAttr.typekind == TKIND_MODULE) ||
4753             (pTypeInfo->TypeAttr.typekind == TKIND_ENUM))
4754         {
4755             ITypeComp *pSubTypeComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4756             HRESULT hr;
4757
4758             hr = ITypeComp_Bind(pSubTypeComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
4759             if (SUCCEEDED(hr) && (*pDescKind != DESCKIND_NONE))
4760             {
4761                 TRACE("found in module or in enum: %s\n", debugstr_w(szName));
4762                 return S_OK;
4763             }
4764         }
4765
4766         if ((pTypeInfo->TypeAttr.typekind == TKIND_COCLASS) &&
4767             (pTypeInfo->TypeAttr.wTypeFlags & TYPEFLAG_FAPPOBJECT))
4768         {
4769             ITypeComp *pSubTypeComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4770             HRESULT hr;
4771             ITypeInfo *subtypeinfo;
4772             BINDPTR subbindptr;
4773             DESCKIND subdesckind;
4774
4775             hr = ITypeComp_Bind(pSubTypeComp, szName, lHash, wFlags,
4776                 &subtypeinfo, &subdesckind, &subbindptr);
4777             if (SUCCEEDED(hr) && (subdesckind != DESCKIND_NONE))
4778             {
4779                 TYPEDESC tdesc_appobject =
4780                 {
4781                     {
4782                         (TYPEDESC *)pTypeInfo->hreftype
4783                     },
4784                     VT_USERDEFINED
4785                 };
4786                 const VARDESC vardesc_appobject =
4787                 {
4788                     -2,         /* memid */
4789                     NULL,       /* lpstrSchema */
4790                     {
4791                         0       /* oInst */
4792                     },
4793                     {
4794                                 /* ELEMDESC */
4795                         {
4796                                 /* TYPEDESC */
4797                                 {
4798                                     &tdesc_appobject
4799                                 },
4800                                 VT_PTR
4801                         },
4802                     },
4803                     0,          /* wVarFlags */
4804                     VAR_STATIC  /* varkind */
4805                 };
4806
4807                 TRACE("found in implicit app object: %s\n", debugstr_w(szName));
4808
4809                 /* cleanup things filled in by Bind call so we can put our
4810                  * application object data in there instead */
4811                 switch (subdesckind)
4812                 {
4813                 case DESCKIND_FUNCDESC:
4814                     ITypeInfo_ReleaseFuncDesc(subtypeinfo, subbindptr.lpfuncdesc);
4815                     break;
4816                 case DESCKIND_VARDESC:
4817                     ITypeInfo_ReleaseVarDesc(subtypeinfo, subbindptr.lpvardesc);
4818                     break;
4819                 default:
4820                     break;
4821                 }
4822                 if (subtypeinfo) ITypeInfo_Release(subtypeinfo);
4823
4824                 if (pTypeInfo->hreftype == -1)
4825                     FIXME("no hreftype for interface %p\n", pTypeInfo);
4826
4827                 hr = TLB_AllocAndInitVarDesc(&vardesc_appobject, &pBindPtr->lpvardesc);
4828                 if (FAILED(hr))
4829                     return hr;
4830
4831                 *pDescKind = DESCKIND_IMPLICITAPPOBJ;
4832                 *ppTInfo = (ITypeInfo *)pTypeInfo;
4833                 ITypeInfo_AddRef(*ppTInfo);
4834                 return S_OK;
4835             }
4836         }
4837     }
4838
4839     TRACE("name not found %s\n", debugstr_w(szName));
4840     return S_OK;
4841 }
4842
4843 static HRESULT WINAPI ITypeLibComp_fnBindType(
4844     ITypeComp * iface,
4845     OLECHAR * szName,
4846     ULONG lHash,
4847     ITypeInfo ** ppTInfo,
4848     ITypeComp ** ppTComp)
4849 {
4850     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4851     ITypeInfoImpl *pTypeInfo;
4852
4853     TRACE("(%s, %x, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
4854
4855     for (pTypeInfo = This->pTypeInfo; pTypeInfo; pTypeInfo = pTypeInfo->next)
4856     {
4857         /* FIXME: should use lHash to do the search */
4858         if (pTypeInfo->Name && !strcmpW(pTypeInfo->Name, szName))
4859         {
4860             TRACE("returning %p\n", pTypeInfo);
4861             *ppTInfo = (ITypeInfo *)&pTypeInfo->lpVtbl;
4862             ITypeInfo_AddRef(*ppTInfo);
4863             *ppTComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4864             ITypeComp_AddRef(*ppTComp);
4865             return S_OK;
4866         }
4867     }
4868
4869     TRACE("not found\n");
4870     *ppTInfo = NULL;
4871     *ppTComp = NULL;
4872     return S_OK;
4873 }
4874
4875 static const ITypeCompVtbl tlbtcvt =
4876 {
4877
4878     ITypeLibComp_fnQueryInterface,
4879     ITypeLibComp_fnAddRef,
4880     ITypeLibComp_fnRelease,
4881
4882     ITypeLibComp_fnBind,
4883     ITypeLibComp_fnBindType
4884 };
4885
4886 /*================== ITypeInfo(2) Methods ===================================*/
4887 static ITypeInfo2 * ITypeInfo_Constructor(void)
4888 {
4889     ITypeInfoImpl * pTypeInfoImpl;
4890
4891     pTypeInfoImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeInfoImpl));
4892     if (pTypeInfoImpl)
4893     {
4894       pTypeInfoImpl->lpVtbl = &tinfvt;
4895       pTypeInfoImpl->lpVtblTypeComp = &tcompvt;
4896       pTypeInfoImpl->ref = 0;
4897       pTypeInfoImpl->hreftype = -1;
4898       pTypeInfoImpl->TypeAttr.memidConstructor = MEMBERID_NIL;
4899       pTypeInfoImpl->TypeAttr.memidDestructor = MEMBERID_NIL;
4900     }
4901     TRACE("(%p)\n", pTypeInfoImpl);
4902     return (ITypeInfo2*) pTypeInfoImpl;
4903 }
4904
4905 /* ITypeInfo::QueryInterface
4906  */
4907 static HRESULT WINAPI ITypeInfo_fnQueryInterface(
4908         ITypeInfo2 *iface,
4909         REFIID riid,
4910         VOID **ppvObject)
4911 {
4912     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4913
4914     TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
4915
4916     *ppvObject=NULL;
4917     if(IsEqualIID(riid, &IID_IUnknown) ||
4918             IsEqualIID(riid,&IID_ITypeInfo)||
4919             IsEqualIID(riid,&IID_ITypeInfo2))
4920         *ppvObject = This;
4921
4922     if(*ppvObject){
4923         ITypeInfo_AddRef(iface);
4924         TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
4925         return S_OK;
4926     }
4927     TRACE("-- Interface: E_NOINTERFACE\n");
4928     return E_NOINTERFACE;
4929 }
4930
4931 /* ITypeInfo::AddRef
4932  */
4933 static ULONG WINAPI ITypeInfo_fnAddRef( ITypeInfo2 *iface)
4934 {
4935     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4936     ULONG ref = InterlockedIncrement(&This->ref);
4937
4938     TRACE("(%p)->ref is %u\n",This, ref);
4939
4940     if (ref == 1 /* incremented from 0 */)
4941         ITypeLib2_AddRef((ITypeLib2*)This->pTypeLib);
4942
4943     return ref;
4944 }
4945
4946 static void ITypeInfo_fnDestroy(ITypeInfoImpl *This)
4947 {
4948     TLBFuncDesc *pFInfo, *pFInfoNext;
4949     TLBVarDesc *pVInfo, *pVInfoNext;
4950     TLBImplType *pImpl, *pImplNext;
4951
4952     TRACE("destroying ITypeInfo(%p)\n",This);
4953
4954     SysFreeString(This->Name);
4955     This->Name = NULL;
4956
4957     SysFreeString(This->DocString);
4958     This->DocString = NULL;
4959
4960     SysFreeString(This->DllName);
4961     This->DllName = NULL;
4962
4963     for (pFInfo = This->funclist; pFInfo; pFInfo = pFInfoNext)
4964     {
4965         INT i;
4966         for(i = 0;i < pFInfo->funcdesc.cParams; i++)
4967         {
4968             ELEMDESC *elemdesc = &pFInfo->funcdesc.lprgelemdescParam[i];
4969             if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
4970             {
4971                 VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue);
4972                 TLB_Free(elemdesc->u.paramdesc.pparamdescex);
4973             }
4974             SysFreeString(pFInfo->pParamDesc[i].Name);
4975         }
4976         TLB_Free(pFInfo->funcdesc.lprgelemdescParam);
4977         TLB_Free(pFInfo->pParamDesc);
4978         TLB_FreeCustData(pFInfo->pCustData);
4979         if (!IS_INTRESOURCE(pFInfo->Entry) && pFInfo->Entry != (BSTR)-1)
4980             SysFreeString(pFInfo->Entry);
4981         SysFreeString(pFInfo->HelpString);
4982         SysFreeString(pFInfo->Name);
4983
4984         pFInfoNext = pFInfo->next;
4985         TLB_Free(pFInfo);
4986     }
4987     for (pVInfo = This->varlist; pVInfo; pVInfo = pVInfoNext)
4988     {
4989         if (pVInfo->vardesc.varkind == VAR_CONST)
4990         {
4991             VariantClear(pVInfo->vardesc.u.lpvarValue);
4992             TLB_Free(pVInfo->vardesc.u.lpvarValue);
4993         }
4994         TLB_FreeCustData(pVInfo->pCustData);
4995         SysFreeString(pVInfo->Name);
4996         pVInfoNext = pVInfo->next;
4997         TLB_Free(pVInfo);
4998     }
4999     for (pImpl = This->impltypelist; pImpl; pImpl = pImplNext)
5000     {
5001         TLB_FreeCustData(pImpl->pCustData);
5002         pImplNext = pImpl->next;
5003         TLB_Free(pImpl);
5004     }
5005     TLB_FreeCustData(This->pCustData);
5006
5007     HeapFree(GetProcessHeap(), 0, This);
5008 }
5009
5010 /* ITypeInfo::Release
5011  */
5012 static ULONG WINAPI ITypeInfo_fnRelease(ITypeInfo2 *iface)
5013 {
5014     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5015     ULONG ref = InterlockedDecrement(&This->ref);
5016
5017     TRACE("(%p)->(%u)\n",This, ref);
5018
5019     if (!ref)
5020     {
5021         BOOL not_attached_to_typelib = This->not_attached_to_typelib;
5022         ITypeLib2_Release((ITypeLib2*)This->pTypeLib);
5023         if (not_attached_to_typelib)
5024             HeapFree(GetProcessHeap(), 0, This);
5025         /* otherwise This will be freed when typelib is freed */
5026     }
5027
5028     return ref;
5029 }
5030
5031 /* ITypeInfo::GetTypeAttr
5032  *
5033  * Retrieves a TYPEATTR structure that contains the attributes of the type
5034  * description.
5035  *
5036  */
5037 static HRESULT WINAPI ITypeInfo_fnGetTypeAttr( ITypeInfo2 *iface,
5038         LPTYPEATTR  *ppTypeAttr)
5039 {
5040     const ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5041     SIZE_T size;
5042
5043     TRACE("(%p)\n",This);
5044
5045     size = sizeof(**ppTypeAttr);
5046     if (This->TypeAttr.typekind == TKIND_ALIAS)
5047         size += TLB_SizeTypeDesc(&This->TypeAttr.tdescAlias, FALSE);
5048
5049     *ppTypeAttr = HeapAlloc(GetProcessHeap(), 0, size);
5050     if (!*ppTypeAttr)
5051         return E_OUTOFMEMORY;
5052
5053     **ppTypeAttr = This->TypeAttr;
5054
5055     if (This->TypeAttr.typekind == TKIND_ALIAS)
5056         TLB_CopyTypeDesc(&(*ppTypeAttr)->tdescAlias,
5057             &This->TypeAttr.tdescAlias, *ppTypeAttr + 1);
5058
5059     if((*ppTypeAttr)->typekind == TKIND_DISPATCH) {
5060         /* This should include all the inherited funcs */
5061         (*ppTypeAttr)->cFuncs = (*ppTypeAttr)->cbSizeVft / sizeof(void *);
5062         (*ppTypeAttr)->cbSizeVft = 7 * sizeof(void *); /* This is always the size of IDispatch's vtbl */
5063         (*ppTypeAttr)->wTypeFlags &= ~TYPEFLAG_FOLEAUTOMATION;
5064     }
5065     return S_OK;
5066 }
5067
5068 /* ITypeInfo::GetTypeComp
5069  *
5070  * Retrieves the ITypeComp interface for the type description, which enables a
5071  * client compiler to bind to the type description's members.
5072  *
5073  */
5074 static HRESULT WINAPI ITypeInfo_fnGetTypeComp( ITypeInfo2 *iface,
5075         ITypeComp  * *ppTComp)
5076 {
5077     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5078
5079     TRACE("(%p)->(%p)\n", This, ppTComp);
5080
5081     *ppTComp = (ITypeComp *)&This->lpVtblTypeComp;
5082     ITypeComp_AddRef(*ppTComp);
5083     return S_OK;
5084 }
5085
5086 static SIZE_T TLB_SizeElemDesc( const ELEMDESC *elemdesc )
5087 {
5088     SIZE_T size = TLB_SizeTypeDesc(&elemdesc->tdesc, FALSE);
5089     if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
5090         size += sizeof(*elemdesc->u.paramdesc.pparamdescex);
5091     return size;
5092 }
5093
5094 static HRESULT TLB_CopyElemDesc( const ELEMDESC *src, ELEMDESC *dest, char **buffer )
5095 {
5096     *dest = *src;
5097     *buffer = TLB_CopyTypeDesc(&dest->tdesc, &src->tdesc, *buffer);
5098     if (src->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
5099     {
5100         const PARAMDESCEX *pparamdescex_src = src->u.paramdesc.pparamdescex;
5101         PARAMDESCEX *pparamdescex_dest = dest->u.paramdesc.pparamdescex = (PARAMDESCEX *)*buffer;
5102         *buffer += sizeof(PARAMDESCEX);
5103         *pparamdescex_dest = *pparamdescex_src;
5104         VariantInit(&pparamdescex_dest->varDefaultValue);
5105         return VariantCopy(&pparamdescex_dest->varDefaultValue, 
5106                            (VARIANTARG *)&pparamdescex_src->varDefaultValue);
5107     }
5108     else
5109         dest->u.paramdesc.pparamdescex = NULL;
5110     return S_OK;
5111 }
5112
5113 static void TLB_FreeElemDesc( ELEMDESC *elemdesc )
5114 {
5115     if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
5116         VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue);
5117 }
5118
5119 static HRESULT TLB_AllocAndInitFuncDesc( const FUNCDESC *src, FUNCDESC **dest_ptr, BOOL dispinterface )
5120 {
5121     FUNCDESC *dest;
5122     char *buffer;
5123     SIZE_T size = sizeof(*src);
5124     SHORT i;
5125     HRESULT hr;
5126
5127     size += sizeof(*src->lprgscode) * src->cScodes;
5128     size += TLB_SizeElemDesc(&src->elemdescFunc);
5129     for (i = 0; i < src->cParams; i++)
5130     {
5131         size += sizeof(ELEMDESC);
5132         size += TLB_SizeElemDesc(&src->lprgelemdescParam[i]);
5133     }
5134
5135     dest = (FUNCDESC *)SysAllocStringByteLen(NULL, size);
5136     if (!dest) return E_OUTOFMEMORY;
5137
5138     *dest = *src;
5139     if (dispinterface)    /* overwrite funckind */
5140         dest->funckind = FUNC_DISPATCH;
5141     buffer = (char *)(dest + 1);
5142
5143     dest->lprgscode = (SCODE *)buffer;
5144     memcpy(dest->lprgscode, src->lprgscode, sizeof(*src->lprgscode) * src->cScodes);
5145     buffer += sizeof(*src->lprgscode) * src->cScodes;
5146
5147     hr = TLB_CopyElemDesc(&src->elemdescFunc, &dest->elemdescFunc, &buffer);
5148     if (FAILED(hr))
5149     {
5150         SysFreeString((BSTR)dest);
5151         return hr;
5152     }
5153
5154     dest->lprgelemdescParam = (ELEMDESC *)buffer;
5155     buffer += sizeof(ELEMDESC) * src->cParams;
5156     for (i = 0; i < src->cParams; i++)
5157     {
5158         hr = TLB_CopyElemDesc(&src->lprgelemdescParam[i], &dest->lprgelemdescParam[i], &buffer);
5159         if (FAILED(hr))
5160             break;
5161     }
5162     if (FAILED(hr))
5163     {
5164         /* undo the above actions */
5165         for (i = i - 1; i >= 0; i--)
5166             TLB_FreeElemDesc(&dest->lprgelemdescParam[i]);
5167         TLB_FreeElemDesc(&dest->elemdescFunc);
5168         SysFreeString((BSTR)dest);
5169         return hr;
5170     }
5171
5172     /* special treatment for dispinterfaces: this makes functions appear
5173      * to return their [retval] value when it is really returning an
5174      * HRESULT */
5175     if (dispinterface && dest->elemdescFunc.tdesc.vt == VT_HRESULT)
5176     {
5177         if (dest->cParams &&
5178             (dest->lprgelemdescParam[dest->cParams - 1].u.paramdesc.wParamFlags & PARAMFLAG_FRETVAL))
5179         {
5180             ELEMDESC *elemdesc = &dest->lprgelemdescParam[dest->cParams - 1];
5181             if (elemdesc->tdesc.vt != VT_PTR)
5182             {
5183                 ERR("elemdesc should have started with VT_PTR instead of:\n");
5184                 if (ERR_ON(ole))
5185                     dump_ELEMDESC(elemdesc);
5186                 return E_UNEXPECTED;
5187             }
5188
5189             /* copy last parameter to the return value. we are using a flat
5190              * buffer so there is no danger of leaking memory in
5191              * elemdescFunc */
5192             dest->elemdescFunc.tdesc = *elemdesc->tdesc.u.lptdesc;
5193
5194             /* remove the last parameter */
5195             dest->cParams--;
5196         }
5197         else
5198             /* otherwise this function is made to appear to have no return
5199              * value */
5200             dest->elemdescFunc.tdesc.vt = VT_VOID;
5201
5202     }
5203
5204     *dest_ptr = dest;
5205     return S_OK;
5206 }
5207
5208 HRESULT ITypeInfoImpl_GetInternalFuncDesc( ITypeInfo *iface, UINT index, const FUNCDESC **ppFuncDesc )
5209 {
5210     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5211     const TLBFuncDesc *pFDesc;
5212     UINT i;
5213
5214     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++, pFDesc=pFDesc->next)
5215         ;
5216
5217     if (pFDesc)
5218     {
5219         *ppFuncDesc = &pFDesc->funcdesc;
5220         return S_OK;
5221     }
5222
5223     return TYPE_E_ELEMENTNOTFOUND;
5224 }
5225
5226 /* internal function to make the inherited interfaces' methods appear
5227  * part of the interface */
5228 static HRESULT ITypeInfoImpl_GetInternalDispatchFuncDesc( ITypeInfo *iface,
5229     UINT index, const FUNCDESC **ppFuncDesc, UINT *funcs, UINT *hrefoffset)
5230 {
5231     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5232     HRESULT hr;
5233     UINT implemented_funcs = 0;
5234
5235     if (funcs)
5236         *funcs = 0;
5237     else
5238         *hrefoffset = DISPATCH_HREF_OFFSET;
5239
5240     if(This->impltypelist)
5241     {
5242         ITypeInfo *pSubTypeInfo;
5243         UINT sub_funcs;
5244
5245         hr = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef, &pSubTypeInfo);
5246         if (FAILED(hr))
5247             return hr;
5248
5249         hr = ITypeInfoImpl_GetInternalDispatchFuncDesc(pSubTypeInfo,
5250                                                        index,
5251                                                        ppFuncDesc,
5252                                                        &sub_funcs, hrefoffset);
5253         implemented_funcs += sub_funcs;
5254         ITypeInfo_Release(pSubTypeInfo);
5255         if (SUCCEEDED(hr))
5256             return hr;
5257         *hrefoffset += DISPATCH_HREF_OFFSET;
5258     }
5259
5260     if (funcs)
5261         *funcs = implemented_funcs + This->TypeAttr.cFuncs;
5262     else
5263         *hrefoffset = 0;
5264     
5265     if (index < implemented_funcs)
5266         return E_INVALIDARG;
5267     return ITypeInfoImpl_GetInternalFuncDesc(iface, index - implemented_funcs,
5268                                              ppFuncDesc);
5269 }
5270
5271 static inline void ITypeInfoImpl_ElemDescAddHrefOffset( LPELEMDESC pElemDesc, UINT hrefoffset)
5272 {
5273     TYPEDESC *pTypeDesc = &pElemDesc->tdesc;
5274     while (TRUE)
5275     {
5276         switch (pTypeDesc->vt)
5277         {
5278         case VT_USERDEFINED:
5279             pTypeDesc->u.hreftype += hrefoffset;
5280             return;
5281         case VT_PTR:
5282         case VT_SAFEARRAY:
5283             pTypeDesc = pTypeDesc->u.lptdesc;
5284             break;
5285         case VT_CARRAY:
5286             pTypeDesc = &pTypeDesc->u.lpadesc->tdescElem;
5287             break;
5288         default:
5289             return;
5290         }
5291     }
5292 }
5293
5294 static inline void ITypeInfoImpl_FuncDescAddHrefOffset( LPFUNCDESC pFuncDesc, UINT hrefoffset)
5295 {
5296     SHORT i;
5297     for (i = 0; i < pFuncDesc->cParams; i++)
5298         ITypeInfoImpl_ElemDescAddHrefOffset(&pFuncDesc->lprgelemdescParam[i], hrefoffset);
5299     ITypeInfoImpl_ElemDescAddHrefOffset(&pFuncDesc->elemdescFunc, hrefoffset);
5300 }
5301
5302 /* ITypeInfo::GetFuncDesc
5303  *
5304  * Retrieves the FUNCDESC structure that contains information about a
5305  * specified function.
5306  *
5307  */
5308 static HRESULT WINAPI ITypeInfo_fnGetFuncDesc( ITypeInfo2 *iface, UINT index,
5309         LPFUNCDESC  *ppFuncDesc)
5310 {
5311     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5312     const FUNCDESC *internal_funcdesc;
5313     HRESULT hr;
5314     UINT hrefoffset = 0;
5315
5316     TRACE("(%p) index %d\n", This, index);
5317
5318     if (This->TypeAttr.typekind == TKIND_DISPATCH)
5319         hr = ITypeInfoImpl_GetInternalDispatchFuncDesc((ITypeInfo *)iface, index,
5320                                                        &internal_funcdesc, NULL,
5321                                                        &hrefoffset);
5322     else
5323         hr = ITypeInfoImpl_GetInternalFuncDesc((ITypeInfo *)iface, index,
5324                                                &internal_funcdesc);
5325     if (FAILED(hr))
5326     {
5327         WARN("description for function %d not found\n", index);
5328         return hr;
5329     }
5330
5331     hr = TLB_AllocAndInitFuncDesc(
5332         internal_funcdesc,
5333         ppFuncDesc,
5334         This->TypeAttr.typekind == TKIND_DISPATCH);
5335
5336     if ((This->TypeAttr.typekind == TKIND_DISPATCH) && hrefoffset)
5337         ITypeInfoImpl_FuncDescAddHrefOffset(*ppFuncDesc, hrefoffset);
5338
5339     TRACE("-- 0x%08x\n", hr);
5340     return hr;
5341 }
5342
5343 static HRESULT TLB_AllocAndInitVarDesc( const VARDESC *src, VARDESC **dest_ptr )
5344 {
5345     VARDESC *dest;
5346     char *buffer;
5347     SIZE_T size = sizeof(*src);
5348     HRESULT hr;
5349
5350     if (src->lpstrSchema) size += (strlenW(src->lpstrSchema) + 1) * sizeof(WCHAR);
5351     if (src->varkind == VAR_CONST)
5352         size += sizeof(VARIANT);
5353     size += TLB_SizeElemDesc(&src->elemdescVar);
5354
5355     dest = (VARDESC *)SysAllocStringByteLen(NULL, size);
5356     if (!dest) return E_OUTOFMEMORY;
5357
5358     *dest = *src;
5359     buffer = (char *)(dest + 1);
5360     if (src->lpstrSchema)
5361     {
5362         int len;
5363         dest->lpstrSchema = (LPOLESTR)buffer;
5364         len = strlenW(src->lpstrSchema);
5365         memcpy(dest->lpstrSchema, src->lpstrSchema, (len + 1) * sizeof(WCHAR));
5366         buffer += (len + 1) * sizeof(WCHAR);
5367     }
5368
5369     if (src->varkind == VAR_CONST)
5370     {
5371         HRESULT hr;
5372
5373         dest->u.lpvarValue = (VARIANT *)buffer;
5374         *dest->u.lpvarValue = *src->u.lpvarValue;
5375         buffer += sizeof(VARIANT);
5376         VariantInit(dest->u.lpvarValue);
5377         hr = VariantCopy(dest->u.lpvarValue, src->u.lpvarValue);
5378         if (FAILED(hr))
5379         {
5380             SysFreeString((BSTR)dest);
5381             return hr;
5382         }
5383     }
5384     hr = TLB_CopyElemDesc(&src->elemdescVar, &dest->elemdescVar, &buffer);
5385     if (FAILED(hr))
5386     {
5387         if (src->varkind == VAR_CONST)
5388             VariantClear(dest->u.lpvarValue);
5389         SysFreeString((BSTR)dest);
5390         return hr;
5391     }
5392     *dest_ptr = dest;
5393     return S_OK;
5394 }
5395
5396 /* ITypeInfo::GetVarDesc
5397  *
5398  * Retrieves a VARDESC structure that describes the specified variable.
5399  *
5400  */
5401 static HRESULT WINAPI ITypeInfo_fnGetVarDesc( ITypeInfo2 *iface, UINT index,
5402         LPVARDESC  *ppVarDesc)
5403 {
5404     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5405     UINT i;
5406     const TLBVarDesc *pVDesc;
5407
5408     TRACE("(%p) index %d\n", This, index);
5409
5410     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next)
5411         ;
5412
5413     if (pVDesc)
5414         return TLB_AllocAndInitVarDesc(&pVDesc->vardesc, ppVarDesc);
5415
5416     return E_INVALIDARG;
5417 }
5418
5419 /* ITypeInfo_GetNames
5420  *
5421  * Retrieves the variable with the specified member ID (or the name of the
5422  * property or method and its parameters) that correspond to the specified
5423  * function ID.
5424  */
5425 static HRESULT WINAPI ITypeInfo_fnGetNames( ITypeInfo2 *iface, MEMBERID memid,
5426         BSTR  *rgBstrNames, UINT cMaxNames, UINT  *pcNames)
5427 {
5428     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5429     const TLBFuncDesc *pFDesc;
5430     const TLBVarDesc *pVDesc;
5431     int i;
5432     TRACE("(%p) memid=0x%08x Maxname=%d\n", This, memid, cMaxNames);
5433     for(pFDesc=This->funclist; pFDesc && pFDesc->funcdesc.memid != memid; pFDesc=pFDesc->next);
5434     if(pFDesc)
5435     {
5436       /* function found, now return function and parameter names */
5437       for(i=0; i<cMaxNames && i <= pFDesc->funcdesc.cParams; i++)
5438       {
5439         if(!i)
5440           *rgBstrNames=SysAllocString(pFDesc->Name);
5441         else
5442           rgBstrNames[i]=SysAllocString(pFDesc->pParamDesc[i-1].Name);
5443       }
5444       *pcNames=i;
5445     }
5446     else
5447     {
5448       for(pVDesc=This->varlist; pVDesc && pVDesc->vardesc.memid != memid; pVDesc=pVDesc->next);
5449       if(pVDesc)
5450       {
5451         *rgBstrNames=SysAllocString(pVDesc->Name);
5452         *pcNames=1;
5453       }
5454       else
5455       {
5456         if(This->impltypelist &&
5457            (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
5458           /* recursive search */
5459           ITypeInfo *pTInfo;
5460           HRESULT result;
5461           result=ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef,
5462                                           &pTInfo);
5463           if(SUCCEEDED(result))
5464           {
5465             result=ITypeInfo_GetNames(pTInfo, memid, rgBstrNames, cMaxNames, pcNames);
5466             ITypeInfo_Release(pTInfo);
5467             return result;
5468           }
5469           WARN("Could not search inherited interface!\n");
5470         }
5471         else
5472         {
5473           WARN("no names found\n");
5474         }
5475         *pcNames=0;
5476         return TYPE_E_ELEMENTNOTFOUND;
5477       }
5478     }
5479     return S_OK;
5480 }
5481
5482
5483 /* ITypeInfo::GetRefTypeOfImplType
5484  *
5485  * If a type description describes a COM class, it retrieves the type
5486  * description of the implemented interface types. For an interface,
5487  * GetRefTypeOfImplType returns the type information for inherited interfaces,
5488  * if any exist.
5489  *
5490  */
5491 static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType(
5492         ITypeInfo2 *iface,
5493         UINT index,
5494         HREFTYPE  *pRefType)
5495 {
5496     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5497     UINT i;
5498     HRESULT hr = S_OK;
5499     const TLBImplType *pImpl = This->impltypelist;
5500
5501     TRACE("(%p) index %d\n", This, index);
5502     if (TRACE_ON(ole)) dump_TypeInfo(This);
5503
5504     if(index==(UINT)-1)
5505     {
5506       /* only valid on dual interfaces;
5507          retrieve the associated TKIND_INTERFACE handle for the current TKIND_DISPATCH
5508       */
5509       if( This->TypeAttr.typekind != TKIND_DISPATCH) return E_INVALIDARG;
5510
5511       if (This->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL)
5512       {
5513         *pRefType = -1;
5514       }
5515       else
5516       {
5517         hr = TYPE_E_ELEMENTNOTFOUND;
5518       }
5519     }
5520     else if(index == 0 && This->TypeAttr.typekind == TKIND_DISPATCH)
5521     {
5522       /* All TKIND_DISPATCHs are made to look like they inherit from IDispatch */
5523       *pRefType = This->pTypeLib->dispatch_href;
5524     }
5525     else
5526     {
5527       /* get element n from linked list */
5528       for(i=0; pImpl && i<index; i++)
5529       {
5530         pImpl = pImpl->next;
5531       }
5532
5533       if (pImpl)
5534         *pRefType = pImpl->hRef;
5535       else
5536         hr = TYPE_E_ELEMENTNOTFOUND;
5537     }
5538
5539     if(TRACE_ON(ole))
5540     {
5541         if(SUCCEEDED(hr))
5542             TRACE("SUCCESS -- hRef = 0x%08x\n", *pRefType );
5543         else
5544             TRACE("FAILURE -- hresult = 0x%08x\n", hr);
5545     }
5546
5547     return hr;
5548 }
5549
5550 /* ITypeInfo::GetImplTypeFlags
5551  *
5552  * Retrieves the IMPLTYPEFLAGS enumeration for one implemented interface
5553  * or base interface in a type description.
5554  */
5555 static HRESULT WINAPI ITypeInfo_fnGetImplTypeFlags( ITypeInfo2 *iface,
5556         UINT index, INT  *pImplTypeFlags)
5557 {
5558     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5559     UINT i;
5560     TLBImplType *pImpl;
5561
5562     TRACE("(%p) index %d\n", This, index);
5563     for(i=0, pImpl=This->impltypelist; i<index && pImpl;
5564         i++, pImpl=pImpl->next)
5565         ;
5566     if(i==index && pImpl){
5567         *pImplTypeFlags=pImpl->implflags;
5568         return S_OK;
5569     }
5570     *pImplTypeFlags=0;
5571     return TYPE_E_ELEMENTNOTFOUND;
5572 }
5573
5574 /* GetIDsOfNames
5575  * Maps between member names and member IDs, and parameter names and
5576  * parameter IDs.
5577  */
5578 static HRESULT WINAPI ITypeInfo_fnGetIDsOfNames( ITypeInfo2 *iface,
5579         LPOLESTR  *rgszNames, UINT cNames, MEMBERID  *pMemId)
5580 {
5581     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5582     const TLBFuncDesc *pFDesc;
5583     const TLBVarDesc *pVDesc;
5584     HRESULT ret=S_OK;
5585     UINT i;
5586
5587     TRACE("(%p) Name %s cNames %d\n", This, debugstr_w(*rgszNames),
5588             cNames);
5589
5590     /* init out parameters in case of failure */
5591     for (i = 0; i < cNames; i++)
5592         pMemId[i] = MEMBERID_NIL;
5593
5594     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next) {
5595         int j;
5596         if(!lstrcmpiW(*rgszNames, pFDesc->Name)) {
5597             if(cNames) *pMemId=pFDesc->funcdesc.memid;
5598             for(i=1; i < cNames; i++){
5599                 for(j=0; j<pFDesc->funcdesc.cParams; j++)
5600                     if(!lstrcmpiW(rgszNames[i],pFDesc->pParamDesc[j].Name))
5601                             break;
5602                 if( j<pFDesc->funcdesc.cParams)
5603                     pMemId[i]=j;
5604                 else
5605                    ret=DISP_E_UNKNOWNNAME;
5606             };
5607             TRACE("-- 0x%08x\n", ret);
5608             return ret;
5609         }
5610     }
5611     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) {
5612         if(!lstrcmpiW(*rgszNames, pVDesc->Name)) {
5613             if(cNames) *pMemId=pVDesc->vardesc.memid;
5614             return ret;
5615         }
5616     }
5617     /* not found, see if it can be found in an inherited interface */
5618     if(This->impltypelist) {
5619         /* recursive search */
5620         ITypeInfo *pTInfo;
5621         ret=ITypeInfo_GetRefTypeInfo(iface,
5622                 This->impltypelist->hRef, &pTInfo);
5623         if(SUCCEEDED(ret)){
5624             ret=ITypeInfo_GetIDsOfNames(pTInfo, rgszNames, cNames, pMemId );
5625             ITypeInfo_Release(pTInfo);
5626             return ret;
5627         }
5628         WARN("Could not search inherited interface!\n");
5629     } else
5630         WARN("no names found\n");
5631     return DISP_E_UNKNOWNNAME;
5632 }
5633
5634
5635 #ifdef __i386__
5636
5637 extern DWORD CDECL call_method( void *func, int nb_args, const DWORD *args );
5638 __ASM_GLOBAL_FUNC( call_method,
5639                    "pushl %ebp\n\t"
5640                    __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
5641                    __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
5642                    "movl %esp,%ebp\n\t"
5643                    __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
5644                    "pushl %esi\n\t"
5645                   __ASM_CFI(".cfi_rel_offset %esi,-4\n\t")
5646                    "pushl %edi\n\t"
5647                   __ASM_CFI(".cfi_rel_offset %edi,-8\n\t")
5648                    "movl 12(%ebp),%edx\n\t"
5649                    "shll $2,%edx\n\t"
5650                    "jz 1f\n\t"
5651                    "subl %edx,%esp\n\t"
5652                    "andl $~15,%esp\n\t"
5653                    "movl 12(%ebp),%ecx\n\t"
5654                    "movl 16(%ebp),%esi\n\t"
5655                    "movl %esp,%edi\n\t"
5656                    "cld\n\t"
5657                    "rep; movsl\n"
5658                    "1:\tcall *8(%ebp)\n\t"
5659                    "leal -8(%ebp),%esp\n\t"
5660                    "popl %edi\n\t"
5661                    __ASM_CFI(".cfi_same_value %edi\n\t")
5662                    "popl %esi\n\t"
5663                    __ASM_CFI(".cfi_same_value %esi\n\t")
5664                    "popl %ebp\n\t"
5665                    __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
5666                    __ASM_CFI(".cfi_same_value %ebp\n\t")
5667                    "ret" )
5668
5669 /* ITypeInfo::Invoke
5670  *
5671  * Invokes a method, or accesses a property of an object, that implements the
5672  * interface described by the type description.
5673  */
5674 DWORD
5675 _invoke(FARPROC func,CALLCONV callconv, int nrargs, DWORD *args) {
5676     DWORD res;
5677
5678     if (TRACE_ON(ole)) {
5679         int i;
5680         TRACE("Calling %p(",func);
5681         for (i=0;i<nrargs;i++) TRACE("%08x,",args[i]);
5682         TRACE(")\n");
5683     }
5684
5685     switch (callconv) {
5686     case CC_STDCALL:
5687     case CC_CDECL:
5688         res = call_method( func, nrargs, args );
5689         break;
5690     default:
5691         FIXME("unsupported calling convention %d\n",callconv);
5692         res = -1;
5693         break;
5694     }
5695     TRACE("returns %08x\n",res);
5696     return res;
5697 }
5698
5699 /* The size of the argument on the stack in DWORD units (in all x86 call
5700  * convetions the arguments on the stack are DWORD-aligned)
5701  */
5702 static int _dispargsize(VARTYPE vt)
5703 {
5704     switch (vt) {
5705     case VT_I8:
5706     case VT_UI8:
5707         return 8/sizeof(DWORD);
5708     case VT_R8:
5709         return sizeof(double)/sizeof(DWORD);
5710     case VT_DECIMAL:
5711         return (sizeof(DECIMAL)+3)/sizeof(DWORD);
5712     case VT_CY:
5713         return sizeof(CY)/sizeof(DWORD);
5714     case VT_DATE:
5715         return sizeof(DATE)/sizeof(DWORD);
5716     case VT_VARIANT:
5717         return (sizeof(VARIANT)+3)/sizeof(DWORD);
5718     case VT_RECORD:
5719         FIXME("VT_RECORD not implemented\n");
5720         return 1;
5721     default:
5722         return 1;
5723     }
5724 }
5725 #endif /* __i386__ */
5726
5727 static HRESULT userdefined_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
5728 {
5729     HRESULT hr = S_OK;
5730     ITypeInfo *tinfo2 = NULL;
5731     TYPEATTR *tattr = NULL;
5732
5733     hr = ITypeInfo_GetRefTypeInfo(tinfo, tdesc->u.hreftype, &tinfo2);
5734     if (hr)
5735     {
5736         ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED, "
5737             "hr = 0x%08x\n",
5738               tdesc->u.hreftype, hr);
5739         return hr;
5740     }
5741     hr = ITypeInfo_GetTypeAttr(tinfo2, &tattr);
5742     if (hr)
5743     {
5744         ERR("ITypeInfo_GetTypeAttr failed, hr = 0x%08x\n", hr);
5745         ITypeInfo_Release(tinfo2);
5746         return hr;
5747     }
5748
5749     switch (tattr->typekind)
5750     {
5751     case TKIND_ENUM:
5752         *vt |= VT_I4;
5753         break;
5754
5755     case TKIND_ALIAS:
5756         tdesc = &tattr->tdescAlias;
5757         hr = typedescvt_to_variantvt(tinfo2, &tattr->tdescAlias, vt);
5758         break;
5759
5760     case TKIND_INTERFACE:
5761         if (tattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE)
5762            *vt |= VT_DISPATCH;
5763         else
5764            *vt |= VT_UNKNOWN;
5765         break;
5766
5767     case TKIND_DISPATCH:
5768         *vt |= VT_DISPATCH;
5769         break;
5770
5771     case TKIND_COCLASS:
5772         *vt |= VT_DISPATCH;
5773         break;
5774
5775     case TKIND_RECORD:
5776         FIXME("TKIND_RECORD unhandled.\n");
5777         hr = E_NOTIMPL;
5778         break;
5779
5780     case TKIND_UNION:
5781         FIXME("TKIND_UNION unhandled.\n");
5782         hr = E_NOTIMPL;
5783         break;
5784
5785     default:
5786         FIXME("TKIND %d unhandled.\n",tattr->typekind);
5787         hr = E_NOTIMPL;
5788         break;
5789     }
5790     ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
5791     ITypeInfo_Release(tinfo2);
5792     return hr;
5793 }
5794
5795 static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
5796 {
5797     HRESULT hr = S_OK;
5798
5799     /* enforce only one level of pointer indirection */
5800     if (!(*vt & VT_BYREF) && !(*vt & VT_ARRAY) && (tdesc->vt == VT_PTR))
5801     {
5802         tdesc = tdesc->u.lptdesc;
5803
5804         /* munch VT_PTR -> VT_USERDEFINED(interface) into VT_UNKNOWN or
5805          * VT_DISPATCH and VT_PTR -> VT_PTR -> VT_USERDEFINED(interface) into 
5806          * VT_BYREF|VT_DISPATCH or VT_BYREF|VT_UNKNOWN */
5807         if ((tdesc->vt == VT_USERDEFINED) ||
5808             ((tdesc->vt == VT_PTR) && (tdesc->u.lptdesc->vt == VT_USERDEFINED)))
5809         {
5810             VARTYPE vt_userdefined = 0;
5811             const TYPEDESC *tdesc_userdefined = tdesc;
5812             if (tdesc->vt == VT_PTR)
5813             {
5814                 vt_userdefined = VT_BYREF;
5815                 tdesc_userdefined = tdesc->u.lptdesc;
5816             }
5817             hr = userdefined_to_variantvt(tinfo, tdesc_userdefined, &vt_userdefined);
5818             if ((hr == S_OK) && 
5819                 (((vt_userdefined & VT_TYPEMASK) == VT_UNKNOWN) ||
5820                  ((vt_userdefined & VT_TYPEMASK) == VT_DISPATCH)))
5821             {
5822                 *vt |= vt_userdefined;
5823                 return S_OK;
5824             }
5825         }
5826         *vt = VT_BYREF;
5827     }
5828
5829     switch (tdesc->vt)
5830     {
5831     case VT_HRESULT:
5832         *vt |= VT_ERROR;
5833         break;
5834     case VT_USERDEFINED:
5835         hr = userdefined_to_variantvt(tinfo, tdesc, vt);
5836         break;
5837     case VT_VOID:
5838     case VT_CARRAY:
5839     case VT_PTR:
5840     case VT_LPSTR:
5841     case VT_LPWSTR:
5842         ERR("cannot convert type %d into variant VT\n", tdesc->vt);
5843         hr = DISP_E_BADVARTYPE;
5844         break;
5845     case VT_SAFEARRAY:
5846         *vt |= VT_ARRAY;
5847         hr = typedescvt_to_variantvt(tinfo, tdesc->u.lptdesc, vt);
5848         break;
5849     case VT_INT:
5850         *vt |= VT_I4;
5851         break;
5852     case VT_UINT:
5853         *vt |= VT_UI4;
5854         break;
5855     default:
5856         *vt |= tdesc->vt;
5857         break;
5858     }
5859     return hr;
5860 }
5861
5862 /***********************************************************************
5863  *              DispCallFunc (OLEAUT32.@)
5864  *
5865  * Invokes a function of the specified calling convention, passing the
5866  * specified arguments and returns the result.
5867  *
5868  * PARAMS
5869  *  pvInstance  [I] Optional pointer to the instance whose function to invoke.
5870  *  oVft        [I] The offset in the vtable. See notes.
5871  *  cc          [I] Calling convention of the function to call.
5872  *  vtReturn    [I] The return type of the function.
5873  *  cActuals    [I] Number of parameters.
5874  *  prgvt       [I] The types of the parameters to pass. This is used for sizing only.
5875  *  prgpvarg    [I] The arguments to pass.
5876  *  pvargResult [O] The return value of the function. Can be NULL.
5877  *
5878  * RETURNS
5879  *  Success: S_OK.
5880  *  Failure: HRESULT code.
5881  *
5882  * NOTES
5883  *  The HRESULT return value of this function is not affected by the return
5884  *  value of the user supplied function, which is returned in pvargResult.
5885  *
5886  *  If pvInstance is NULL then a non-object function is to be called and oVft
5887  *  is the address of the function to call.
5888  *
5889  * The cc parameter can be one of the following values:
5890  *|CC_FASTCALL
5891  *|CC_CDECL
5892  *|CC_PASCAL
5893  *|CC_STDCALL
5894  *|CC_FPFASTCALL
5895  *|CC_SYSCALL
5896  *|CC_MPWCDECL
5897  *|CC_MPWPASCAL
5898  *
5899  */
5900 HRESULT WINAPI
5901 DispCallFunc(
5902     void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals,
5903     VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult)
5904 {
5905 #ifdef __i386__
5906     int argsize, argspos;
5907     UINT i;
5908     DWORD *args;
5909     HRESULT hres;
5910
5911     TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
5912         pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
5913         pvargResult, V_VT(pvargResult));
5914
5915     argsize = 0;
5916     if (pvInstance)
5917         argsize++; /* for This pointer */
5918
5919     for (i=0;i<cActuals;i++)
5920     {
5921         TRACE("arg %u: type %d, size %d\n",i,prgvt[i],_dispargsize(prgvt[i]));
5922         dump_Variant(prgpvarg[i]);
5923         argsize += _dispargsize(prgvt[i]);
5924     }
5925     args = HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*argsize);
5926
5927     argspos = 0;
5928     if (pvInstance)
5929     {
5930         args[0] = (DWORD)pvInstance; /* the This pointer is always the first parameter */
5931         argspos++;
5932     }
5933
5934     for (i=0;i<cActuals;i++)
5935     {
5936         VARIANT *arg = prgpvarg[i];
5937         TRACE("Storing arg %u (%d as %d)\n",i,V_VT(arg),prgvt[i]);
5938         if (prgvt[i] == VT_VARIANT)
5939             memcpy(&args[argspos], arg, _dispargsize(prgvt[i]) * sizeof(DWORD));
5940         else
5941             memcpy(&args[argspos], &V_NONE(arg), _dispargsize(prgvt[i]) * sizeof(DWORD));
5942         argspos += _dispargsize(prgvt[i]);
5943     }
5944
5945     if (pvInstance)
5946     {
5947         FARPROC *vtable = *(FARPROC**)pvInstance;
5948         hres = _invoke(vtable[oVft/sizeof(void *)], cc, argsize, args);
5949     }
5950     else
5951         /* if we aren't invoking an object then the function pointer is stored
5952          * in oVft */
5953         hres = _invoke((FARPROC)oVft, cc, argsize, args);
5954
5955     if (pvargResult && (vtReturn != VT_EMPTY))
5956     {
5957         TRACE("Method returned 0x%08x\n",hres);
5958         V_VT(pvargResult) = vtReturn;
5959         V_UI4(pvargResult) = hres;
5960     }
5961     HeapFree(GetProcessHeap(),0,args);
5962     return S_OK;
5963 #else
5964     FIXME( "(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d)): not implemented for this CPU\n",
5965            pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg, pvargResult, V_VT(pvargResult));
5966     return E_NOTIMPL;
5967 #endif
5968 }
5969
5970 #define INVBUF_ELEMENT_SIZE \
5971     (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *) + sizeof(VARTYPE))
5972 #define INVBUF_GET_ARG_ARRAY(buffer, params) (buffer)
5973 #define INVBUF_GET_MISSING_ARG_ARRAY(buffer, params) \
5974     ((VARIANTARG *)((char *)(buffer) + sizeof(VARIANTARG) * (params)))
5975 #define INVBUF_GET_ARG_PTR_ARRAY(buffer, params) \
5976     ((VARIANTARG **)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG)) * (params)))
5977 #define INVBUF_GET_ARG_TYPE_ARRAY(buffer, params) \
5978     ((VARTYPE *)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *)) * (params)))
5979
5980 static HRESULT WINAPI ITypeInfo_fnInvoke(
5981     ITypeInfo2 *iface,
5982     VOID  *pIUnk,
5983     MEMBERID memid,
5984     UINT16 wFlags,
5985     DISPPARAMS  *pDispParams,
5986     VARIANT  *pVarResult,
5987     EXCEPINFO  *pExcepInfo,
5988     UINT  *pArgErr)
5989 {
5990     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5991     int i;
5992     unsigned int var_index;
5993     TYPEKIND type_kind;
5994     HRESULT hres;
5995     const TLBFuncDesc *pFuncInfo;
5996
5997     TRACE("(%p)(%p,id=%d,flags=0x%08x,%p,%p,%p,%p)\n",
5998       This,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr
5999     );
6000
6001     if (!pDispParams)
6002     {
6003         ERR("NULL pDispParams not allowed\n");
6004         return E_INVALIDARG;
6005     }
6006
6007     dump_DispParms(pDispParams);
6008
6009     if (pDispParams->cNamedArgs > pDispParams->cArgs)
6010     {
6011         ERR("named argument array cannot be bigger than argument array (%d/%d)\n",
6012             pDispParams->cNamedArgs, pDispParams->cArgs);
6013         return E_INVALIDARG;
6014     }
6015
6016     /* we do this instead of using GetFuncDesc since it will return a fake
6017      * FUNCDESC for dispinterfaces and we want the real function description */
6018     for (pFuncInfo = This->funclist; pFuncInfo; pFuncInfo=pFuncInfo->next)
6019         if ((memid == pFuncInfo->funcdesc.memid) &&
6020             (wFlags & pFuncInfo->funcdesc.invkind))
6021             break;
6022
6023     if (pFuncInfo) {
6024         const FUNCDESC *func_desc = &pFuncInfo->funcdesc;
6025
6026         if (TRACE_ON(ole))
6027         {
6028             TRACE("invoking:\n");
6029             dump_TLBFuncDescOne(pFuncInfo);
6030         }
6031         
6032         switch (func_desc->funckind) {
6033         case FUNC_PUREVIRTUAL:
6034         case FUNC_VIRTUAL: {
6035             void *buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INVBUF_ELEMENT_SIZE * func_desc->cParams);
6036             VARIANT varresult;
6037             VARIANT retval; /* pointer for storing byref retvals in */
6038             VARIANTARG **prgpvarg = INVBUF_GET_ARG_PTR_ARRAY(buffer, func_desc->cParams);
6039             VARIANTARG *rgvarg = INVBUF_GET_ARG_ARRAY(buffer, func_desc->cParams);
6040             VARTYPE *rgvt = INVBUF_GET_ARG_TYPE_ARRAY(buffer, func_desc->cParams);
6041             UINT cNamedArgs = pDispParams->cNamedArgs;
6042             DISPID *rgdispidNamedArgs = pDispParams->rgdispidNamedArgs;
6043             UINT vargs_converted=0;
6044
6045             hres = S_OK;
6046
6047             if (func_desc->invkind & (INVOKE_PROPERTYPUT|INVOKE_PROPERTYPUTREF))
6048             {
6049                 if (!cNamedArgs || (rgdispidNamedArgs[0] != DISPID_PROPERTYPUT))
6050                 {
6051                     ERR("first named arg for property put invocation must be DISPID_PROPERTYPUT\n");
6052                     hres = DISP_E_PARAMNOTFOUND;
6053                     goto func_fail;
6054                 }
6055                 /* ignore the DISPID_PROPERTYPUT named argument from now on */
6056                 cNamedArgs--;
6057                 rgdispidNamedArgs++;
6058             }
6059
6060             if (func_desc->cParamsOpt < 0 && cNamedArgs)
6061             {
6062                 ERR("functions with the vararg attribute do not support named arguments\n");
6063                 hres = DISP_E_NONAMEDARGS;
6064                 goto func_fail;
6065             }
6066
6067             for (i = 0; i < func_desc->cParams; i++)
6068             {
6069                 TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc;
6070                 hres = typedescvt_to_variantvt((ITypeInfo *)iface, tdesc, &rgvt[i]);
6071                 if (FAILED(hres))
6072                     goto func_fail;
6073             }
6074
6075             TRACE("changing args\n");
6076             for (i = 0; i < func_desc->cParams; i++)
6077             {
6078                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
6079                 VARIANTARG *src_arg;
6080
6081                 if (wParamFlags & PARAMFLAG_FLCID)
6082                 {
6083                     VARIANTARG *arg;
6084                     arg = prgpvarg[i] = &rgvarg[i];
6085                     V_VT(arg) = VT_I4;
6086                     V_I4(arg) = This->pTypeLib->lcid;
6087                     continue;
6088                 }
6089
6090                 if (cNamedArgs)
6091                 {
6092                     USHORT j;
6093                     src_arg = NULL;
6094                     for (j = 0; j < cNamedArgs; j++)
6095                         if (rgdispidNamedArgs[j] == i)
6096                         {
6097                             src_arg = &pDispParams->rgvarg[j];
6098                             break;
6099                         }
6100                 }
6101                 else
6102                 {
6103                     src_arg = vargs_converted < pDispParams->cArgs ? &pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted] : NULL;
6104                     vargs_converted++;
6105                 }
6106
6107                 if (wParamFlags & PARAMFLAG_FRETVAL)
6108                 {
6109                     /* under most conditions the caller is not allowed to
6110                      * pass in a dispparam arg in the index of what would be
6111                      * the retval parameter. however, there is an exception
6112                      * where the extra parameter is used in an extra
6113                      * IDispatch::Invoke below */
6114                     if ((i < pDispParams->cArgs) &&
6115                         ((func_desc->cParams != 1) || !pVarResult ||
6116                          !(func_desc->invkind & INVOKE_PROPERTYGET)))
6117                     {
6118                         hres = DISP_E_BADPARAMCOUNT;
6119                         break;
6120                     }
6121
6122                     /* note: this check is placed so that if the caller passes
6123                      * in a VARIANTARG for the retval we just ignore it, like
6124                      * native does */
6125                     if (i == func_desc->cParams - 1)
6126                     {
6127                         VARIANTARG *arg;
6128                         arg = prgpvarg[i] = &rgvarg[i];
6129                         memset(arg, 0, sizeof(*arg));
6130                         V_VT(arg) = rgvt[i];
6131                         memset(&retval, 0, sizeof(retval));
6132                         V_BYREF(arg) = &retval;
6133                     }
6134                     else
6135                     {
6136                         ERR("[retval] parameter must be the last parameter of the method (%d/%d)\n", i, func_desc->cParams);
6137                         hres = E_UNEXPECTED;
6138                         break;
6139                     }
6140                 }
6141                 else if (src_arg)
6142                 {
6143                     dump_Variant(src_arg);
6144
6145                     if (rgvt[i] == VT_VARIANT)
6146                         hres = VariantCopy(&rgvarg[i], src_arg);
6147                     else if (rgvt[i] == (VT_VARIANT | VT_BYREF))
6148                     {
6149                         if (rgvt[i] == V_VT(src_arg))
6150                             V_VARIANTREF(&rgvarg[i]) = V_VARIANTREF(src_arg);
6151                         else
6152                         {
6153                             VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
6154                             if (wParamFlags & PARAMFLAG_FIN)
6155                                 hres = VariantCopy(&missing_arg[i], src_arg);
6156                             V_VARIANTREF(&rgvarg[i]) = &missing_arg[i];
6157                         }
6158                         V_VT(&rgvarg[i]) = rgvt[i];
6159                     }
6160                     else if (rgvt[i] == (VT_VARIANT | VT_ARRAY) && func_desc->cParamsOpt < 0 && i == func_desc->cParams-1)
6161                     {
6162                         SAFEARRAY *a;
6163                         SAFEARRAYBOUND bound;
6164                         VARIANT *v;
6165                         LONG j;
6166                         bound.lLbound = 0;
6167                         bound.cElements = pDispParams->cArgs-i;
6168                         if (!(a = SafeArrayCreate(VT_VARIANT, 1, &bound)))
6169                         {
6170                             ERR("SafeArrayCreate failed\n");
6171                             break;
6172                         }
6173                         hres = SafeArrayAccessData(a, (LPVOID)&v);
6174                         if (hres != S_OK)
6175                         {
6176                             ERR("SafeArrayAccessData failed with %x\n", hres);
6177                             break;
6178                         }
6179                         for (j = 0; j < bound.cElements; j++)
6180                             VariantCopy(&v[j], &pDispParams->rgvarg[pDispParams->cArgs - 1 - i - j]);
6181                         hres = SafeArrayUnaccessData(a);
6182                         if (hres != S_OK)
6183                         {
6184                             ERR("SafeArrayUnaccessData failed with %x\n", hres);
6185                             break;
6186                         }
6187                         V_ARRAY(&rgvarg[i]) = a;
6188                         V_VT(&rgvarg[i]) = rgvt[i];
6189                     }
6190                     else if ((rgvt[i] & VT_BYREF) && !V_ISBYREF(src_arg))
6191                     {
6192                         VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
6193                         if (wParamFlags & PARAMFLAG_FIN)
6194                             hres = VariantChangeType(&missing_arg[i], src_arg, 0, rgvt[i] & ~VT_BYREF);
6195                         else
6196                             V_VT(&missing_arg[i]) = rgvt[i] & ~VT_BYREF;
6197                         V_BYREF(&rgvarg[i]) = &V_NONE(&missing_arg[i]);
6198                         V_VT(&rgvarg[i]) = rgvt[i];
6199                     }
6200                     else if ((rgvt[i] & VT_BYREF) && (rgvt[i] == V_VT(src_arg)))
6201                     {
6202                         V_BYREF(&rgvarg[i]) = V_BYREF(src_arg);
6203                         V_VT(&rgvarg[i]) = rgvt[i];
6204                     }
6205                     else
6206                     {
6207                         /* FIXME: this doesn't work for VT_BYREF arguments if
6208                          * they are not the same type as in the paramdesc */
6209                         V_VT(&rgvarg[i]) = V_VT(src_arg);
6210                         hres = VariantChangeType(&rgvarg[i], src_arg, 0, rgvt[i]);
6211                         V_VT(&rgvarg[i]) = rgvt[i];
6212                     }
6213
6214                     if (FAILED(hres))
6215                     {
6216                         ERR("failed to convert param %d to %s%s from %s%s\n", i,
6217                             debugstr_vt(rgvt[i]), debugstr_vf(rgvt[i]),
6218                             debugstr_VT(src_arg), debugstr_VF(src_arg));
6219                         break;
6220                     }
6221                     prgpvarg[i] = &rgvarg[i];
6222                 }
6223                 else if (wParamFlags & PARAMFLAG_FOPT)
6224                 {
6225                     VARIANTARG *arg;
6226                     arg = prgpvarg[i] = &rgvarg[i];
6227                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
6228                     {
6229                         hres = VariantCopy(arg, &func_desc->lprgelemdescParam[i].u.paramdesc.pparamdescex->varDefaultValue);
6230                         if (FAILED(hres))
6231                             break;
6232                     }
6233                     else
6234                     {
6235                         VARIANTARG *missing_arg;
6236                         /* if the function wants a pointer to a variant then
6237                          * set that up, otherwise just pass the VT_ERROR in
6238                          * the argument by value */
6239                         if (rgvt[i] & VT_BYREF)
6240                         {
6241                             missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams) + i;
6242                             V_VT(arg) = VT_VARIANT | VT_BYREF;
6243                             V_VARIANTREF(arg) = missing_arg;
6244                         }
6245                         else
6246                             missing_arg = arg;
6247                         V_VT(missing_arg) = VT_ERROR;
6248                         V_ERROR(missing_arg) = DISP_E_PARAMNOTFOUND;
6249                     }
6250                 }
6251                 else
6252                 {
6253                     hres = DISP_E_BADPARAMCOUNT;
6254                     break;
6255                 }
6256             }
6257             if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
6258
6259             /* VT_VOID is a special case for return types, so it is not
6260              * handled in the general function */
6261             if (func_desc->elemdescFunc.tdesc.vt == VT_VOID)
6262                 V_VT(&varresult) = VT_EMPTY;
6263             else
6264             {
6265                 V_VT(&varresult) = 0;
6266                 hres = typedescvt_to_variantvt((ITypeInfo *)iface, &func_desc->elemdescFunc.tdesc, &V_VT(&varresult));
6267                 if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
6268             }
6269
6270             hres = DispCallFunc(pIUnk, func_desc->oVft, func_desc->callconv,
6271                                 V_VT(&varresult), func_desc->cParams, rgvt,
6272                                 prgpvarg, &varresult);
6273
6274             vargs_converted = 0;
6275
6276             for (i = 0; i < func_desc->cParams; i++)
6277             {
6278                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
6279                 VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
6280
6281                 if (wParamFlags & PARAMFLAG_FLCID)
6282                     continue;
6283                 else if (wParamFlags & PARAMFLAG_FRETVAL)
6284                 {
6285                     if (TRACE_ON(ole))
6286                     {
6287                         TRACE("[retval] value: ");
6288                         dump_Variant(prgpvarg[i]);
6289                     }
6290
6291                     if (pVarResult)
6292                     {
6293                         VariantInit(pVarResult);
6294                         /* deref return value */
6295                         hres = VariantCopyInd(pVarResult, prgpvarg[i]);
6296                     }
6297
6298                     VARIANT_ClearInd(prgpvarg[i]);
6299                 }
6300                 else if (vargs_converted < pDispParams->cArgs)
6301                 {
6302                     VARIANTARG *arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted];
6303                     if (wParamFlags & PARAMFLAG_FOUT)
6304                     {
6305                         if ((rgvt[i] & VT_BYREF) && !(V_VT(arg) & VT_BYREF))
6306                         {
6307                             hres = VariantChangeType(arg, &rgvarg[i], 0, V_VT(arg));
6308
6309                             if (FAILED(hres))
6310                             {
6311                                 ERR("failed to convert param %d to vt %d\n", i,
6312                                     V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted]));
6313                                 break;
6314                             }
6315                         }
6316                     }
6317                     else if (V_VT(prgpvarg[i]) == (VT_VARIANT | VT_ARRAY) &&
6318                              func_desc->cParamsOpt < 0 &&
6319                              i == func_desc->cParams-1)
6320                     {
6321                         SAFEARRAY *a = V_ARRAY(prgpvarg[i]);
6322                         LONG j, ubound;
6323                         VARIANT *v;
6324                         hres = SafeArrayGetUBound(a, 1, &ubound);
6325                         if (hres != S_OK)
6326                         {
6327                             ERR("SafeArrayGetUBound failed with %x\n", hres);
6328                             break;
6329                         }
6330                         hres = SafeArrayAccessData(a, (LPVOID)&v);
6331                         if (hres != S_OK)
6332                         {
6333                             ERR("SafeArrayAccessData failed with %x\n", hres);
6334                             break;
6335                         }
6336                         for (j = 0; j <= ubound; j++)
6337                             VariantClear(&v[j]);
6338                         hres = SafeArrayUnaccessData(a);
6339                         if (hres != S_OK)
6340                         {
6341                             ERR("SafeArrayUnaccessData failed with %x\n", hres);
6342                             break;
6343                         }
6344                     }
6345                     VariantClear(&rgvarg[i]);
6346                     vargs_converted++;
6347                 }
6348                 else if (wParamFlags & PARAMFLAG_FOPT)
6349                 {
6350                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
6351                         VariantClear(&rgvarg[i]);
6352                 }
6353
6354                 VariantClear(&missing_arg[i]);
6355             }
6356
6357             if ((V_VT(&varresult) == VT_ERROR) && FAILED(V_ERROR(&varresult)))
6358             {
6359                 WARN("invoked function failed with error 0x%08x\n", V_ERROR(&varresult));
6360                 hres = DISP_E_EXCEPTION;
6361                 if (pExcepInfo)
6362                 {
6363                     IErrorInfo *pErrorInfo;
6364                     pExcepInfo->scode = V_ERROR(&varresult);
6365                     if (GetErrorInfo(0, &pErrorInfo) == S_OK)
6366                     {
6367                         IErrorInfo_GetDescription(pErrorInfo, &pExcepInfo->bstrDescription);
6368                         IErrorInfo_GetHelpFile(pErrorInfo, &pExcepInfo->bstrHelpFile);
6369                         IErrorInfo_GetSource(pErrorInfo, &pExcepInfo->bstrSource);
6370                         IErrorInfo_GetHelpContext(pErrorInfo, &pExcepInfo->dwHelpContext);
6371
6372                         IErrorInfo_Release(pErrorInfo);
6373                     }
6374                 }
6375             }
6376             if (V_VT(&varresult) != VT_ERROR)
6377             {
6378                 TRACE("varresult value: ");
6379                 dump_Variant(&varresult);
6380
6381                 if (pVarResult)
6382                 {
6383                     VariantClear(pVarResult);
6384                     *pVarResult = varresult;
6385                 }
6386                 else
6387                     VariantClear(&varresult);
6388             }
6389
6390             if (SUCCEEDED(hres) && pVarResult && (func_desc->cParams == 1) &&
6391                 (func_desc->invkind & INVOKE_PROPERTYGET) &&
6392                 (func_desc->lprgelemdescParam[0].u.paramdesc.wParamFlags & PARAMFLAG_FRETVAL) &&
6393                 (pDispParams->cArgs != 0))
6394             {
6395                 if (V_VT(pVarResult) == VT_DISPATCH)
6396                 {
6397                     IDispatch *pDispatch = V_DISPATCH(pVarResult);
6398                     /* Note: not VariantClear; we still need the dispatch
6399                      * pointer to be valid */
6400                     VariantInit(pVarResult);
6401                     hres = IDispatch_Invoke(pDispatch, DISPID_VALUE, &IID_NULL,
6402                         GetSystemDefaultLCID(), INVOKE_PROPERTYGET,
6403                         pDispParams, pVarResult, pExcepInfo, pArgErr);
6404                     IDispatch_Release(pDispatch);
6405                 }
6406                 else
6407                 {
6408                     VariantClear(pVarResult);
6409                     hres = DISP_E_NOTACOLLECTION;
6410                 }
6411             }
6412
6413 func_fail:
6414             HeapFree(GetProcessHeap(), 0, buffer);
6415             break;
6416         }
6417         case FUNC_DISPATCH:  {
6418            IDispatch *disp;
6419
6420            hres = IUnknown_QueryInterface((LPUNKNOWN)pIUnk,&IID_IDispatch,(LPVOID*)&disp);
6421            if (SUCCEEDED(hres)) {
6422                FIXME("Calling Invoke in IDispatch iface. untested!\n");
6423                hres = IDispatch_Invoke(
6424                                      disp,memid,&IID_NULL,LOCALE_USER_DEFAULT,wFlags,pDispParams,
6425                                      pVarResult,pExcepInfo,pArgErr
6426                                      );
6427                if (FAILED(hres))
6428                    FIXME("IDispatch::Invoke failed with %08x. (Could be not a real error?)\n", hres);
6429                IDispatch_Release(disp);
6430            } else
6431                FIXME("FUNC_DISPATCH used on object without IDispatch iface?\n");
6432            break;
6433         }
6434         default:
6435             FIXME("Unknown function invocation type %d\n", func_desc->funckind);
6436             hres = E_FAIL;
6437             break;
6438         }
6439
6440         TRACE("-- 0x%08x\n", hres);
6441         return hres;
6442
6443     } else if(SUCCEEDED(hres = ITypeInfo2_GetVarIndexOfMemId(iface, memid, &var_index))) {
6444         VARDESC *var_desc;
6445
6446         hres = ITypeInfo2_GetVarDesc(iface, var_index, &var_desc);
6447         if(FAILED(hres)) return hres;
6448         
6449         FIXME("varseek: Found memid, but variable-based invoking not supported\n");
6450         dump_VARDESC(var_desc);
6451         ITypeInfo2_ReleaseVarDesc(iface, var_desc);
6452         return E_NOTIMPL;
6453     }
6454
6455     /* not found, look for it in inherited interfaces */
6456     ITypeInfo2_GetTypeKind(iface, &type_kind);
6457     if(type_kind == TKIND_INTERFACE || type_kind == TKIND_DISPATCH) {
6458         if(This->impltypelist) {
6459             /* recursive search */
6460             ITypeInfo *pTInfo;
6461             hres = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef, &pTInfo);
6462             if(SUCCEEDED(hres)){
6463                 hres = ITypeInfo_Invoke(pTInfo,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr);
6464                 ITypeInfo_Release(pTInfo);
6465                 return hres;
6466             }
6467             WARN("Could not search inherited interface!\n");
6468         }
6469     }
6470     ERR("did not find member id %d, flags 0x%x!\n", memid, wFlags);
6471     return DISP_E_MEMBERNOTFOUND;
6472 }
6473
6474 /* ITypeInfo::GetDocumentation
6475  *
6476  * Retrieves the documentation string, the complete Help file name and path,
6477  * and the context ID for the Help topic for a specified type description.
6478  *
6479  * (Can be tested by the Visual Basic Editor in Word for instance.)
6480  */
6481 static HRESULT WINAPI ITypeInfo_fnGetDocumentation( ITypeInfo2 *iface,
6482         MEMBERID memid, BSTR  *pBstrName, BSTR  *pBstrDocString,
6483         DWORD  *pdwHelpContext, BSTR  *pBstrHelpFile)
6484 {
6485     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6486     const TLBFuncDesc *pFDesc;
6487     const TLBVarDesc *pVDesc;
6488     TRACE("(%p) memid %d Name(%p) DocString(%p)"
6489           " HelpContext(%p) HelpFile(%p)\n",
6490         This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
6491     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
6492         if(pBstrName)
6493             *pBstrName=SysAllocString(This->Name);
6494         if(pBstrDocString)
6495             *pBstrDocString=SysAllocString(This->DocString);
6496         if(pdwHelpContext)
6497             *pdwHelpContext=This->dwHelpContext;
6498         if(pBstrHelpFile)
6499             *pBstrHelpFile=SysAllocString(This->DocString);/* FIXME */
6500         return S_OK;
6501     }else {/* for a member */
6502     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
6503         if(pFDesc->funcdesc.memid==memid){
6504           if(pBstrName)
6505             *pBstrName = SysAllocString(pFDesc->Name);
6506           if(pBstrDocString)
6507             *pBstrDocString=SysAllocString(pFDesc->HelpString);
6508           if(pdwHelpContext)
6509             *pdwHelpContext=pFDesc->helpcontext;
6510           return S_OK;
6511         }
6512     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
6513         if(pVDesc->vardesc.memid==memid){
6514             if(pBstrName)
6515               *pBstrName = SysAllocString(pVDesc->Name);
6516             if(pBstrDocString)
6517               *pBstrDocString=SysAllocString(pVDesc->HelpString);
6518             if(pdwHelpContext)
6519               *pdwHelpContext=pVDesc->HelpContext;
6520             return S_OK;
6521         }
6522     }
6523
6524     if(This->impltypelist &&
6525        (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
6526         /* recursive search */
6527         ITypeInfo *pTInfo;
6528         HRESULT result;
6529         result = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef,
6530                                         &pTInfo);
6531         if(SUCCEEDED(result)) {
6532             result = ITypeInfo_GetDocumentation(pTInfo, memid, pBstrName,
6533                 pBstrDocString, pdwHelpContext, pBstrHelpFile);
6534             ITypeInfo_Release(pTInfo);
6535             return result;
6536         }
6537         WARN("Could not search inherited interface!\n");
6538     }
6539
6540     WARN("member %d not found\n", memid);
6541     return TYPE_E_ELEMENTNOTFOUND;
6542 }
6543
6544 /*  ITypeInfo::GetDllEntry
6545  *
6546  * Retrieves a description or specification of an entry point for a function
6547  * in a DLL.
6548  */
6549 static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid,
6550         INVOKEKIND invKind, BSTR  *pBstrDllName, BSTR  *pBstrName,
6551         WORD  *pwOrdinal)
6552 {
6553     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6554     const TLBFuncDesc *pFDesc;
6555
6556     TRACE("(%p)->(memid %x, %d, %p, %p, %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
6557
6558     if (pBstrDllName) *pBstrDllName = NULL;
6559     if (pBstrName) *pBstrName = NULL;
6560     if (pwOrdinal) *pwOrdinal = 0;
6561
6562     if (This->TypeAttr.typekind != TKIND_MODULE)
6563         return TYPE_E_BADMODULEKIND;
6564
6565     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
6566         if(pFDesc->funcdesc.memid==memid){
6567             dump_TypeInfo(This);
6568             if (TRACE_ON(ole))
6569                 dump_TLBFuncDescOne(pFDesc);
6570
6571             if (pBstrDllName)
6572                 *pBstrDllName = SysAllocString(This->DllName);
6573
6574             if (!IS_INTRESOURCE(pFDesc->Entry) && (pFDesc->Entry != (void*)-1)) {
6575                 if (pBstrName)
6576                     *pBstrName = SysAllocString(pFDesc->Entry);
6577                 if (pwOrdinal)
6578                     *pwOrdinal = -1;
6579                 return S_OK;
6580             }
6581             if (pBstrName)
6582                 *pBstrName = NULL;
6583             if (pwOrdinal)
6584                 *pwOrdinal = (DWORD)pFDesc->Entry;
6585             return S_OK;
6586         }
6587     return TYPE_E_ELEMENTNOTFOUND;
6588 }
6589
6590 /* internal function to make the inherited interfaces' methods appear
6591  * part of the interface */
6592 static HRESULT ITypeInfoImpl_GetDispatchRefTypeInfo( ITypeInfo *iface,
6593     HREFTYPE *hRefType, ITypeInfo  **ppTInfo)
6594 {
6595     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6596     HRESULT hr;
6597
6598     TRACE("%p, 0x%x\n", iface, *hRefType);
6599
6600     if (This->impltypelist && (*hRefType & DISPATCH_HREF_MASK))
6601     {
6602         ITypeInfo *pSubTypeInfo;
6603
6604         hr = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef, &pSubTypeInfo);
6605         if (FAILED(hr))
6606             return hr;
6607
6608         hr = ITypeInfoImpl_GetDispatchRefTypeInfo(pSubTypeInfo,
6609                                                   hRefType, ppTInfo);
6610         ITypeInfo_Release(pSubTypeInfo);
6611         if (SUCCEEDED(hr))
6612             return hr;
6613     }
6614     *hRefType -= DISPATCH_HREF_OFFSET;
6615
6616     if (!(*hRefType & DISPATCH_HREF_MASK))
6617         return ITypeInfo_GetRefTypeInfo(iface, *hRefType, ppTInfo);
6618     else
6619         return E_FAIL;
6620 }
6621
6622 /* ITypeInfo::GetRefTypeInfo
6623  *
6624  * If a type description references other type descriptions, it retrieves
6625  * the referenced type descriptions.
6626  */
6627 static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo(
6628         ITypeInfo2 *iface,
6629         HREFTYPE hRefType,
6630         ITypeInfo  **ppTInfo)
6631 {
6632     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6633     HRESULT result = E_FAIL;
6634
6635     if ((This->hreftype != -1) && (This->hreftype == hRefType))
6636     {
6637         *ppTInfo = (ITypeInfo *)&This->lpVtbl;
6638         ITypeInfo_AddRef(*ppTInfo);
6639         result = S_OK;
6640     }
6641     else if (hRefType == -1 &&
6642         (This->TypeAttr.typekind   == TKIND_DISPATCH) &&
6643         (This->TypeAttr.wTypeFlags &  TYPEFLAG_FDUAL))
6644     {
6645           /* when we meet a DUAL dispinterface, we must create the interface
6646           * version of it.
6647           */
6648           ITypeInfoImpl* pTypeInfoImpl = (ITypeInfoImpl*) ITypeInfo_Constructor();
6649
6650
6651           /* the interface version contains the same information as the dispinterface
6652            * copy the contents of the structs.
6653            */
6654           *pTypeInfoImpl = *This;
6655           pTypeInfoImpl->ref = 0;
6656
6657           /* change the type to interface */
6658           pTypeInfoImpl->TypeAttr.typekind = TKIND_INTERFACE;
6659
6660           *ppTInfo = (ITypeInfo*) pTypeInfoImpl;
6661
6662           /* the AddRef implicitly adds a reference to the parent typelib, which
6663            * stops the copied data from being destroyed until the new typeinfo's
6664            * refcount goes to zero, but we need to signal to the new instance to
6665            * not free its data structures when it is destroyed */
6666           pTypeInfoImpl->not_attached_to_typelib = TRUE;
6667
6668           ITypeInfo_AddRef(*ppTInfo);
6669
6670           result = S_OK;
6671
6672     } else if ((hRefType != -1) && (hRefType & DISPATCH_HREF_MASK) &&
6673         (This->TypeAttr.typekind   == TKIND_DISPATCH))
6674     {
6675         HREFTYPE href_dispatch = hRefType;
6676         result = ITypeInfoImpl_GetDispatchRefTypeInfo((ITypeInfo *)iface, &href_dispatch, ppTInfo);
6677     } else {
6678         TLBRefType *ref_type;
6679         LIST_FOR_EACH_ENTRY(ref_type, &This->pTypeLib->ref_list, TLBRefType, entry)
6680         {
6681             if(ref_type->reference == hRefType)
6682                 break;
6683         }
6684         if(&ref_type->entry == &This->pTypeLib->ref_list)
6685         {
6686             FIXME("Can't find pRefType for ref %x\n", hRefType);
6687             goto end;
6688         }
6689         if(hRefType != -1) {
6690             ITypeLib *pTLib = NULL;
6691
6692             if(ref_type->pImpTLInfo == TLB_REF_INTERNAL) {
6693                 UINT Index;
6694                 result = ITypeInfo_GetContainingTypeLib(iface, &pTLib, &Index);
6695             } else {
6696                 if(ref_type->pImpTLInfo->pImpTypeLib) {
6697                     TRACE("typeinfo in imported typelib that is already loaded\n");
6698                     pTLib = (ITypeLib*)ref_type->pImpTLInfo->pImpTypeLib;
6699                     ITypeLib2_AddRef(pTLib);
6700                     result = S_OK;
6701                 } else {
6702                     TRACE("typeinfo in imported typelib that isn't already loaded\n");
6703                     result = LoadRegTypeLib( &ref_type->pImpTLInfo->guid,
6704                                              ref_type->pImpTLInfo->wVersionMajor,
6705                                              ref_type->pImpTLInfo->wVersionMinor,
6706                                              ref_type->pImpTLInfo->lcid,
6707                                              &pTLib);
6708
6709                     if(FAILED(result)) {
6710                         BSTR libnam=SysAllocString(ref_type->pImpTLInfo->name);
6711                         result=LoadTypeLib(libnam, &pTLib);
6712                         SysFreeString(libnam);
6713                     }
6714                     if(SUCCEEDED(result)) {
6715                         ref_type->pImpTLInfo->pImpTypeLib = (ITypeLibImpl*)pTLib;
6716                         ITypeLib2_AddRef(pTLib);
6717                     }
6718                 }
6719             }
6720             if(SUCCEEDED(result)) {
6721                 if(ref_type->index == TLB_REF_USE_GUID)
6722                     result = ITypeLib2_GetTypeInfoOfGuid(pTLib,
6723                                                          &ref_type->guid,
6724                                                          ppTInfo);
6725                 else
6726                     result = ITypeLib2_GetTypeInfo(pTLib, ref_type->index,
6727                                                    ppTInfo);
6728             }
6729             if (pTLib != NULL)
6730                 ITypeLib2_Release(pTLib);
6731         }
6732     }
6733
6734 end:
6735     TRACE("(%p) hreftype 0x%04x loaded %s (%p)\n", This, hRefType,
6736           SUCCEEDED(result)? "SUCCESS":"FAILURE", *ppTInfo);
6737     return result;
6738 }
6739
6740 /* ITypeInfo::AddressOfMember
6741  *
6742  * Retrieves the addresses of static functions or variables, such as those
6743  * defined in a DLL.
6744  */
6745 static HRESULT WINAPI ITypeInfo_fnAddressOfMember( ITypeInfo2 *iface,
6746         MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
6747 {
6748     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6749     HRESULT hr;
6750     BSTR dll, entry;
6751     WORD ordinal;
6752     HMODULE module;
6753
6754     TRACE("(%p)->(0x%x, 0x%x, %p)\n", This, memid, invKind, ppv);
6755
6756     hr = ITypeInfo_GetDllEntry(iface, memid, invKind, &dll, &entry, &ordinal);
6757     if (FAILED(hr))
6758         return hr;
6759
6760     module = LoadLibraryW(dll);
6761     if (!module)
6762     {
6763         ERR("couldn't load %s\n", debugstr_w(dll));
6764         SysFreeString(dll);
6765         SysFreeString(entry);
6766         return STG_E_FILENOTFOUND;
6767     }
6768     /* FIXME: store library somewhere where we can free it */
6769
6770     if (entry)
6771     {
6772         LPSTR entryA;
6773         INT len = WideCharToMultiByte(CP_ACP, 0, entry, -1, NULL, 0, NULL, NULL);
6774         entryA = HeapAlloc(GetProcessHeap(), 0, len);
6775         WideCharToMultiByte(CP_ACP, 0, entry, -1, entryA, len, NULL, NULL);
6776
6777         *ppv = GetProcAddress(module, entryA);
6778         if (!*ppv)
6779             ERR("function not found %s\n", debugstr_a(entryA));
6780
6781         HeapFree(GetProcessHeap(), 0, entryA);
6782     }
6783     else
6784     {
6785         *ppv = GetProcAddress(module, MAKEINTRESOURCEA(ordinal));
6786         if (!*ppv)
6787             ERR("function not found %d\n", ordinal);
6788     }
6789
6790     SysFreeString(dll);
6791     SysFreeString(entry);
6792
6793     if (!*ppv)
6794         return TYPE_E_DLLFUNCTIONNOTFOUND;
6795
6796     return S_OK;
6797 }
6798
6799 /* ITypeInfo::CreateInstance
6800  *
6801  * Creates a new instance of a type that describes a component object class
6802  * (coclass).
6803  */
6804 static HRESULT WINAPI ITypeInfo_fnCreateInstance( ITypeInfo2 *iface,
6805         IUnknown *pOuterUnk, REFIID riid, VOID  **ppvObj)
6806 {
6807     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6808     HRESULT hr;
6809     TYPEATTR *pTA;
6810
6811     TRACE("(%p)->(%p, %s, %p)\n", This, pOuterUnk, debugstr_guid(riid), ppvObj);
6812
6813     *ppvObj = NULL;
6814
6815     if(pOuterUnk)
6816     {
6817         WARN("Not able to aggregate\n");
6818         return CLASS_E_NOAGGREGATION;
6819     }
6820
6821     hr = ITypeInfo_GetTypeAttr(iface, &pTA);
6822     if(FAILED(hr)) return hr;
6823
6824     if(pTA->typekind != TKIND_COCLASS)
6825     {
6826         WARN("CreateInstance on typeinfo of type %x\n", pTA->typekind);
6827         hr = E_INVALIDARG;
6828         goto end;
6829     }
6830
6831     hr = S_FALSE;
6832     if(pTA->wTypeFlags & TYPEFLAG_FAPPOBJECT)
6833     {
6834         IUnknown *pUnk;
6835         hr = GetActiveObject(&pTA->guid, NULL, &pUnk);
6836         TRACE("GetActiveObject rets %08x\n", hr);
6837         if(hr == S_OK)
6838         {
6839             hr = IUnknown_QueryInterface(pUnk, riid, ppvObj);
6840             IUnknown_Release(pUnk);
6841         }
6842     }
6843
6844     if(hr != S_OK)
6845         hr = CoCreateInstance(&pTA->guid, NULL,
6846                               CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
6847                               riid, ppvObj);
6848
6849 end:
6850     ITypeInfo_ReleaseTypeAttr(iface, pTA);
6851     return hr;
6852 }
6853
6854 /* ITypeInfo::GetMops
6855  *
6856  * Retrieves marshalling information.
6857  */
6858 static HRESULT WINAPI ITypeInfo_fnGetMops( ITypeInfo2 *iface, MEMBERID memid,
6859                                 BSTR  *pBstrMops)
6860 {
6861     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6862     FIXME("(%p) stub!\n", This);
6863     return S_OK;
6864 }
6865
6866 /* ITypeInfo::GetContainingTypeLib
6867  *
6868  * Retrieves the containing type library and the index of the type description
6869  * within that type library.
6870  */
6871 static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( ITypeInfo2 *iface,
6872         ITypeLib  * *ppTLib, UINT  *pIndex)
6873 {
6874     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6875     
6876     /* If a pointer is null, we simply ignore it, the ATL in particular passes pIndex as 0 */
6877     if (pIndex) {
6878       *pIndex=This->index;
6879       TRACE("returning pIndex=%d\n", *pIndex);
6880     }
6881     
6882     if (ppTLib) {
6883       *ppTLib=(LPTYPELIB )(This->pTypeLib);
6884       ITypeLib2_AddRef(*ppTLib);
6885       TRACE("returning ppTLib=%p\n", *ppTLib);
6886     }
6887     
6888     return S_OK;
6889 }
6890
6891 /* ITypeInfo::ReleaseTypeAttr
6892  *
6893  * Releases a TYPEATTR previously returned by GetTypeAttr.
6894  *
6895  */
6896 static void WINAPI ITypeInfo_fnReleaseTypeAttr( ITypeInfo2 *iface,
6897         TYPEATTR* pTypeAttr)
6898 {
6899     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6900     TRACE("(%p)->(%p)\n", This, pTypeAttr);
6901     HeapFree(GetProcessHeap(), 0, pTypeAttr);
6902 }
6903
6904 /* ITypeInfo::ReleaseFuncDesc
6905  *
6906  * Releases a FUNCDESC previously returned by GetFuncDesc. *
6907  */
6908 static void WINAPI ITypeInfo_fnReleaseFuncDesc(
6909         ITypeInfo2 *iface,
6910         FUNCDESC *pFuncDesc)
6911 {
6912     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6913     SHORT i;
6914
6915     TRACE("(%p)->(%p)\n", This, pFuncDesc);
6916
6917     for (i = 0; i < pFuncDesc->cParams; i++)
6918         TLB_FreeElemDesc(&pFuncDesc->lprgelemdescParam[i]);
6919     TLB_FreeElemDesc(&pFuncDesc->elemdescFunc);
6920
6921     SysFreeString((BSTR)pFuncDesc);
6922 }
6923
6924 /* ITypeInfo::ReleaseVarDesc
6925  *
6926  * Releases a VARDESC previously returned by GetVarDesc.
6927  */
6928 static void WINAPI ITypeInfo_fnReleaseVarDesc( ITypeInfo2 *iface,
6929         VARDESC *pVarDesc)
6930 {
6931     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6932     TRACE("(%p)->(%p)\n", This, pVarDesc);
6933
6934     TLB_FreeElemDesc(&pVarDesc->elemdescVar);
6935     if (pVarDesc->varkind == VAR_CONST)
6936         VariantClear(pVarDesc->u.lpvarValue);
6937     SysFreeString((BSTR)pVarDesc);
6938 }
6939
6940 /* ITypeInfo2::GetTypeKind
6941  *
6942  * Returns the TYPEKIND enumeration quickly, without doing any allocations.
6943  *
6944  */
6945 static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo2 * iface,
6946     TYPEKIND *pTypeKind)
6947 {
6948     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6949     *pTypeKind=This->TypeAttr.typekind;
6950     TRACE("(%p) type 0x%0x\n", This,*pTypeKind);
6951     return S_OK;
6952 }
6953
6954 /* ITypeInfo2::GetTypeFlags
6955  *
6956  * Returns the type flags without any allocations. This returns a DWORD type
6957  * flag, which expands the type flags without growing the TYPEATTR (type
6958  * attribute).
6959  *
6960  */
6961 static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo2 *iface, ULONG *pTypeFlags)
6962 {
6963     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6964     *pTypeFlags=This->TypeAttr.wTypeFlags;
6965     TRACE("(%p) flags 0x%x\n", This,*pTypeFlags);
6966     return S_OK;
6967 }
6968
6969 /* ITypeInfo2::GetFuncIndexOfMemId
6970  * Binds to a specific member based on a known DISPID, where the member name
6971  * is not known (for example, when binding to a default member).
6972  *
6973  */
6974 static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo2 * iface,
6975     MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex)
6976 {
6977     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6978     const TLBFuncDesc *pFuncInfo;
6979     int i;
6980     HRESULT result;
6981
6982     for(i = 0, pFuncInfo = This->funclist; pFuncInfo; i++, pFuncInfo=pFuncInfo->next)
6983         if(memid == pFuncInfo->funcdesc.memid && (invKind & pFuncInfo->funcdesc.invkind))
6984             break;
6985     if(pFuncInfo) {
6986         *pFuncIndex = i;
6987         result = S_OK;
6988     } else
6989         result = TYPE_E_ELEMENTNOTFOUND;
6990
6991     TRACE("(%p) memid 0x%08x invKind 0x%04x -> %s\n", This,
6992           memid, invKind, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
6993     return result;
6994 }
6995
6996 /* TypeInfo2::GetVarIndexOfMemId
6997  *
6998  * Binds to a specific member based on a known DISPID, where the member name
6999  * is not known (for example, when binding to a default member).
7000  *
7001  */
7002 static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( ITypeInfo2 * iface,
7003     MEMBERID memid, UINT *pVarIndex)
7004 {
7005     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7006     TLBVarDesc *pVarInfo;
7007     int i;
7008     HRESULT result;
7009     for(i=0, pVarInfo=This->varlist; pVarInfo &&
7010             memid != pVarInfo->vardesc.memid; i++, pVarInfo=pVarInfo->next)
7011         ;
7012     if(pVarInfo) {
7013         *pVarIndex = i;
7014         result = S_OK;
7015     } else
7016         result = TYPE_E_ELEMENTNOTFOUND;
7017
7018     TRACE("(%p) memid 0x%08x -> %s\n", This,
7019           memid, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
7020     return result;
7021 }
7022
7023 /* ITypeInfo2::GetCustData
7024  *
7025  * Gets the custom data
7026  */
7027 static HRESULT WINAPI ITypeInfo2_fnGetCustData(
7028         ITypeInfo2 * iface,
7029         REFGUID guid,
7030         VARIANT *pVarVal)
7031 {
7032     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7033     TLBCustData *pCData;
7034
7035     for(pCData=This->pCustData; pCData; pCData = pCData->next)
7036         if( IsEqualIID(guid, &pCData->guid)) break;
7037
7038     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
7039
7040     VariantInit( pVarVal);
7041     if (pCData)
7042         VariantCopy( pVarVal, &pCData->data);
7043     else
7044         VariantClear( pVarVal );
7045     return S_OK;
7046 }
7047
7048 /* ITypeInfo2::GetFuncCustData
7049  *
7050  * Gets the custom data
7051  */
7052 static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData(
7053         ITypeInfo2 * iface,
7054         UINT index,
7055         REFGUID guid,
7056         VARIANT *pVarVal)
7057 {
7058     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7059     TLBCustData *pCData=NULL;
7060     TLBFuncDesc * pFDesc;
7061     UINT i;
7062     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
7063             pFDesc=pFDesc->next);
7064
7065     if(pFDesc)
7066         for(pCData=pFDesc->pCustData; pCData; pCData = pCData->next)
7067             if( IsEqualIID(guid, &pCData->guid)) break;
7068
7069     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
7070
7071     if(pCData){
7072         VariantInit( pVarVal);
7073         VariantCopy( pVarVal, &pCData->data);
7074         return S_OK;
7075     }
7076     return E_INVALIDARG;  /* FIXME: correct? */
7077 }
7078
7079 /* ITypeInfo2::GetParamCustData
7080  *
7081  * Gets the custom data
7082  */
7083 static HRESULT WINAPI ITypeInfo2_fnGetParamCustData(
7084         ITypeInfo2 * iface,
7085         UINT indexFunc,
7086         UINT indexParam,
7087         REFGUID guid,
7088         VARIANT *pVarVal)
7089 {
7090     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7091     TLBCustData *pCData=NULL;
7092     TLBFuncDesc * pFDesc;
7093     UINT i;
7094
7095     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,pFDesc=pFDesc->next);
7096
7097     if(pFDesc && indexParam<pFDesc->funcdesc.cParams)
7098         for(pCData=pFDesc->pParamDesc[indexParam].pCustData; pCData;
7099                 pCData = pCData->next)
7100             if( IsEqualIID(guid, &pCData->guid)) break;
7101
7102     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
7103
7104     if(pCData)
7105     {
7106         VariantInit( pVarVal);
7107         VariantCopy( pVarVal, &pCData->data);
7108         return S_OK;
7109     }
7110     return E_INVALIDARG;  /* FIXME: correct? */
7111 }
7112
7113 /* ITypeInfo2::GetVarCustData
7114  *
7115  * Gets the custom data
7116  */
7117 static HRESULT WINAPI ITypeInfo2_fnGetVarCustData(
7118         ITypeInfo2 * iface,
7119         UINT index,
7120         REFGUID guid,
7121         VARIANT *pVarVal)
7122 {
7123     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7124     TLBCustData *pCData=NULL;
7125     TLBVarDesc * pVDesc;
7126     UINT i;
7127
7128     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next);
7129
7130     if(pVDesc)
7131     {
7132       for(pCData=pVDesc->pCustData; pCData; pCData = pCData->next)
7133       {
7134         if( IsEqualIID(guid, &pCData->guid)) break;
7135       }
7136     }
7137
7138     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
7139
7140     if(pCData)
7141     {
7142         VariantInit( pVarVal);
7143         VariantCopy( pVarVal, &pCData->data);
7144         return S_OK;
7145     }
7146     return E_INVALIDARG;  /* FIXME: correct? */
7147 }
7148
7149 /* ITypeInfo2::GetImplCustData
7150  *
7151  * Gets the custom data
7152  */
7153 static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData(
7154         ITypeInfo2 * iface,
7155         UINT index,
7156         REFGUID guid,
7157         VARIANT *pVarVal)
7158 {
7159     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7160     TLBCustData *pCData=NULL;
7161     TLBImplType * pRDesc;
7162     UINT i;
7163
7164     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++, pRDesc=pRDesc->next);
7165
7166     if(pRDesc)
7167     {
7168       for(pCData=pRDesc->pCustData; pCData; pCData = pCData->next)
7169       {
7170         if( IsEqualIID(guid, &pCData->guid)) break;
7171       }
7172     }
7173
7174     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
7175
7176     if(pCData)
7177     {
7178         VariantInit( pVarVal);
7179         VariantCopy( pVarVal, &pCData->data);
7180         return S_OK;
7181     }
7182     return E_INVALIDARG;  /* FIXME: correct? */
7183 }
7184
7185 /* ITypeInfo2::GetDocumentation2
7186  *
7187  * Retrieves the documentation string, the complete Help file name and path,
7188  * the localization context to use, and the context ID for the library Help
7189  * topic in the Help file.
7190  *
7191  */
7192 static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2(
7193         ITypeInfo2 * iface,
7194         MEMBERID memid,
7195         LCID lcid,
7196         BSTR *pbstrHelpString,
7197         DWORD *pdwHelpStringContext,
7198         BSTR *pbstrHelpStringDll)
7199 {
7200     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7201     const TLBFuncDesc *pFDesc;
7202     const TLBVarDesc *pVDesc;
7203     TRACE("(%p) memid %d lcid(0x%x)  HelpString(%p) "
7204           "HelpStringContext(%p) HelpStringDll(%p)\n",
7205           This, memid, lcid, pbstrHelpString, pdwHelpStringContext,
7206           pbstrHelpStringDll );
7207     /* the help string should be obtained from the helpstringdll,
7208      * using the _DLLGetDocumentation function, based on the supplied
7209      * lcid. Nice to do sometime...
7210      */
7211     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
7212         if(pbstrHelpString)
7213             *pbstrHelpString=SysAllocString(This->Name);
7214         if(pdwHelpStringContext)
7215             *pdwHelpStringContext=This->dwHelpStringContext;
7216         if(pbstrHelpStringDll)
7217             *pbstrHelpStringDll=
7218                 SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
7219         return S_OK;
7220     }else {/* for a member */
7221     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
7222         if(pFDesc->funcdesc.memid==memid){
7223              if(pbstrHelpString)
7224                 *pbstrHelpString=SysAllocString(pFDesc->HelpString);
7225             if(pdwHelpStringContext)
7226                 *pdwHelpStringContext=pFDesc->HelpStringContext;
7227             if(pbstrHelpStringDll)
7228                 *pbstrHelpStringDll=
7229                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
7230         return S_OK;
7231     }
7232     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
7233         if(pVDesc->vardesc.memid==memid){
7234              if(pbstrHelpString)
7235                 *pbstrHelpString=SysAllocString(pVDesc->HelpString);
7236             if(pdwHelpStringContext)
7237                 *pdwHelpStringContext=pVDesc->HelpStringContext;
7238             if(pbstrHelpStringDll)
7239                 *pbstrHelpStringDll=
7240                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
7241             return S_OK;
7242         }
7243     }
7244     return TYPE_E_ELEMENTNOTFOUND;
7245 }
7246
7247 /* ITypeInfo2::GetAllCustData
7248  *
7249  * Gets all custom data items for the Type info.
7250  *
7251  */
7252 static HRESULT WINAPI ITypeInfo2_fnGetAllCustData(
7253         ITypeInfo2 * iface,
7254         CUSTDATA *pCustData)
7255 {
7256     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7257     TLBCustData *pCData;
7258     int i;
7259
7260     TRACE("(%p) returning %d items\n", This, This->ctCustData);
7261
7262     pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
7263     if(pCustData->prgCustData ){
7264         pCustData->cCustData=This->ctCustData;
7265         for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
7266             pCustData->prgCustData[i].guid=pCData->guid;
7267             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
7268         }
7269     }else{
7270         ERR(" OUT OF MEMORY!\n");
7271         return E_OUTOFMEMORY;
7272     }
7273     return S_OK;
7274 }
7275
7276 /* ITypeInfo2::GetAllFuncCustData
7277  *
7278  * Gets all custom data items for the specified Function
7279  *
7280  */
7281 static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData(
7282         ITypeInfo2 * iface,
7283         UINT index,
7284         CUSTDATA *pCustData)
7285 {
7286     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7287     TLBCustData *pCData;
7288     TLBFuncDesc * pFDesc;
7289     UINT i;
7290     TRACE("(%p) index %d\n", This, index);
7291     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
7292             pFDesc=pFDesc->next)
7293         ;
7294     if(pFDesc){
7295         pCustData->prgCustData =
7296             TLB_Alloc(pFDesc->ctCustData * sizeof(CUSTDATAITEM));
7297         if(pCustData->prgCustData ){
7298             pCustData->cCustData=pFDesc->ctCustData;
7299             for(i=0, pCData=pFDesc->pCustData; pCData; i++,
7300                     pCData = pCData->next){
7301                 pCustData->prgCustData[i].guid=pCData->guid;
7302                 VariantCopy(& pCustData->prgCustData[i].varValue,
7303                         & pCData->data);
7304             }
7305         }else{
7306             ERR(" OUT OF MEMORY!\n");
7307             return E_OUTOFMEMORY;
7308         }
7309         return S_OK;
7310     }
7311     return TYPE_E_ELEMENTNOTFOUND;
7312 }
7313
7314 /* ITypeInfo2::GetAllParamCustData
7315  *
7316  * Gets all custom data items for the Functions
7317  *
7318  */
7319 static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo2 * iface,
7320     UINT indexFunc, UINT indexParam, CUSTDATA *pCustData)
7321 {
7322     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7323     TLBCustData *pCData=NULL;
7324     TLBFuncDesc * pFDesc;
7325     UINT i;
7326     TRACE("(%p) index %d\n", This, indexFunc);
7327     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,
7328             pFDesc=pFDesc->next)
7329         ;
7330     if(pFDesc && indexParam<pFDesc->funcdesc.cParams){
7331         pCustData->prgCustData =
7332             TLB_Alloc(pFDesc->pParamDesc[indexParam].ctCustData *
7333                     sizeof(CUSTDATAITEM));
7334         if(pCustData->prgCustData ){
7335             pCustData->cCustData=pFDesc->pParamDesc[indexParam].ctCustData;
7336             for(i=0, pCData=pFDesc->pParamDesc[indexParam].pCustData;
7337                     pCData; i++, pCData = pCData->next){
7338                 pCustData->prgCustData[i].guid=pCData->guid;
7339                 VariantCopy(& pCustData->prgCustData[i].varValue,
7340                         & pCData->data);
7341             }
7342         }else{
7343             ERR(" OUT OF MEMORY!\n");
7344             return E_OUTOFMEMORY;
7345         }
7346         return S_OK;
7347     }
7348     return TYPE_E_ELEMENTNOTFOUND;
7349 }
7350
7351 /* ITypeInfo2::GetAllVarCustData
7352  *
7353  * Gets all custom data items for the specified Variable
7354  *
7355  */
7356 static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo2 * iface,
7357     UINT index, CUSTDATA *pCustData)
7358 {
7359     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7360     TLBCustData *pCData;
7361     TLBVarDesc * pVDesc;
7362     UINT i;
7363     TRACE("(%p) index %d\n", This, index);
7364     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++,
7365             pVDesc=pVDesc->next)
7366         ;
7367     if(pVDesc){
7368         pCustData->prgCustData =
7369             TLB_Alloc(pVDesc->ctCustData * sizeof(CUSTDATAITEM));
7370         if(pCustData->prgCustData ){
7371             pCustData->cCustData=pVDesc->ctCustData;
7372             for(i=0, pCData=pVDesc->pCustData; pCData; i++,
7373                     pCData = pCData->next){
7374                 pCustData->prgCustData[i].guid=pCData->guid;
7375                 VariantCopy(& pCustData->prgCustData[i].varValue,
7376                         & pCData->data);
7377             }
7378         }else{
7379             ERR(" OUT OF MEMORY!\n");
7380             return E_OUTOFMEMORY;
7381         }
7382         return S_OK;
7383     }
7384     return TYPE_E_ELEMENTNOTFOUND;
7385 }
7386
7387 /* ITypeInfo2::GetAllImplCustData
7388  *
7389  * Gets all custom data items for the specified implementation type
7390  *
7391  */
7392 static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData(
7393         ITypeInfo2 * iface,
7394         UINT index,
7395         CUSTDATA *pCustData)
7396 {
7397     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7398     TLBCustData *pCData;
7399     TLBImplType * pRDesc;
7400     UINT i;
7401     TRACE("(%p) index %d\n", This, index);
7402     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++,
7403             pRDesc=pRDesc->next)
7404         ;
7405     if(pRDesc){
7406         pCustData->prgCustData =
7407             TLB_Alloc(pRDesc->ctCustData * sizeof(CUSTDATAITEM));
7408         if(pCustData->prgCustData ){
7409             pCustData->cCustData=pRDesc->ctCustData;
7410             for(i=0, pCData=pRDesc->pCustData; pCData; i++,
7411                     pCData = pCData->next){
7412                 pCustData->prgCustData[i].guid=pCData->guid;
7413                 VariantCopy(& pCustData->prgCustData[i].varValue,
7414                         & pCData->data);
7415             }
7416         }else{
7417             ERR(" OUT OF MEMORY!\n");
7418             return E_OUTOFMEMORY;
7419         }
7420         return S_OK;
7421     }
7422     return TYPE_E_ELEMENTNOTFOUND;
7423 }
7424
7425 static const ITypeInfo2Vtbl tinfvt =
7426 {
7427
7428     ITypeInfo_fnQueryInterface,
7429     ITypeInfo_fnAddRef,
7430     ITypeInfo_fnRelease,
7431
7432     ITypeInfo_fnGetTypeAttr,
7433     ITypeInfo_fnGetTypeComp,
7434     ITypeInfo_fnGetFuncDesc,
7435     ITypeInfo_fnGetVarDesc,
7436     ITypeInfo_fnGetNames,
7437     ITypeInfo_fnGetRefTypeOfImplType,
7438     ITypeInfo_fnGetImplTypeFlags,
7439     ITypeInfo_fnGetIDsOfNames,
7440     ITypeInfo_fnInvoke,
7441     ITypeInfo_fnGetDocumentation,
7442     ITypeInfo_fnGetDllEntry,
7443     ITypeInfo_fnGetRefTypeInfo,
7444     ITypeInfo_fnAddressOfMember,
7445     ITypeInfo_fnCreateInstance,
7446     ITypeInfo_fnGetMops,
7447     ITypeInfo_fnGetContainingTypeLib,
7448     ITypeInfo_fnReleaseTypeAttr,
7449     ITypeInfo_fnReleaseFuncDesc,
7450     ITypeInfo_fnReleaseVarDesc,
7451
7452     ITypeInfo2_fnGetTypeKind,
7453     ITypeInfo2_fnGetTypeFlags,
7454     ITypeInfo2_fnGetFuncIndexOfMemId,
7455     ITypeInfo2_fnGetVarIndexOfMemId,
7456     ITypeInfo2_fnGetCustData,
7457     ITypeInfo2_fnGetFuncCustData,
7458     ITypeInfo2_fnGetParamCustData,
7459     ITypeInfo2_fnGetVarCustData,
7460     ITypeInfo2_fnGetImplTypeCustData,
7461     ITypeInfo2_fnGetDocumentation2,
7462     ITypeInfo2_fnGetAllCustData,
7463     ITypeInfo2_fnGetAllFuncCustData,
7464     ITypeInfo2_fnGetAllParamCustData,
7465     ITypeInfo2_fnGetAllVarCustData,
7466     ITypeInfo2_fnGetAllImplTypeCustData,
7467 };
7468
7469 /******************************************************************************
7470  * CreateDispTypeInfo [OLEAUT32.31]
7471  *
7472  * Build type information for an object so it can be called through an
7473  * IDispatch interface.
7474  *
7475  * RETURNS
7476  *  Success: S_OK. pptinfo contains the created ITypeInfo object.
7477  *  Failure: E_INVALIDARG, if one or more arguments is invalid.
7478  *
7479  * NOTES
7480  *  This call allows an objects methods to be accessed through IDispatch, by
7481  *  building an ITypeInfo object that IDispatch can use to call through.
7482  */
7483 HRESULT WINAPI CreateDispTypeInfo(
7484         INTERFACEDATA *pidata, /* [I] Description of the interface to build type info for */
7485         LCID lcid, /* [I] Locale Id */
7486         ITypeInfo **pptinfo) /* [O] Destination for created ITypeInfo object */
7487 {
7488     ITypeInfoImpl *pTIClass, *pTIIface;
7489     ITypeLibImpl *pTypeLibImpl;
7490     unsigned int param, func;
7491     TLBFuncDesc **ppFuncDesc;
7492     TLBRefType *ref;
7493
7494     TRACE("\n");
7495     pTypeLibImpl = TypeLibImpl_Constructor();
7496     if (!pTypeLibImpl) return E_FAIL;
7497
7498     pTIIface = (ITypeInfoImpl*)ITypeInfo_Constructor();
7499     pTIIface->pTypeLib = pTypeLibImpl;
7500     pTIIface->index = 0;
7501     pTIIface->Name = NULL;
7502     pTIIface->dwHelpContext = -1;
7503     memset(&pTIIface->TypeAttr.guid, 0, sizeof(GUID));
7504     pTIIface->TypeAttr.lcid = lcid;
7505     pTIIface->TypeAttr.typekind = TKIND_INTERFACE;
7506     pTIIface->TypeAttr.wMajorVerNum = 0;
7507     pTIIface->TypeAttr.wMinorVerNum = 0;
7508     pTIIface->TypeAttr.cbAlignment = 2;
7509     pTIIface->TypeAttr.cbSizeInstance = -1;
7510     pTIIface->TypeAttr.cbSizeVft = -1;
7511     pTIIface->TypeAttr.cFuncs = 0;
7512     pTIIface->TypeAttr.cImplTypes = 0;
7513     pTIIface->TypeAttr.cVars = 0;
7514     pTIIface->TypeAttr.wTypeFlags = 0;
7515
7516     ppFuncDesc = &pTIIface->funclist;
7517     for(func = 0; func < pidata->cMembers; func++) {
7518         METHODDATA *md = pidata->pmethdata + func;
7519         *ppFuncDesc = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppFuncDesc));
7520         (*ppFuncDesc)->Name = SysAllocString(md->szName);
7521         (*ppFuncDesc)->funcdesc.memid = md->dispid;
7522         (*ppFuncDesc)->funcdesc.lprgscode = NULL;
7523         (*ppFuncDesc)->funcdesc.funckind = FUNC_VIRTUAL;
7524         (*ppFuncDesc)->funcdesc.invkind = md->wFlags;
7525         (*ppFuncDesc)->funcdesc.callconv = md->cc;
7526         (*ppFuncDesc)->funcdesc.cParams = md->cArgs;
7527         (*ppFuncDesc)->funcdesc.cParamsOpt = 0;
7528         (*ppFuncDesc)->funcdesc.oVft = md->iMeth * sizeof(void *);
7529         (*ppFuncDesc)->funcdesc.cScodes = 0;
7530         (*ppFuncDesc)->funcdesc.wFuncFlags = 0;
7531         (*ppFuncDesc)->funcdesc.elemdescFunc.tdesc.vt = md->vtReturn;
7532         (*ppFuncDesc)->funcdesc.elemdescFunc.u.paramdesc.wParamFlags = PARAMFLAG_NONE;
7533         (*ppFuncDesc)->funcdesc.elemdescFunc.u.paramdesc.pparamdescex = NULL;
7534         (*ppFuncDesc)->funcdesc.lprgelemdescParam = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7535                                                               md->cArgs * sizeof(ELEMDESC));
7536         (*ppFuncDesc)->pParamDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7537                                               md->cArgs * sizeof(TLBParDesc));
7538         for(param = 0; param < md->cArgs; param++) {
7539             (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].tdesc.vt = md->ppdata[param].vt;
7540             (*ppFuncDesc)->pParamDesc[param].Name = SysAllocString(md->ppdata[param].szName);
7541         }
7542         (*ppFuncDesc)->helpcontext = 0;
7543         (*ppFuncDesc)->HelpStringContext = 0;
7544         (*ppFuncDesc)->HelpString = NULL;
7545         (*ppFuncDesc)->Entry = NULL;
7546         (*ppFuncDesc)->ctCustData = 0;
7547         (*ppFuncDesc)->pCustData = NULL;
7548         (*ppFuncDesc)->next = NULL;
7549         pTIIface->TypeAttr.cFuncs++;
7550         ppFuncDesc = &(*ppFuncDesc)->next;
7551     }
7552
7553     dump_TypeInfo(pTIIface);
7554
7555     pTypeLibImpl->pTypeInfo = pTIIface;
7556     pTypeLibImpl->TypeInfoCount++;
7557
7558     pTIClass = (ITypeInfoImpl*)ITypeInfo_Constructor();
7559     pTIClass->pTypeLib = pTypeLibImpl;
7560     pTIClass->index = 1;
7561     pTIClass->Name = NULL;
7562     pTIClass->dwHelpContext = -1;
7563     memset(&pTIClass->TypeAttr.guid, 0, sizeof(GUID));
7564     pTIClass->TypeAttr.lcid = lcid;
7565     pTIClass->TypeAttr.typekind = TKIND_COCLASS;
7566     pTIClass->TypeAttr.wMajorVerNum = 0;
7567     pTIClass->TypeAttr.wMinorVerNum = 0;
7568     pTIClass->TypeAttr.cbAlignment = 2;
7569     pTIClass->TypeAttr.cbSizeInstance = -1;
7570     pTIClass->TypeAttr.cbSizeVft = -1;
7571     pTIClass->TypeAttr.cFuncs = 0;
7572     pTIClass->TypeAttr.cImplTypes = 1;
7573     pTIClass->TypeAttr.cVars = 0;
7574     pTIClass->TypeAttr.wTypeFlags = 0;
7575
7576     pTIClass->impltypelist = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pTIClass->impltypelist));
7577     pTIClass->impltypelist->hRef = 0;
7578
7579     ref = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ref));
7580     ref->index = 0;
7581     ref->reference = 0;
7582     ref->pImpTLInfo = TLB_REF_INTERNAL;
7583     list_add_head(&pTypeLibImpl->ref_list, &ref->entry);
7584
7585     dump_TypeInfo(pTIClass);
7586
7587     pTIIface->next = pTIClass;
7588     pTypeLibImpl->TypeInfoCount++;
7589
7590     *pptinfo = (ITypeInfo*)pTIClass;
7591
7592     ITypeInfo_AddRef(*pptinfo);
7593     ITypeLib_Release((ITypeLib *)&pTypeLibImpl->lpVtbl);
7594
7595     return S_OK;
7596
7597 }
7598
7599 static HRESULT WINAPI ITypeComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
7600 {
7601     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7602
7603     return ITypeInfo_QueryInterface((ITypeInfo *)This, riid, ppv);
7604 }
7605
7606 static ULONG WINAPI ITypeComp_fnAddRef(ITypeComp * iface)
7607 {
7608     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7609
7610     return ITypeInfo_AddRef((ITypeInfo *)This);
7611 }
7612
7613 static ULONG WINAPI ITypeComp_fnRelease(ITypeComp * iface)
7614 {
7615     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7616
7617     return ITypeInfo_Release((ITypeInfo *)This);
7618 }
7619
7620 static HRESULT WINAPI ITypeComp_fnBind(
7621     ITypeComp * iface,
7622     OLECHAR * szName,
7623     ULONG lHash,
7624     WORD wFlags,
7625     ITypeInfo ** ppTInfo,
7626     DESCKIND * pDescKind,
7627     BINDPTR * pBindPtr)
7628 {
7629     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7630     const TLBFuncDesc *pFDesc;
7631     const TLBVarDesc *pVDesc;
7632     HRESULT hr = DISP_E_MEMBERNOTFOUND;
7633
7634     TRACE("(%s, %x, 0x%x, %p, %p, %p)\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
7635
7636     *pDescKind = DESCKIND_NONE;
7637     pBindPtr->lpfuncdesc = NULL;
7638     *ppTInfo = NULL;
7639
7640     for(pFDesc = This->funclist; pFDesc; pFDesc = pFDesc->next)
7641         if (!strcmpiW(pFDesc->Name, szName)) {
7642             if (!wFlags || (pFDesc->funcdesc.invkind & wFlags))
7643                 break;
7644             else
7645                 /* name found, but wrong flags */
7646                 hr = TYPE_E_TYPEMISMATCH;
7647         }
7648
7649     if (pFDesc)
7650     {
7651         HRESULT hr = TLB_AllocAndInitFuncDesc(
7652             &pFDesc->funcdesc,
7653             &pBindPtr->lpfuncdesc,
7654             This->TypeAttr.typekind == TKIND_DISPATCH);
7655         if (FAILED(hr))
7656             return hr;
7657         *pDescKind = DESCKIND_FUNCDESC;
7658         *ppTInfo = (ITypeInfo *)&This->lpVtbl;
7659         ITypeInfo_AddRef(*ppTInfo);
7660         return S_OK;
7661     } else {
7662         for(pVDesc = This->varlist; pVDesc; pVDesc = pVDesc->next) {
7663             if (!strcmpiW(pVDesc->Name, szName)) {
7664                 HRESULT hr = TLB_AllocAndInitVarDesc(&pVDesc->vardesc, &pBindPtr->lpvardesc);
7665                 if (FAILED(hr))
7666                     return hr;
7667                 *pDescKind = DESCKIND_VARDESC;
7668                 *ppTInfo = (ITypeInfo *)&This->lpVtbl;
7669                 ITypeInfo_AddRef(*ppTInfo);
7670                 return S_OK;
7671             }
7672         }
7673     }
7674     /* FIXME: search each inherited interface, not just the first */
7675     if (hr == DISP_E_MEMBERNOTFOUND && This->impltypelist) {
7676         /* recursive search */
7677         ITypeInfo *pTInfo;
7678         ITypeComp *pTComp;
7679         HRESULT hr;
7680         hr=ITypeInfo_GetRefTypeInfo((ITypeInfo *)&This->lpVtbl, This->impltypelist->hRef, &pTInfo);
7681         if (SUCCEEDED(hr))
7682         {
7683             hr = ITypeInfo_GetTypeComp(pTInfo,&pTComp);
7684             ITypeInfo_Release(pTInfo);
7685         }
7686         if (SUCCEEDED(hr))
7687         {
7688             hr = ITypeComp_Bind(pTComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
7689             ITypeComp_Release(pTComp);
7690             return hr;
7691         }
7692         WARN("Could not search inherited interface!\n");
7693     }
7694     WARN("did not find member with name %s, flags 0x%x!\n", debugstr_w(szName), wFlags);
7695     return hr;
7696 }
7697
7698 static HRESULT WINAPI ITypeComp_fnBindType(
7699     ITypeComp * iface,
7700     OLECHAR * szName,
7701     ULONG lHash,
7702     ITypeInfo ** ppTInfo,
7703     ITypeComp ** ppTComp)
7704 {
7705     TRACE("(%s, %x, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
7706
7707     /* strange behaviour (does nothing) but like the
7708      * original */
7709
7710     if (!ppTInfo || !ppTComp)
7711         return E_POINTER;
7712
7713     *ppTInfo = NULL;
7714     *ppTComp = NULL;
7715
7716     return S_OK;
7717 }
7718
7719 static const ITypeCompVtbl tcompvt =
7720 {
7721
7722     ITypeComp_fnQueryInterface,
7723     ITypeComp_fnAddRef,
7724     ITypeComp_fnRelease,
7725
7726     ITypeComp_fnBind,
7727     ITypeComp_fnBindType
7728 };