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