oleaut32/tests: Fix test failures and crash on Win9x/WinME.
[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     unsigned long  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     unsigned long  dwHelpContext;
1062     unsigned long  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 - 1);
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     default:
5878         *vt |= tdesc->vt;
5879         break;
5880     }
5881     return hr;
5882 }
5883
5884 /***********************************************************************
5885  *              DispCallFunc (OLEAUT32.@)
5886  *
5887  * Invokes a function of the specified calling convention, passing the
5888  * specified arguments and returns the result.
5889  *
5890  * PARAMS
5891  *  pvInstance  [I] Optional pointer to the instance whose function to invoke.
5892  *  oVft        [I] The offset in the vtable. See notes.
5893  *  cc          [I] Calling convention of the function to call.
5894  *  vtReturn    [I] The return type of the function.
5895  *  cActuals    [I] Number of parameters.
5896  *  prgvt       [I] The types of the parameters to pass. This is used for sizing only.
5897  *  prgpvarg    [I] The arguments to pass.
5898  *  pvargResult [O] The return value of the function. Can be NULL.
5899  *
5900  * RETURNS
5901  *  Success: S_OK.
5902  *  Failure: HRESULT code.
5903  *
5904  * NOTES
5905  *  The HRESULT return value of this function is not affected by the return
5906  *  value of the user supplied function, which is returned in pvargResult.
5907  *
5908  *  If pvInstance is NULL then a non-object function is to be called and oVft
5909  *  is the address of the function to call.
5910  *
5911  * The cc parameter can be one of the following values:
5912  *|CC_FASTCALL
5913  *|CC_CDECL
5914  *|CC_PASCAL
5915  *|CC_STDCALL
5916  *|CC_FPFASTCALL
5917  *|CC_SYSCALL
5918  *|CC_MPWCDECL
5919  *|CC_MPWPASCAL
5920  *
5921  */
5922 HRESULT WINAPI
5923 DispCallFunc(
5924     void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals,
5925     VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult)
5926 {
5927     int argsize, argspos;
5928     UINT i;
5929     DWORD *args;
5930     HRESULT hres;
5931
5932     TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
5933         pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
5934         pvargResult, V_VT(pvargResult));
5935
5936     argsize = 0;
5937     if (pvInstance)
5938         argsize++; /* for This pointer */
5939
5940     for (i=0;i<cActuals;i++)
5941     {
5942         TRACE("arg %u: type %d, size %d\n",i,prgvt[i],_dispargsize(prgvt[i]));
5943         dump_Variant(prgpvarg[i]);
5944         argsize += _dispargsize(prgvt[i]);
5945     }
5946     args = HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*argsize);
5947
5948     argspos = 0;
5949     if (pvInstance)
5950     {
5951         args[0] = (DWORD)pvInstance; /* the This pointer is always the first parameter */
5952         argspos++;
5953     }
5954
5955     for (i=0;i<cActuals;i++)
5956     {
5957         VARIANT *arg = prgpvarg[i];
5958         TRACE("Storing arg %u (%d as %d)\n",i,V_VT(arg),prgvt[i]);
5959         if (prgvt[i] == VT_VARIANT)
5960             memcpy(&args[argspos], arg, _dispargsize(prgvt[i]) * sizeof(DWORD));
5961         else
5962             memcpy(&args[argspos], &V_NONE(arg), _dispargsize(prgvt[i]) * sizeof(DWORD));
5963         argspos += _dispargsize(prgvt[i]);
5964     }
5965
5966     if (pvInstance)
5967     {
5968         FARPROC *vtable = *(FARPROC**)pvInstance;
5969         hres = _invoke(vtable[oVft/sizeof(void *)], cc, argsize, args);
5970     }
5971     else
5972         /* if we aren't invoking an object then the function pointer is stored
5973          * in oVft */
5974         hres = _invoke((FARPROC)oVft, cc, argsize, args);
5975
5976     if (pvargResult && (vtReturn != VT_EMPTY))
5977     {
5978         TRACE("Method returned 0x%08x\n",hres);
5979         V_VT(pvargResult) = vtReturn;
5980         V_UI4(pvargResult) = hres;
5981     }
5982
5983     HeapFree(GetProcessHeap(),0,args);
5984     return S_OK;
5985 }
5986
5987 #define INVBUF_ELEMENT_SIZE \
5988     (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *) + sizeof(VARTYPE))
5989 #define INVBUF_GET_ARG_ARRAY(buffer, params) (buffer)
5990 #define INVBUF_GET_MISSING_ARG_ARRAY(buffer, params) \
5991     ((VARIANTARG *)((char *)(buffer) + sizeof(VARIANTARG) * (params)))
5992 #define INVBUF_GET_ARG_PTR_ARRAY(buffer, params) \
5993     ((VARIANTARG **)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG)) * (params)))
5994 #define INVBUF_GET_ARG_TYPE_ARRAY(buffer, params) \
5995     ((VARTYPE *)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *)) * (params)))
5996
5997 static HRESULT WINAPI ITypeInfo_fnInvoke(
5998     ITypeInfo2 *iface,
5999     VOID  *pIUnk,
6000     MEMBERID memid,
6001     UINT16 wFlags,
6002     DISPPARAMS  *pDispParams,
6003     VARIANT  *pVarResult,
6004     EXCEPINFO  *pExcepInfo,
6005     UINT  *pArgErr)
6006 {
6007     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6008     int i;
6009     unsigned int var_index;
6010     TYPEKIND type_kind;
6011     HRESULT hres;
6012     const TLBFuncDesc *pFuncInfo;
6013
6014     TRACE("(%p)(%p,id=%d,flags=0x%08x,%p,%p,%p,%p)\n",
6015       This,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr
6016     );
6017
6018     if (!pDispParams)
6019     {
6020         ERR("NULL pDispParams not allowed\n");
6021         return E_INVALIDARG;
6022     }
6023
6024     dump_DispParms(pDispParams);
6025
6026     if (pDispParams->cNamedArgs > pDispParams->cArgs)
6027     {
6028         ERR("named argument array cannot be bigger than argument array (%d/%d)\n",
6029             pDispParams->cNamedArgs, pDispParams->cArgs);
6030         return E_INVALIDARG;
6031     }
6032
6033     /* we do this instead of using GetFuncDesc since it will return a fake
6034      * FUNCDESC for dispinterfaces and we want the real function description */
6035     for (pFuncInfo = This->funclist; pFuncInfo; pFuncInfo=pFuncInfo->next)
6036         if ((memid == pFuncInfo->funcdesc.memid) &&
6037             (wFlags & pFuncInfo->funcdesc.invkind))
6038             break;
6039
6040     if (pFuncInfo) {
6041         const FUNCDESC *func_desc = &pFuncInfo->funcdesc;
6042
6043         if (TRACE_ON(ole))
6044         {
6045             TRACE("invoking:\n");
6046             dump_TLBFuncDescOne(pFuncInfo);
6047         }
6048         
6049         switch (func_desc->funckind) {
6050         case FUNC_PUREVIRTUAL:
6051         case FUNC_VIRTUAL: {
6052             void *buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INVBUF_ELEMENT_SIZE * func_desc->cParams);
6053             VARIANT varresult;
6054             VARIANT retval; /* pointer for storing byref retvals in */
6055             VARIANTARG **prgpvarg = INVBUF_GET_ARG_PTR_ARRAY(buffer, func_desc->cParams);
6056             VARIANTARG *rgvarg = INVBUF_GET_ARG_ARRAY(buffer, func_desc->cParams);
6057             VARTYPE *rgvt = INVBUF_GET_ARG_TYPE_ARRAY(buffer, func_desc->cParams);
6058             UINT cNamedArgs = pDispParams->cNamedArgs;
6059             DISPID *rgdispidNamedArgs = pDispParams->rgdispidNamedArgs;
6060
6061             hres = S_OK;
6062
6063             if (func_desc->invkind & (INVOKE_PROPERTYPUT|INVOKE_PROPERTYPUTREF))
6064             {
6065                 if (!cNamedArgs || (rgdispidNamedArgs[0] != DISPID_PROPERTYPUT))
6066                 {
6067                     ERR("first named arg for property put invocation must be DISPID_PROPERTYPUT\n");
6068                     hres = DISP_E_PARAMNOTFOUND;
6069                     goto func_fail;
6070                 }
6071                 /* ignore the DISPID_PROPERTYPUT named argument from now on */
6072                 cNamedArgs--;
6073                 rgdispidNamedArgs++;
6074             }
6075
6076             if (func_desc->cParamsOpt < 0 && cNamedArgs)
6077             {
6078                 ERR("functions with the vararg attribute do not support named arguments\n");
6079                 hres = DISP_E_NONAMEDARGS;
6080                 goto func_fail;
6081             }
6082
6083             for (i = 0; i < func_desc->cParams; i++)
6084             {
6085                 TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc;
6086                 hres = typedescvt_to_variantvt((ITypeInfo *)iface, tdesc, &rgvt[i]);
6087                 if (FAILED(hres))
6088                     goto func_fail;
6089             }
6090
6091             TRACE("changing args\n");
6092             for (i = 0; i < func_desc->cParams; i++)
6093             {
6094                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
6095                 VARIANTARG *src_arg;
6096
6097                 if (cNamedArgs)
6098                 {
6099                     USHORT j;
6100                     src_arg = NULL;
6101                     for (j = 0; j < cNamedArgs; j++)
6102                         if (rgdispidNamedArgs[j] == i)
6103                         {
6104                             src_arg = &pDispParams->rgvarg[j];
6105                             break;
6106                         }
6107                 }
6108                 else
6109                     src_arg = i < pDispParams->cArgs ? &pDispParams->rgvarg[pDispParams->cArgs - 1 - i] : NULL;
6110
6111                 if (wParamFlags & PARAMFLAG_FRETVAL)
6112                 {
6113                     /* under most conditions the caller is not allowed to
6114                      * pass in a dispparam arg in the index of what would be
6115                      * the retval parameter. however, there is an exception
6116                      * where the extra parameter is used in an extra
6117                      * IDispatch::Invoke below */
6118                     if ((i < pDispParams->cArgs) &&
6119                         ((func_desc->cParams != 1) || !pVarResult ||
6120                          !(func_desc->invkind & INVOKE_PROPERTYGET)))
6121                     {
6122                         hres = DISP_E_BADPARAMCOUNT;
6123                         break;
6124                     }
6125
6126                     /* note: this check is placed so that if the caller passes
6127                      * in a VARIANTARG for the retval we just ignore it, like
6128                      * native does */
6129                     if (i == func_desc->cParams - 1)
6130                     {
6131                         VARIANTARG *arg;
6132                         arg = prgpvarg[i] = &rgvarg[i];
6133                         memset(arg, 0, sizeof(*arg));
6134                         V_VT(arg) = rgvt[i];
6135                         memset(&retval, 0, sizeof(retval));
6136                         V_BYREF(arg) = &retval;
6137                     }
6138                     else
6139                     {
6140                         ERR("[retval] parameter must be the last parameter of the method (%d/%d)\n", i, func_desc->cParams);
6141                         hres = E_UNEXPECTED;
6142                         break;
6143                     }
6144                 }
6145                 else if (src_arg)
6146                 {
6147                     dump_Variant(src_arg);
6148
6149                     if (rgvt[i] == VT_VARIANT)
6150                         hres = VariantCopy(&rgvarg[i], src_arg);
6151                     else if (rgvt[i] == (VT_VARIANT | VT_BYREF))
6152                     {
6153                         if (rgvt[i] == V_VT(src_arg))
6154                             V_VARIANTREF(&rgvarg[i]) = V_VARIANTREF(src_arg);
6155                         else
6156                         {
6157                             VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
6158                             hres = VariantCopy(&missing_arg[i], src_arg);
6159                             V_VARIANTREF(&rgvarg[i]) = &missing_arg[i];
6160                         }
6161                         V_VT(&rgvarg[i]) = rgvt[i];
6162                     }
6163                     else if (rgvt[i] == (VT_VARIANT | VT_ARRAY) && func_desc->cParamsOpt < 0 && i == func_desc->cParams-1)
6164                     {
6165                         SAFEARRAY *a;
6166                         SAFEARRAYBOUND bound;
6167                         VARIANT *v;
6168                         LONG j;
6169                         bound.lLbound = 0;
6170                         bound.cElements = pDispParams->cArgs-i;
6171                         if (!(a = SafeArrayCreate(VT_VARIANT, 1, &bound)))
6172                         {
6173                             ERR("SafeArrayCreate failed\n");
6174                             break;
6175                         }
6176                         hres = SafeArrayAccessData(a, (LPVOID)&v);
6177                         if (hres != S_OK)
6178                         {
6179                             ERR("SafeArrayAccessData failed with %x\n", hres);
6180                             break;
6181                         }
6182                         for (j = 0; j < bound.cElements; j++)
6183                             VariantCopy(&v[j], &pDispParams->rgvarg[pDispParams->cArgs - 1 - i - j]);
6184                         hres = SafeArrayUnaccessData(a);
6185                         if (hres != S_OK)
6186                         {
6187                             ERR("SafeArrayUnaccessData failed with %x\n", hres);
6188                             break;
6189                         }
6190                         V_ARRAY(&rgvarg[i]) = a;
6191                         V_VT(&rgvarg[i]) = rgvt[i];
6192                     }
6193                     else if ((rgvt[i] & VT_BYREF) && !V_ISBYREF(src_arg))
6194                     {
6195                         VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
6196                         V_VT(&missing_arg[i]) = V_VT(src_arg);
6197                         hres = VariantChangeType(&missing_arg[i], src_arg, 0, rgvt[i] & ~VT_BYREF);
6198                         V_BYREF(&rgvarg[i]) = &V_NONE(&missing_arg[i]);
6199                         V_VT(&rgvarg[i]) = rgvt[i];
6200                     }
6201                     else if ((rgvt[i] & VT_BYREF) && (rgvt[i] == V_VT(src_arg)))
6202                     {
6203                         V_BYREF(&rgvarg[i]) = V_BYREF(src_arg);
6204                         V_VT(&rgvarg[i]) = rgvt[i];
6205                     }
6206                     else
6207                     {
6208                         /* FIXME: this doesn't work for VT_BYREF arguments if
6209                          * they are not the same type as in the paramdesc */
6210                         V_VT(&rgvarg[i]) = V_VT(src_arg);
6211                         hres = VariantChangeType(&rgvarg[i], src_arg, 0, rgvt[i]);
6212                         V_VT(&rgvarg[i]) = rgvt[i];
6213                     }
6214
6215                     if (FAILED(hres))
6216                     {
6217                         ERR("failed to convert param %d to %s%s from %s%s\n", i,
6218                             debugstr_vt(rgvt[i]), debugstr_vf(rgvt[i]),
6219                             debugstr_VT(src_arg), debugstr_VF(src_arg));
6220                         break;
6221                     }
6222                     prgpvarg[i] = &rgvarg[i];
6223                 }
6224                 else if (wParamFlags & PARAMFLAG_FOPT)
6225                 {
6226                     VARIANTARG *arg;
6227                     arg = prgpvarg[i] = &rgvarg[i];
6228                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
6229                     {
6230                         hres = VariantCopy(arg, &func_desc->lprgelemdescParam[i].u.paramdesc.pparamdescex->varDefaultValue);
6231                         if (FAILED(hres))
6232                             break;
6233                     }
6234                     else
6235                     {
6236                         VARIANTARG *missing_arg;
6237                         /* if the function wants a pointer to a variant then
6238                          * set that up, otherwise just pass the VT_ERROR in
6239                          * the argument by value */
6240                         if (rgvt[i] & VT_BYREF)
6241                         {
6242                             missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams) + i;
6243                             V_VT(arg) = VT_VARIANT | VT_BYREF;
6244                             V_VARIANTREF(arg) = missing_arg;
6245                         }
6246                         else
6247                             missing_arg = arg;
6248                         V_VT(missing_arg) = VT_ERROR;
6249                         V_ERROR(missing_arg) = DISP_E_PARAMNOTFOUND;
6250                     }
6251                 }
6252                 else
6253                 {
6254                     hres = DISP_E_BADPARAMCOUNT;
6255                     break;
6256                 }
6257             }
6258             if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
6259
6260             /* VT_VOID is a special case for return types, so it is not
6261              * handled in the general function */
6262             if (func_desc->elemdescFunc.tdesc.vt == VT_VOID)
6263                 V_VT(&varresult) = VT_EMPTY;
6264             else
6265             {
6266                 V_VT(&varresult) = 0;
6267                 hres = typedescvt_to_variantvt((ITypeInfo *)iface, &func_desc->elemdescFunc.tdesc, &V_VT(&varresult));
6268                 if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
6269             }
6270
6271             hres = DispCallFunc(pIUnk, func_desc->oVft, func_desc->callconv,
6272                                 V_VT(&varresult), func_desc->cParams, rgvt,
6273                                 prgpvarg, &varresult);
6274
6275             for (i = 0; i < func_desc->cParams; i++)
6276             {
6277                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
6278                 if (wParamFlags & PARAMFLAG_FRETVAL)
6279                 {
6280                     if (TRACE_ON(ole))
6281                     {
6282                         TRACE("[retval] value: ");
6283                         dump_Variant(prgpvarg[i]);
6284                     }
6285
6286                     if (pVarResult)
6287                     {
6288                         VariantInit(pVarResult);
6289                         /* deref return value */
6290                         hres = VariantCopyInd(pVarResult, prgpvarg[i]);
6291                     }
6292
6293                     /* free data stored in varresult. Note that
6294                      * VariantClear doesn't do what we want because we are
6295                      * working with byref types. */
6296                     /* FIXME: clear safearrays, bstrs, records and
6297                      * variants here too */
6298                     if ((V_VT(prgpvarg[i]) == (VT_UNKNOWN | VT_BYREF)) ||
6299                          (V_VT(prgpvarg[i]) == (VT_DISPATCH | VT_BYREF)))
6300                     {
6301                         if(*V_UNKNOWNREF(prgpvarg[i]))
6302                             IUnknown_Release(*V_UNKNOWNREF(prgpvarg[i]));
6303                     }
6304                     break;
6305                 }
6306                 else if (i < pDispParams->cArgs)
6307                 {
6308                     if (wParamFlags & PARAMFLAG_FOUT)
6309                     {
6310                         VARIANTARG *arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - i];
6311
6312                         if ((rgvt[i] == VT_BYREF) && (V_VT(arg) != VT_BYREF))
6313                             hres = VariantChangeType(arg, &rgvarg[i], 0, V_VT(arg));
6314
6315                         if (FAILED(hres))
6316                         {
6317                             ERR("failed to convert param %d to vt %d\n", i,
6318                                 V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1 - i]));
6319                             break;
6320                         }
6321                     }
6322                     else if (V_VT(prgpvarg[i]) == (VT_VARIANT | VT_ARRAY) &&
6323                              func_desc->cParamsOpt < 0 &&
6324                              i == func_desc->cParams-1)
6325                     {
6326                         SAFEARRAY *a = V_ARRAY(prgpvarg[i]);
6327                         LONG j, ubound;
6328                         VARIANT *v;
6329                         hres = SafeArrayGetUBound(a, 1, &ubound);
6330                         if (hres != S_OK)
6331                         {
6332                             ERR("SafeArrayGetUBound failed with %x\n", hres);
6333                             break;
6334                         }
6335                         hres = SafeArrayAccessData(a, (LPVOID)&v);
6336                         if (hres != S_OK)
6337                         {
6338                             ERR("SafeArrayAccessData failed with %x\n", hres);
6339                             break;
6340                         }
6341                         for (j = 0; j <= ubound; j++)
6342                             VariantClear(&v[j]);
6343                         hres = SafeArrayUnaccessData(a);
6344                         if (hres != S_OK)
6345                         {
6346                             ERR("SafeArrayUnaccessData failed with %x\n", hres);
6347                             break;
6348                         }
6349                     }
6350                     VariantClear(&rgvarg[i]);
6351                 }
6352                 else if (wParamFlags & PARAMFLAG_FOPT)
6353                 {
6354                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
6355                         VariantClear(&rgvarg[i]);
6356                 }
6357             }
6358
6359             if ((V_VT(&varresult) == VT_ERROR) && FAILED(V_ERROR(&varresult)))
6360             {
6361                 WARN("invoked function failed with error 0x%08x\n", V_ERROR(&varresult));
6362                 hres = DISP_E_EXCEPTION;
6363                 if (pExcepInfo)
6364                 {
6365                     IErrorInfo *pErrorInfo;
6366                     pExcepInfo->scode = V_ERROR(&varresult);
6367                     if (GetErrorInfo(0, &pErrorInfo) == S_OK)
6368                     {
6369                         IErrorInfo_GetDescription(pErrorInfo, &pExcepInfo->bstrDescription);
6370                         IErrorInfo_GetHelpFile(pErrorInfo, &pExcepInfo->bstrHelpFile);
6371                         IErrorInfo_GetSource(pErrorInfo, &pExcepInfo->bstrSource);
6372                         IErrorInfo_GetHelpContext(pErrorInfo, &pExcepInfo->dwHelpContext);
6373
6374                         IErrorInfo_Release(pErrorInfo);
6375                     }
6376                 }
6377             }
6378             if (V_VT(&varresult) != VT_ERROR)
6379             {
6380                 TRACE("varresult value: ");
6381                 dump_Variant(&varresult);
6382
6383                 if (pVarResult)
6384                 {
6385                     VariantClear(pVarResult);
6386                     *pVarResult = varresult;
6387                 }
6388                 else
6389                     VariantClear(&varresult);
6390             }
6391
6392             if (SUCCEEDED(hres) && pVarResult && (func_desc->cParams == 1) &&
6393                 (func_desc->invkind & INVOKE_PROPERTYGET) &&
6394                 (func_desc->lprgelemdescParam[0].u.paramdesc.wParamFlags & PARAMFLAG_FRETVAL) &&
6395                 (pDispParams->cArgs != 0))
6396             {
6397                 if (V_VT(pVarResult) == VT_DISPATCH)
6398                 {
6399                     IDispatch *pDispatch = V_DISPATCH(pVarResult);
6400                     /* Note: not VariantClear; we still need the dispatch
6401                      * pointer to be valid */
6402                     VariantInit(pVarResult);
6403                     hres = IDispatch_Invoke(pDispatch, DISPID_VALUE, &IID_NULL,
6404                         GetSystemDefaultLCID(), INVOKE_PROPERTYGET,
6405                         pDispParams, pVarResult, pExcepInfo, pArgErr);
6406                     IDispatch_Release(pDispatch);
6407                 }
6408                 else
6409                 {
6410                     VariantClear(pVarResult);
6411                     hres = DISP_E_NOTACOLLECTION;
6412                 }
6413             }
6414
6415 func_fail:
6416             HeapFree(GetProcessHeap(), 0, buffer);
6417             break;
6418         }
6419         case FUNC_DISPATCH:  {
6420            IDispatch *disp;
6421
6422            hres = IUnknown_QueryInterface((LPUNKNOWN)pIUnk,&IID_IDispatch,(LPVOID*)&disp);
6423            if (SUCCEEDED(hres)) {
6424                FIXME("Calling Invoke in IDispatch iface. untested!\n");
6425                hres = IDispatch_Invoke(
6426                                      disp,memid,&IID_NULL,LOCALE_USER_DEFAULT,wFlags,pDispParams,
6427                                      pVarResult,pExcepInfo,pArgErr
6428                                      );
6429                if (FAILED(hres))
6430                    FIXME("IDispatch::Invoke failed with %08x. (Could be not a real error?)\n", hres);
6431                IDispatch_Release(disp);
6432            } else
6433                FIXME("FUNC_DISPATCH used on object without IDispatch iface?\n");
6434            break;
6435         }
6436         default:
6437             FIXME("Unknown function invocation type %d\n", func_desc->funckind);
6438             hres = E_FAIL;
6439             break;
6440         }
6441
6442         TRACE("-- 0x%08x\n", hres);
6443         return hres;
6444
6445     } else if(SUCCEEDED(hres = ITypeInfo2_GetVarIndexOfMemId(iface, memid, &var_index))) {
6446         VARDESC *var_desc;
6447
6448         hres = ITypeInfo2_GetVarDesc(iface, var_index, &var_desc);
6449         if(FAILED(hres)) return hres;
6450         
6451         FIXME("varseek: Found memid, but variable-based invoking not supported\n");
6452         dump_VARDESC(var_desc);
6453         ITypeInfo2_ReleaseVarDesc(iface, var_desc);
6454         return E_NOTIMPL;
6455     }
6456
6457     /* not found, look for it in inherited interfaces */
6458     ITypeInfo2_GetTypeKind(iface, &type_kind);
6459     if(type_kind == TKIND_INTERFACE || type_kind == TKIND_DISPATCH) {
6460         if(This->impltypelist) {
6461             /* recursive search */
6462             ITypeInfo *pTInfo;
6463             hres = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef, &pTInfo);
6464             if(SUCCEEDED(hres)){
6465                 hres = ITypeInfo_Invoke(pTInfo,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr);
6466                 ITypeInfo_Release(pTInfo);
6467                 return hres;
6468             }
6469             WARN("Could not search inherited interface!\n");
6470         }
6471     }
6472     ERR("did not find member id %d, flags 0x%x!\n", memid, wFlags);
6473     return DISP_E_MEMBERNOTFOUND;
6474 }
6475
6476 /* ITypeInfo::GetDocumentation
6477  *
6478  * Retrieves the documentation string, the complete Help file name and path,
6479  * and the context ID for the Help topic for a specified type description.
6480  *
6481  * (Can be tested by the Visual Basic Editor in Word for instance.)
6482  */
6483 static HRESULT WINAPI ITypeInfo_fnGetDocumentation( ITypeInfo2 *iface,
6484         MEMBERID memid, BSTR  *pBstrName, BSTR  *pBstrDocString,
6485         DWORD  *pdwHelpContext, BSTR  *pBstrHelpFile)
6486 {
6487     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6488     const TLBFuncDesc *pFDesc;
6489     const TLBVarDesc *pVDesc;
6490     TRACE("(%p) memid %d Name(%p) DocString(%p)"
6491           " HelpContext(%p) HelpFile(%p)\n",
6492         This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
6493     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
6494         if(pBstrName)
6495             *pBstrName=SysAllocString(This->Name);
6496         if(pBstrDocString)
6497             *pBstrDocString=SysAllocString(This->DocString);
6498         if(pdwHelpContext)
6499             *pdwHelpContext=This->dwHelpContext;
6500         if(pBstrHelpFile)
6501             *pBstrHelpFile=SysAllocString(This->DocString);/* FIXME */
6502         return S_OK;
6503     }else {/* for a member */
6504     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
6505         if(pFDesc->funcdesc.memid==memid){
6506           if(pBstrName)
6507             *pBstrName = SysAllocString(pFDesc->Name);
6508           if(pBstrDocString)
6509             *pBstrDocString=SysAllocString(pFDesc->HelpString);
6510           if(pdwHelpContext)
6511             *pdwHelpContext=pFDesc->helpcontext;
6512           return S_OK;
6513         }
6514     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
6515         if(pVDesc->vardesc.memid==memid){
6516             if(pBstrName)
6517               *pBstrName = SysAllocString(pVDesc->Name);
6518             if(pBstrDocString)
6519               *pBstrDocString=SysAllocString(pVDesc->HelpString);
6520             if(pdwHelpContext)
6521               *pdwHelpContext=pVDesc->HelpContext;
6522             return S_OK;
6523         }
6524     }
6525
6526     if(This->impltypelist &&
6527        (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
6528         /* recursive search */
6529         ITypeInfo *pTInfo;
6530         HRESULT result;
6531         result = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef,
6532                                         &pTInfo);
6533         if(SUCCEEDED(result)) {
6534             result = ITypeInfo_GetDocumentation(pTInfo, memid, pBstrName,
6535                 pBstrDocString, pdwHelpContext, pBstrHelpFile);
6536             ITypeInfo_Release(pTInfo);
6537             return result;
6538         }
6539         WARN("Could not search inherited interface!\n");
6540     }
6541
6542     WARN("member %d not found\n", memid);
6543     return TYPE_E_ELEMENTNOTFOUND;
6544 }
6545
6546 /*  ITypeInfo::GetDllEntry
6547  *
6548  * Retrieves a description or specification of an entry point for a function
6549  * in a DLL.
6550  */
6551 static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid,
6552         INVOKEKIND invKind, BSTR  *pBstrDllName, BSTR  *pBstrName,
6553         WORD  *pwOrdinal)
6554 {
6555     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6556     const TLBFuncDesc *pFDesc;
6557
6558     TRACE("(%p)->(memid %x, %d, %p, %p, %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
6559
6560     if (pBstrDllName) *pBstrDllName = NULL;
6561     if (pBstrName) *pBstrName = NULL;
6562     if (pwOrdinal) *pwOrdinal = 0;
6563
6564     if (This->TypeAttr.typekind != TKIND_MODULE)
6565         return TYPE_E_BADMODULEKIND;
6566
6567     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
6568         if(pFDesc->funcdesc.memid==memid){
6569             dump_TypeInfo(This);
6570             if (TRACE_ON(ole))
6571                 dump_TLBFuncDescOne(pFDesc);
6572
6573             if (pBstrDllName)
6574                 *pBstrDllName = SysAllocString(This->DllName);
6575
6576             if (HIWORD(pFDesc->Entry) && (pFDesc->Entry != (void*)-1)) {
6577                 if (pBstrName)
6578                     *pBstrName = SysAllocString(pFDesc->Entry);
6579                 if (pwOrdinal)
6580                     *pwOrdinal = -1;
6581                 return S_OK;
6582             }
6583             if (pBstrName)
6584                 *pBstrName = NULL;
6585             if (pwOrdinal)
6586                 *pwOrdinal = (DWORD)pFDesc->Entry;
6587             return S_OK;
6588         }
6589     return TYPE_E_ELEMENTNOTFOUND;
6590 }
6591
6592 /* internal function to make the inherited interfaces' methods appear
6593  * part of the interface */
6594 static HRESULT ITypeInfoImpl_GetDispatchRefTypeInfo( ITypeInfo *iface,
6595     HREFTYPE *hRefType, ITypeInfo  **ppTInfo)
6596 {
6597     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6598     HRESULT hr;
6599
6600     TRACE("%p, 0x%x\n", iface, *hRefType);
6601
6602     if (This->impltypelist && (*hRefType & DISPATCH_HREF_MASK))
6603     {
6604         ITypeInfo *pSubTypeInfo;
6605
6606         hr = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef, &pSubTypeInfo);
6607         if (FAILED(hr))
6608             return hr;
6609
6610         hr = ITypeInfoImpl_GetDispatchRefTypeInfo(pSubTypeInfo,
6611                                                   hRefType, ppTInfo);
6612         ITypeInfo_Release(pSubTypeInfo);
6613         if (SUCCEEDED(hr))
6614             return hr;
6615     }
6616     *hRefType -= DISPATCH_HREF_OFFSET;
6617
6618     if (!(*hRefType & DISPATCH_HREF_MASK))
6619         return ITypeInfo_GetRefTypeInfo(iface, *hRefType, ppTInfo);
6620     else
6621         return E_FAIL;
6622 }
6623
6624 /* ITypeInfo::GetRefTypeInfo
6625  *
6626  * If a type description references other type descriptions, it retrieves
6627  * the referenced type descriptions.
6628  */
6629 static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo(
6630         ITypeInfo2 *iface,
6631         HREFTYPE hRefType,
6632         ITypeInfo  **ppTInfo)
6633 {
6634     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6635     HRESULT result = E_FAIL;
6636
6637     if ((This->hreftype != -1) && (This->hreftype == hRefType))
6638     {
6639         *ppTInfo = (ITypeInfo *)&This->lpVtbl;
6640         ITypeInfo_AddRef(*ppTInfo);
6641         result = S_OK;
6642     }
6643     else if (hRefType == -1 &&
6644         (This->TypeAttr.typekind   == TKIND_DISPATCH) &&
6645         (This->TypeAttr.wTypeFlags &  TYPEFLAG_FDUAL))
6646     {
6647           /* when we meet a DUAL dispinterface, we must create the interface
6648           * version of it.
6649           */
6650           ITypeInfoImpl* pTypeInfoImpl = (ITypeInfoImpl*) ITypeInfo_Constructor();
6651
6652
6653           /* the interface version contains the same information as the dispinterface
6654            * copy the contents of the structs.
6655            */
6656           *pTypeInfoImpl = *This;
6657           pTypeInfoImpl->ref = 0;
6658
6659           /* change the type to interface */
6660           pTypeInfoImpl->TypeAttr.typekind = TKIND_INTERFACE;
6661
6662           *ppTInfo = (ITypeInfo*) pTypeInfoImpl;
6663
6664           /* we use data structures from This, so we need to keep a reference
6665            * to it to stop it being destroyed and signal to the new instance to
6666            * not free its data structures when it is destroyed */
6667           pTypeInfoImpl->no_free_data = TRUE;
6668           pTypeInfoImpl->next = This;
6669           ITypeInfo_AddRef((ITypeInfo*) This);
6670
6671           ITypeInfo_AddRef(*ppTInfo);
6672
6673           result = S_OK;
6674
6675     } else if ((hRefType != -1) && (hRefType & DISPATCH_HREF_MASK) &&
6676         (This->TypeAttr.typekind   == TKIND_DISPATCH) &&
6677         (This->TypeAttr.wTypeFlags &  TYPEFLAG_FDUAL))
6678     {
6679         HREFTYPE href_dispatch = hRefType;
6680         result = ITypeInfoImpl_GetDispatchRefTypeInfo((ITypeInfo *)iface, &href_dispatch, ppTInfo);
6681     } else {
6682         TLBRefType *ref_type;
6683         LIST_FOR_EACH_ENTRY(ref_type, &This->pTypeLib->ref_list, TLBRefType, entry)
6684         {
6685             if(ref_type->reference == hRefType)
6686                 break;
6687         }
6688         if(&ref_type->entry == &This->pTypeLib->ref_list)
6689         {
6690             FIXME("Can't find pRefType for ref %x\n", hRefType);
6691             goto end;
6692         }
6693         if(hRefType != -1) {
6694             ITypeLib *pTLib = NULL;
6695
6696             if(ref_type->pImpTLInfo == TLB_REF_INTERNAL) {
6697                 UINT Index;
6698                 result = ITypeInfo_GetContainingTypeLib(iface, &pTLib, &Index);
6699             } else {
6700                 if(ref_type->pImpTLInfo->pImpTypeLib) {
6701                     TRACE("typeinfo in imported typelib that is already loaded\n");
6702                     pTLib = (ITypeLib*)ref_type->pImpTLInfo->pImpTypeLib;
6703                     ITypeLib2_AddRef(pTLib);
6704                     result = S_OK;
6705                 } else {
6706                     TRACE("typeinfo in imported typelib that isn't already loaded\n");
6707                     result = LoadRegTypeLib( &ref_type->pImpTLInfo->guid,
6708                                              ref_type->pImpTLInfo->wVersionMajor,
6709                                              ref_type->pImpTLInfo->wVersionMinor,
6710                                              ref_type->pImpTLInfo->lcid,
6711                                              &pTLib);
6712
6713                     if(FAILED(result)) {
6714                         BSTR libnam=SysAllocString(ref_type->pImpTLInfo->name);
6715                         result=LoadTypeLib(libnam, &pTLib);
6716                         SysFreeString(libnam);
6717                     }
6718                     if(SUCCEEDED(result)) {
6719                         ref_type->pImpTLInfo->pImpTypeLib = (ITypeLibImpl*)pTLib;
6720                         ITypeLib2_AddRef(pTLib);
6721                     }
6722                 }
6723             }
6724             if(SUCCEEDED(result)) {
6725                 if(ref_type->index == TLB_REF_USE_GUID)
6726                     result = ITypeLib2_GetTypeInfoOfGuid(pTLib,
6727                                                          &ref_type->guid,
6728                                                          ppTInfo);
6729                 else
6730                     result = ITypeLib2_GetTypeInfo(pTLib, ref_type->index,
6731                                                    ppTInfo);
6732             }
6733             if (pTLib != NULL)
6734                 ITypeLib2_Release(pTLib);
6735         }
6736     }
6737
6738 end:
6739     TRACE("(%p) hreftype 0x%04x loaded %s (%p)\n", This, hRefType,
6740           SUCCEEDED(result)? "SUCCESS":"FAILURE", *ppTInfo);
6741     return result;
6742 }
6743
6744 /* ITypeInfo::AddressOfMember
6745  *
6746  * Retrieves the addresses of static functions or variables, such as those
6747  * defined in a DLL.
6748  */
6749 static HRESULT WINAPI ITypeInfo_fnAddressOfMember( ITypeInfo2 *iface,
6750         MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
6751 {
6752     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6753     HRESULT hr;
6754     BSTR dll, entry;
6755     WORD ordinal;
6756     HMODULE module;
6757
6758     TRACE("(%p)->(0x%x, 0x%x, %p)\n", This, memid, invKind, ppv);
6759
6760     hr = ITypeInfo_GetDllEntry(iface, memid, invKind, &dll, &entry, &ordinal);
6761     if (FAILED(hr))
6762         return hr;
6763
6764     module = LoadLibraryW(dll);
6765     if (!module)
6766     {
6767         ERR("couldn't load %s\n", debugstr_w(dll));
6768         SysFreeString(dll);
6769         SysFreeString(entry);
6770         return STG_E_FILENOTFOUND;
6771     }
6772     /* FIXME: store library somewhere where we can free it */
6773
6774     if (entry)
6775     {
6776         LPSTR entryA;
6777         INT len = WideCharToMultiByte(CP_ACP, 0, entry, -1, NULL, 0, NULL, NULL);
6778         entryA = HeapAlloc(GetProcessHeap(), 0, len);
6779         WideCharToMultiByte(CP_ACP, 0, entry, -1, entryA, len, NULL, NULL);
6780
6781         *ppv = GetProcAddress(module, entryA);
6782         if (!*ppv)
6783             ERR("function not found %s\n", debugstr_a(entryA));
6784
6785         HeapFree(GetProcessHeap(), 0, entryA);
6786     }
6787     else
6788     {
6789         *ppv = GetProcAddress(module, MAKEINTRESOURCEA(ordinal));
6790         if (!*ppv)
6791             ERR("function not found %d\n", ordinal);
6792     }
6793
6794     SysFreeString(dll);
6795     SysFreeString(entry);
6796
6797     if (!*ppv)
6798         return TYPE_E_DLLFUNCTIONNOTFOUND;
6799
6800     return S_OK;
6801 }
6802
6803 /* ITypeInfo::CreateInstance
6804  *
6805  * Creates a new instance of a type that describes a component object class
6806  * (coclass).
6807  */
6808 static HRESULT WINAPI ITypeInfo_fnCreateInstance( ITypeInfo2 *iface,
6809         IUnknown *pOuterUnk, REFIID riid, VOID  **ppvObj)
6810 {
6811     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6812     HRESULT hr;
6813     TYPEATTR *pTA;
6814
6815     TRACE("(%p)->(%p, %s, %p)\n", This, pOuterUnk, debugstr_guid(riid), ppvObj);
6816
6817     *ppvObj = NULL;
6818
6819     if(pOuterUnk)
6820     {
6821         WARN("Not able to aggregate\n");
6822         return CLASS_E_NOAGGREGATION;
6823     }
6824
6825     hr = ITypeInfo_GetTypeAttr(iface, &pTA);
6826     if(FAILED(hr)) return hr;
6827
6828     if(pTA->typekind != TKIND_COCLASS)
6829     {
6830         WARN("CreateInstance on typeinfo of type %x\n", pTA->typekind);
6831         hr = E_INVALIDARG;
6832         goto end;
6833     }
6834
6835     hr = S_FALSE;
6836     if(pTA->wTypeFlags & TYPEFLAG_FAPPOBJECT)
6837     {
6838         IUnknown *pUnk;
6839         hr = GetActiveObject(&pTA->guid, NULL, &pUnk);
6840         TRACE("GetActiveObject rets %08x\n", hr);
6841         if(hr == S_OK)
6842         {
6843             hr = IUnknown_QueryInterface(pUnk, riid, ppvObj);
6844             IUnknown_Release(pUnk);
6845         }
6846     }
6847
6848     if(hr != S_OK)
6849         hr = CoCreateInstance(&pTA->guid, NULL,
6850                               CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
6851                               riid, ppvObj);
6852
6853 end:
6854     ITypeInfo_ReleaseTypeAttr(iface, pTA);
6855     return hr;
6856 }
6857
6858 /* ITypeInfo::GetMops
6859  *
6860  * Retrieves marshalling information.
6861  */
6862 static HRESULT WINAPI ITypeInfo_fnGetMops( ITypeInfo2 *iface, MEMBERID memid,
6863                                 BSTR  *pBstrMops)
6864 {
6865     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6866     FIXME("(%p) stub!\n", This);
6867     return S_OK;
6868 }
6869
6870 /* ITypeInfo::GetContainingTypeLib
6871  *
6872  * Retrieves the containing type library and the index of the type description
6873  * within that type library.
6874  */
6875 static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( ITypeInfo2 *iface,
6876         ITypeLib  * *ppTLib, UINT  *pIndex)
6877 {
6878     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6879     
6880     /* If a pointer is null, we simply ignore it, the ATL in particular passes pIndex as 0 */
6881     if (pIndex) {
6882       *pIndex=This->index;
6883       TRACE("returning pIndex=%d\n", *pIndex);
6884     }
6885     
6886     if (ppTLib) {
6887       *ppTLib=(LPTYPELIB )(This->pTypeLib);
6888       ITypeLib2_AddRef(*ppTLib);
6889       TRACE("returning ppTLib=%p\n", *ppTLib);
6890     }
6891     
6892     return S_OK;
6893 }
6894
6895 /* ITypeInfo::ReleaseTypeAttr
6896  *
6897  * Releases a TYPEATTR previously returned by GetTypeAttr.
6898  *
6899  */
6900 static void WINAPI ITypeInfo_fnReleaseTypeAttr( ITypeInfo2 *iface,
6901         TYPEATTR* pTypeAttr)
6902 {
6903     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6904     TRACE("(%p)->(%p)\n", This, pTypeAttr);
6905     HeapFree(GetProcessHeap(), 0, pTypeAttr);
6906 }
6907
6908 /* ITypeInfo::ReleaseFuncDesc
6909  *
6910  * Releases a FUNCDESC previously returned by GetFuncDesc. *
6911  */
6912 static void WINAPI ITypeInfo_fnReleaseFuncDesc(
6913         ITypeInfo2 *iface,
6914         FUNCDESC *pFuncDesc)
6915 {
6916     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6917     SHORT i;
6918
6919     TRACE("(%p)->(%p)\n", This, pFuncDesc);
6920
6921     for (i = 0; i < pFuncDesc->cParams; i++)
6922         TLB_FreeElemDesc(&pFuncDesc->lprgelemdescParam[i]);
6923     TLB_FreeElemDesc(&pFuncDesc->elemdescFunc);
6924
6925     SysFreeString((BSTR)pFuncDesc);
6926 }
6927
6928 /* ITypeInfo::ReleaseVarDesc
6929  *
6930  * Releases a VARDESC previously returned by GetVarDesc.
6931  */
6932 static void WINAPI ITypeInfo_fnReleaseVarDesc( ITypeInfo2 *iface,
6933         VARDESC *pVarDesc)
6934 {
6935     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6936     TRACE("(%p)->(%p)\n", This, pVarDesc);
6937
6938     TLB_FreeElemDesc(&pVarDesc->elemdescVar);
6939     if (pVarDesc->varkind == VAR_CONST)
6940         VariantClear(pVarDesc->u.lpvarValue);
6941     SysFreeString((BSTR)pVarDesc);
6942 }
6943
6944 /* ITypeInfo2::GetTypeKind
6945  *
6946  * Returns the TYPEKIND enumeration quickly, without doing any allocations.
6947  *
6948  */
6949 static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo2 * iface,
6950     TYPEKIND *pTypeKind)
6951 {
6952     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6953     *pTypeKind=This->TypeAttr.typekind;
6954     TRACE("(%p) type 0x%0x\n", This,*pTypeKind);
6955     return S_OK;
6956 }
6957
6958 /* ITypeInfo2::GetTypeFlags
6959  *
6960  * Returns the type flags without any allocations. This returns a DWORD type
6961  * flag, which expands the type flags without growing the TYPEATTR (type
6962  * attribute).
6963  *
6964  */
6965 static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo2 *iface, ULONG *pTypeFlags)
6966 {
6967     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6968     *pTypeFlags=This->TypeAttr.wTypeFlags;
6969     TRACE("(%p) flags 0x%x\n", This,*pTypeFlags);
6970     return S_OK;
6971 }
6972
6973 /* ITypeInfo2::GetFuncIndexOfMemId
6974  * Binds to a specific member based on a known DISPID, where the member name
6975  * is not known (for example, when binding to a default member).
6976  *
6977  */
6978 static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo2 * iface,
6979     MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex)
6980 {
6981     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6982     const TLBFuncDesc *pFuncInfo;
6983     int i;
6984     HRESULT result;
6985
6986     for(i = 0, pFuncInfo = This->funclist; pFuncInfo; i++, pFuncInfo=pFuncInfo->next)
6987         if(memid == pFuncInfo->funcdesc.memid && (invKind & pFuncInfo->funcdesc.invkind))
6988             break;
6989     if(pFuncInfo) {
6990         *pFuncIndex = i;
6991         result = S_OK;
6992     } else
6993         result = TYPE_E_ELEMENTNOTFOUND;
6994
6995     TRACE("(%p) memid 0x%08x invKind 0x%04x -> %s\n", This,
6996           memid, invKind, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
6997     return result;
6998 }
6999
7000 /* TypeInfo2::GetVarIndexOfMemId
7001  *
7002  * Binds to a specific member based on a known DISPID, where the member name
7003  * is not known (for example, when binding to a default member).
7004  *
7005  */
7006 static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( ITypeInfo2 * iface,
7007     MEMBERID memid, UINT *pVarIndex)
7008 {
7009     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7010     TLBVarDesc *pVarInfo;
7011     int i;
7012     HRESULT result;
7013     for(i=0, pVarInfo=This->varlist; pVarInfo &&
7014             memid != pVarInfo->vardesc.memid; i++, pVarInfo=pVarInfo->next)
7015         ;
7016     if(pVarInfo) {
7017         *pVarIndex = i;
7018         result = S_OK;
7019     } else
7020         result = TYPE_E_ELEMENTNOTFOUND;
7021
7022     TRACE("(%p) memid 0x%08x -> %s\n", This,
7023           memid, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
7024     return result;
7025 }
7026
7027 /* ITypeInfo2::GetCustData
7028  *
7029  * Gets the custom data
7030  */
7031 static HRESULT WINAPI ITypeInfo2_fnGetCustData(
7032         ITypeInfo2 * iface,
7033         REFGUID guid,
7034         VARIANT *pVarVal)
7035 {
7036     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7037     TLBCustData *pCData;
7038
7039     for(pCData=This->pCustData; pCData; pCData = pCData->next)
7040         if( IsEqualIID(guid, &pCData->guid)) break;
7041
7042     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
7043
7044     if(pCData)
7045     {
7046         VariantInit( pVarVal);
7047         VariantCopy( pVarVal, &pCData->data);
7048         return S_OK;
7049     }
7050     return E_INVALIDARG;  /* FIXME: correct? */
7051 }
7052
7053 /* ITypeInfo2::GetFuncCustData
7054  *
7055  * Gets the custom data
7056  */
7057 static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData(
7058         ITypeInfo2 * iface,
7059         UINT index,
7060         REFGUID guid,
7061         VARIANT *pVarVal)
7062 {
7063     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7064     TLBCustData *pCData=NULL;
7065     TLBFuncDesc * pFDesc;
7066     UINT i;
7067     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
7068             pFDesc=pFDesc->next);
7069
7070     if(pFDesc)
7071         for(pCData=pFDesc->pCustData; pCData; pCData = pCData->next)
7072             if( IsEqualIID(guid, &pCData->guid)) break;
7073
7074     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
7075
7076     if(pCData){
7077         VariantInit( pVarVal);
7078         VariantCopy( pVarVal, &pCData->data);
7079         return S_OK;
7080     }
7081     return E_INVALIDARG;  /* FIXME: correct? */
7082 }
7083
7084 /* ITypeInfo2::GetParamCustData
7085  *
7086  * Gets the custom data
7087  */
7088 static HRESULT WINAPI ITypeInfo2_fnGetParamCustData(
7089         ITypeInfo2 * iface,
7090         UINT indexFunc,
7091         UINT indexParam,
7092         REFGUID guid,
7093         VARIANT *pVarVal)
7094 {
7095     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7096     TLBCustData *pCData=NULL;
7097     TLBFuncDesc * pFDesc;
7098     UINT i;
7099
7100     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,pFDesc=pFDesc->next);
7101
7102     if(pFDesc && indexParam<pFDesc->funcdesc.cParams)
7103         for(pCData=pFDesc->pParamDesc[indexParam].pCustData; pCData;
7104                 pCData = pCData->next)
7105             if( IsEqualIID(guid, &pCData->guid)) break;
7106
7107     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
7108
7109     if(pCData)
7110     {
7111         VariantInit( pVarVal);
7112         VariantCopy( pVarVal, &pCData->data);
7113         return S_OK;
7114     }
7115     return E_INVALIDARG;  /* FIXME: correct? */
7116 }
7117
7118 /* ITypeInfo2::GetVarCustData
7119  *
7120  * Gets the custom data
7121  */
7122 static HRESULT WINAPI ITypeInfo2_fnGetVarCustData(
7123         ITypeInfo2 * iface,
7124         UINT index,
7125         REFGUID guid,
7126         VARIANT *pVarVal)
7127 {
7128     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7129     TLBCustData *pCData=NULL;
7130     TLBVarDesc * pVDesc;
7131     UINT i;
7132
7133     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next);
7134
7135     if(pVDesc)
7136     {
7137       for(pCData=pVDesc->pCustData; pCData; pCData = pCData->next)
7138       {
7139         if( IsEqualIID(guid, &pCData->guid)) break;
7140       }
7141     }
7142
7143     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
7144
7145     if(pCData)
7146     {
7147         VariantInit( pVarVal);
7148         VariantCopy( pVarVal, &pCData->data);
7149         return S_OK;
7150     }
7151     return E_INVALIDARG;  /* FIXME: correct? */
7152 }
7153
7154 /* ITypeInfo2::GetImplCustData
7155  *
7156  * Gets the custom data
7157  */
7158 static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData(
7159         ITypeInfo2 * iface,
7160         UINT index,
7161         REFGUID guid,
7162         VARIANT *pVarVal)
7163 {
7164     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7165     TLBCustData *pCData=NULL;
7166     TLBImplType * pRDesc;
7167     UINT i;
7168
7169     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++, pRDesc=pRDesc->next);
7170
7171     if(pRDesc)
7172     {
7173       for(pCData=pRDesc->pCustData; pCData; pCData = pCData->next)
7174       {
7175         if( IsEqualIID(guid, &pCData->guid)) break;
7176       }
7177     }
7178
7179     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
7180
7181     if(pCData)
7182     {
7183         VariantInit( pVarVal);
7184         VariantCopy( pVarVal, &pCData->data);
7185         return S_OK;
7186     }
7187     return E_INVALIDARG;  /* FIXME: correct? */
7188 }
7189
7190 /* ITypeInfo2::GetDocumentation2
7191  *
7192  * Retrieves the documentation string, the complete Help file name and path,
7193  * the localization context to use, and the context ID for the library Help
7194  * topic in the Help file.
7195  *
7196  */
7197 static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2(
7198         ITypeInfo2 * iface,
7199         MEMBERID memid,
7200         LCID lcid,
7201         BSTR *pbstrHelpString,
7202         DWORD *pdwHelpStringContext,
7203         BSTR *pbstrHelpStringDll)
7204 {
7205     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7206     const TLBFuncDesc *pFDesc;
7207     const TLBVarDesc *pVDesc;
7208     TRACE("(%p) memid %d lcid(0x%x)  HelpString(%p) "
7209           "HelpStringContext(%p) HelpStringDll(%p)\n",
7210           This, memid, lcid, pbstrHelpString, pdwHelpStringContext,
7211           pbstrHelpStringDll );
7212     /* the help string should be obtained from the helpstringdll,
7213      * using the _DLLGetDocumentation function, based on the supplied
7214      * lcid. Nice to do sometime...
7215      */
7216     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
7217         if(pbstrHelpString)
7218             *pbstrHelpString=SysAllocString(This->Name);
7219         if(pdwHelpStringContext)
7220             *pdwHelpStringContext=This->dwHelpStringContext;
7221         if(pbstrHelpStringDll)
7222             *pbstrHelpStringDll=
7223                 SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
7224         return S_OK;
7225     }else {/* for a member */
7226     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
7227         if(pFDesc->funcdesc.memid==memid){
7228              if(pbstrHelpString)
7229                 *pbstrHelpString=SysAllocString(pFDesc->HelpString);
7230             if(pdwHelpStringContext)
7231                 *pdwHelpStringContext=pFDesc->HelpStringContext;
7232             if(pbstrHelpStringDll)
7233                 *pbstrHelpStringDll=
7234                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
7235         return S_OK;
7236     }
7237     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
7238         if(pVDesc->vardesc.memid==memid){
7239              if(pbstrHelpString)
7240                 *pbstrHelpString=SysAllocString(pVDesc->HelpString);
7241             if(pdwHelpStringContext)
7242                 *pdwHelpStringContext=pVDesc->HelpStringContext;
7243             if(pbstrHelpStringDll)
7244                 *pbstrHelpStringDll=
7245                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
7246             return S_OK;
7247         }
7248     }
7249     return TYPE_E_ELEMENTNOTFOUND;
7250 }
7251
7252 /* ITypeInfo2::GetAllCustData
7253  *
7254  * Gets all custom data items for the Type info.
7255  *
7256  */
7257 static HRESULT WINAPI ITypeInfo2_fnGetAllCustData(
7258         ITypeInfo2 * iface,
7259         CUSTDATA *pCustData)
7260 {
7261     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7262     TLBCustData *pCData;
7263     int i;
7264
7265     TRACE("(%p) returning %d items\n", This, This->ctCustData);
7266
7267     pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
7268     if(pCustData->prgCustData ){
7269         pCustData->cCustData=This->ctCustData;
7270         for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
7271             pCustData->prgCustData[i].guid=pCData->guid;
7272             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
7273         }
7274     }else{
7275         ERR(" OUT OF MEMORY!\n");
7276         return E_OUTOFMEMORY;
7277     }
7278     return S_OK;
7279 }
7280
7281 /* ITypeInfo2::GetAllFuncCustData
7282  *
7283  * Gets all custom data items for the specified Function
7284  *
7285  */
7286 static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData(
7287         ITypeInfo2 * iface,
7288         UINT index,
7289         CUSTDATA *pCustData)
7290 {
7291     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7292     TLBCustData *pCData;
7293     TLBFuncDesc * pFDesc;
7294     UINT i;
7295     TRACE("(%p) index %d\n", This, index);
7296     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
7297             pFDesc=pFDesc->next)
7298         ;
7299     if(pFDesc){
7300         pCustData->prgCustData =
7301             TLB_Alloc(pFDesc->ctCustData * sizeof(CUSTDATAITEM));
7302         if(pCustData->prgCustData ){
7303             pCustData->cCustData=pFDesc->ctCustData;
7304             for(i=0, pCData=pFDesc->pCustData; pCData; i++,
7305                     pCData = pCData->next){
7306                 pCustData->prgCustData[i].guid=pCData->guid;
7307                 VariantCopy(& pCustData->prgCustData[i].varValue,
7308                         & pCData->data);
7309             }
7310         }else{
7311             ERR(" OUT OF MEMORY!\n");
7312             return E_OUTOFMEMORY;
7313         }
7314         return S_OK;
7315     }
7316     return TYPE_E_ELEMENTNOTFOUND;
7317 }
7318
7319 /* ITypeInfo2::GetAllParamCustData
7320  *
7321  * Gets all custom data items for the Functions
7322  *
7323  */
7324 static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo2 * iface,
7325     UINT indexFunc, UINT indexParam, CUSTDATA *pCustData)
7326 {
7327     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7328     TLBCustData *pCData=NULL;
7329     TLBFuncDesc * pFDesc;
7330     UINT i;
7331     TRACE("(%p) index %d\n", This, indexFunc);
7332     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,
7333             pFDesc=pFDesc->next)
7334         ;
7335     if(pFDesc && indexParam<pFDesc->funcdesc.cParams){
7336         pCustData->prgCustData =
7337             TLB_Alloc(pFDesc->pParamDesc[indexParam].ctCustData *
7338                     sizeof(CUSTDATAITEM));
7339         if(pCustData->prgCustData ){
7340             pCustData->cCustData=pFDesc->pParamDesc[indexParam].ctCustData;
7341             for(i=0, pCData=pFDesc->pParamDesc[indexParam].pCustData;
7342                     pCData; i++, pCData = pCData->next){
7343                 pCustData->prgCustData[i].guid=pCData->guid;
7344                 VariantCopy(& pCustData->prgCustData[i].varValue,
7345                         & pCData->data);
7346             }
7347         }else{
7348             ERR(" OUT OF MEMORY!\n");
7349             return E_OUTOFMEMORY;
7350         }
7351         return S_OK;
7352     }
7353     return TYPE_E_ELEMENTNOTFOUND;
7354 }
7355
7356 /* ITypeInfo2::GetAllVarCustData
7357  *
7358  * Gets all custom data items for the specified Variable
7359  *
7360  */
7361 static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo2 * iface,
7362     UINT index, CUSTDATA *pCustData)
7363 {
7364     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7365     TLBCustData *pCData;
7366     TLBVarDesc * pVDesc;
7367     UINT i;
7368     TRACE("(%p) index %d\n", This, index);
7369     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++,
7370             pVDesc=pVDesc->next)
7371         ;
7372     if(pVDesc){
7373         pCustData->prgCustData =
7374             TLB_Alloc(pVDesc->ctCustData * sizeof(CUSTDATAITEM));
7375         if(pCustData->prgCustData ){
7376             pCustData->cCustData=pVDesc->ctCustData;
7377             for(i=0, pCData=pVDesc->pCustData; pCData; i++,
7378                     pCData = pCData->next){
7379                 pCustData->prgCustData[i].guid=pCData->guid;
7380                 VariantCopy(& pCustData->prgCustData[i].varValue,
7381                         & pCData->data);
7382             }
7383         }else{
7384             ERR(" OUT OF MEMORY!\n");
7385             return E_OUTOFMEMORY;
7386         }
7387         return S_OK;
7388     }
7389     return TYPE_E_ELEMENTNOTFOUND;
7390 }
7391
7392 /* ITypeInfo2::GetAllImplCustData
7393  *
7394  * Gets all custom data items for the specified implementation type
7395  *
7396  */
7397 static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData(
7398         ITypeInfo2 * iface,
7399         UINT index,
7400         CUSTDATA *pCustData)
7401 {
7402     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7403     TLBCustData *pCData;
7404     TLBImplType * pRDesc;
7405     UINT i;
7406     TRACE("(%p) index %d\n", This, index);
7407     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++,
7408             pRDesc=pRDesc->next)
7409         ;
7410     if(pRDesc){
7411         pCustData->prgCustData =
7412             TLB_Alloc(pRDesc->ctCustData * sizeof(CUSTDATAITEM));
7413         if(pCustData->prgCustData ){
7414             pCustData->cCustData=pRDesc->ctCustData;
7415             for(i=0, pCData=pRDesc->pCustData; pCData; i++,
7416                     pCData = pCData->next){
7417                 pCustData->prgCustData[i].guid=pCData->guid;
7418                 VariantCopy(& pCustData->prgCustData[i].varValue,
7419                         & pCData->data);
7420             }
7421         }else{
7422             ERR(" OUT OF MEMORY!\n");
7423             return E_OUTOFMEMORY;
7424         }
7425         return S_OK;
7426     }
7427     return TYPE_E_ELEMENTNOTFOUND;
7428 }
7429
7430 static const ITypeInfo2Vtbl tinfvt =
7431 {
7432
7433     ITypeInfo_fnQueryInterface,
7434     ITypeInfo_fnAddRef,
7435     ITypeInfo_fnRelease,
7436
7437     ITypeInfo_fnGetTypeAttr,
7438     ITypeInfo_fnGetTypeComp,
7439     ITypeInfo_fnGetFuncDesc,
7440     ITypeInfo_fnGetVarDesc,
7441     ITypeInfo_fnGetNames,
7442     ITypeInfo_fnGetRefTypeOfImplType,
7443     ITypeInfo_fnGetImplTypeFlags,
7444     ITypeInfo_fnGetIDsOfNames,
7445     ITypeInfo_fnInvoke,
7446     ITypeInfo_fnGetDocumentation,
7447     ITypeInfo_fnGetDllEntry,
7448     ITypeInfo_fnGetRefTypeInfo,
7449     ITypeInfo_fnAddressOfMember,
7450     ITypeInfo_fnCreateInstance,
7451     ITypeInfo_fnGetMops,
7452     ITypeInfo_fnGetContainingTypeLib,
7453     ITypeInfo_fnReleaseTypeAttr,
7454     ITypeInfo_fnReleaseFuncDesc,
7455     ITypeInfo_fnReleaseVarDesc,
7456
7457     ITypeInfo2_fnGetTypeKind,
7458     ITypeInfo2_fnGetTypeFlags,
7459     ITypeInfo2_fnGetFuncIndexOfMemId,
7460     ITypeInfo2_fnGetVarIndexOfMemId,
7461     ITypeInfo2_fnGetCustData,
7462     ITypeInfo2_fnGetFuncCustData,
7463     ITypeInfo2_fnGetParamCustData,
7464     ITypeInfo2_fnGetVarCustData,
7465     ITypeInfo2_fnGetImplTypeCustData,
7466     ITypeInfo2_fnGetDocumentation2,
7467     ITypeInfo2_fnGetAllCustData,
7468     ITypeInfo2_fnGetAllFuncCustData,
7469     ITypeInfo2_fnGetAllParamCustData,
7470     ITypeInfo2_fnGetAllVarCustData,
7471     ITypeInfo2_fnGetAllImplTypeCustData,
7472 };
7473
7474 /******************************************************************************
7475  * CreateDispTypeInfo [OLEAUT32.31]
7476  *
7477  * Build type information for an object so it can be called through an
7478  * IDispatch interface.
7479  *
7480  * RETURNS
7481  *  Success: S_OK. pptinfo contains the created ITypeInfo object.
7482  *  Failure: E_INVALIDARG, if one or more arguments is invalid.
7483  *
7484  * NOTES
7485  *  This call allows an objects methods to be accessed through IDispatch, by
7486  *  building an ITypeInfo object that IDispatch can use to call through.
7487  */
7488 HRESULT WINAPI CreateDispTypeInfo(
7489         INTERFACEDATA *pidata, /* [I] Description of the interface to build type info for */
7490         LCID lcid, /* [I] Locale Id */
7491         ITypeInfo **pptinfo) /* [O] Destination for created ITypeInfo object */
7492 {
7493     ITypeInfoImpl *pTIClass, *pTIIface;
7494     ITypeLibImpl *pTypeLibImpl;
7495     unsigned int param, func;
7496     TLBFuncDesc **ppFuncDesc;
7497     TLBRefType *ref;
7498
7499     TRACE("\n");
7500     pTypeLibImpl = TypeLibImpl_Constructor();
7501     if (!pTypeLibImpl) return E_FAIL;
7502
7503     pTIIface = (ITypeInfoImpl*)ITypeInfo_Constructor();
7504     pTIIface->pTypeLib = pTypeLibImpl;
7505     pTIIface->index = 0;
7506     pTIIface->Name = NULL;
7507     pTIIface->dwHelpContext = -1;
7508     memset(&pTIIface->TypeAttr.guid, 0, sizeof(GUID));
7509     pTIIface->TypeAttr.lcid = lcid;
7510     pTIIface->TypeAttr.typekind = TKIND_INTERFACE;
7511     pTIIface->TypeAttr.wMajorVerNum = 0;
7512     pTIIface->TypeAttr.wMinorVerNum = 0;
7513     pTIIface->TypeAttr.cbAlignment = 2;
7514     pTIIface->TypeAttr.cbSizeInstance = -1;
7515     pTIIface->TypeAttr.cbSizeVft = -1;
7516     pTIIface->TypeAttr.cFuncs = 0;
7517     pTIIface->TypeAttr.cImplTypes = 0;
7518     pTIIface->TypeAttr.cVars = 0;
7519     pTIIface->TypeAttr.wTypeFlags = 0;
7520
7521     ppFuncDesc = &pTIIface->funclist;
7522     for(func = 0; func < pidata->cMembers; func++) {
7523         METHODDATA *md = pidata->pmethdata + func;
7524         *ppFuncDesc = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppFuncDesc));
7525         (*ppFuncDesc)->Name = SysAllocString(md->szName);
7526         (*ppFuncDesc)->funcdesc.memid = md->dispid;
7527         (*ppFuncDesc)->funcdesc.lprgscode = NULL;
7528         (*ppFuncDesc)->funcdesc.funckind = FUNC_VIRTUAL;
7529         (*ppFuncDesc)->funcdesc.invkind = md->wFlags;
7530         (*ppFuncDesc)->funcdesc.callconv = md->cc;
7531         (*ppFuncDesc)->funcdesc.cParams = md->cArgs;
7532         (*ppFuncDesc)->funcdesc.cParamsOpt = 0;
7533         (*ppFuncDesc)->funcdesc.oVft = md->iMeth * sizeof(void *);
7534         (*ppFuncDesc)->funcdesc.cScodes = 0;
7535         (*ppFuncDesc)->funcdesc.wFuncFlags = 0;
7536         (*ppFuncDesc)->funcdesc.elemdescFunc.tdesc.vt = md->vtReturn;
7537         (*ppFuncDesc)->funcdesc.elemdescFunc.u.paramdesc.wParamFlags = PARAMFLAG_NONE;
7538         (*ppFuncDesc)->funcdesc.elemdescFunc.u.paramdesc.pparamdescex = NULL;
7539         (*ppFuncDesc)->funcdesc.lprgelemdescParam = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7540                                                               md->cArgs * sizeof(ELEMDESC));
7541         (*ppFuncDesc)->pParamDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7542                                               md->cArgs * sizeof(TLBParDesc));
7543         for(param = 0; param < md->cArgs; param++) {
7544             (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].tdesc.vt = md->ppdata[param].vt;
7545             (*ppFuncDesc)->pParamDesc[param].Name = SysAllocString(md->ppdata[param].szName);
7546         }
7547         (*ppFuncDesc)->helpcontext = 0;
7548         (*ppFuncDesc)->HelpStringContext = 0;
7549         (*ppFuncDesc)->HelpString = NULL;
7550         (*ppFuncDesc)->Entry = NULL;
7551         (*ppFuncDesc)->ctCustData = 0;
7552         (*ppFuncDesc)->pCustData = NULL;
7553         (*ppFuncDesc)->next = NULL;
7554         pTIIface->TypeAttr.cFuncs++;
7555         ppFuncDesc = &(*ppFuncDesc)->next;
7556     }
7557
7558     dump_TypeInfo(pTIIface);
7559
7560     pTypeLibImpl->pTypeInfo = pTIIface;
7561     pTypeLibImpl->TypeInfoCount++;
7562
7563     pTIClass = (ITypeInfoImpl*)ITypeInfo_Constructor();
7564     pTIClass->pTypeLib = pTypeLibImpl;
7565     pTIClass->index = 1;
7566     pTIClass->Name = NULL;
7567     pTIClass->dwHelpContext = -1;
7568     memset(&pTIClass->TypeAttr.guid, 0, sizeof(GUID));
7569     pTIClass->TypeAttr.lcid = lcid;
7570     pTIClass->TypeAttr.typekind = TKIND_COCLASS;
7571     pTIClass->TypeAttr.wMajorVerNum = 0;
7572     pTIClass->TypeAttr.wMinorVerNum = 0;
7573     pTIClass->TypeAttr.cbAlignment = 2;
7574     pTIClass->TypeAttr.cbSizeInstance = -1;
7575     pTIClass->TypeAttr.cbSizeVft = -1;
7576     pTIClass->TypeAttr.cFuncs = 0;
7577     pTIClass->TypeAttr.cImplTypes = 1;
7578     pTIClass->TypeAttr.cVars = 0;
7579     pTIClass->TypeAttr.wTypeFlags = 0;
7580
7581     pTIClass->impltypelist = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pTIClass->impltypelist));
7582     pTIClass->impltypelist->hRef = 0;
7583
7584     ref = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ref));
7585     ref->index = 0;
7586     ref->reference = 0;
7587     ref->pImpTLInfo = TLB_REF_INTERNAL;
7588     list_add_head(&pTypeLibImpl->ref_list, &ref->entry);
7589
7590     dump_TypeInfo(pTIClass);
7591
7592     pTIIface->next = pTIClass;
7593     pTypeLibImpl->TypeInfoCount++;
7594
7595     *pptinfo = (ITypeInfo*)pTIClass;
7596
7597     ITypeInfo_AddRef(*pptinfo);
7598     ITypeLib_Release((ITypeLib *)&pTypeLibImpl->lpVtbl);
7599
7600     return S_OK;
7601
7602 }
7603
7604 static HRESULT WINAPI ITypeComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
7605 {
7606     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7607
7608     return ITypeInfo_QueryInterface((ITypeInfo *)This, riid, ppv);
7609 }
7610
7611 static ULONG WINAPI ITypeComp_fnAddRef(ITypeComp * iface)
7612 {
7613     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7614
7615     return ITypeInfo_AddRef((ITypeInfo *)This);
7616 }
7617
7618 static ULONG WINAPI ITypeComp_fnRelease(ITypeComp * iface)
7619 {
7620     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7621
7622     return ITypeInfo_Release((ITypeInfo *)This);
7623 }
7624
7625 static HRESULT WINAPI ITypeComp_fnBind(
7626     ITypeComp * iface,
7627     OLECHAR * szName,
7628     ULONG lHash,
7629     WORD wFlags,
7630     ITypeInfo ** ppTInfo,
7631     DESCKIND * pDescKind,
7632     BINDPTR * pBindPtr)
7633 {
7634     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7635     const TLBFuncDesc *pFDesc;
7636     const TLBVarDesc *pVDesc;
7637     HRESULT hr = DISP_E_MEMBERNOTFOUND;
7638
7639     TRACE("(%s, %x, 0x%x, %p, %p, %p)\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
7640
7641     *pDescKind = DESCKIND_NONE;
7642     pBindPtr->lpfuncdesc = NULL;
7643     *ppTInfo = NULL;
7644
7645     for(pFDesc = This->funclist; pFDesc; pFDesc = pFDesc->next)
7646         if (!strcmpiW(pFDesc->Name, szName)) {
7647             if (!wFlags || (pFDesc->funcdesc.invkind & wFlags))
7648                 break;
7649             else
7650                 /* name found, but wrong flags */
7651                 hr = TYPE_E_TYPEMISMATCH;
7652         }
7653
7654     if (pFDesc)
7655     {
7656         HRESULT hr = TLB_AllocAndInitFuncDesc(
7657             &pFDesc->funcdesc,
7658             &pBindPtr->lpfuncdesc,
7659             This->TypeAttr.typekind == TKIND_DISPATCH);
7660         if (FAILED(hr))
7661             return hr;
7662         *pDescKind = DESCKIND_FUNCDESC;
7663         *ppTInfo = (ITypeInfo *)&This->lpVtbl;
7664         ITypeInfo_AddRef(*ppTInfo);
7665         return S_OK;
7666     } else {
7667         for(pVDesc = This->varlist; pVDesc; pVDesc = pVDesc->next) {
7668             if (!strcmpiW(pVDesc->Name, szName)) {
7669                 HRESULT hr = TLB_AllocAndInitVarDesc(&pVDesc->vardesc, &pBindPtr->lpvardesc);
7670                 if (FAILED(hr))
7671                     return hr;
7672                 *pDescKind = DESCKIND_VARDESC;
7673                 *ppTInfo = (ITypeInfo *)&This->lpVtbl;
7674                 ITypeInfo_AddRef(*ppTInfo);
7675                 return S_OK;
7676             }
7677         }
7678     }
7679     /* FIXME: search each inherited interface, not just the first */
7680     if (hr == DISP_E_MEMBERNOTFOUND && This->impltypelist) {
7681         /* recursive search */
7682         ITypeInfo *pTInfo;
7683         ITypeComp *pTComp;
7684         HRESULT hr;
7685         hr=ITypeInfo_GetRefTypeInfo((ITypeInfo *)&This->lpVtbl, This->impltypelist->hRef, &pTInfo);
7686         if (SUCCEEDED(hr))
7687         {
7688             hr = ITypeInfo_GetTypeComp(pTInfo,&pTComp);
7689             ITypeInfo_Release(pTInfo);
7690         }
7691         if (SUCCEEDED(hr))
7692         {
7693             hr = ITypeComp_Bind(pTComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
7694             ITypeComp_Release(pTComp);
7695             return hr;
7696         }
7697         WARN("Could not search inherited interface!\n");
7698     }
7699     WARN("did not find member with name %s, flags 0x%x!\n", debugstr_w(szName), wFlags);
7700     return hr;
7701 }
7702
7703 static HRESULT WINAPI ITypeComp_fnBindType(
7704     ITypeComp * iface,
7705     OLECHAR * szName,
7706     ULONG lHash,
7707     ITypeInfo ** ppTInfo,
7708     ITypeComp ** ppTComp)
7709 {
7710     TRACE("(%s, %x, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
7711
7712     /* strange behaviour (does nothing) but like the
7713      * original */
7714
7715     if (!ppTInfo || !ppTComp)
7716         return E_POINTER;
7717
7718     *ppTInfo = NULL;
7719     *ppTComp = NULL;
7720
7721     return S_OK;
7722 }
7723
7724 static const ITypeCompVtbl tcompvt =
7725 {
7726
7727     ITypeComp_fnQueryInterface,
7728     ITypeComp_fnAddRef,
7729     ITypeComp_fnRelease,
7730
7731     ITypeComp_fnBind,
7732     ITypeComp_fnBindType
7733 };