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