oleaut32: Improve MEMBERID assignment in ICreateTypeInfo::LayOut.
[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 DWORD CDECL call_method( void *func, int nb_args, const DWORD *args );
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                    "shll $2,%edx\n\t"
5722                    "jz 1f\n\t"
5723                    "subl %edx,%esp\n\t"
5724                    "andl $~15,%esp\n\t"
5725                    "movl 12(%ebp),%ecx\n\t"
5726                    "movl 16(%ebp),%esi\n\t"
5727                    "movl %esp,%edi\n\t"
5728                    "cld\n\t"
5729                    "rep; movsl\n"
5730                    "1:\tcall *8(%ebp)\n\t"
5731                    "leal -8(%ebp),%esp\n\t"
5732                    "popl %edi\n\t"
5733                    __ASM_CFI(".cfi_same_value %edi\n\t")
5734                    "popl %esi\n\t"
5735                    __ASM_CFI(".cfi_same_value %esi\n\t")
5736                    "popl %ebp\n\t"
5737                    __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
5738                    __ASM_CFI(".cfi_same_value %ebp\n\t")
5739                    "ret" )
5740
5741 /* ITypeInfo::Invoke
5742  *
5743  * Invokes a method, or accesses a property of an object, that implements the
5744  * interface described by the type description.
5745  */
5746 DWORD
5747 _invoke(FARPROC func,CALLCONV callconv, int nrargs, DWORD *args) {
5748     DWORD res;
5749
5750     if (TRACE_ON(ole)) {
5751         int i;
5752         TRACE("Calling %p(",func);
5753         for (i=0;i<min(nrargs,30);i++) TRACE("%08x,",args[i]);
5754         if (nrargs > 30) TRACE("...");
5755         TRACE(")\n");
5756     }
5757
5758     switch (callconv) {
5759     case CC_STDCALL:
5760     case CC_CDECL:
5761         res = call_method( func, nrargs, args );
5762         break;
5763     default:
5764         FIXME("unsupported calling convention %d\n",callconv);
5765         res = -1;
5766         break;
5767     }
5768     TRACE("returns %08x\n",res);
5769     return res;
5770 }
5771
5772 /* The size of the argument on the stack in DWORD units (in all x86 call
5773  * convetions the arguments on the stack are DWORD-aligned)
5774  */
5775 static int _dispargsize(VARTYPE vt)
5776 {
5777     switch (vt) {
5778     case VT_I8:
5779     case VT_UI8:
5780         return 8/sizeof(DWORD);
5781     case VT_R8:
5782         return sizeof(double)/sizeof(DWORD);
5783     case VT_DECIMAL:
5784         return (sizeof(DECIMAL)+3)/sizeof(DWORD);
5785     case VT_CY:
5786         return sizeof(CY)/sizeof(DWORD);
5787     case VT_DATE:
5788         return sizeof(DATE)/sizeof(DWORD);
5789     case VT_VARIANT:
5790         return (sizeof(VARIANT)+3)/sizeof(DWORD);
5791     case VT_RECORD:
5792         FIXME("VT_RECORD not implemented\n");
5793         return 1;
5794     default:
5795         return 1;
5796     }
5797 }
5798 #endif /* __i386__ */
5799
5800 static HRESULT userdefined_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
5801 {
5802     HRESULT hr = S_OK;
5803     ITypeInfo *tinfo2 = NULL;
5804     TYPEATTR *tattr = NULL;
5805
5806     hr = ITypeInfo_GetRefTypeInfo(tinfo, tdesc->u.hreftype, &tinfo2);
5807     if (hr)
5808     {
5809         ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED, "
5810             "hr = 0x%08x\n",
5811               tdesc->u.hreftype, hr);
5812         return hr;
5813     }
5814     hr = ITypeInfo_GetTypeAttr(tinfo2, &tattr);
5815     if (hr)
5816     {
5817         ERR("ITypeInfo_GetTypeAttr failed, hr = 0x%08x\n", hr);
5818         ITypeInfo_Release(tinfo2);
5819         return hr;
5820     }
5821
5822     switch (tattr->typekind)
5823     {
5824     case TKIND_ENUM:
5825         *vt |= VT_I4;
5826         break;
5827
5828     case TKIND_ALIAS:
5829         tdesc = &tattr->tdescAlias;
5830         hr = typedescvt_to_variantvt(tinfo2, &tattr->tdescAlias, vt);
5831         break;
5832
5833     case TKIND_INTERFACE:
5834         if (tattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE)
5835            *vt |= VT_DISPATCH;
5836         else
5837            *vt |= VT_UNKNOWN;
5838         break;
5839
5840     case TKIND_DISPATCH:
5841         *vt |= VT_DISPATCH;
5842         break;
5843
5844     case TKIND_COCLASS:
5845         *vt |= VT_DISPATCH;
5846         break;
5847
5848     case TKIND_RECORD:
5849         FIXME("TKIND_RECORD unhandled.\n");
5850         hr = E_NOTIMPL;
5851         break;
5852
5853     case TKIND_UNION:
5854         FIXME("TKIND_UNION unhandled.\n");
5855         hr = E_NOTIMPL;
5856         break;
5857
5858     default:
5859         FIXME("TKIND %d unhandled.\n",tattr->typekind);
5860         hr = E_NOTIMPL;
5861         break;
5862     }
5863     ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
5864     ITypeInfo_Release(tinfo2);
5865     return hr;
5866 }
5867
5868 static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
5869 {
5870     HRESULT hr = S_OK;
5871
5872     /* enforce only one level of pointer indirection */
5873     if (!(*vt & VT_BYREF) && !(*vt & VT_ARRAY) && (tdesc->vt == VT_PTR))
5874     {
5875         tdesc = tdesc->u.lptdesc;
5876
5877         /* munch VT_PTR -> VT_USERDEFINED(interface) into VT_UNKNOWN or
5878          * VT_DISPATCH and VT_PTR -> VT_PTR -> VT_USERDEFINED(interface) into 
5879          * VT_BYREF|VT_DISPATCH or VT_BYREF|VT_UNKNOWN */
5880         if ((tdesc->vt == VT_USERDEFINED) ||
5881             ((tdesc->vt == VT_PTR) && (tdesc->u.lptdesc->vt == VT_USERDEFINED)))
5882         {
5883             VARTYPE vt_userdefined = 0;
5884             const TYPEDESC *tdesc_userdefined = tdesc;
5885             if (tdesc->vt == VT_PTR)
5886             {
5887                 vt_userdefined = VT_BYREF;
5888                 tdesc_userdefined = tdesc->u.lptdesc;
5889             }
5890             hr = userdefined_to_variantvt(tinfo, tdesc_userdefined, &vt_userdefined);
5891             if ((hr == S_OK) && 
5892                 (((vt_userdefined & VT_TYPEMASK) == VT_UNKNOWN) ||
5893                  ((vt_userdefined & VT_TYPEMASK) == VT_DISPATCH)))
5894             {
5895                 *vt |= vt_userdefined;
5896                 return S_OK;
5897             }
5898         }
5899         *vt = VT_BYREF;
5900     }
5901
5902     switch (tdesc->vt)
5903     {
5904     case VT_HRESULT:
5905         *vt |= VT_ERROR;
5906         break;
5907     case VT_USERDEFINED:
5908         hr = userdefined_to_variantvt(tinfo, tdesc, vt);
5909         break;
5910     case VT_VOID:
5911     case VT_CARRAY:
5912     case VT_PTR:
5913     case VT_LPSTR:
5914     case VT_LPWSTR:
5915         ERR("cannot convert type %d into variant VT\n", tdesc->vt);
5916         hr = DISP_E_BADVARTYPE;
5917         break;
5918     case VT_SAFEARRAY:
5919         *vt |= VT_ARRAY;
5920         hr = typedescvt_to_variantvt(tinfo, tdesc->u.lptdesc, vt);
5921         break;
5922     case VT_INT:
5923         *vt |= VT_I4;
5924         break;
5925     case VT_UINT:
5926         *vt |= VT_UI4;
5927         break;
5928     default:
5929         *vt |= tdesc->vt;
5930         break;
5931     }
5932     return hr;
5933 }
5934
5935 /***********************************************************************
5936  *              DispCallFunc (OLEAUT32.@)
5937  *
5938  * Invokes a function of the specified calling convention, passing the
5939  * specified arguments and returns the result.
5940  *
5941  * PARAMS
5942  *  pvInstance  [I] Optional pointer to the instance whose function to invoke.
5943  *  oVft        [I] The offset in the vtable. See notes.
5944  *  cc          [I] Calling convention of the function to call.
5945  *  vtReturn    [I] The return type of the function.
5946  *  cActuals    [I] Number of parameters.
5947  *  prgvt       [I] The types of the parameters to pass. This is used for sizing only.
5948  *  prgpvarg    [I] The arguments to pass.
5949  *  pvargResult [O] The return value of the function. Can be NULL.
5950  *
5951  * RETURNS
5952  *  Success: S_OK.
5953  *  Failure: HRESULT code.
5954  *
5955  * NOTES
5956  *  The HRESULT return value of this function is not affected by the return
5957  *  value of the user supplied function, which is returned in pvargResult.
5958  *
5959  *  If pvInstance is NULL then a non-object function is to be called and oVft
5960  *  is the address of the function to call.
5961  *
5962  * The cc parameter can be one of the following values:
5963  *|CC_FASTCALL
5964  *|CC_CDECL
5965  *|CC_PASCAL
5966  *|CC_STDCALL
5967  *|CC_FPFASTCALL
5968  *|CC_SYSCALL
5969  *|CC_MPWCDECL
5970  *|CC_MPWPASCAL
5971  *
5972  */
5973 HRESULT WINAPI
5974 DispCallFunc(
5975     void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals,
5976     VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult)
5977 {
5978 #ifdef __i386__
5979     int argsize, argspos;
5980     UINT i;
5981     DWORD *args;
5982     HRESULT hres;
5983
5984     TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
5985         pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
5986         pvargResult, V_VT(pvargResult));
5987
5988     argsize = 0;
5989     if (pvInstance)
5990         argsize++; /* for This pointer */
5991
5992     for (i=0;i<cActuals;i++)
5993     {
5994         TRACE("arg %u: type %d, size %d\n",i,prgvt[i],_dispargsize(prgvt[i]));
5995         dump_Variant(prgpvarg[i]);
5996         argsize += _dispargsize(prgvt[i]);
5997     }
5998     args = HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*argsize);
5999
6000     argspos = 0;
6001     if (pvInstance)
6002     {
6003         args[0] = (DWORD)pvInstance; /* the This pointer is always the first parameter */
6004         argspos++;
6005     }
6006
6007     for (i=0;i<cActuals;i++)
6008     {
6009         VARIANT *arg = prgpvarg[i];
6010         TRACE("Storing arg %u (%d as %d)\n",i,V_VT(arg),prgvt[i]);
6011         if (prgvt[i] == VT_VARIANT)
6012             memcpy(&args[argspos], arg, _dispargsize(prgvt[i]) * sizeof(DWORD));
6013         else
6014             memcpy(&args[argspos], &V_NONE(arg), _dispargsize(prgvt[i]) * sizeof(DWORD));
6015         argspos += _dispargsize(prgvt[i]);
6016     }
6017
6018     if (pvInstance)
6019     {
6020         FARPROC *vtable = *(FARPROC**)pvInstance;
6021         hres = _invoke(vtable[oVft/sizeof(void *)], cc, argsize, args);
6022     }
6023     else
6024         /* if we aren't invoking an object then the function pointer is stored
6025          * in oVft */
6026         hres = _invoke((FARPROC)oVft, cc, argsize, args);
6027
6028     if (pvargResult && (vtReturn != VT_EMPTY))
6029     {
6030         TRACE("Method returned 0x%08x\n",hres);
6031         V_VT(pvargResult) = vtReturn;
6032         V_UI4(pvargResult) = hres;
6033     }
6034     HeapFree(GetProcessHeap(),0,args);
6035     return S_OK;
6036 #else
6037     FIXME( "(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d)): not implemented for this CPU\n",
6038            pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg, pvargResult, V_VT(pvargResult));
6039     return E_NOTIMPL;
6040 #endif
6041 }
6042
6043 #define INVBUF_ELEMENT_SIZE \
6044     (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *) + sizeof(VARTYPE))
6045 #define INVBUF_GET_ARG_ARRAY(buffer, params) (buffer)
6046 #define INVBUF_GET_MISSING_ARG_ARRAY(buffer, params) \
6047     ((VARIANTARG *)((char *)(buffer) + sizeof(VARIANTARG) * (params)))
6048 #define INVBUF_GET_ARG_PTR_ARRAY(buffer, params) \
6049     ((VARIANTARG **)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG)) * (params)))
6050 #define INVBUF_GET_ARG_TYPE_ARRAY(buffer, params) \
6051     ((VARTYPE *)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *)) * (params)))
6052
6053 static HRESULT WINAPI ITypeInfo_fnInvoke(
6054     ITypeInfo2 *iface,
6055     VOID  *pIUnk,
6056     MEMBERID memid,
6057     UINT16 wFlags,
6058     DISPPARAMS  *pDispParams,
6059     VARIANT  *pVarResult,
6060     EXCEPINFO  *pExcepInfo,
6061     UINT  *pArgErr)
6062 {
6063     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6064     int i;
6065     unsigned int var_index;
6066     TYPEKIND type_kind;
6067     HRESULT hres;
6068     const TLBFuncDesc *pFuncInfo;
6069
6070     TRACE("(%p)(%p,id=%d,flags=0x%08x,%p,%p,%p,%p)\n",
6071       This,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr
6072     );
6073
6074     if( This->TypeAttr.wTypeFlags & TYPEFLAG_FRESTRICTED )
6075         return DISP_E_MEMBERNOTFOUND;
6076
6077     if (!pDispParams)
6078     {
6079         ERR("NULL pDispParams not allowed\n");
6080         return E_INVALIDARG;
6081     }
6082
6083     dump_DispParms(pDispParams);
6084
6085     if (pDispParams->cNamedArgs > pDispParams->cArgs)
6086     {
6087         ERR("named argument array cannot be bigger than argument array (%d/%d)\n",
6088             pDispParams->cNamedArgs, pDispParams->cArgs);
6089         return E_INVALIDARG;
6090     }
6091
6092     /* we do this instead of using GetFuncDesc since it will return a fake
6093      * FUNCDESC for dispinterfaces and we want the real function description */
6094     for (pFuncInfo = This->funclist; pFuncInfo; pFuncInfo=pFuncInfo->next)
6095         if ((memid == pFuncInfo->funcdesc.memid) &&
6096             (wFlags & pFuncInfo->funcdesc.invkind) &&
6097             (pFuncInfo->funcdesc.wFuncFlags & FUNCFLAG_FRESTRICTED) == 0)
6098             break;
6099
6100     if (pFuncInfo) {
6101         const FUNCDESC *func_desc = &pFuncInfo->funcdesc;
6102
6103         if (TRACE_ON(ole))
6104         {
6105             TRACE("invoking:\n");
6106             dump_TLBFuncDescOne(pFuncInfo);
6107         }
6108         
6109         switch (func_desc->funckind) {
6110         case FUNC_PUREVIRTUAL:
6111         case FUNC_VIRTUAL: {
6112             void *buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INVBUF_ELEMENT_SIZE * func_desc->cParams);
6113             VARIANT varresult;
6114             VARIANT retval; /* pointer for storing byref retvals in */
6115             VARIANTARG **prgpvarg = INVBUF_GET_ARG_PTR_ARRAY(buffer, func_desc->cParams);
6116             VARIANTARG *rgvarg = INVBUF_GET_ARG_ARRAY(buffer, func_desc->cParams);
6117             VARTYPE *rgvt = INVBUF_GET_ARG_TYPE_ARRAY(buffer, func_desc->cParams);
6118             UINT cNamedArgs = pDispParams->cNamedArgs;
6119             DISPID *rgdispidNamedArgs = pDispParams->rgdispidNamedArgs;
6120             UINT vargs_converted=0;
6121
6122             hres = S_OK;
6123
6124             if (func_desc->invkind & (INVOKE_PROPERTYPUT|INVOKE_PROPERTYPUTREF))
6125             {
6126                 if (!cNamedArgs || (rgdispidNamedArgs[0] != DISPID_PROPERTYPUT))
6127                 {
6128                     ERR("first named arg for property put invocation must be DISPID_PROPERTYPUT\n");
6129                     hres = DISP_E_PARAMNOTFOUND;
6130                     goto func_fail;
6131                 }
6132             }
6133
6134             if (func_desc->cParamsOpt < 0 && cNamedArgs)
6135             {
6136                 ERR("functions with the vararg attribute do not support named arguments\n");
6137                 hres = DISP_E_NONAMEDARGS;
6138                 goto func_fail;
6139             }
6140
6141             for (i = 0; i < func_desc->cParams; i++)
6142             {
6143                 TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc;
6144                 hres = typedescvt_to_variantvt((ITypeInfo *)iface, tdesc, &rgvt[i]);
6145                 if (FAILED(hres))
6146                     goto func_fail;
6147             }
6148
6149             TRACE("changing args\n");
6150             for (i = 0; i < func_desc->cParams; i++)
6151             {
6152                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
6153                 VARIANTARG *src_arg;
6154
6155                 if (wParamFlags & PARAMFLAG_FLCID)
6156                 {
6157                     VARIANTARG *arg;
6158                     arg = prgpvarg[i] = &rgvarg[i];
6159                     V_VT(arg) = VT_I4;
6160                     V_I4(arg) = This->pTypeLib->lcid;
6161                     continue;
6162                 }
6163
6164                 src_arg = NULL;
6165
6166                 if (cNamedArgs)
6167                 {
6168                     USHORT j;
6169                     for (j = 0; j < cNamedArgs; j++)
6170                         if (rgdispidNamedArgs[j] == i || (i == func_desc->cParams-1 && rgdispidNamedArgs[j] == DISPID_PROPERTYPUT))
6171                         {
6172                             src_arg = &pDispParams->rgvarg[j];
6173                             break;
6174                         }
6175                 }
6176
6177                 if (!src_arg && vargs_converted + cNamedArgs < pDispParams->cArgs)
6178                 {
6179                     src_arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted];
6180                     vargs_converted++;
6181                 }
6182
6183                 if (wParamFlags & PARAMFLAG_FRETVAL)
6184                 {
6185                     /* under most conditions the caller is not allowed to
6186                      * pass in a dispparam arg in the index of what would be
6187                      * the retval parameter. however, there is an exception
6188                      * where the extra parameter is used in an extra
6189                      * IDispatch::Invoke below */
6190                     if ((i < pDispParams->cArgs) &&
6191                         ((func_desc->cParams != 1) || !pVarResult ||
6192                          !(func_desc->invkind & INVOKE_PROPERTYGET)))
6193                     {
6194                         hres = DISP_E_BADPARAMCOUNT;
6195                         break;
6196                     }
6197
6198                     /* note: this check is placed so that if the caller passes
6199                      * in a VARIANTARG for the retval we just ignore it, like
6200                      * native does */
6201                     if (i == func_desc->cParams - 1)
6202                     {
6203                         VARIANTARG *arg;
6204                         arg = prgpvarg[i] = &rgvarg[i];
6205                         memset(arg, 0, sizeof(*arg));
6206                         V_VT(arg) = rgvt[i];
6207                         memset(&retval, 0, sizeof(retval));
6208                         V_BYREF(arg) = &retval;
6209                     }
6210                     else
6211                     {
6212                         ERR("[retval] parameter must be the last parameter of the method (%d/%d)\n", i, func_desc->cParams);
6213                         hres = E_UNEXPECTED;
6214                         break;
6215                     }
6216                 }
6217                 else if (src_arg)
6218                 {
6219                     dump_Variant(src_arg);
6220
6221                     if (rgvt[i] == VT_VARIANT)
6222                         hres = VariantCopy(&rgvarg[i], src_arg);
6223                     else if (rgvt[i] == (VT_VARIANT | VT_BYREF))
6224                     {
6225                         if (rgvt[i] == V_VT(src_arg))
6226                             V_VARIANTREF(&rgvarg[i]) = V_VARIANTREF(src_arg);
6227                         else
6228                         {
6229                             VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
6230                             if (wParamFlags & PARAMFLAG_FIN)
6231                                 hres = VariantCopy(&missing_arg[i], src_arg);
6232                             V_VARIANTREF(&rgvarg[i]) = &missing_arg[i];
6233                         }
6234                         V_VT(&rgvarg[i]) = rgvt[i];
6235                     }
6236                     else if (rgvt[i] == (VT_VARIANT | VT_ARRAY) && func_desc->cParamsOpt < 0 && i == func_desc->cParams-1)
6237                     {
6238                         SAFEARRAY *a;
6239                         SAFEARRAYBOUND bound;
6240                         VARIANT *v;
6241                         LONG j;
6242                         bound.lLbound = 0;
6243                         bound.cElements = pDispParams->cArgs-i;
6244                         if (!(a = SafeArrayCreate(VT_VARIANT, 1, &bound)))
6245                         {
6246                             ERR("SafeArrayCreate failed\n");
6247                             break;
6248                         }
6249                         hres = SafeArrayAccessData(a, (LPVOID)&v);
6250                         if (hres != S_OK)
6251                         {
6252                             ERR("SafeArrayAccessData failed with %x\n", hres);
6253                             break;
6254                         }
6255                         for (j = 0; j < bound.cElements; j++)
6256                             VariantCopy(&v[j], &pDispParams->rgvarg[pDispParams->cArgs - 1 - i - j]);
6257                         hres = SafeArrayUnaccessData(a);
6258                         if (hres != S_OK)
6259                         {
6260                             ERR("SafeArrayUnaccessData failed with %x\n", hres);
6261                             break;
6262                         }
6263                         V_ARRAY(&rgvarg[i]) = a;
6264                         V_VT(&rgvarg[i]) = rgvt[i];
6265                     }
6266                     else if ((rgvt[i] & VT_BYREF) && !V_ISBYREF(src_arg))
6267                     {
6268                         VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
6269                         if (wParamFlags & PARAMFLAG_FIN)
6270                             hres = VariantChangeType(&missing_arg[i], src_arg, 0, rgvt[i] & ~VT_BYREF);
6271                         else
6272                             V_VT(&missing_arg[i]) = rgvt[i] & ~VT_BYREF;
6273                         V_BYREF(&rgvarg[i]) = &V_NONE(&missing_arg[i]);
6274                         V_VT(&rgvarg[i]) = rgvt[i];
6275                     }
6276                     else if ((rgvt[i] & VT_BYREF) && (rgvt[i] == V_VT(src_arg)))
6277                     {
6278                         V_BYREF(&rgvarg[i]) = V_BYREF(src_arg);
6279                         V_VT(&rgvarg[i]) = rgvt[i];
6280                     }
6281                     else
6282                     {
6283                         /* FIXME: this doesn't work for VT_BYREF arguments if
6284                          * they are not the same type as in the paramdesc */
6285                         V_VT(&rgvarg[i]) = V_VT(src_arg);
6286                         hres = VariantChangeType(&rgvarg[i], src_arg, 0, rgvt[i]);
6287                         V_VT(&rgvarg[i]) = rgvt[i];
6288                     }
6289
6290                     if (FAILED(hres))
6291                     {
6292                         ERR("failed to convert param %d to %s%s from %s%s\n", i,
6293                             debugstr_vt(rgvt[i]), debugstr_vf(rgvt[i]),
6294                             debugstr_VT(src_arg), debugstr_VF(src_arg));
6295                         break;
6296                     }
6297                     prgpvarg[i] = &rgvarg[i];
6298                 }
6299                 else if (wParamFlags & PARAMFLAG_FOPT)
6300                 {
6301                     VARIANTARG *arg;
6302                     arg = prgpvarg[i] = &rgvarg[i];
6303                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
6304                     {
6305                         hres = VariantCopy(arg, &func_desc->lprgelemdescParam[i].u.paramdesc.pparamdescex->varDefaultValue);
6306                         if (FAILED(hres))
6307                             break;
6308                     }
6309                     else
6310                     {
6311                         VARIANTARG *missing_arg;
6312                         /* if the function wants a pointer to a variant then
6313                          * set that up, otherwise just pass the VT_ERROR in
6314                          * the argument by value */
6315                         if (rgvt[i] & VT_BYREF)
6316                         {
6317                             missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams) + i;
6318                             V_VT(arg) = VT_VARIANT | VT_BYREF;
6319                             V_VARIANTREF(arg) = missing_arg;
6320                         }
6321                         else
6322                             missing_arg = arg;
6323                         V_VT(missing_arg) = VT_ERROR;
6324                         V_ERROR(missing_arg) = DISP_E_PARAMNOTFOUND;
6325                     }
6326                 }
6327                 else
6328                 {
6329                     hres = DISP_E_BADPARAMCOUNT;
6330                     break;
6331                 }
6332             }
6333             if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
6334
6335             /* VT_VOID is a special case for return types, so it is not
6336              * handled in the general function */
6337             if (func_desc->elemdescFunc.tdesc.vt == VT_VOID)
6338                 V_VT(&varresult) = VT_EMPTY;
6339             else
6340             {
6341                 V_VT(&varresult) = 0;
6342                 hres = typedescvt_to_variantvt((ITypeInfo *)iface, &func_desc->elemdescFunc.tdesc, &V_VT(&varresult));
6343                 if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
6344             }
6345
6346             hres = DispCallFunc(pIUnk, func_desc->oVft, func_desc->callconv,
6347                                 V_VT(&varresult), func_desc->cParams, rgvt,
6348                                 prgpvarg, &varresult);
6349
6350             vargs_converted = 0;
6351
6352             for (i = 0; i < func_desc->cParams; i++)
6353             {
6354                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
6355                 VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
6356
6357                 if (wParamFlags & PARAMFLAG_FLCID)
6358                     continue;
6359                 else if (wParamFlags & PARAMFLAG_FRETVAL)
6360                 {
6361                     if (TRACE_ON(ole))
6362                     {
6363                         TRACE("[retval] value: ");
6364                         dump_Variant(prgpvarg[i]);
6365                     }
6366
6367                     if (pVarResult)
6368                     {
6369                         VariantInit(pVarResult);
6370                         /* deref return value */
6371                         hres = VariantCopyInd(pVarResult, prgpvarg[i]);
6372                     }
6373
6374                     VARIANT_ClearInd(prgpvarg[i]);
6375                 }
6376                 else if (vargs_converted < pDispParams->cArgs)
6377                 {
6378                     VARIANTARG *arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted];
6379                     if (wParamFlags & PARAMFLAG_FOUT)
6380                     {
6381                         if ((rgvt[i] & VT_BYREF) && !(V_VT(arg) & VT_BYREF))
6382                         {
6383                             hres = VariantChangeType(arg, &rgvarg[i], 0, V_VT(arg));
6384
6385                             if (FAILED(hres))
6386                             {
6387                                 ERR("failed to convert param %d to vt %d\n", i,
6388                                     V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted]));
6389                                 break;
6390                             }
6391                         }
6392                     }
6393                     else if (V_VT(prgpvarg[i]) == (VT_VARIANT | VT_ARRAY) &&
6394                              func_desc->cParamsOpt < 0 &&
6395                              i == func_desc->cParams-1)
6396                     {
6397                         SAFEARRAY *a = V_ARRAY(prgpvarg[i]);
6398                         LONG j, ubound;
6399                         VARIANT *v;
6400                         hres = SafeArrayGetUBound(a, 1, &ubound);
6401                         if (hres != S_OK)
6402                         {
6403                             ERR("SafeArrayGetUBound failed with %x\n", hres);
6404                             break;
6405                         }
6406                         hres = SafeArrayAccessData(a, (LPVOID)&v);
6407                         if (hres != S_OK)
6408                         {
6409                             ERR("SafeArrayAccessData failed with %x\n", hres);
6410                             break;
6411                         }
6412                         for (j = 0; j <= ubound; j++)
6413                             VariantClear(&v[j]);
6414                         hres = SafeArrayUnaccessData(a);
6415                         if (hres != S_OK)
6416                         {
6417                             ERR("SafeArrayUnaccessData failed with %x\n", hres);
6418                             break;
6419                         }
6420                     }
6421                     VariantClear(&rgvarg[i]);
6422                     vargs_converted++;
6423                 }
6424                 else if (wParamFlags & PARAMFLAG_FOPT)
6425                 {
6426                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
6427                         VariantClear(&rgvarg[i]);
6428                 }
6429
6430                 VariantClear(&missing_arg[i]);
6431             }
6432
6433             if ((V_VT(&varresult) == VT_ERROR) && FAILED(V_ERROR(&varresult)))
6434             {
6435                 WARN("invoked function failed with error 0x%08x\n", V_ERROR(&varresult));
6436                 hres = DISP_E_EXCEPTION;
6437                 if (pExcepInfo)
6438                 {
6439                     IErrorInfo *pErrorInfo;
6440                     pExcepInfo->scode = V_ERROR(&varresult);
6441                     if (GetErrorInfo(0, &pErrorInfo) == S_OK)
6442                     {
6443                         IErrorInfo_GetDescription(pErrorInfo, &pExcepInfo->bstrDescription);
6444                         IErrorInfo_GetHelpFile(pErrorInfo, &pExcepInfo->bstrHelpFile);
6445                         IErrorInfo_GetSource(pErrorInfo, &pExcepInfo->bstrSource);
6446                         IErrorInfo_GetHelpContext(pErrorInfo, &pExcepInfo->dwHelpContext);
6447
6448                         IErrorInfo_Release(pErrorInfo);
6449                     }
6450                 }
6451             }
6452             if (V_VT(&varresult) != VT_ERROR)
6453             {
6454                 TRACE("varresult value: ");
6455                 dump_Variant(&varresult);
6456
6457                 if (pVarResult)
6458                 {
6459                     VariantClear(pVarResult);
6460                     *pVarResult = varresult;
6461                 }
6462                 else
6463                     VariantClear(&varresult);
6464             }
6465
6466             if (SUCCEEDED(hres) && pVarResult && (func_desc->cParams == 1) &&
6467                 (func_desc->invkind & INVOKE_PROPERTYGET) &&
6468                 (func_desc->lprgelemdescParam[0].u.paramdesc.wParamFlags & PARAMFLAG_FRETVAL) &&
6469                 (pDispParams->cArgs != 0))
6470             {
6471                 if (V_VT(pVarResult) == VT_DISPATCH)
6472                 {
6473                     IDispatch *pDispatch = V_DISPATCH(pVarResult);
6474                     /* Note: not VariantClear; we still need the dispatch
6475                      * pointer to be valid */
6476                     VariantInit(pVarResult);
6477                     hres = IDispatch_Invoke(pDispatch, DISPID_VALUE, &IID_NULL,
6478                         GetSystemDefaultLCID(), INVOKE_PROPERTYGET,
6479                         pDispParams, pVarResult, pExcepInfo, pArgErr);
6480                     IDispatch_Release(pDispatch);
6481                 }
6482                 else
6483                 {
6484                     VariantClear(pVarResult);
6485                     hres = DISP_E_NOTACOLLECTION;
6486                 }
6487             }
6488
6489 func_fail:
6490             HeapFree(GetProcessHeap(), 0, buffer);
6491             break;
6492         }
6493         case FUNC_DISPATCH:  {
6494            IDispatch *disp;
6495
6496            hres = IUnknown_QueryInterface((LPUNKNOWN)pIUnk,&IID_IDispatch,(LPVOID*)&disp);
6497            if (SUCCEEDED(hres)) {
6498                FIXME("Calling Invoke in IDispatch iface. untested!\n");
6499                hres = IDispatch_Invoke(
6500                                      disp,memid,&IID_NULL,LOCALE_USER_DEFAULT,wFlags,pDispParams,
6501                                      pVarResult,pExcepInfo,pArgErr
6502                                      );
6503                if (FAILED(hres))
6504                    FIXME("IDispatch::Invoke failed with %08x. (Could be not a real error?)\n", hres);
6505                IDispatch_Release(disp);
6506            } else
6507                FIXME("FUNC_DISPATCH used on object without IDispatch iface?\n");
6508            break;
6509         }
6510         default:
6511             FIXME("Unknown function invocation type %d\n", func_desc->funckind);
6512             hres = E_FAIL;
6513             break;
6514         }
6515
6516         TRACE("-- 0x%08x\n", hres);
6517         return hres;
6518
6519     } else if(SUCCEEDED(hres = ITypeInfo2_GetVarIndexOfMemId(iface, memid, &var_index))) {
6520         VARDESC *var_desc;
6521
6522         hres = ITypeInfo2_GetVarDesc(iface, var_index, &var_desc);
6523         if(FAILED(hres)) return hres;
6524         
6525         FIXME("varseek: Found memid, but variable-based invoking not supported\n");
6526         dump_VARDESC(var_desc);
6527         ITypeInfo2_ReleaseVarDesc(iface, var_desc);
6528         return E_NOTIMPL;
6529     }
6530
6531     /* not found, look for it in inherited interfaces */
6532     ITypeInfo2_GetTypeKind(iface, &type_kind);
6533     if(type_kind == TKIND_INTERFACE || type_kind == TKIND_DISPATCH) {
6534         if(This->impltypelist) {
6535             /* recursive search */
6536             ITypeInfo *pTInfo;
6537             hres = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef, &pTInfo);
6538             if(SUCCEEDED(hres)){
6539                 hres = ITypeInfo_Invoke(pTInfo,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr);
6540                 ITypeInfo_Release(pTInfo);
6541                 return hres;
6542             }
6543             WARN("Could not search inherited interface!\n");
6544         }
6545     }
6546     WARN("did not find member id %d, flags 0x%x!\n", memid, wFlags);
6547     return DISP_E_MEMBERNOTFOUND;
6548 }
6549
6550 /* ITypeInfo::GetDocumentation
6551  *
6552  * Retrieves the documentation string, the complete Help file name and path,
6553  * and the context ID for the Help topic for a specified type description.
6554  *
6555  * (Can be tested by the Visual Basic Editor in Word for instance.)
6556  */
6557 static HRESULT WINAPI ITypeInfo_fnGetDocumentation( ITypeInfo2 *iface,
6558         MEMBERID memid, BSTR  *pBstrName, BSTR  *pBstrDocString,
6559         DWORD  *pdwHelpContext, BSTR  *pBstrHelpFile)
6560 {
6561     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6562     const TLBFuncDesc *pFDesc;
6563     const TLBVarDesc *pVDesc;
6564     TRACE("(%p) memid %d Name(%p) DocString(%p)"
6565           " HelpContext(%p) HelpFile(%p)\n",
6566         This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
6567     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
6568         if(pBstrName)
6569             *pBstrName=SysAllocString(This->Name);
6570         if(pBstrDocString)
6571             *pBstrDocString=SysAllocString(This->DocString);
6572         if(pdwHelpContext)
6573             *pdwHelpContext=This->dwHelpContext;
6574         if(pBstrHelpFile)
6575             *pBstrHelpFile=SysAllocString(This->DocString);/* FIXME */
6576         return S_OK;
6577     }else {/* for a member */
6578     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
6579         if(pFDesc->funcdesc.memid==memid){
6580           if(pBstrName)
6581             *pBstrName = SysAllocString(pFDesc->Name);
6582           if(pBstrDocString)
6583             *pBstrDocString=SysAllocString(pFDesc->HelpString);
6584           if(pdwHelpContext)
6585             *pdwHelpContext=pFDesc->helpcontext;
6586           return S_OK;
6587         }
6588     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
6589         if(pVDesc->vardesc.memid==memid){
6590             if(pBstrName)
6591               *pBstrName = SysAllocString(pVDesc->Name);
6592             if(pBstrDocString)
6593               *pBstrDocString=SysAllocString(pVDesc->HelpString);
6594             if(pdwHelpContext)
6595               *pdwHelpContext=pVDesc->HelpContext;
6596             return S_OK;
6597         }
6598     }
6599
6600     if(This->impltypelist &&
6601        (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
6602         /* recursive search */
6603         ITypeInfo *pTInfo;
6604         HRESULT result;
6605         result = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef,
6606                                         &pTInfo);
6607         if(SUCCEEDED(result)) {
6608             result = ITypeInfo_GetDocumentation(pTInfo, memid, pBstrName,
6609                 pBstrDocString, pdwHelpContext, pBstrHelpFile);
6610             ITypeInfo_Release(pTInfo);
6611             return result;
6612         }
6613         WARN("Could not search inherited interface!\n");
6614     }
6615
6616     WARN("member %d not found\n", memid);
6617     return TYPE_E_ELEMENTNOTFOUND;
6618 }
6619
6620 /*  ITypeInfo::GetDllEntry
6621  *
6622  * Retrieves a description or specification of an entry point for a function
6623  * in a DLL.
6624  */
6625 static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid,
6626         INVOKEKIND invKind, BSTR  *pBstrDllName, BSTR  *pBstrName,
6627         WORD  *pwOrdinal)
6628 {
6629     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6630     const TLBFuncDesc *pFDesc;
6631
6632     TRACE("(%p)->(memid %x, %d, %p, %p, %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
6633
6634     if (pBstrDllName) *pBstrDllName = NULL;
6635     if (pBstrName) *pBstrName = NULL;
6636     if (pwOrdinal) *pwOrdinal = 0;
6637
6638     if (This->TypeAttr.typekind != TKIND_MODULE)
6639         return TYPE_E_BADMODULEKIND;
6640
6641     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
6642         if(pFDesc->funcdesc.memid==memid){
6643             dump_TypeInfo(This);
6644             if (TRACE_ON(ole))
6645                 dump_TLBFuncDescOne(pFDesc);
6646
6647             if (pBstrDllName)
6648                 *pBstrDllName = SysAllocString(This->DllName);
6649
6650             if (!IS_INTRESOURCE(pFDesc->Entry) && (pFDesc->Entry != (void*)-1)) {
6651                 if (pBstrName)
6652                     *pBstrName = SysAllocString(pFDesc->Entry);
6653                 if (pwOrdinal)
6654                     *pwOrdinal = -1;
6655                 return S_OK;
6656             }
6657             if (pBstrName)
6658                 *pBstrName = NULL;
6659             if (pwOrdinal)
6660                 *pwOrdinal = LOWORD(pFDesc->Entry);
6661             return S_OK;
6662         }
6663     return TYPE_E_ELEMENTNOTFOUND;
6664 }
6665
6666 /* internal function to make the inherited interfaces' methods appear
6667  * part of the interface */
6668 static HRESULT ITypeInfoImpl_GetDispatchRefTypeInfo( ITypeInfo *iface,
6669     HREFTYPE *hRefType, ITypeInfo  **ppTInfo)
6670 {
6671     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6672     HRESULT hr;
6673
6674     TRACE("%p, 0x%x\n", iface, *hRefType);
6675
6676     if (This->impltypelist && (*hRefType & DISPATCH_HREF_MASK))
6677     {
6678         ITypeInfo *pSubTypeInfo;
6679
6680         hr = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef, &pSubTypeInfo);
6681         if (FAILED(hr))
6682             return hr;
6683
6684         hr = ITypeInfoImpl_GetDispatchRefTypeInfo(pSubTypeInfo,
6685                                                   hRefType, ppTInfo);
6686         ITypeInfo_Release(pSubTypeInfo);
6687         if (SUCCEEDED(hr))
6688             return hr;
6689     }
6690     *hRefType -= DISPATCH_HREF_OFFSET;
6691
6692     if (!(*hRefType & DISPATCH_HREF_MASK))
6693         return ITypeInfo_GetRefTypeInfo(iface, *hRefType, ppTInfo);
6694     else
6695         return E_FAIL;
6696 }
6697
6698 /* ITypeInfo::GetRefTypeInfo
6699  *
6700  * If a type description references other type descriptions, it retrieves
6701  * the referenced type descriptions.
6702  */
6703 static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo(
6704         ITypeInfo2 *iface,
6705         HREFTYPE hRefType,
6706         ITypeInfo  **ppTInfo)
6707 {
6708     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6709     HRESULT result = E_FAIL;
6710
6711     if ((This->hreftype != -1) && (This->hreftype == hRefType))
6712     {
6713         *ppTInfo = (ITypeInfo *)&This->lpVtbl;
6714         ITypeInfo_AddRef(*ppTInfo);
6715         result = S_OK;
6716     }
6717     else if (hRefType == -1 &&
6718         (This->TypeAttr.typekind   == TKIND_DISPATCH) &&
6719         (This->TypeAttr.wTypeFlags &  TYPEFLAG_FDUAL))
6720     {
6721           /* when we meet a DUAL dispinterface, we must create the interface
6722           * version of it.
6723           */
6724           ITypeInfoImpl* pTypeInfoImpl = (ITypeInfoImpl*) ITypeInfo_Constructor();
6725
6726
6727           /* the interface version contains the same information as the dispinterface
6728            * copy the contents of the structs.
6729            */
6730           *pTypeInfoImpl = *This;
6731           pTypeInfoImpl->ref = 0;
6732
6733           /* change the type to interface */
6734           pTypeInfoImpl->TypeAttr.typekind = TKIND_INTERFACE;
6735
6736           *ppTInfo = (ITypeInfo*) pTypeInfoImpl;
6737
6738           /* the AddRef implicitly adds a reference to the parent typelib, which
6739            * stops the copied data from being destroyed until the new typeinfo's
6740            * refcount goes to zero, but we need to signal to the new instance to
6741            * not free its data structures when it is destroyed */
6742           pTypeInfoImpl->not_attached_to_typelib = TRUE;
6743
6744           ITypeInfo_AddRef(*ppTInfo);
6745
6746           result = S_OK;
6747
6748     } else if ((hRefType != -1) && (hRefType & DISPATCH_HREF_MASK) &&
6749         (This->TypeAttr.typekind   == TKIND_DISPATCH))
6750     {
6751         HREFTYPE href_dispatch = hRefType;
6752         result = ITypeInfoImpl_GetDispatchRefTypeInfo((ITypeInfo *)iface, &href_dispatch, ppTInfo);
6753     } else {
6754         TLBRefType *ref_type;
6755         LIST_FOR_EACH_ENTRY(ref_type, &This->pTypeLib->ref_list, TLBRefType, entry)
6756         {
6757             if(ref_type->reference == hRefType)
6758                 break;
6759         }
6760         if(&ref_type->entry == &This->pTypeLib->ref_list)
6761         {
6762             FIXME("Can't find pRefType for ref %x\n", hRefType);
6763             goto end;
6764         }
6765         if(hRefType != -1) {
6766             ITypeLib *pTLib = NULL;
6767
6768             if(ref_type->pImpTLInfo == TLB_REF_INTERNAL) {
6769                 UINT Index;
6770                 result = ITypeInfo_GetContainingTypeLib(iface, &pTLib, &Index);
6771             } else {
6772                 if(ref_type->pImpTLInfo->pImpTypeLib) {
6773                     TRACE("typeinfo in imported typelib that is already loaded\n");
6774                     pTLib = (ITypeLib*)ref_type->pImpTLInfo->pImpTypeLib;
6775                     ITypeLib2_AddRef(pTLib);
6776                     result = S_OK;
6777                 } else {
6778                     TRACE("typeinfo in imported typelib that isn't already loaded\n");
6779                     result = LoadRegTypeLib( &ref_type->pImpTLInfo->guid,
6780                                              ref_type->pImpTLInfo->wVersionMajor,
6781                                              ref_type->pImpTLInfo->wVersionMinor,
6782                                              ref_type->pImpTLInfo->lcid,
6783                                              &pTLib);
6784
6785                     if(FAILED(result)) {
6786                         BSTR libnam=SysAllocString(ref_type->pImpTLInfo->name);
6787                         result=LoadTypeLib(libnam, &pTLib);
6788                         SysFreeString(libnam);
6789                     }
6790                     if(SUCCEEDED(result)) {
6791                         ref_type->pImpTLInfo->pImpTypeLib = (ITypeLibImpl*)pTLib;
6792                         ITypeLib2_AddRef(pTLib);
6793                     }
6794                 }
6795             }
6796             if(SUCCEEDED(result)) {
6797                 if(ref_type->index == TLB_REF_USE_GUID)
6798                     result = ITypeLib2_GetTypeInfoOfGuid(pTLib,
6799                                                          &ref_type->guid,
6800                                                          ppTInfo);
6801                 else
6802                     result = ITypeLib2_GetTypeInfo(pTLib, ref_type->index,
6803                                                    ppTInfo);
6804             }
6805             if (pTLib != NULL)
6806                 ITypeLib2_Release(pTLib);
6807         }
6808     }
6809
6810 end:
6811     TRACE("(%p) hreftype 0x%04x loaded %s (%p)\n", This, hRefType,
6812           SUCCEEDED(result)? "SUCCESS":"FAILURE", *ppTInfo);
6813     return result;
6814 }
6815
6816 /* ITypeInfo::AddressOfMember
6817  *
6818  * Retrieves the addresses of static functions or variables, such as those
6819  * defined in a DLL.
6820  */
6821 static HRESULT WINAPI ITypeInfo_fnAddressOfMember( ITypeInfo2 *iface,
6822         MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
6823 {
6824     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6825     HRESULT hr;
6826     BSTR dll, entry;
6827     WORD ordinal;
6828     HMODULE module;
6829
6830     TRACE("(%p)->(0x%x, 0x%x, %p)\n", This, memid, invKind, ppv);
6831
6832     hr = ITypeInfo_GetDllEntry(iface, memid, invKind, &dll, &entry, &ordinal);
6833     if (FAILED(hr))
6834         return hr;
6835
6836     module = LoadLibraryW(dll);
6837     if (!module)
6838     {
6839         ERR("couldn't load %s\n", debugstr_w(dll));
6840         SysFreeString(dll);
6841         SysFreeString(entry);
6842         return STG_E_FILENOTFOUND;
6843     }
6844     /* FIXME: store library somewhere where we can free it */
6845
6846     if (entry)
6847     {
6848         LPSTR entryA;
6849         INT len = WideCharToMultiByte(CP_ACP, 0, entry, -1, NULL, 0, NULL, NULL);
6850         entryA = HeapAlloc(GetProcessHeap(), 0, len);
6851         WideCharToMultiByte(CP_ACP, 0, entry, -1, entryA, len, NULL, NULL);
6852
6853         *ppv = GetProcAddress(module, entryA);
6854         if (!*ppv)
6855             ERR("function not found %s\n", debugstr_a(entryA));
6856
6857         HeapFree(GetProcessHeap(), 0, entryA);
6858     }
6859     else
6860     {
6861         *ppv = GetProcAddress(module, MAKEINTRESOURCEA(ordinal));
6862         if (!*ppv)
6863             ERR("function not found %d\n", ordinal);
6864     }
6865
6866     SysFreeString(dll);
6867     SysFreeString(entry);
6868
6869     if (!*ppv)
6870         return TYPE_E_DLLFUNCTIONNOTFOUND;
6871
6872     return S_OK;
6873 }
6874
6875 /* ITypeInfo::CreateInstance
6876  *
6877  * Creates a new instance of a type that describes a component object class
6878  * (coclass).
6879  */
6880 static HRESULT WINAPI ITypeInfo_fnCreateInstance( ITypeInfo2 *iface,
6881         IUnknown *pOuterUnk, REFIID riid, VOID  **ppvObj)
6882 {
6883     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6884     HRESULT hr;
6885     TYPEATTR *pTA;
6886
6887     TRACE("(%p)->(%p, %s, %p)\n", This, pOuterUnk, debugstr_guid(riid), ppvObj);
6888
6889     *ppvObj = NULL;
6890
6891     if(pOuterUnk)
6892     {
6893         WARN("Not able to aggregate\n");
6894         return CLASS_E_NOAGGREGATION;
6895     }
6896
6897     hr = ITypeInfo_GetTypeAttr(iface, &pTA);
6898     if(FAILED(hr)) return hr;
6899
6900     if(pTA->typekind != TKIND_COCLASS)
6901     {
6902         WARN("CreateInstance on typeinfo of type %x\n", pTA->typekind);
6903         hr = E_INVALIDARG;
6904         goto end;
6905     }
6906
6907     hr = S_FALSE;
6908     if(pTA->wTypeFlags & TYPEFLAG_FAPPOBJECT)
6909     {
6910         IUnknown *pUnk;
6911         hr = GetActiveObject(&pTA->guid, NULL, &pUnk);
6912         TRACE("GetActiveObject rets %08x\n", hr);
6913         if(hr == S_OK)
6914         {
6915             hr = IUnknown_QueryInterface(pUnk, riid, ppvObj);
6916             IUnknown_Release(pUnk);
6917         }
6918     }
6919
6920     if(hr != S_OK)
6921         hr = CoCreateInstance(&pTA->guid, NULL,
6922                               CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
6923                               riid, ppvObj);
6924
6925 end:
6926     ITypeInfo_ReleaseTypeAttr(iface, pTA);
6927     return hr;
6928 }
6929
6930 /* ITypeInfo::GetMops
6931  *
6932  * Retrieves marshalling information.
6933  */
6934 static HRESULT WINAPI ITypeInfo_fnGetMops( ITypeInfo2 *iface, MEMBERID memid,
6935                                 BSTR  *pBstrMops)
6936 {
6937     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6938     FIXME("(%p %d) stub!\n", This, memid);
6939     *pBstrMops = NULL;
6940     return S_OK;
6941 }
6942
6943 /* ITypeInfo::GetContainingTypeLib
6944  *
6945  * Retrieves the containing type library and the index of the type description
6946  * within that type library.
6947  */
6948 static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( ITypeInfo2 *iface,
6949         ITypeLib  * *ppTLib, UINT  *pIndex)
6950 {
6951     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6952     
6953     /* If a pointer is null, we simply ignore it, the ATL in particular passes pIndex as 0 */
6954     if (pIndex) {
6955       *pIndex=This->index;
6956       TRACE("returning pIndex=%d\n", *pIndex);
6957     }
6958     
6959     if (ppTLib) {
6960       *ppTLib=(LPTYPELIB )(This->pTypeLib);
6961       ITypeLib2_AddRef(*ppTLib);
6962       TRACE("returning ppTLib=%p\n", *ppTLib);
6963     }
6964     
6965     return S_OK;
6966 }
6967
6968 /* ITypeInfo::ReleaseTypeAttr
6969  *
6970  * Releases a TYPEATTR previously returned by GetTypeAttr.
6971  *
6972  */
6973 static void WINAPI ITypeInfo_fnReleaseTypeAttr( ITypeInfo2 *iface,
6974         TYPEATTR* pTypeAttr)
6975 {
6976     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6977     TRACE("(%p)->(%p)\n", This, pTypeAttr);
6978     HeapFree(GetProcessHeap(), 0, pTypeAttr);
6979 }
6980
6981 /* ITypeInfo::ReleaseFuncDesc
6982  *
6983  * Releases a FUNCDESC previously returned by GetFuncDesc. *
6984  */
6985 static void WINAPI ITypeInfo_fnReleaseFuncDesc(
6986         ITypeInfo2 *iface,
6987         FUNCDESC *pFuncDesc)
6988 {
6989     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6990     SHORT i;
6991
6992     TRACE("(%p)->(%p)\n", This, pFuncDesc);
6993
6994     for (i = 0; i < pFuncDesc->cParams; i++)
6995         TLB_FreeElemDesc(&pFuncDesc->lprgelemdescParam[i]);
6996     TLB_FreeElemDesc(&pFuncDesc->elemdescFunc);
6997
6998     SysFreeString((BSTR)pFuncDesc);
6999 }
7000
7001 /* ITypeInfo::ReleaseVarDesc
7002  *
7003  * Releases a VARDESC previously returned by GetVarDesc.
7004  */
7005 static void WINAPI ITypeInfo_fnReleaseVarDesc( ITypeInfo2 *iface,
7006         VARDESC *pVarDesc)
7007 {
7008     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7009     TRACE("(%p)->(%p)\n", This, pVarDesc);
7010
7011     TLB_FreeElemDesc(&pVarDesc->elemdescVar);
7012     if (pVarDesc->varkind == VAR_CONST)
7013         VariantClear(pVarDesc->u.lpvarValue);
7014     SysFreeString((BSTR)pVarDesc);
7015 }
7016
7017 /* ITypeInfo2::GetTypeKind
7018  *
7019  * Returns the TYPEKIND enumeration quickly, without doing any allocations.
7020  *
7021  */
7022 static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo2 * iface,
7023     TYPEKIND *pTypeKind)
7024 {
7025     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7026     *pTypeKind=This->TypeAttr.typekind;
7027     TRACE("(%p) type 0x%0x\n", This,*pTypeKind);
7028     return S_OK;
7029 }
7030
7031 /* ITypeInfo2::GetTypeFlags
7032  *
7033  * Returns the type flags without any allocations. This returns a DWORD type
7034  * flag, which expands the type flags without growing the TYPEATTR (type
7035  * attribute).
7036  *
7037  */
7038 static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo2 *iface, ULONG *pTypeFlags)
7039 {
7040     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7041     *pTypeFlags=This->TypeAttr.wTypeFlags;
7042     TRACE("(%p) flags 0x%x\n", This,*pTypeFlags);
7043     return S_OK;
7044 }
7045
7046 /* ITypeInfo2::GetFuncIndexOfMemId
7047  * Binds to a specific member based on a known DISPID, where the member name
7048  * is not known (for example, when binding to a default member).
7049  *
7050  */
7051 static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo2 * iface,
7052     MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex)
7053 {
7054     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7055     const TLBFuncDesc *pFuncInfo;
7056     int i;
7057     HRESULT result;
7058
7059     for(i = 0, pFuncInfo = This->funclist; pFuncInfo; i++, pFuncInfo=pFuncInfo->next)
7060         if(memid == pFuncInfo->funcdesc.memid && (invKind & pFuncInfo->funcdesc.invkind))
7061             break;
7062     if(pFuncInfo) {
7063         *pFuncIndex = i;
7064         result = S_OK;
7065     } else
7066         result = TYPE_E_ELEMENTNOTFOUND;
7067
7068     TRACE("(%p) memid 0x%08x invKind 0x%04x -> %s\n", This,
7069           memid, invKind, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
7070     return result;
7071 }
7072
7073 /* TypeInfo2::GetVarIndexOfMemId
7074  *
7075  * Binds to a specific member based on a known DISPID, where the member name
7076  * is not known (for example, when binding to a default member).
7077  *
7078  */
7079 static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( ITypeInfo2 * iface,
7080     MEMBERID memid, UINT *pVarIndex)
7081 {
7082     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7083     TLBVarDesc *pVarInfo;
7084     int i;
7085     HRESULT result;
7086     for(i=0, pVarInfo=This->varlist; pVarInfo &&
7087             memid != pVarInfo->vardesc.memid; i++, pVarInfo=pVarInfo->next)
7088         ;
7089     if(pVarInfo) {
7090         *pVarIndex = i;
7091         result = S_OK;
7092     } else
7093         result = TYPE_E_ELEMENTNOTFOUND;
7094
7095     TRACE("(%p) memid 0x%08x -> %s\n", This,
7096           memid, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
7097     return result;
7098 }
7099
7100 /* ITypeInfo2::GetCustData
7101  *
7102  * Gets the custom data
7103  */
7104 static HRESULT WINAPI ITypeInfo2_fnGetCustData(
7105         ITypeInfo2 * iface,
7106         REFGUID guid,
7107         VARIANT *pVarVal)
7108 {
7109     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7110     TLBCustData *pCData;
7111
7112     for(pCData=This->pCustData; pCData; pCData = pCData->next)
7113         if( IsEqualIID(guid, &pCData->guid)) break;
7114
7115     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
7116
7117     VariantInit( pVarVal);
7118     if (pCData)
7119         VariantCopy( pVarVal, &pCData->data);
7120     else
7121         VariantClear( pVarVal );
7122     return S_OK;
7123 }
7124
7125 /* ITypeInfo2::GetFuncCustData
7126  *
7127  * Gets the custom data
7128  */
7129 static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData(
7130         ITypeInfo2 * iface,
7131         UINT index,
7132         REFGUID guid,
7133         VARIANT *pVarVal)
7134 {
7135     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7136     TLBCustData *pCData=NULL;
7137     TLBFuncDesc * pFDesc;
7138     UINT i;
7139     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
7140             pFDesc=pFDesc->next);
7141
7142     if(pFDesc)
7143         for(pCData=pFDesc->pCustData; pCData; pCData = pCData->next)
7144             if( IsEqualIID(guid, &pCData->guid)) break;
7145
7146     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
7147
7148     if(pCData){
7149         VariantInit( pVarVal);
7150         VariantCopy( pVarVal, &pCData->data);
7151         return S_OK;
7152     }
7153     return E_INVALIDARG;  /* FIXME: correct? */
7154 }
7155
7156 /* ITypeInfo2::GetParamCustData
7157  *
7158  * Gets the custom data
7159  */
7160 static HRESULT WINAPI ITypeInfo2_fnGetParamCustData(
7161         ITypeInfo2 * iface,
7162         UINT indexFunc,
7163         UINT indexParam,
7164         REFGUID guid,
7165         VARIANT *pVarVal)
7166 {
7167     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7168     TLBCustData *pCData=NULL;
7169     TLBFuncDesc * pFDesc;
7170     UINT i;
7171
7172     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,pFDesc=pFDesc->next);
7173
7174     if(pFDesc && indexParam<pFDesc->funcdesc.cParams)
7175         for(pCData=pFDesc->pParamDesc[indexParam].pCustData; pCData;
7176                 pCData = pCData->next)
7177             if( IsEqualIID(guid, &pCData->guid)) break;
7178
7179     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
7180
7181     if(pCData)
7182     {
7183         VariantInit( pVarVal);
7184         VariantCopy( pVarVal, &pCData->data);
7185         return S_OK;
7186     }
7187     return E_INVALIDARG;  /* FIXME: correct? */
7188 }
7189
7190 /* ITypeInfo2::GetVarCustData
7191  *
7192  * Gets the custom data
7193  */
7194 static HRESULT WINAPI ITypeInfo2_fnGetVarCustData(
7195         ITypeInfo2 * iface,
7196         UINT index,
7197         REFGUID guid,
7198         VARIANT *pVarVal)
7199 {
7200     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7201     TLBCustData *pCData=NULL;
7202     TLBVarDesc * pVDesc;
7203     UINT i;
7204
7205     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next);
7206
7207     if(pVDesc)
7208     {
7209       for(pCData=pVDesc->pCustData; pCData; pCData = pCData->next)
7210       {
7211         if( IsEqualIID(guid, &pCData->guid)) break;
7212       }
7213     }
7214
7215     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
7216
7217     if(pCData)
7218     {
7219         VariantInit( pVarVal);
7220         VariantCopy( pVarVal, &pCData->data);
7221         return S_OK;
7222     }
7223     return E_INVALIDARG;  /* FIXME: correct? */
7224 }
7225
7226 /* ITypeInfo2::GetImplCustData
7227  *
7228  * Gets the custom data
7229  */
7230 static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData(
7231         ITypeInfo2 * iface,
7232         UINT index,
7233         REFGUID guid,
7234         VARIANT *pVarVal)
7235 {
7236     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7237     TLBCustData *pCData=NULL;
7238     TLBImplType * pRDesc;
7239     UINT i;
7240
7241     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++, pRDesc=pRDesc->next);
7242
7243     if(pRDesc)
7244     {
7245       for(pCData=pRDesc->pCustData; pCData; pCData = pCData->next)
7246       {
7247         if( IsEqualIID(guid, &pCData->guid)) break;
7248       }
7249     }
7250
7251     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
7252
7253     if(pCData)
7254     {
7255         VariantInit( pVarVal);
7256         VariantCopy( pVarVal, &pCData->data);
7257         return S_OK;
7258     }
7259     return E_INVALIDARG;  /* FIXME: correct? */
7260 }
7261
7262 /* ITypeInfo2::GetDocumentation2
7263  *
7264  * Retrieves the documentation string, the complete Help file name and path,
7265  * the localization context to use, and the context ID for the library Help
7266  * topic in the Help file.
7267  *
7268  */
7269 static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2(
7270         ITypeInfo2 * iface,
7271         MEMBERID memid,
7272         LCID lcid,
7273         BSTR *pbstrHelpString,
7274         DWORD *pdwHelpStringContext,
7275         BSTR *pbstrHelpStringDll)
7276 {
7277     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7278     const TLBFuncDesc *pFDesc;
7279     const TLBVarDesc *pVDesc;
7280     TRACE("(%p) memid %d lcid(0x%x)  HelpString(%p) "
7281           "HelpStringContext(%p) HelpStringDll(%p)\n",
7282           This, memid, lcid, pbstrHelpString, pdwHelpStringContext,
7283           pbstrHelpStringDll );
7284     /* the help string should be obtained from the helpstringdll,
7285      * using the _DLLGetDocumentation function, based on the supplied
7286      * lcid. Nice to do sometime...
7287      */
7288     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
7289         if(pbstrHelpString)
7290             *pbstrHelpString=SysAllocString(This->Name);
7291         if(pdwHelpStringContext)
7292             *pdwHelpStringContext=This->dwHelpStringContext;
7293         if(pbstrHelpStringDll)
7294             *pbstrHelpStringDll=
7295                 SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
7296         return S_OK;
7297     }else {/* for a member */
7298     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
7299         if(pFDesc->funcdesc.memid==memid){
7300              if(pbstrHelpString)
7301                 *pbstrHelpString=SysAllocString(pFDesc->HelpString);
7302             if(pdwHelpStringContext)
7303                 *pdwHelpStringContext=pFDesc->HelpStringContext;
7304             if(pbstrHelpStringDll)
7305                 *pbstrHelpStringDll=
7306                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
7307         return S_OK;
7308     }
7309     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
7310         if(pVDesc->vardesc.memid==memid){
7311              if(pbstrHelpString)
7312                 *pbstrHelpString=SysAllocString(pVDesc->HelpString);
7313             if(pdwHelpStringContext)
7314                 *pdwHelpStringContext=pVDesc->HelpStringContext;
7315             if(pbstrHelpStringDll)
7316                 *pbstrHelpStringDll=
7317                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
7318             return S_OK;
7319         }
7320     }
7321     return TYPE_E_ELEMENTNOTFOUND;
7322 }
7323
7324 /* ITypeInfo2::GetAllCustData
7325  *
7326  * Gets all custom data items for the Type info.
7327  *
7328  */
7329 static HRESULT WINAPI ITypeInfo2_fnGetAllCustData(
7330         ITypeInfo2 * iface,
7331         CUSTDATA *pCustData)
7332 {
7333     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7334     TLBCustData *pCData;
7335     int i;
7336
7337     TRACE("(%p) returning %d items\n", This, This->ctCustData);
7338
7339     pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
7340     if(pCustData->prgCustData ){
7341         pCustData->cCustData=This->ctCustData;
7342         for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
7343             pCustData->prgCustData[i].guid=pCData->guid;
7344             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
7345         }
7346     }else{
7347         ERR(" OUT OF MEMORY!\n");
7348         return E_OUTOFMEMORY;
7349     }
7350     return S_OK;
7351 }
7352
7353 /* ITypeInfo2::GetAllFuncCustData
7354  *
7355  * Gets all custom data items for the specified Function
7356  *
7357  */
7358 static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData(
7359         ITypeInfo2 * iface,
7360         UINT index,
7361         CUSTDATA *pCustData)
7362 {
7363     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7364     TLBCustData *pCData;
7365     TLBFuncDesc * pFDesc;
7366     UINT i;
7367     TRACE("(%p) index %d\n", This, index);
7368     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
7369             pFDesc=pFDesc->next)
7370         ;
7371     if(pFDesc){
7372         pCustData->prgCustData =
7373             TLB_Alloc(pFDesc->ctCustData * sizeof(CUSTDATAITEM));
7374         if(pCustData->prgCustData ){
7375             pCustData->cCustData=pFDesc->ctCustData;
7376             for(i=0, pCData=pFDesc->pCustData; pCData; i++,
7377                     pCData = pCData->next){
7378                 pCustData->prgCustData[i].guid=pCData->guid;
7379                 VariantCopy(& pCustData->prgCustData[i].varValue,
7380                         & pCData->data);
7381             }
7382         }else{
7383             ERR(" OUT OF MEMORY!\n");
7384             return E_OUTOFMEMORY;
7385         }
7386         return S_OK;
7387     }
7388     return TYPE_E_ELEMENTNOTFOUND;
7389 }
7390
7391 /* ITypeInfo2::GetAllParamCustData
7392  *
7393  * Gets all custom data items for the Functions
7394  *
7395  */
7396 static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo2 * iface,
7397     UINT indexFunc, UINT indexParam, CUSTDATA *pCustData)
7398 {
7399     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7400     TLBCustData *pCData=NULL;
7401     TLBFuncDesc * pFDesc;
7402     UINT i;
7403     TRACE("(%p) index %d\n", This, indexFunc);
7404     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,
7405             pFDesc=pFDesc->next)
7406         ;
7407     if(pFDesc && indexParam<pFDesc->funcdesc.cParams){
7408         pCustData->prgCustData =
7409             TLB_Alloc(pFDesc->pParamDesc[indexParam].ctCustData *
7410                     sizeof(CUSTDATAITEM));
7411         if(pCustData->prgCustData ){
7412             pCustData->cCustData=pFDesc->pParamDesc[indexParam].ctCustData;
7413             for(i=0, pCData=pFDesc->pParamDesc[indexParam].pCustData;
7414                     pCData; i++, pCData = pCData->next){
7415                 pCustData->prgCustData[i].guid=pCData->guid;
7416                 VariantCopy(& pCustData->prgCustData[i].varValue,
7417                         & pCData->data);
7418             }
7419         }else{
7420             ERR(" OUT OF MEMORY!\n");
7421             return E_OUTOFMEMORY;
7422         }
7423         return S_OK;
7424     }
7425     return TYPE_E_ELEMENTNOTFOUND;
7426 }
7427
7428 /* ITypeInfo2::GetAllVarCustData
7429  *
7430  * Gets all custom data items for the specified Variable
7431  *
7432  */
7433 static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo2 * iface,
7434     UINT index, CUSTDATA *pCustData)
7435 {
7436     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7437     TLBCustData *pCData;
7438     TLBVarDesc * pVDesc;
7439     UINT i;
7440     TRACE("(%p) index %d\n", This, index);
7441     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++,
7442             pVDesc=pVDesc->next)
7443         ;
7444     if(pVDesc){
7445         pCustData->prgCustData =
7446             TLB_Alloc(pVDesc->ctCustData * sizeof(CUSTDATAITEM));
7447         if(pCustData->prgCustData ){
7448             pCustData->cCustData=pVDesc->ctCustData;
7449             for(i=0, pCData=pVDesc->pCustData; pCData; i++,
7450                     pCData = pCData->next){
7451                 pCustData->prgCustData[i].guid=pCData->guid;
7452                 VariantCopy(& pCustData->prgCustData[i].varValue,
7453                         & pCData->data);
7454             }
7455         }else{
7456             ERR(" OUT OF MEMORY!\n");
7457             return E_OUTOFMEMORY;
7458         }
7459         return S_OK;
7460     }
7461     return TYPE_E_ELEMENTNOTFOUND;
7462 }
7463
7464 /* ITypeInfo2::GetAllImplCustData
7465  *
7466  * Gets all custom data items for the specified implementation type
7467  *
7468  */
7469 static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData(
7470         ITypeInfo2 * iface,
7471         UINT index,
7472         CUSTDATA *pCustData)
7473 {
7474     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7475     TLBCustData *pCData;
7476     TLBImplType * pRDesc;
7477     UINT i;
7478     TRACE("(%p) index %d\n", This, index);
7479     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++,
7480             pRDesc=pRDesc->next)
7481         ;
7482     if(pRDesc){
7483         pCustData->prgCustData =
7484             TLB_Alloc(pRDesc->ctCustData * sizeof(CUSTDATAITEM));
7485         if(pCustData->prgCustData ){
7486             pCustData->cCustData=pRDesc->ctCustData;
7487             for(i=0, pCData=pRDesc->pCustData; pCData; i++,
7488                     pCData = pCData->next){
7489                 pCustData->prgCustData[i].guid=pCData->guid;
7490                 VariantCopy(& pCustData->prgCustData[i].varValue,
7491                         & pCData->data);
7492             }
7493         }else{
7494             ERR(" OUT OF MEMORY!\n");
7495             return E_OUTOFMEMORY;
7496         }
7497         return S_OK;
7498     }
7499     return TYPE_E_ELEMENTNOTFOUND;
7500 }
7501
7502 static const ITypeInfo2Vtbl tinfvt =
7503 {
7504
7505     ITypeInfo_fnQueryInterface,
7506     ITypeInfo_fnAddRef,
7507     ITypeInfo_fnRelease,
7508
7509     ITypeInfo_fnGetTypeAttr,
7510     ITypeInfo_fnGetTypeComp,
7511     ITypeInfo_fnGetFuncDesc,
7512     ITypeInfo_fnGetVarDesc,
7513     ITypeInfo_fnGetNames,
7514     ITypeInfo_fnGetRefTypeOfImplType,
7515     ITypeInfo_fnGetImplTypeFlags,
7516     ITypeInfo_fnGetIDsOfNames,
7517     ITypeInfo_fnInvoke,
7518     ITypeInfo_fnGetDocumentation,
7519     ITypeInfo_fnGetDllEntry,
7520     ITypeInfo_fnGetRefTypeInfo,
7521     ITypeInfo_fnAddressOfMember,
7522     ITypeInfo_fnCreateInstance,
7523     ITypeInfo_fnGetMops,
7524     ITypeInfo_fnGetContainingTypeLib,
7525     ITypeInfo_fnReleaseTypeAttr,
7526     ITypeInfo_fnReleaseFuncDesc,
7527     ITypeInfo_fnReleaseVarDesc,
7528
7529     ITypeInfo2_fnGetTypeKind,
7530     ITypeInfo2_fnGetTypeFlags,
7531     ITypeInfo2_fnGetFuncIndexOfMemId,
7532     ITypeInfo2_fnGetVarIndexOfMemId,
7533     ITypeInfo2_fnGetCustData,
7534     ITypeInfo2_fnGetFuncCustData,
7535     ITypeInfo2_fnGetParamCustData,
7536     ITypeInfo2_fnGetVarCustData,
7537     ITypeInfo2_fnGetImplTypeCustData,
7538     ITypeInfo2_fnGetDocumentation2,
7539     ITypeInfo2_fnGetAllCustData,
7540     ITypeInfo2_fnGetAllFuncCustData,
7541     ITypeInfo2_fnGetAllParamCustData,
7542     ITypeInfo2_fnGetAllVarCustData,
7543     ITypeInfo2_fnGetAllImplTypeCustData,
7544 };
7545
7546 /******************************************************************************
7547  * CreateDispTypeInfo [OLEAUT32.31]
7548  *
7549  * Build type information for an object so it can be called through an
7550  * IDispatch interface.
7551  *
7552  * RETURNS
7553  *  Success: S_OK. pptinfo contains the created ITypeInfo object.
7554  *  Failure: E_INVALIDARG, if one or more arguments is invalid.
7555  *
7556  * NOTES
7557  *  This call allows an objects methods to be accessed through IDispatch, by
7558  *  building an ITypeInfo object that IDispatch can use to call through.
7559  */
7560 HRESULT WINAPI CreateDispTypeInfo(
7561         INTERFACEDATA *pidata, /* [I] Description of the interface to build type info for */
7562         LCID lcid, /* [I] Locale Id */
7563         ITypeInfo **pptinfo) /* [O] Destination for created ITypeInfo object */
7564 {
7565     ITypeInfoImpl *pTIClass, *pTIIface;
7566     ITypeLibImpl *pTypeLibImpl;
7567     unsigned int param, func;
7568     TLBFuncDesc **ppFuncDesc;
7569     TLBRefType *ref;
7570
7571     TRACE("\n");
7572     pTypeLibImpl = TypeLibImpl_Constructor();
7573     if (!pTypeLibImpl) return E_FAIL;
7574
7575     pTIIface = (ITypeInfoImpl*)ITypeInfo_Constructor();
7576     pTIIface->pTypeLib = pTypeLibImpl;
7577     pTIIface->index = 0;
7578     pTIIface->Name = NULL;
7579     pTIIface->dwHelpContext = -1;
7580     memset(&pTIIface->TypeAttr.guid, 0, sizeof(GUID));
7581     pTIIface->TypeAttr.lcid = lcid;
7582     pTIIface->TypeAttr.typekind = TKIND_INTERFACE;
7583     pTIIface->TypeAttr.wMajorVerNum = 0;
7584     pTIIface->TypeAttr.wMinorVerNum = 0;
7585     pTIIface->TypeAttr.cbAlignment = 2;
7586     pTIIface->TypeAttr.cbSizeInstance = -1;
7587     pTIIface->TypeAttr.cbSizeVft = -1;
7588     pTIIface->TypeAttr.cFuncs = 0;
7589     pTIIface->TypeAttr.cImplTypes = 0;
7590     pTIIface->TypeAttr.cVars = 0;
7591     pTIIface->TypeAttr.wTypeFlags = 0;
7592
7593     ppFuncDesc = &pTIIface->funclist;
7594     for(func = 0; func < pidata->cMembers; func++) {
7595         METHODDATA *md = pidata->pmethdata + func;
7596         *ppFuncDesc = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppFuncDesc));
7597         (*ppFuncDesc)->Name = SysAllocString(md->szName);
7598         (*ppFuncDesc)->funcdesc.memid = md->dispid;
7599         (*ppFuncDesc)->funcdesc.lprgscode = NULL;
7600         (*ppFuncDesc)->funcdesc.funckind = FUNC_VIRTUAL;
7601         (*ppFuncDesc)->funcdesc.invkind = md->wFlags;
7602         (*ppFuncDesc)->funcdesc.callconv = md->cc;
7603         (*ppFuncDesc)->funcdesc.cParams = md->cArgs;
7604         (*ppFuncDesc)->funcdesc.cParamsOpt = 0;
7605         (*ppFuncDesc)->funcdesc.oVft = md->iMeth * sizeof(void *);
7606         (*ppFuncDesc)->funcdesc.cScodes = 0;
7607         (*ppFuncDesc)->funcdesc.wFuncFlags = 0;
7608         (*ppFuncDesc)->funcdesc.elemdescFunc.tdesc.vt = md->vtReturn;
7609         (*ppFuncDesc)->funcdesc.elemdescFunc.u.paramdesc.wParamFlags = PARAMFLAG_NONE;
7610         (*ppFuncDesc)->funcdesc.elemdescFunc.u.paramdesc.pparamdescex = NULL;
7611         (*ppFuncDesc)->funcdesc.lprgelemdescParam = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7612                                                               md->cArgs * sizeof(ELEMDESC));
7613         (*ppFuncDesc)->pParamDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7614                                               md->cArgs * sizeof(TLBParDesc));
7615         for(param = 0; param < md->cArgs; param++) {
7616             (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].tdesc.vt = md->ppdata[param].vt;
7617             (*ppFuncDesc)->pParamDesc[param].Name = SysAllocString(md->ppdata[param].szName);
7618         }
7619         (*ppFuncDesc)->helpcontext = 0;
7620         (*ppFuncDesc)->HelpStringContext = 0;
7621         (*ppFuncDesc)->HelpString = NULL;
7622         (*ppFuncDesc)->Entry = NULL;
7623         (*ppFuncDesc)->ctCustData = 0;
7624         (*ppFuncDesc)->pCustData = NULL;
7625         (*ppFuncDesc)->next = NULL;
7626         pTIIface->TypeAttr.cFuncs++;
7627         ppFuncDesc = &(*ppFuncDesc)->next;
7628     }
7629
7630     dump_TypeInfo(pTIIface);
7631
7632     pTypeLibImpl->pTypeInfo = pTIIface;
7633     pTypeLibImpl->TypeInfoCount++;
7634
7635     pTIClass = (ITypeInfoImpl*)ITypeInfo_Constructor();
7636     pTIClass->pTypeLib = pTypeLibImpl;
7637     pTIClass->index = 1;
7638     pTIClass->Name = NULL;
7639     pTIClass->dwHelpContext = -1;
7640     memset(&pTIClass->TypeAttr.guid, 0, sizeof(GUID));
7641     pTIClass->TypeAttr.lcid = lcid;
7642     pTIClass->TypeAttr.typekind = TKIND_COCLASS;
7643     pTIClass->TypeAttr.wMajorVerNum = 0;
7644     pTIClass->TypeAttr.wMinorVerNum = 0;
7645     pTIClass->TypeAttr.cbAlignment = 2;
7646     pTIClass->TypeAttr.cbSizeInstance = -1;
7647     pTIClass->TypeAttr.cbSizeVft = -1;
7648     pTIClass->TypeAttr.cFuncs = 0;
7649     pTIClass->TypeAttr.cImplTypes = 1;
7650     pTIClass->TypeAttr.cVars = 0;
7651     pTIClass->TypeAttr.wTypeFlags = 0;
7652
7653     pTIClass->impltypelist = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pTIClass->impltypelist));
7654     pTIClass->impltypelist->hRef = 0;
7655
7656     ref = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ref));
7657     ref->index = 0;
7658     ref->reference = 0;
7659     ref->pImpTLInfo = TLB_REF_INTERNAL;
7660     list_add_head(&pTypeLibImpl->ref_list, &ref->entry);
7661
7662     dump_TypeInfo(pTIClass);
7663
7664     pTIIface->next = pTIClass;
7665     pTypeLibImpl->TypeInfoCount++;
7666
7667     *pptinfo = (ITypeInfo*)pTIClass;
7668
7669     ITypeInfo_AddRef(*pptinfo);
7670     ITypeLib_Release((ITypeLib *)&pTypeLibImpl->lpVtbl);
7671
7672     return S_OK;
7673
7674 }
7675
7676 static HRESULT WINAPI ITypeComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
7677 {
7678     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7679
7680     return ITypeInfo_QueryInterface((ITypeInfo *)This, riid, ppv);
7681 }
7682
7683 static ULONG WINAPI ITypeComp_fnAddRef(ITypeComp * iface)
7684 {
7685     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7686
7687     return ITypeInfo_AddRef((ITypeInfo *)This);
7688 }
7689
7690 static ULONG WINAPI ITypeComp_fnRelease(ITypeComp * iface)
7691 {
7692     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7693
7694     return ITypeInfo_Release((ITypeInfo *)This);
7695 }
7696
7697 static HRESULT WINAPI ITypeComp_fnBind(
7698     ITypeComp * iface,
7699     OLECHAR * szName,
7700     ULONG lHash,
7701     WORD wFlags,
7702     ITypeInfo ** ppTInfo,
7703     DESCKIND * pDescKind,
7704     BINDPTR * pBindPtr)
7705 {
7706     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7707     const TLBFuncDesc *pFDesc;
7708     const TLBVarDesc *pVDesc;
7709     HRESULT hr = S_OK;
7710
7711     TRACE("(%p)->(%s, %x, 0x%x, %p, %p, %p)\n", This, debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
7712
7713     *pDescKind = DESCKIND_NONE;
7714     pBindPtr->lpfuncdesc = NULL;
7715     *ppTInfo = NULL;
7716
7717     for(pFDesc = This->funclist; pFDesc; pFDesc = pFDesc->next)
7718         if (!strcmpiW(pFDesc->Name, szName)) {
7719             if (!wFlags || (pFDesc->funcdesc.invkind & wFlags))
7720                 break;
7721             else
7722                 /* name found, but wrong flags */
7723                 hr = TYPE_E_TYPEMISMATCH;
7724         }
7725
7726     if (pFDesc)
7727     {
7728         HRESULT hr = TLB_AllocAndInitFuncDesc(
7729             &pFDesc->funcdesc,
7730             &pBindPtr->lpfuncdesc,
7731             This->TypeAttr.typekind == TKIND_DISPATCH);
7732         if (FAILED(hr))
7733             return hr;
7734         *pDescKind = DESCKIND_FUNCDESC;
7735         *ppTInfo = (ITypeInfo *)&This->lpVtbl;
7736         ITypeInfo_AddRef(*ppTInfo);
7737         return S_OK;
7738     } else {
7739         for(pVDesc = This->varlist; pVDesc; pVDesc = pVDesc->next) {
7740             if (!strcmpiW(pVDesc->Name, szName)) {
7741                 HRESULT hr = TLB_AllocAndInitVarDesc(&pVDesc->vardesc, &pBindPtr->lpvardesc);
7742                 if (FAILED(hr))
7743                     return hr;
7744                 *pDescKind = DESCKIND_VARDESC;
7745                 *ppTInfo = (ITypeInfo *)&This->lpVtbl;
7746                 ITypeInfo_AddRef(*ppTInfo);
7747                 return S_OK;
7748             }
7749         }
7750     }
7751     /* FIXME: search each inherited interface, not just the first */
7752     if (hr == DISP_E_MEMBERNOTFOUND && This->impltypelist) {
7753         /* recursive search */
7754         ITypeInfo *pTInfo;
7755         ITypeComp *pTComp;
7756         HRESULT hr;
7757         hr=ITypeInfo_GetRefTypeInfo((ITypeInfo *)&This->lpVtbl, This->impltypelist->hRef, &pTInfo);
7758         if (SUCCEEDED(hr))
7759         {
7760             hr = ITypeInfo_GetTypeComp(pTInfo,&pTComp);
7761             ITypeInfo_Release(pTInfo);
7762         }
7763         if (SUCCEEDED(hr))
7764         {
7765             hr = ITypeComp_Bind(pTComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
7766             ITypeComp_Release(pTComp);
7767             return hr;
7768         }
7769         WARN("Could not search inherited interface!\n");
7770     }
7771     TRACE("did not find member with name %s, flags 0x%x\n", debugstr_w(szName), wFlags);
7772     return hr;
7773 }
7774
7775 static HRESULT WINAPI ITypeComp_fnBindType(
7776     ITypeComp * iface,
7777     OLECHAR * szName,
7778     ULONG lHash,
7779     ITypeInfo ** ppTInfo,
7780     ITypeComp ** ppTComp)
7781 {
7782     TRACE("(%s, %x, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
7783
7784     /* strange behaviour (does nothing) but like the
7785      * original */
7786
7787     if (!ppTInfo || !ppTComp)
7788         return E_POINTER;
7789
7790     *ppTInfo = NULL;
7791     *ppTComp = NULL;
7792
7793     return S_OK;
7794 }
7795
7796 static const ITypeCompVtbl tcompvt =
7797 {
7798
7799     ITypeComp_fnQueryInterface,
7800     ITypeComp_fnAddRef,
7801     ITypeComp_fnRelease,
7802
7803     ITypeComp_fnBind,
7804     ITypeComp_fnBindType
7805 };