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