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