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