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