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