- Read DLL name from modules in MSFT typelibs.
[wine] / dlls / oleaut32 / typelib.c
1 /*
2  *      TYPELIB
3  *
4  *      Copyright 1997  Marcus Meissner
5  *                    1999  Rein Klazes
6  *                    2000  Francois Jacques
7  *                    2001  Huw D M Davies for CodeWeavers
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  * --------------------------------------------------------------------------------------
24  * Known problems (2000, Francois Jacques)
25  *
26  * - Tested using OLEVIEW (Platform SDK tool) only.
27  *
28  * - dual interface dispinterfaces. vtable-interface ITypeInfo instances are
29  *   creating by doing a straight copy of the dispinterface instance and just changing
30  *   its typekind. Pointed structures aren't copied - only the address of the pointers.
31  *   So when you release the dispinterface, you delete the vtable-interface structures
32  *   as well... fortunately, clean up of structures is not implemented.
33  *
34  * - locale stuff is partially implemented but hasn't been tested.
35  *
36  * - typelib file is still read in its entirety, but it is released now.
37  * - some garbage is read from function names on some very rare occasions.
38  *
39  * --------------------------------------------------------------------------------------
40  *  Known problems left from previous implementation (1999, Rein Klazes) :
41  *
42  * -. Data structures are straightforward, but slow for look-ups.
43  * -. (related) nothing is hashed
44  * -. there are a number of stubs in ITypeLib and ITypeInfo interfaces. Most
45  *      of them I don't know yet how to implement them.
46  * -. Most error return values are just guessed not checked with windows
47  *      behaviour.
48  * -. didn't bother with a c++ interface
49  * -. lousy fatal error handling
50  * -. some methods just return pointers to internal data structures, this is
51  *      partly laziness, partly I want to check how windows does it.
52  *
53  */
54
55 #include "config.h"
56 #include "wine/port.h"
57
58 #include <stdlib.h>
59 #include <string.h>
60 #include <stdarg.h>
61 #include <stdio.h>
62 #include <ctype.h>
63
64 #define COBJMACROS
65 #define NONAMELESSUNION
66 #define NONAMELESSSTRUCT
67
68 #include "winerror.h"
69 #include "windef.h"
70 #include "winbase.h"
71 #include "winnls.h"
72 #include "winreg.h"
73 #include "winuser.h"
74
75 #include "wine/unicode.h"
76 #include "objbase.h"
77 #include "typelib.h"
78 #include "wine/debug.h"
79 #include "variant.h"
80
81 WINE_DEFAULT_DEBUG_CHANNEL(ole);
82 WINE_DECLARE_DEBUG_CHANNEL(typelib);
83
84 /* The OLE Automation ProxyStub Interface Class (aka Typelib Marshaler) */
85 const GUID CLSID_PSOAInterface = { 0x00020424, 0, 0, { 0xC0, 0, 0, 0, 0, 0, 0, 0x46 } };
86
87 static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, TYPEDESC *tdesc, VARTYPE *vt);
88
89 /****************************************************************************
90  *              FromLExxx
91  *
92  * Takes p_iVal (which is in little endian) and returns it
93  *   in the host machine's byte order.
94  */
95 #ifdef WORDS_BIGENDIAN
96 static WORD FromLEWord(WORD p_iVal)
97 {
98   return (((p_iVal & 0x00FF) << 8) |
99           ((p_iVal & 0xFF00) >> 8));
100 }
101
102
103 static DWORD FromLEDWord(DWORD p_iVal)
104 {
105   return (((p_iVal & 0x000000FF) << 24) |
106           ((p_iVal & 0x0000FF00) <<  8) |
107           ((p_iVal & 0x00FF0000) >>  8) |
108           ((p_iVal & 0xFF000000) >> 24));
109 }
110 #else
111 #define FromLEWord(X)  (X)
112 #define FromLEDWord(X) (X)
113 #endif
114
115
116 /****************************************************************************
117  *              FromLExxx
118  *
119  * Fix byte order in any structure if necessary
120  */
121 #ifdef WORDS_BIGENDIAN
122 static void FromLEWords(void *p_Val, int p_iSize)
123 {
124   WORD *Val = p_Val;
125
126   p_iSize /= sizeof(WORD);
127
128   while (p_iSize) {
129     *Val = FromLEWord(*Val);
130     Val++;
131     p_iSize--;
132   }
133 }
134
135
136 static void FromLEDWords(void *p_Val, int p_iSize)
137 {
138   DWORD *Val = p_Val;
139
140   p_iSize /= sizeof(DWORD);
141
142   while (p_iSize) {
143     *Val = FromLEDWord(*Val);
144     Val++;
145     p_iSize--;
146   }
147 }
148 #else
149 #define FromLEWords(X,Y) /*nothing*/
150 #define FromLEDWords(X,Y) /*nothing*/
151 #endif
152
153 /* get the path of a typelib key, in the form "Typelib\\<guid>\\<maj>.<min>" */
154 /* buffer must be at least 60 characters long */
155 static WCHAR *get_typelib_key( REFGUID guid, WORD wMaj, WORD wMin, WCHAR *buffer )
156 {
157     static const WCHAR TypelibW[] = {'T','y','p','e','l','i','b','\\',0};
158     static const WCHAR VersionFormatW[] = {'\\','%','u','.','%','u',0};
159
160     memcpy( buffer, TypelibW, sizeof(TypelibW) );
161     StringFromGUID2( guid, buffer + strlenW(buffer), 40 );
162     sprintfW( buffer + strlenW(buffer), VersionFormatW, wMaj, wMin );
163     return buffer;
164 }
165
166 /* get the path of an interface key, in the form "Interface\\<guid>" */
167 /* buffer must be at least 50 characters long */
168 static WCHAR *get_interface_key( REFGUID guid, WCHAR *buffer )
169 {
170     static const WCHAR InterfaceW[] = {'I','n','t','e','r','f','a','c','e','\\',0};
171
172     memcpy( buffer, InterfaceW, sizeof(InterfaceW) );
173     StringFromGUID2( guid, buffer + strlenW(buffer), 40 );
174     return buffer;
175 }
176
177 /* get the lcid subkey for a typelib, in the form "<lcid>\\<syskind>" */
178 /* buffer must be at least 16 characters long */
179 static WCHAR *get_lcid_subkey( LCID lcid, SYSKIND syskind, WCHAR *buffer )
180 {
181     static const WCHAR LcidFormatW[] = {'%','l','x','\\',0};
182     static const WCHAR win16W[] = {'w','i','n','1','6',0};
183     static const WCHAR win32W[] = {'w','i','n','3','2',0};
184
185     sprintfW( buffer, LcidFormatW, lcid );
186     switch(syskind)
187     {
188     case SYS_WIN16: strcatW( buffer, win16W ); break;
189     case SYS_WIN32: strcatW( buffer, win32W ); break;
190     default:
191         TRACE("Typelib is for unsupported syskind %i\n", syskind);
192         return NULL;
193     }
194     return buffer;
195 }
196
197 int TLB_ReadTypeLib(LPCWSTR file, INT index, ITypeLib2 **ppTypelib);
198
199
200 /****************************************************************************
201  *              QueryPathOfRegTypeLib   [OLEAUT32.164]
202  *
203  * Gets the path to a registered type library.
204  *
205  * PARAMS
206  *  guid [I] referenced guid
207  *  wMaj [I] major version
208  *  wMin [I] minor version
209  *  lcid [I] locale id
210  *  path [O] path of typelib
211  *
212  * RETURNS
213  *  Success: S_OK.
214  *  Failure: If the type library is not registered then TYPE_E_LIBNOTREGISTERED
215  *  or TYPE_E_REGISTRYACCESS if the type library registration key couldn't be
216  *  opened.
217  */
218 HRESULT WINAPI QueryPathOfRegTypeLib(
219         REFGUID guid,
220         WORD wMaj,
221         WORD wMin,
222         LCID lcid,
223         LPBSTR path )
224 {
225     HRESULT hr = TYPE_E_LIBNOTREGISTERED;
226     LCID myLCID = lcid;
227     HKEY hkey;
228     WCHAR buffer[60];
229     WCHAR Path[MAX_PATH];
230     LONG res;
231
232     TRACE_(typelib)("(%s, %x.%x, 0x%lx, %p)\n", debugstr_guid(guid), wMaj, wMin, lcid, path);
233
234     get_typelib_key( guid, wMaj, wMin, buffer );
235
236     res = RegOpenKeyExW( HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hkey );
237     if (res == ERROR_FILE_NOT_FOUND)
238     {
239         TRACE_(typelib)("%s not found\n", debugstr_w(buffer));
240         return TYPE_E_LIBNOTREGISTERED;
241     }
242     else if (res != ERROR_SUCCESS)
243     {
244         TRACE_(typelib)("failed to open %s for read access\n", debugstr_w(buffer));
245         return TYPE_E_REGISTRYACCESS;
246     }
247
248     while (hr != S_OK)
249     {
250         LONG dwPathLen = sizeof(Path);
251
252         get_lcid_subkey( myLCID, SYS_WIN32, buffer );
253
254         if (RegQueryValueW(hkey, buffer, Path, &dwPathLen))
255         {
256             if (!lcid)
257                 break;
258             else if (myLCID == lcid)
259             {
260                 /* try with sub-langid */
261                 myLCID = SUBLANGID(lcid);
262             }
263             else if ((myLCID == SUBLANGID(lcid)) && myLCID)
264             {
265                 /* try with system langid */
266                 myLCID = 0;
267             }
268             else
269             {
270                 break;
271             }
272         }
273         else
274         {
275             *path = SysAllocString( Path );
276             hr = S_OK;
277         }
278     }
279     RegCloseKey( hkey );
280     TRACE_(typelib)("-- 0x%08lx\n", hr);
281     return hr;
282 }
283
284 /******************************************************************************
285  * CreateTypeLib [OLEAUT32.160]  creates a typelib
286  *
287  * RETURNS
288  *    Success: S_OK
289  *    Failure: Status
290  */
291 HRESULT WINAPI CreateTypeLib(
292         SYSKIND syskind, LPCOLESTR szFile, ICreateTypeLib** ppctlib
293 ) {
294     FIXME("(%d,%s,%p), stub!\n",syskind,debugstr_w(szFile),ppctlib);
295     return E_FAIL;
296 }
297
298 /******************************************************************************
299  *              LoadTypeLib     [OLEAUT32.161]
300  *
301  * Loads a type library
302  *
303  * PARAMS
304  *  szFile [I] Name of file to load from.
305  *  pptLib [O] Pointer that receives ITypeLib object on success.
306  *
307  * RETURNS
308  *    Success: S_OK
309  *    Failure: Status
310  *
311  * SEE
312  *  LoadTypeLibEx, LoadRegTypeLib, CreateTypeLib.
313  */
314 HRESULT WINAPI LoadTypeLib(const OLECHAR *szFile, ITypeLib * *pptLib)
315 {
316     TRACE("(%s,%p)\n",debugstr_w(szFile), pptLib);
317     return LoadTypeLibEx(szFile, REGKIND_DEFAULT, pptLib);
318 }
319
320 /******************************************************************************
321  *              LoadTypeLibEx   [OLEAUT32.183]
322  *
323  * Loads and optionally registers a type library
324  *
325  * RETURNS
326  *    Success: S_OK
327  *    Failure: Status
328  */
329 HRESULT WINAPI LoadTypeLibEx(
330     LPCOLESTR szFile,  /* [in] Name of file to load from */
331     REGKIND  regkind,  /* [in] Specify kind of registration */
332     ITypeLib **pptLib) /* [out] Pointer to pointer to loaded type library */
333 {
334     WCHAR szPath[MAX_PATH+1], szFileCopy[MAX_PATH+1];
335     WCHAR *pIndexStr;
336     HRESULT res;
337     INT index = 1;
338
339     TRACE("(%s,%d,%p)\n",debugstr_w(szFile), regkind, pptLib);
340
341     /* by default try and load using LoadLibrary (for builtin stdole32.tlb) */
342     memcpy(szPath, szFile, (strlenW(szFile)+1)*sizeof(WCHAR));
343     
344     *pptLib = NULL;
345     if(!SearchPathW(NULL,szFile,NULL,sizeof(szPath)/sizeof(WCHAR),szPath,
346                     NULL)) {
347
348         /* Look for a trailing '\\' followed by an index */
349         pIndexStr = strrchrW(szFile, '\\');
350         if(pIndexStr && pIndexStr != szFile && *++pIndexStr != '\0') {
351             index = atoiW(pIndexStr);
352             memcpy(szFileCopy, szFile,
353                    (pIndexStr - szFile - 1) * sizeof(WCHAR));
354             szFileCopy[pIndexStr - szFile - 1] = '\0';
355             if(!SearchPathW(NULL,szFileCopy,NULL,sizeof(szPath)/sizeof(WCHAR),
356                             szPath,NULL))
357                 return TYPE_E_CANTLOADLIBRARY;
358             if (GetFileAttributesW(szFileCopy) & FILE_ATTRIBUTE_DIRECTORY)
359                 return TYPE_E_CANTLOADLIBRARY;
360         }
361     }
362
363     TRACE("File %s index %d\n", debugstr_w(szPath), index);
364
365     res = TLB_ReadTypeLib(szPath, index, (ITypeLib2**)pptLib);
366
367     if (SUCCEEDED(res))
368         switch(regkind)
369         {
370             case REGKIND_DEFAULT:
371                 /* don't register typelibs supplied with full path. Experimentation confirms the following */
372                 if ((!szFile) ||
373                     ((szFile[0] == '\\') && (szFile[1] == '\\')) ||
374                     (szFile[0] && (szFile[1] == ':'))) break;
375                 /* else fall-through */
376
377             case REGKIND_REGISTER:
378                 if (!SUCCEEDED(res = RegisterTypeLib(*pptLib, (LPOLESTR)szPath, NULL)))
379                 {
380                     IUnknown_Release(*pptLib);
381                     *pptLib = 0;
382                 }
383                 break;
384             case REGKIND_NONE:
385                 break;
386         }
387
388     TRACE(" returns %08lx\n",res);
389     return res;
390 }
391
392 /******************************************************************************
393  *              LoadRegTypeLib  [OLEAUT32.162]
394  *
395  * Loads a registered type library.
396  *
397  * PARAMS
398  *  rguid     [I] GUID of the registered type library.
399  *  wVerMajor [I] major version.
400  *  wVerMinor [I] minor version.
401  *  lcid      [I] locale ID.
402  *  ppTLib    [O] pointer that receives an ITypeLib object on success.
403  *
404  * RETURNS
405  *  Success: S_OK.
406  *  Failure: Any HRESULT code returned from QueryPathOfRegTypeLib or
407  *  LoadTypeLib.
408  */
409 HRESULT WINAPI LoadRegTypeLib(
410         REFGUID rguid,
411         WORD wVerMajor,
412         WORD wVerMinor,
413         LCID lcid,
414         ITypeLib **ppTLib)
415 {
416     BSTR bstr=NULL;
417     HRESULT res=QueryPathOfRegTypeLib( rguid, wVerMajor, wVerMinor, lcid, &bstr);
418
419     if(SUCCEEDED(res))
420     {
421         res= LoadTypeLib(bstr, ppTLib);
422         SysFreeString(bstr);
423     }
424
425     TRACE("(IID: %s) load %s (%p)\n",debugstr_guid(rguid), SUCCEEDED(res)? "SUCCESS":"FAILED", *ppTLib);
426
427     return res;
428 }
429
430
431 /* some string constants shared between RegisterTypeLib and UnRegisterTypeLib */
432 static const WCHAR TypeLibW[] = {'T','y','p','e','L','i','b',0};
433 static const WCHAR FLAGSW[] = {'F','L','A','G','S',0};
434 static const WCHAR HELPDIRW[] = {'H','E','L','P','D','I','R',0};
435 static const WCHAR ProxyStubClsidW[] = {'P','r','o','x','y','S','t','u','b','C','l','s','i','d',0};
436 static const WCHAR ProxyStubClsid32W[] = {'P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
437
438 /******************************************************************************
439  *              RegisterTypeLib [OLEAUT32.163]
440  * Adds information about a type library to the System Registry
441  * NOTES
442  *    Docs: ITypeLib FAR * ptlib
443  *    Docs: OLECHAR FAR* szFullPath
444  *    Docs: OLECHAR FAR* szHelpDir
445  *
446  * RETURNS
447  *    Success: S_OK
448  *    Failure: Status
449  */
450 HRESULT WINAPI RegisterTypeLib(
451      ITypeLib * ptlib,     /* [in] Pointer to the library*/
452      OLECHAR * szFullPath, /* [in] full Path of the library*/
453      OLECHAR * szHelpDir)  /* [in] dir to the helpfile for the library,
454                                                          may be NULL*/
455 {
456     static const WCHAR PSOA[] = {'{','0','0','0','2','0','4','2','4','-',
457                                  '0','0','0','0','-','0','0','0','0','-','C','0','0','0','-',
458                                  '0','0','0','0','0','0','0','0','0','0','4','6','}',0};
459     HRESULT res;
460     TLIBATTR *attr;
461     WCHAR keyName[60];
462     WCHAR tmp[16];
463     HKEY key, subKey;
464     UINT types, tidx;
465     TYPEKIND kind;
466     DWORD disposition;
467
468     if (ptlib == NULL || szFullPath == NULL)
469         return E_INVALIDARG;
470
471     if (!SUCCEEDED(ITypeLib_GetLibAttr(ptlib, &attr)))
472         return E_FAIL;
473
474     get_typelib_key( &attr->guid, attr->wMajorVerNum, attr->wMinorVerNum, keyName );
475
476     res = S_OK;
477     if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0,
478         KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS)
479     {
480         LPOLESTR doc;
481
482         /* Set the human-readable name of the typelib */
483         if (SUCCEEDED(ITypeLib_GetDocumentation(ptlib, -1, NULL, &doc, NULL, NULL)))
484         {
485             if (RegSetValueExW(key, NULL, 0, REG_SZ,
486                 (BYTE *)doc, (lstrlenW(doc)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS)
487                 res = E_FAIL;
488
489             SysFreeString(doc);
490         }
491         else
492             res = E_FAIL;
493
494         /* Make up the name of the typelib path subkey */
495         if (!get_lcid_subkey( attr->lcid, attr->syskind, tmp )) res = E_FAIL;
496
497         /* Create the typelib path subkey */
498         if (res == S_OK && RegCreateKeyExW(key, tmp, 0, NULL, 0,
499             KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
500         {
501             if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
502                 (BYTE *)szFullPath, (lstrlenW(szFullPath)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS)
503                 res = E_FAIL;
504
505             RegCloseKey(subKey);
506         }
507         else
508             res = E_FAIL;
509
510         /* Create the flags subkey */
511         if (res == S_OK && RegCreateKeyExW(key, FLAGSW, 0, NULL, 0,
512             KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
513         {
514             /* FIXME: is %u correct? */
515             static const WCHAR formatW[] = {'%','u',0};
516             WCHAR buf[20];
517             sprintfW(buf, formatW, attr->wLibFlags);
518             if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
519                                (BYTE *)buf, (strlenW(buf) + 1)*sizeof(WCHAR) ) != ERROR_SUCCESS)
520                 res = E_FAIL;
521
522             RegCloseKey(subKey);
523         }
524         else
525             res = E_FAIL;
526
527         /* create the helpdir subkey */
528         if (res == S_OK && RegCreateKeyExW(key, HELPDIRW, 0, NULL, 0,
529             KEY_WRITE, NULL, &subKey, &disposition) == ERROR_SUCCESS)
530         {
531             BOOL freeHelpDir = FALSE;
532             OLECHAR* pIndexStr;
533
534             /* if we created a new key, and helpDir was null, set the helpdir
535                to the directory which contains the typelib. However,
536                if we just opened an existing key, we leave the helpdir alone */
537             if ((disposition == REG_CREATED_NEW_KEY) && (szHelpDir == NULL)) {
538                 szHelpDir = SysAllocString(szFullPath);
539                 pIndexStr = strrchrW(szHelpDir, '\\');
540                 if (pIndexStr) {
541                     *pIndexStr = 0;
542                 }
543                 freeHelpDir = TRUE;
544             }
545
546             /* if we have an szHelpDir, set it! */
547             if (szHelpDir != NULL) {
548                 if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
549                     (BYTE *)szHelpDir, (lstrlenW(szHelpDir)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS) {
550                     res = E_FAIL;
551                 }
552             }
553
554             /* tidy up */
555             if (freeHelpDir) SysFreeString(szHelpDir);
556             RegCloseKey(subKey);
557
558         } else {
559             res = E_FAIL;
560         }
561
562         RegCloseKey(key);
563     }
564     else
565         res = E_FAIL;
566
567     /* register OLE Automation-compatible interfaces for this typelib */
568     types = ITypeLib_GetTypeInfoCount(ptlib);
569     for (tidx=0; tidx<types; tidx++) {
570         if (SUCCEEDED(ITypeLib_GetTypeInfoType(ptlib, tidx, &kind))) {
571             LPOLESTR name = NULL;
572             ITypeInfo *tinfo = NULL;
573
574             ITypeLib_GetDocumentation(ptlib, tidx, &name, NULL, NULL, NULL);
575
576             switch (kind) {
577             case TKIND_INTERFACE:
578                 TRACE_(typelib)("%d: interface %s\n", tidx, debugstr_w(name));
579                 ITypeLib_GetTypeInfo(ptlib, tidx, &tinfo);
580                 break;
581
582             case TKIND_DISPATCH:
583                 TRACE_(typelib)("%d: dispinterface %s\n", tidx, debugstr_w(name));
584                 ITypeLib_GetTypeInfo(ptlib, tidx, &tinfo);
585                 break;
586
587             default:
588                 TRACE_(typelib)("%d: %s\n", tidx, debugstr_w(name));
589                 break;
590             }
591
592             if (tinfo) {
593                 TYPEATTR *tattr = NULL;
594                 ITypeInfo_GetTypeAttr(tinfo, &tattr);
595
596                 if (tattr) {
597                     TRACE_(typelib)("guid=%s, flags=%04x (",
598                                     debugstr_guid(&tattr->guid),
599                                     tattr->wTypeFlags);
600
601                     if (TRACE_ON(typelib)) {
602 #define XX(x) if (TYPEFLAG_##x & tattr->wTypeFlags) MESSAGE(#x"|");
603                         XX(FAPPOBJECT);
604                         XX(FCANCREATE);
605                         XX(FLICENSED);
606                         XX(FPREDECLID);
607                         XX(FHIDDEN);
608                         XX(FCONTROL);
609                         XX(FDUAL);
610                         XX(FNONEXTENSIBLE);
611                         XX(FOLEAUTOMATION);
612                         XX(FRESTRICTED);
613                         XX(FAGGREGATABLE);
614                         XX(FREPLACEABLE);
615                         XX(FDISPATCHABLE);
616                         XX(FREVERSEBIND);
617                         XX(FPROXY);
618 #undef XX
619                         MESSAGE("\n");
620                     }
621
622                     if (tattr->wTypeFlags & (TYPEFLAG_FOLEAUTOMATION|TYPEFLAG_FDUAL))
623                     {
624                         /* register interface<->typelib coupling */
625                         get_interface_key( &tattr->guid, keyName );
626                         if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0,
627                                             KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS)
628                         {
629                             if (name)
630                                 RegSetValueExW(key, NULL, 0, REG_SZ,
631                                                (BYTE *)name, (strlenW(name)+1) * sizeof(OLECHAR));
632
633                             if (RegCreateKeyExW(key, ProxyStubClsidW, 0, NULL, 0,
634                                 KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) {
635                                 RegSetValueExW(subKey, NULL, 0, REG_SZ,
636                                                (BYTE*)PSOA, sizeof PSOA);
637                                 RegCloseKey(subKey);
638                             }
639
640                             if (RegCreateKeyExW(key, ProxyStubClsid32W, 0, NULL, 0,
641                                 KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) {
642                                 RegSetValueExW(subKey, NULL, 0, REG_SZ,
643                                                (BYTE*)PSOA, sizeof PSOA);
644                                 RegCloseKey(subKey);
645                             }
646
647                             if (RegCreateKeyExW(key, TypeLibW, 0, NULL, 0,
648                                 KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
649                             {
650                                 WCHAR buffer[40];
651                                 static const WCHAR fmtver[] = {'%','u','.','%','u',0 };
652                                 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
653
654                                 StringFromGUID2(&attr->guid, buffer, 40);
655                                 RegSetValueExW(subKey, NULL, 0, REG_SZ,
656                                                (BYTE *)buffer, (strlenW(buffer)+1) * sizeof(WCHAR));
657                                 sprintfW(buffer, fmtver, attr->wMajorVerNum, attr->wMinorVerNum);
658                                 RegSetValueExW(subKey, VersionW, 0, REG_SZ,
659                                                (BYTE*)buffer, (strlenW(buffer)+1) * sizeof(WCHAR));
660                                 RegCloseKey(subKey);
661                             }
662
663                             RegCloseKey(key);
664                         }
665                     }
666
667                     ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
668                 }
669
670                 ITypeInfo_Release(tinfo);
671             }
672
673             SysFreeString(name);
674         }
675     }
676
677     ITypeLib_ReleaseTLibAttr(ptlib, attr);
678
679     return res;
680 }
681
682
683 /******************************************************************************
684  *      UnRegisterTypeLib       [OLEAUT32.186]
685  * Removes information about a type library from the System Registry
686  * NOTES
687  *
688  * RETURNS
689  *    Success: S_OK
690  *    Failure: Status
691  */
692 HRESULT WINAPI UnRegisterTypeLib(
693     REFGUID libid,      /* [in] Guid of the library */
694         WORD wVerMajor, /* [in] major version */
695         WORD wVerMinor, /* [in] minor version */
696         LCID lcid,      /* [in] locale id */
697         SYSKIND syskind)
698 {
699     BSTR tlibPath = NULL;
700     DWORD tmpLength;
701     WCHAR keyName[60];
702     WCHAR subKeyName[50];
703     int result = S_OK;
704     DWORD i = 0;
705     BOOL deleteOtherStuff;
706     HKEY key = NULL;
707     HKEY subKey = NULL;
708     TYPEATTR* typeAttr = NULL;
709     TYPEKIND kind;
710     ITypeInfo* typeInfo = NULL;
711     ITypeLib* typeLib = NULL;
712     int numTypes;
713
714     TRACE("(IID: %s): stub\n",debugstr_guid(libid));
715
716     /* Create the path to the key */
717     get_typelib_key( libid, wVerMajor, wVerMinor, keyName );
718
719     if (syskind != SYS_WIN16 && syskind != SYS_WIN32)
720     {
721         TRACE("Unsupported syskind %i\n", syskind);
722         result = E_INVALIDARG;
723         goto end;
724     }
725
726     /* get the path to the typelib on disk */
727     if (QueryPathOfRegTypeLib(libid, wVerMajor, wVerMinor, lcid, &tlibPath) != S_OK) {
728         result = E_INVALIDARG;
729         goto end;
730     }
731
732     /* Try and open the key to the type library. */
733     if (RegOpenKeyExW(HKEY_CLASSES_ROOT, keyName, 0, KEY_READ | KEY_WRITE, &key) != S_OK) {
734         result = E_INVALIDARG;
735         goto end;
736     }
737
738     /* Try and load the type library */
739     if (LoadTypeLibEx(tlibPath, REGKIND_NONE, &typeLib)) {
740         result = TYPE_E_INVALIDSTATE;
741         goto end;
742     }
743
744     /* remove any types registered with this typelib */
745     numTypes = ITypeLib_GetTypeInfoCount(typeLib);
746     for (i=0; i<numTypes; i++) {
747         /* get the kind of type */
748         if (ITypeLib_GetTypeInfoType(typeLib, i, &kind) != S_OK) {
749             goto enddeleteloop;
750         }
751
752         /* skip non-interfaces, and get type info for the type */
753         if ((kind != TKIND_INTERFACE) && (kind != TKIND_DISPATCH)) {
754             goto enddeleteloop;
755         }
756         if (ITypeLib_GetTypeInfo(typeLib, i, &typeInfo) != S_OK) {
757             goto enddeleteloop;
758         }
759         if (ITypeInfo_GetTypeAttr(typeInfo, &typeAttr) != S_OK) {
760             goto enddeleteloop;
761         }
762
763         /* the path to the type */
764         get_interface_key( &typeAttr->guid, subKeyName );
765
766         /* Delete its bits */
767         if (RegOpenKeyExW(HKEY_CLASSES_ROOT, subKeyName, 0, KEY_WRITE, &subKey) != S_OK) {
768             goto enddeleteloop;
769         }
770         RegDeleteKeyW(subKey, ProxyStubClsidW);
771         RegDeleteKeyW(subKey, ProxyStubClsid32W);
772         RegDeleteKeyW(subKey, TypeLibW);
773         RegCloseKey(subKey);
774         subKey = NULL;
775         RegDeleteKeyW(HKEY_CLASSES_ROOT, subKeyName);
776
777 enddeleteloop:
778         if (typeAttr) ITypeInfo_ReleaseTypeAttr(typeInfo, typeAttr);
779         typeAttr = NULL;
780         if (typeInfo) ITypeInfo_Release(typeInfo);
781         typeInfo = NULL;
782     }
783
784     /* Now, delete the type library path subkey */
785     get_lcid_subkey( lcid, syskind, subKeyName );
786     RegDeleteKeyW(key, subKeyName);
787     *strrchrW( subKeyName, '\\' ) = 0;  /* remove last path component */
788     RegDeleteKeyW(key, subKeyName);
789
790     /* check if there is anything besides the FLAGS/HELPDIR keys.
791        If there is, we don't delete them */
792     tmpLength = sizeof(subKeyName)/sizeof(WCHAR);
793     deleteOtherStuff = TRUE;
794     i = 0;
795     while(RegEnumKeyExW(key, i++, subKeyName, &tmpLength, NULL, NULL, NULL, NULL) == S_OK) {
796         tmpLength = sizeof(subKeyName)/sizeof(WCHAR);
797
798         /* if its not FLAGS or HELPDIR, then we must keep the rest of the key */
799         if (!strcmpW(subKeyName, FLAGSW)) continue;
800         if (!strcmpW(subKeyName, HELPDIRW)) continue;
801         deleteOtherStuff = FALSE;
802         break;
803     }
804
805     /* only delete the other parts of the key if we're absolutely sure */
806     if (deleteOtherStuff) {
807         RegDeleteKeyW(key, FLAGSW);
808         RegDeleteKeyW(key, HELPDIRW);
809         RegCloseKey(key);
810         key = NULL;
811
812         RegDeleteKeyW(HKEY_CLASSES_ROOT, keyName);
813         *strrchrW( keyName, '\\' ) = 0;  /* remove last path component */
814         RegDeleteKeyW(HKEY_CLASSES_ROOT, keyName);
815     }
816
817 end:
818     if (tlibPath) SysFreeString(tlibPath);
819     if (typeLib) ITypeLib_Release(typeLib);
820     if (subKey) RegCloseKey(subKey);
821     if (key) RegCloseKey(key);
822     return result;
823 }
824
825 /*======================= ITypeLib implementation =======================*/
826
827 typedef struct tagTLBCustData
828 {
829     GUID guid;
830     VARIANT data;
831     struct tagTLBCustData* next;
832 } TLBCustData;
833
834 /* data structure for import typelibs */
835 typedef struct tagTLBImpLib
836 {
837     int offset;                 /* offset in the file (MSFT)
838                                    offset in nametable (SLTG)
839                                    just used to identify library while reading
840                                    data from file */
841     GUID guid;                  /* libid */
842     BSTR name;                  /* name */
843
844     LCID lcid;                  /* lcid of imported typelib */
845
846     WORD wVersionMajor;         /* major version number */
847     WORD wVersionMinor;         /* minor version number */
848
849     struct tagITypeLibImpl *pImpTypeLib; /* pointer to loaded typelib, or
850                                             NULL if not yet loaded */
851     struct tagTLBImpLib * next;
852 } TLBImpLib;
853
854 /* internal ITypeLib data */
855 typedef struct tagITypeLibImpl
856 {
857     const ITypeLib2Vtbl *lpVtbl;
858     const ITypeCompVtbl *lpVtblTypeComp;
859     LONG ref;
860     TLIBATTR LibAttr;            /* guid,lcid,syskind,version,flags */
861
862     /* strings can be stored in tlb as multibyte strings BUT they are *always*
863      * exported to the application as a UNICODE string.
864      */
865     BSTR Name;
866     BSTR DocString;
867     BSTR HelpFile;
868     BSTR HelpStringDll;
869     unsigned long  dwHelpContext;
870     int TypeInfoCount;          /* nr of typeinfo's in librarry */
871     struct tagITypeInfoImpl *pTypeInfo;   /* linked list of type info data */
872     int ctCustData;             /* number of items in cust data list */
873     TLBCustData * pCustData;    /* linked list to cust data */
874     TLBImpLib   * pImpLibs;     /* linked list to all imported typelibs */
875     TYPEDESC * pTypeDesc;       /* array of TypeDescriptions found in the
876                                    libary. Only used while read MSFT
877                                    typelibs */
878
879     /* typelibs are cached, keyed by path and index, so store the linked list info within them */
880     struct tagITypeLibImpl *next, *prev;
881     WCHAR *path;
882     INT index;
883 } ITypeLibImpl;
884
885 static const ITypeLib2Vtbl tlbvt;
886 static const ITypeCompVtbl tlbtcvt;
887
888 static inline ITypeLibImpl *impl_from_ITypeComp( ITypeComp *iface )
889 {
890     return (ITypeLibImpl *)((char*)iface - FIELD_OFFSET(ITypeLibImpl, lpVtblTypeComp));
891 }
892
893 /* ITypeLib methods */
894 static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength);
895 static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength);
896
897 /*======================= ITypeInfo implementation =======================*/
898
899 /* data for referenced types */
900 typedef struct tagTLBRefType
901 {
902     INT index;              /* Type index for internal ref or for external ref
903                                it the format is SLTG.  -2 indicates to
904                                use guid */
905
906     GUID guid;              /* guid of the referenced type */
907                             /* if index == TLB_REF_USE_GUID */
908
909     HREFTYPE reference;     /* The href of this ref */
910     TLBImpLib *pImpTLInfo;  /* If ref is external ptr to library data
911                                TLB_REF_INTERNAL for internal refs
912                                TLB_REF_NOT_FOUND for broken refs */
913
914     struct tagTLBRefType * next;
915 } TLBRefType;
916
917 #define TLB_REF_USE_GUID -2
918
919 #define TLB_REF_INTERNAL (void*)-2
920 #define TLB_REF_NOT_FOUND (void*)-1
921
922 /* internal Parameter data */
923 typedef struct tagTLBParDesc
924 {
925     BSTR Name;
926     int ctCustData;
927     TLBCustData * pCustData;        /* linked list to cust data */
928 } TLBParDesc;
929
930 /* internal Function data */
931 typedef struct tagTLBFuncDesc
932 {
933     FUNCDESC funcdesc;      /* lots of info on the function and its attributes. */
934     BSTR Name;             /* the name of this function */
935     TLBParDesc *pParamDesc; /* array with param names and custom data */
936     int helpcontext;
937     int HelpStringContext;
938     BSTR HelpString;
939     BSTR Entry;            /* if its Hiword==0, it numeric; -1 is not present*/
940     int ctCustData;
941     TLBCustData * pCustData;        /* linked list to cust data; */
942     struct tagTLBFuncDesc * next;
943 } TLBFuncDesc;
944
945 /* internal Variable data */
946 typedef struct tagTLBVarDesc
947 {
948     VARDESC vardesc;        /* lots of info on the variable and its attributes. */
949     BSTR Name;             /* the name of this variable */
950     int HelpContext;
951     int HelpStringContext;  /* FIXME: where? */
952     BSTR HelpString;
953     int ctCustData;
954     TLBCustData * pCustData;/* linked list to cust data; */
955     struct tagTLBVarDesc * next;
956 } TLBVarDesc;
957
958 /* internal implemented interface data */
959 typedef struct tagTLBImplType
960 {
961     HREFTYPE hRef;          /* hRef of interface */
962     int implflags;          /* IMPLFLAG_*s */
963     int ctCustData;
964     TLBCustData * pCustData;/* linked list to custom data; */
965     struct tagTLBImplType *next;
966 } TLBImplType;
967
968 /* internal TypeInfo data */
969 typedef struct tagITypeInfoImpl
970 {
971     const ITypeInfo2Vtbl *lpVtbl;
972     const ITypeCompVtbl  *lpVtblTypeComp;
973     LONG ref;
974     TYPEATTR TypeAttr ;         /* _lots_ of type information. */
975     ITypeLibImpl * pTypeLib;        /* back pointer to typelib */
976     int index;                  /* index in this typelib; */
977     /* type libs seem to store the doc strings in ascii
978      * so why should we do it in unicode?
979      */
980     BSTR Name;
981     BSTR DocString;
982     BSTR DllName;
983     unsigned long  dwHelpContext;
984     unsigned long  dwHelpStringContext;
985
986     /* functions  */
987     TLBFuncDesc * funclist;     /* linked list with function descriptions */
988
989     /* variables  */
990     TLBVarDesc * varlist;       /* linked list with variable descriptions */
991
992     /* Implemented Interfaces  */
993     TLBImplType * impltypelist;
994
995     TLBRefType * reflist;
996     int ctCustData;
997     TLBCustData * pCustData;        /* linked list to cust data; */
998     struct tagITypeInfoImpl * next;
999 } ITypeInfoImpl;
1000
1001 static inline ITypeInfoImpl *info_impl_from_ITypeComp( ITypeComp *iface )
1002 {
1003     return (ITypeInfoImpl *)((char*)iface - FIELD_OFFSET(ITypeInfoImpl, lpVtblTypeComp));
1004 }
1005
1006 static const ITypeInfo2Vtbl tinfvt;
1007 static const ITypeCompVtbl  tcompvt;
1008
1009 static ITypeInfo2 * WINAPI ITypeInfo_Constructor(void);
1010
1011 typedef struct tagTLBContext
1012 {
1013         unsigned int oStart;  /* start of TLB in file */
1014         unsigned int pos;     /* current pos */
1015         unsigned int length;  /* total length */
1016         void *mapping;        /* memory mapping */
1017         MSFT_SegDir * pTblDir;
1018         ITypeLibImpl* pLibInfo;
1019 } TLBContext;
1020
1021
1022 static void MSFT_DoRefType(TLBContext *pcx, ITypeInfoImpl *pTI, int offset);
1023
1024 /*
1025  debug
1026 */
1027 static void dump_TypeDesc(TYPEDESC *pTD,char *szVarType) {
1028     if (pTD->vt & VT_RESERVED)
1029         szVarType += strlen(strcpy(szVarType, "reserved | "));
1030     if (pTD->vt & VT_BYREF)
1031         szVarType += strlen(strcpy(szVarType, "ref to "));
1032     if (pTD->vt & VT_ARRAY)
1033         szVarType += strlen(strcpy(szVarType, "array of "));
1034     if (pTD->vt & VT_VECTOR)
1035         szVarType += strlen(strcpy(szVarType, "vector of "));
1036     switch(pTD->vt & VT_TYPEMASK) {
1037     case VT_UI1: sprintf(szVarType, "VT_UI1"); break;
1038     case VT_I2: sprintf(szVarType, "VT_I2"); break;
1039     case VT_I4: sprintf(szVarType, "VT_I4"); break;
1040     case VT_R4: sprintf(szVarType, "VT_R4"); break;
1041     case VT_R8: sprintf(szVarType, "VT_R8"); break;
1042     case VT_BOOL: sprintf(szVarType, "VT_BOOL"); break;
1043     case VT_ERROR: sprintf(szVarType, "VT_ERROR"); break;
1044     case VT_CY: sprintf(szVarType, "VT_CY"); break;
1045     case VT_DATE: sprintf(szVarType, "VT_DATE"); break;
1046     case VT_BSTR: sprintf(szVarType, "VT_BSTR"); break;
1047     case VT_UNKNOWN: sprintf(szVarType, "VT_UNKNOWN"); break;
1048     case VT_DISPATCH: sprintf(szVarType, "VT_DISPATCH"); break;
1049     case VT_I1: sprintf(szVarType, "VT_I1"); break;
1050     case VT_UI2: sprintf(szVarType, "VT_UI2"); break;
1051     case VT_UI4: sprintf(szVarType, "VT_UI4"); break;
1052     case VT_INT: sprintf(szVarType, "VT_INT"); break;
1053     case VT_UINT: sprintf(szVarType, "VT_UINT"); break;
1054     case VT_VARIANT: sprintf(szVarType, "VT_VARIANT"); break;
1055     case VT_VOID: sprintf(szVarType, "VT_VOID"); break;
1056     case VT_HRESULT: sprintf(szVarType, "VT_HRESULT"); break;
1057     case VT_USERDEFINED: sprintf(szVarType, "VT_USERDEFINED ref = %lx",
1058                                  pTD->u.hreftype); break;
1059     case VT_PTR: sprintf(szVarType, "ptr to ");
1060       dump_TypeDesc(pTD->u.lptdesc, szVarType + 7);
1061       break;
1062     case VT_SAFEARRAY: sprintf(szVarType, "safearray of ");
1063       dump_TypeDesc(pTD->u.lptdesc, szVarType + 13);
1064       break;
1065     case VT_CARRAY: sprintf(szVarType, "%d dim array of ",
1066                             pTD->u.lpadesc->cDims); /* FIXME print out sizes */
1067       dump_TypeDesc(&pTD->u.lpadesc->tdescElem, szVarType + strlen(szVarType));
1068       break;
1069
1070     default: sprintf(szVarType, "unknown(%d)", pTD->vt & VT_TYPEMASK); break;
1071     }
1072 }
1073
1074 static void dump_ELEMDESC(ELEMDESC *edesc) {
1075   char buf[200];
1076   dump_TypeDesc(&edesc->tdesc,buf);
1077   MESSAGE("\t\ttdesc.vartype %d (%s)\n",edesc->tdesc.vt,buf);
1078   MESSAGE("\t\tu.parmadesc.flags %x\n",edesc->u.paramdesc.wParamFlags);
1079   MESSAGE("\t\tu.parmadesc.lpex %p\n",edesc->u.paramdesc.pparamdescex);
1080 }
1081 static void dump_FUNCDESC(FUNCDESC *funcdesc) {
1082   int i;
1083   MESSAGE("memid is %08lx\n",funcdesc->memid);
1084   for (i=0;i<funcdesc->cParams;i++) {
1085       MESSAGE("Param %d:\n",i);
1086       dump_ELEMDESC(funcdesc->lprgelemdescParam+i);
1087   }
1088   MESSAGE("\tfunckind: %d (",funcdesc->funckind);
1089   switch (funcdesc->funckind) {
1090   case FUNC_VIRTUAL: MESSAGE("virtual");break;
1091   case FUNC_PUREVIRTUAL: MESSAGE("pure virtual");break;
1092   case FUNC_NONVIRTUAL: MESSAGE("nonvirtual");break;
1093   case FUNC_STATIC: MESSAGE("static");break;
1094   case FUNC_DISPATCH: MESSAGE("dispatch");break;
1095   default: MESSAGE("unknown");break;
1096   }
1097   MESSAGE(")\n\tinvkind: %d (",funcdesc->invkind);
1098   switch (funcdesc->invkind) {
1099   case INVOKE_FUNC: MESSAGE("func");break;
1100   case INVOKE_PROPERTYGET: MESSAGE("property get");break;
1101   case INVOKE_PROPERTYPUT: MESSAGE("property put");break;
1102   case INVOKE_PROPERTYPUTREF: MESSAGE("property put ref");break;
1103   }
1104   MESSAGE(")\n\tcallconv: %d (",funcdesc->callconv);
1105   switch (funcdesc->callconv) {
1106   case CC_CDECL: MESSAGE("cdecl");break;
1107   case CC_PASCAL: MESSAGE("pascal");break;
1108   case CC_STDCALL: MESSAGE("stdcall");break;
1109   case CC_SYSCALL: MESSAGE("syscall");break;
1110   default:break;
1111   }
1112   MESSAGE(")\n\toVft: %d\n", funcdesc->oVft);
1113   MESSAGE("\tcParamsOpt: %d\n", funcdesc->cParamsOpt);
1114   MESSAGE("\twFlags: %x\n", funcdesc->wFuncFlags);
1115
1116   MESSAGE("\telemdescFunc (return value type):\n");
1117   dump_ELEMDESC(&funcdesc->elemdescFunc);
1118 }
1119
1120 static const char * typekind_desc[] =
1121 {
1122         "TKIND_ENUM",
1123         "TKIND_RECORD",
1124         "TKIND_MODULE",
1125         "TKIND_INTERFACE",
1126         "TKIND_DISPATCH",
1127         "TKIND_COCLASS",
1128         "TKIND_ALIAS",
1129         "TKIND_UNION",
1130         "TKIND_MAX"
1131 };
1132
1133 static void dump_TLBFuncDescOne(TLBFuncDesc * pfd)
1134 {
1135   int i;
1136   if (!TRACE_ON(typelib))
1137       return;
1138   MESSAGE("%s(%u)\n", debugstr_w(pfd->Name), pfd->funcdesc.cParams);
1139   for (i=0;i<pfd->funcdesc.cParams;i++)
1140       MESSAGE("\tparm%d: %s\n",i,debugstr_w(pfd->pParamDesc[i].Name));
1141
1142
1143   dump_FUNCDESC(&(pfd->funcdesc));
1144
1145   MESSAGE("\thelpstring: %s\n", debugstr_w(pfd->HelpString));
1146   MESSAGE("\tentry: %s\n", debugstr_w(pfd->Entry));
1147 }
1148 static void dump_TLBFuncDesc(TLBFuncDesc * pfd)
1149 {
1150         while (pfd)
1151         {
1152           dump_TLBFuncDescOne(pfd);
1153           pfd = pfd->next;
1154         };
1155 }
1156 static void dump_TLBVarDesc(TLBVarDesc * pvd)
1157 {
1158         while (pvd)
1159         {
1160           TRACE_(typelib)("%s\n", debugstr_w(pvd->Name));
1161           pvd = pvd->next;
1162         };
1163 }
1164
1165 static void dump_TLBImpLib(TLBImpLib *import)
1166 {
1167     TRACE_(typelib)("%s %s\n", debugstr_guid(&(import->guid)),
1168                     debugstr_w(import->name));
1169     TRACE_(typelib)("v%d.%d lcid=%lx offset=%x\n", import->wVersionMajor,
1170                     import->wVersionMinor, import->lcid, import->offset);
1171 }
1172
1173 static void dump_TLBRefType(TLBRefType * prt)
1174 {
1175         while (prt)
1176         {
1177           TRACE_(typelib)("href:0x%08lx\n", prt->reference);
1178           if(prt->index == -1)
1179             TRACE_(typelib)("%s\n", debugstr_guid(&(prt->guid)));
1180           else
1181             TRACE_(typelib)("type no: %d\n", prt->index);
1182
1183           if(prt->pImpTLInfo != TLB_REF_INTERNAL &&
1184              prt->pImpTLInfo != TLB_REF_NOT_FOUND) {
1185               TRACE_(typelib)("in lib\n");
1186               dump_TLBImpLib(prt->pImpTLInfo);
1187           }
1188           prt = prt->next;
1189         };
1190 }
1191
1192 static void dump_TLBImplType(TLBImplType * impl)
1193 {
1194     while (impl) {
1195         TRACE_(typelib)(
1196                 "implementing/inheriting interface hRef = %lx implflags %x\n",
1197                 impl->hRef, impl->implflags);
1198         impl = impl->next;
1199     }
1200 }
1201
1202 void dump_Variant(VARIANT * pvar)
1203 {
1204     SYSTEMTIME st;
1205
1206     TRACE("%p->{%s%s", pvar, debugstr_VT(pvar), debugstr_VF(pvar));
1207
1208     if (pvar)
1209     {
1210       if (V_ISBYREF(pvar) || V_TYPE(pvar) == VT_UNKNOWN ||
1211           V_TYPE(pvar) == VT_DISPATCH || V_TYPE(pvar) == VT_RECORD)
1212       {
1213         TRACE(",%p", V_BYREF(pvar));
1214       }
1215       else if (V_ISARRAY(pvar) || V_ISVECTOR(pvar))
1216       {
1217         TRACE(",FIXME");
1218       }
1219       else switch (V_TYPE(pvar))
1220       {
1221       case VT_I1:   TRACE(",%d", V_I1(pvar)); break;
1222       case VT_UI1:  TRACE(",%d", V_UI1(pvar)); break;
1223       case VT_I2:   TRACE(",%d", V_I2(pvar)); break;
1224       case VT_UI2:  TRACE(",%d", V_UI2(pvar)); break;
1225       case VT_INT:
1226       case VT_I4:   TRACE(",%ld", V_I4(pvar)); break;
1227       case VT_UINT:
1228       case VT_UI4:  TRACE(",%ld", V_UI4(pvar)); break;
1229       case VT_I8:   TRACE(",0x%08lx,0x%08lx", (ULONG)(V_I8(pvar) >> 32),
1230                           (ULONG)(V_I8(pvar) & 0xffffffff)); break;
1231       case VT_UI8:  TRACE(",0x%08lx,0x%08lx", (ULONG)(V_UI8(pvar) >> 32),
1232                           (ULONG)(V_UI8(pvar) & 0xffffffff)); break;
1233       case VT_R4:   TRACE(",%3.3e", V_R4(pvar)); break;
1234       case VT_R8:   TRACE(",%3.3e", V_R8(pvar)); break;
1235       case VT_BOOL: TRACE(",%s", V_BOOL(pvar) ? "TRUE" : "FALSE"); break;
1236       case VT_BSTR: TRACE(",%s", debugstr_w(V_BSTR(pvar))); break;
1237       case VT_CY:   TRACE(",0x%08lx,0x%08lx", V_CY(pvar).s.Hi,
1238                            V_CY(pvar).s.Lo); break;
1239       case VT_DATE:
1240         if(!VariantTimeToSystemTime(V_DATE(pvar), &st))
1241           TRACE(",<invalid>");
1242         else
1243           TRACE(",%04d/%02d/%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay,
1244                 st.wHour, st.wMinute, st.wSecond);
1245         break;
1246       case VT_ERROR:
1247       case VT_VOID:
1248       case VT_USERDEFINED:
1249       case VT_EMPTY:
1250       case VT_NULL:  break;
1251       default:       TRACE(",?"); break;
1252       }
1253     }
1254     TRACE("}\n");
1255 }
1256
1257 static void dump_DispParms(DISPPARAMS * pdp)
1258 {
1259     int index = 0;
1260
1261     TRACE("args=%u named args=%u\n", pdp->cArgs, pdp->cNamedArgs);
1262
1263     while (index < pdp->cArgs)
1264     {
1265         dump_Variant( &pdp->rgvarg[index] );
1266         ++index;
1267     }
1268 }
1269
1270 static void dump_TypeInfo(ITypeInfoImpl * pty)
1271 {
1272     TRACE("%p ref=%lu\n", pty, pty->ref);
1273     TRACE("attr:%s\n", debugstr_guid(&(pty->TypeAttr.guid)));
1274     TRACE("kind:%s\n", typekind_desc[pty->TypeAttr.typekind]);
1275     TRACE("fct:%u var:%u impl:%u\n",
1276       pty->TypeAttr.cFuncs, pty->TypeAttr.cVars, pty->TypeAttr.cImplTypes);
1277     TRACE("parent tlb:%p index in TLB:%u\n",pty->pTypeLib, pty->index);
1278     TRACE("%s %s\n", debugstr_w(pty->Name), debugstr_w(pty->DocString));
1279     if (pty->TypeAttr.typekind == TKIND_MODULE) TRACE("dllname:%s\n", debugstr_w(pty->DllName));
1280     dump_TLBFuncDesc(pty->funclist);
1281     dump_TLBVarDesc(pty->varlist);
1282     dump_TLBImplType(pty->impltypelist);
1283 }
1284
1285 static void dump_VARDESC(VARDESC *v)
1286 {
1287     MESSAGE("memid %ld\n",v->memid);
1288     MESSAGE("lpstrSchema %s\n",debugstr_w(v->lpstrSchema));
1289     MESSAGE("oInst %ld\n",v->u.oInst);
1290     dump_ELEMDESC(&(v->elemdescVar));
1291     MESSAGE("wVarFlags %x\n",v->wVarFlags);
1292     MESSAGE("varkind %d\n",v->varkind);
1293 }
1294
1295 static TYPEDESC stndTypeDesc[VT_LPWSTR+1]=
1296 {
1297     /* VT_LPWSTR is largest type that */
1298     /* may appear in type description*/
1299     {{0}, 0},{{0}, 1},{{0}, 2},{{0}, 3},{{0}, 4},
1300     {{0}, 5},{{0}, 6},{{0}, 7},{{0}, 8},{{0}, 9},
1301     {{0},10},{{0},11},{{0},12},{{0},13},{{0},14},
1302     {{0},15},{{0},16},{{0},17},{{0},18},{{0},19},
1303     {{0},20},{{0},21},{{0},22},{{0},23},{{0},24},
1304     {{0},25},{{0},26},{{0},27},{{0},28},{{0},29},
1305     {{0},30},{{0},31}
1306 };
1307
1308 static void TLB_abort(void)
1309 {
1310     DebugBreak();
1311 }
1312 static void * TLB_Alloc(unsigned size)
1313 {
1314     void * ret;
1315     if((ret=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size))==NULL){
1316         /* FIXME */
1317         ERR("cannot allocate memory\n");
1318     }
1319     return ret;
1320 }
1321
1322 static void TLB_Free(void * ptr)
1323 {
1324     HeapFree(GetProcessHeap(), 0, ptr);
1325 }
1326
1327 /* deep copy a typedesc */
1328 static void copy_typedesc(TYPEDESC *out, const TYPEDESC *in)
1329 {
1330     out->vt = in->vt;
1331     switch(in->vt) {
1332     case VT_PTR:
1333         out->u.lptdesc = HeapAlloc(GetProcessHeap(), 0, sizeof(TYPEDESC));
1334         copy_typedesc(out->u.lptdesc, in->u.lptdesc);
1335         break;
1336     case VT_USERDEFINED:
1337         out->u.hreftype = in->u.hreftype;
1338         break;
1339     case VT_CARRAY:
1340         out->u.lpadesc = HeapAlloc(GetProcessHeap(), 0, sizeof(ARRAYDESC) +
1341                                    (in->u.lpadesc->cDims - 1) * sizeof(SAFEARRAYBOUND));
1342         copy_typedesc(&out->u.lpadesc->tdescElem, &in->u.lpadesc->tdescElem);
1343         out->u.lpadesc->cDims = in->u.lpadesc->cDims;
1344         memcpy(out->u.lpadesc->rgbounds, in->u.lpadesc->rgbounds, in->u.lpadesc->cDims * sizeof(SAFEARRAYBOUND));
1345         break;
1346     default:
1347         break;
1348     }
1349 }
1350
1351 /* free()s any allocated memory pointed to by the tdesc.  NB does not
1352    free the tdesc itself - this is because the tdesc is typically part
1353    of a larger structure */
1354 static void free_deep_typedesc(TYPEDESC *tdesc)
1355 {
1356     switch(tdesc->vt) {
1357     case VT_PTR:
1358         free_deep_typedesc(tdesc->u.lptdesc);
1359         HeapFree(GetProcessHeap(), 0, tdesc->u.lptdesc);
1360         tdesc->u.lptdesc = NULL;
1361         break;
1362     case VT_CARRAY:
1363         free_deep_typedesc(&tdesc->u.lpadesc->tdescElem);
1364         HeapFree(GetProcessHeap(), 0, tdesc->u.lpadesc);
1365         tdesc->u.lpadesc = NULL;
1366         break;
1367     default:
1368         break;
1369     }
1370 }
1371
1372 /**********************************************************************
1373  *
1374  *  Functions for reading MSFT typelibs (those created by CreateTypeLib2)
1375  */
1376 /* read function */
1377 static DWORD MSFT_Read(void *buffer,  DWORD count, TLBContext *pcx, long where )
1378 {
1379     TRACE_(typelib)("pos=0x%08x len=0x%08lx 0x%08x 0x%08x 0x%08lx\n",
1380        pcx->pos, count, pcx->oStart, pcx->length, where);
1381
1382     if (where != DO_NOT_SEEK)
1383     {
1384         where += pcx->oStart;
1385         if (where > pcx->length)
1386         {
1387             /* FIXME */
1388             ERR("seek beyond end (%ld/%d)\n", where, pcx->length );
1389             TLB_abort();
1390         }
1391         pcx->pos = where;
1392     }
1393     if (pcx->pos + count > pcx->length) count = pcx->length - pcx->pos;
1394     memcpy( buffer, (char *)pcx->mapping + pcx->pos, count );
1395     pcx->pos += count;
1396     return count;
1397 }
1398
1399 static DWORD MSFT_ReadLEDWords(void *buffer,  DWORD count, TLBContext *pcx,
1400                                long where )
1401 {
1402   DWORD ret;
1403
1404   ret = MSFT_Read(buffer, count, pcx, where);
1405   FromLEDWords(buffer, ret);
1406
1407   return ret;
1408 }
1409
1410 static DWORD MSFT_ReadLEWords(void *buffer,  DWORD count, TLBContext *pcx,
1411                               long where )
1412 {
1413   DWORD ret;
1414
1415   ret = MSFT_Read(buffer, count, pcx, where);
1416   FromLEWords(buffer, ret);
1417
1418   return ret;
1419 }
1420
1421 static void MSFT_ReadGuid( GUID *pGuid, int offset, TLBContext *pcx)
1422 {
1423     if(offset<0 || pcx->pTblDir->pGuidTab.offset <0){
1424         memset(pGuid,0, sizeof(GUID));
1425         return;
1426     }
1427     MSFT_Read(pGuid, sizeof(GUID), pcx, pcx->pTblDir->pGuidTab.offset+offset );
1428     pGuid->Data1 = FromLEDWord(pGuid->Data1);
1429     pGuid->Data2 = FromLEWord(pGuid->Data2);
1430     pGuid->Data3 = FromLEWord(pGuid->Data3);
1431     TRACE_(typelib)("%s\n", debugstr_guid(pGuid));
1432 }
1433
1434 static BSTR MSFT_ReadName( TLBContext *pcx, int offset)
1435 {
1436     char * name;
1437     MSFT_NameIntro niName;
1438     int lengthInChars;
1439     WCHAR* pwstring = NULL;
1440     BSTR bstrName = NULL;
1441
1442     if (offset < 0)
1443     {
1444         ERR_(typelib)("bad offset %d\n", offset);
1445         return NULL;
1446     }
1447     MSFT_ReadLEDWords(&niName, sizeof(niName), pcx,
1448                       pcx->pTblDir->pNametab.offset+offset);
1449     niName.namelen &= 0xFF; /* FIXME: correct ? */
1450     name=TLB_Alloc((niName.namelen & 0xff) +1);
1451     MSFT_Read(name, (niName.namelen & 0xff), pcx, DO_NOT_SEEK);
1452     name[niName.namelen & 0xff]='\0';
1453
1454     lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
1455                                         name, -1, NULL, 0);
1456
1457     /* no invalid characters in string */
1458     if (lengthInChars)
1459     {
1460         pwstring = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*lengthInChars);
1461
1462         /* don't check for invalid character since this has been done previously */
1463         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name, -1, pwstring, lengthInChars);
1464
1465         bstrName = SysAllocStringLen(pwstring, lengthInChars);
1466         lengthInChars = SysStringLen(bstrName);
1467         HeapFree(GetProcessHeap(), 0, pwstring);
1468     }
1469
1470     TRACE_(typelib)("%s %d\n", debugstr_w(bstrName), lengthInChars);
1471     return bstrName;
1472 }
1473
1474 static BSTR MSFT_ReadString( TLBContext *pcx, int offset)
1475 {
1476     char * string;
1477     INT16 length;
1478     int lengthInChars;
1479     BSTR bstr = NULL;
1480
1481     if(offset<0) return NULL;
1482     MSFT_ReadLEWords(&length, sizeof(INT16), pcx, pcx->pTblDir->pStringtab.offset+offset);
1483     if(length <= 0) return 0;
1484     string=TLB_Alloc(length +1);
1485     MSFT_Read(string, length, pcx, DO_NOT_SEEK);
1486     string[length]='\0';
1487
1488     lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
1489                                         string, -1, NULL, 0);
1490
1491     /* no invalid characters in string */
1492     if (lengthInChars)
1493     {
1494         WCHAR* pwstring = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*lengthInChars);
1495
1496         /* don't check for invalid character since this has been done previously */
1497         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, string, -1, pwstring, lengthInChars);
1498
1499         bstr = SysAllocStringLen(pwstring, lengthInChars);
1500         lengthInChars = SysStringLen(bstr);
1501         HeapFree(GetProcessHeap(), 0, pwstring);
1502     }
1503
1504     TRACE_(typelib)("%s %d\n", debugstr_w(bstr), lengthInChars);
1505     return bstr;
1506 }
1507 /*
1508  * read a value and fill a VARIANT structure
1509  */
1510 static void MSFT_ReadValue( VARIANT * pVar, int offset, TLBContext *pcx )
1511 {
1512     int size;
1513
1514     TRACE_(typelib)("\n");
1515
1516     if(offset <0) { /* data are packed in here */
1517         V_VT(pVar) = (offset & 0x7c000000 )>> 26;
1518         V_I2(pVar) = offset & 0x3ffffff;
1519         return;
1520     }
1521     MSFT_ReadLEWords(&(V_VT(pVar)), sizeof(VARTYPE), pcx,
1522                      pcx->pTblDir->pCustData.offset + offset );
1523     TRACE_(typelib)("Vartype = %x\n", V_VT(pVar));
1524     switch (V_VT(pVar)){
1525         case VT_EMPTY:  /* FIXME: is this right? */
1526         case VT_NULL:   /* FIXME: is this right? */
1527         case VT_I2  :   /* this should not happen */
1528         case VT_I4  :
1529         case VT_R4  :
1530         case VT_ERROR   :
1531         case VT_BOOL    :
1532         case VT_I1  :
1533         case VT_UI1 :
1534         case VT_UI2 :
1535         case VT_UI4 :
1536         case VT_INT :
1537         case VT_UINT    :
1538         case VT_VOID    : /* FIXME: is this right? */
1539         case VT_HRESULT :
1540             size=4; break;
1541         case VT_R8  :
1542         case VT_CY  :
1543         case VT_DATE    :
1544         case VT_I8  :
1545         case VT_UI8 :
1546         case VT_DECIMAL :  /* FIXME: is this right? */
1547         case VT_FILETIME :
1548             size=8;break;
1549             /* pointer types with known behaviour */
1550         case VT_BSTR    :{
1551             char * ptr;
1552             MSFT_ReadLEDWords(&size, sizeof(INT), pcx, DO_NOT_SEEK );
1553             if(size < 0) {
1554                 FIXME("BSTR length = %d?\n", size);
1555             } else {
1556                 ptr=TLB_Alloc(size);/* allocate temp buffer */
1557                 MSFT_Read(ptr, size, pcx, DO_NOT_SEEK);/* read string (ANSI) */
1558                 V_BSTR(pVar)=SysAllocStringLen(NULL,size);
1559                 /* FIXME: do we need a AtoW conversion here? */
1560                 V_UNION(pVar, bstrVal[size])=L'\0';
1561                 while(size--) V_UNION(pVar, bstrVal[size])=ptr[size];
1562                 TLB_Free(ptr);
1563             }
1564         }
1565         size=-4; break;
1566     /* FIXME: this will not work AT ALL when the variant contains a pointer */
1567         case VT_DISPATCH :
1568         case VT_VARIANT :
1569         case VT_UNKNOWN :
1570         case VT_PTR :
1571         case VT_SAFEARRAY :
1572         case VT_CARRAY  :
1573         case VT_USERDEFINED :
1574         case VT_LPSTR   :
1575         case VT_LPWSTR  :
1576         case VT_BLOB    :
1577         case VT_STREAM  :
1578         case VT_STORAGE :
1579         case VT_STREAMED_OBJECT :
1580         case VT_STORED_OBJECT   :
1581         case VT_BLOB_OBJECT :
1582         case VT_CF  :
1583         case VT_CLSID   :
1584         default:
1585             size=0;
1586             FIXME("VARTYPE %d is not supported, setting pointer to NULL\n",
1587                 V_VT(pVar));
1588     }
1589
1590     if(size>0) /* (big|small) endian correct? */
1591         MSFT_Read(&(V_I2(pVar)), size, pcx, DO_NOT_SEEK );
1592     return;
1593 }
1594 /*
1595  * create a linked list with custom data
1596  */
1597 static int MSFT_CustData( TLBContext *pcx, int offset, TLBCustData** ppCustData )
1598 {
1599     MSFT_CDGuid entry;
1600     TLBCustData* pNew;
1601     int count=0;
1602
1603     TRACE_(typelib)("\n");
1604
1605     while(offset >=0){
1606         count++;
1607         pNew=TLB_Alloc(sizeof(TLBCustData));
1608         MSFT_ReadLEDWords(&entry, sizeof(entry), pcx, pcx->pTblDir->pCDGuids.offset+offset);
1609         MSFT_ReadGuid(&(pNew->guid), entry.GuidOffset , pcx);
1610         MSFT_ReadValue(&(pNew->data), entry.DataOffset, pcx);
1611         /* add new custom data at head of the list */
1612         pNew->next=*ppCustData;
1613         *ppCustData=pNew;
1614         offset = entry.next;
1615     }
1616     return count;
1617 }
1618
1619 static void MSFT_GetTdesc(TLBContext *pcx, INT type, TYPEDESC *pTd,
1620                           ITypeInfoImpl *pTI)
1621 {
1622     if(type <0)
1623         pTd->vt=type & VT_TYPEMASK;
1624     else
1625         *pTd=pcx->pLibInfo->pTypeDesc[type/(2*sizeof(INT))];
1626
1627     if(pTd->vt == VT_USERDEFINED)
1628       MSFT_DoRefType(pcx, pTI, pTd->u.hreftype);
1629
1630     TRACE_(typelib)("vt type = %X\n", pTd->vt);
1631 }
1632
1633 static void
1634 MSFT_DoFuncs(TLBContext*     pcx,
1635             ITypeInfoImpl*  pTI,
1636             int             cFuncs,
1637             int             cVars,
1638             int             offset,
1639             TLBFuncDesc**   pptfd)
1640 {
1641     /*
1642      * member information is stored in a data structure at offset
1643      * indicated by the memoffset field of the typeinfo structure
1644      * There are several distinctive parts.
1645      * The first part starts with a field that holds the total length
1646      * of this (first) part excluding this field. Then follow the records,
1647      * for each member there is one record.
1648      *
1649      * The first entry is always the length of the record (including this
1650      * length word).
1651      * The rest of the record depends on the type of the member. If there is
1652      * a field indicating the member type (function, variable, interface, etc)
1653      * I have not found it yet. At this time we depend on the information
1654      * in the type info and the usual order how things are stored.
1655      *
1656      * Second follows an array sized nrMEM*sizeof(INT) with a member id
1657      * for each member;
1658      *
1659      * Third is an equal sized array with file offsets to the name entry
1660      * of each member.
1661      *
1662      * The fourth and last (?) part is an array with offsets to the records
1663      * in the first part of this file segment.
1664      */
1665
1666     int infolen, nameoffset, reclength, nrattributes, i;
1667     int recoffset = offset + sizeof(INT);
1668
1669     char recbuf[512];
1670     MSFT_FuncRecord * pFuncRec=(MSFT_FuncRecord *) recbuf;
1671
1672     TRACE_(typelib)("\n");
1673
1674     MSFT_ReadLEDWords(&infolen, sizeof(INT), pcx, offset);
1675
1676     for ( i = 0; i < cFuncs ; i++ )
1677     {
1678         *pptfd = TLB_Alloc(sizeof(TLBFuncDesc));
1679
1680         /* name, eventually add to a hash table */
1681         MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx,
1682                           offset + infolen + (cFuncs + cVars + i + 1) * sizeof(INT));
1683
1684         (*pptfd)->Name = MSFT_ReadName(pcx, nameoffset);
1685
1686         /* read the function information record */
1687         MSFT_ReadLEDWords(&reclength, sizeof(INT), pcx, recoffset);
1688
1689         reclength &= 0x1ff;
1690
1691         MSFT_ReadLEDWords(pFuncRec, reclength - sizeof(INT), pcx, DO_NOT_SEEK);
1692
1693         /* do the attributes */
1694         nrattributes = (reclength - pFuncRec->nrargs * 3 * sizeof(int) - 0x18)
1695                        / sizeof(int);
1696
1697         if ( nrattributes > 0 )
1698         {
1699             (*pptfd)->helpcontext = pFuncRec->OptAttr[0] ;
1700
1701             if ( nrattributes > 1 )
1702             {
1703                 (*pptfd)->HelpString = MSFT_ReadString(pcx,
1704                                                       pFuncRec->OptAttr[1]) ;
1705
1706                 if ( nrattributes > 2 )
1707                 {
1708                     if ( pFuncRec->FKCCIC & 0x2000 )
1709                     {
1710                        (*pptfd)->Entry = (WCHAR*) pFuncRec->OptAttr[2] ;
1711                     }
1712                     else
1713                     {
1714                         (*pptfd)->Entry = MSFT_ReadString(pcx,
1715                                                          pFuncRec->OptAttr[2]);
1716                     }
1717                     if( nrattributes > 5 )
1718                     {
1719                         (*pptfd)->HelpStringContext = pFuncRec->OptAttr[5] ;
1720
1721                         if ( nrattributes > 6 && pFuncRec->FKCCIC & 0x80 )
1722                         {
1723                             MSFT_CustData(pcx,
1724                                           pFuncRec->OptAttr[6],
1725                                           &(*pptfd)->pCustData);
1726                         }
1727                     }
1728                 }
1729             }
1730         }
1731
1732         /* fill the FuncDesc Structure */
1733         MSFT_ReadLEDWords( & (*pptfd)->funcdesc.memid, sizeof(INT), pcx,
1734                            offset + infolen + ( i + 1) * sizeof(INT));
1735
1736         (*pptfd)->funcdesc.funckind   =  (pFuncRec->FKCCIC)      & 0x7;
1737         (*pptfd)->funcdesc.invkind    =  (pFuncRec->FKCCIC) >> 3 & 0xF;
1738         (*pptfd)->funcdesc.callconv   =  (pFuncRec->FKCCIC) >> 8 & 0xF;
1739         (*pptfd)->funcdesc.cParams    =   pFuncRec->nrargs  ;
1740         (*pptfd)->funcdesc.cParamsOpt =   pFuncRec->nroargs ;
1741         (*pptfd)->funcdesc.oVft       =   pFuncRec->VtableOffset ;
1742         (*pptfd)->funcdesc.wFuncFlags =   LOWORD(pFuncRec->Flags) ;
1743
1744         MSFT_GetTdesc(pcx,
1745                       pFuncRec->DataType,
1746                       &(*pptfd)->funcdesc.elemdescFunc.tdesc,
1747                       pTI);
1748
1749         /* do the parameters/arguments */
1750         if(pFuncRec->nrargs)
1751         {
1752             int j = 0;
1753             MSFT_ParameterInfo paraminfo;
1754
1755             (*pptfd)->funcdesc.lprgelemdescParam =
1756                 TLB_Alloc(pFuncRec->nrargs * sizeof(ELEMDESC));
1757
1758             (*pptfd)->pParamDesc =
1759                 TLB_Alloc(pFuncRec->nrargs * sizeof(TLBParDesc));
1760
1761             MSFT_ReadLEDWords(&paraminfo, sizeof(paraminfo), pcx,
1762                               recoffset + reclength - pFuncRec->nrargs * sizeof(MSFT_ParameterInfo));
1763
1764             for ( j = 0 ; j < pFuncRec->nrargs ; j++ )
1765             {
1766                 TYPEDESC* lpArgTypeDesc = 0;
1767
1768                 MSFT_GetTdesc(pcx,
1769                               paraminfo.DataType,
1770                               &(*pptfd)->funcdesc.lprgelemdescParam[j].tdesc,
1771                               pTI);
1772
1773                 (*pptfd)->funcdesc.lprgelemdescParam[j].u.paramdesc.wParamFlags = paraminfo.Flags;
1774
1775                 /* name */
1776                 if (paraminfo.oName == -1)
1777                     /* this occurs for [propput] or [propget] methods, so
1778                      * we should just set the name of the parameter to the
1779                      * name of the method. */
1780                     (*pptfd)->pParamDesc[j].Name = SysAllocString((*pptfd)->Name);
1781                 else
1782                     (*pptfd)->pParamDesc[j].Name =
1783                         MSFT_ReadName( pcx, paraminfo.oName );
1784                 TRACE_(typelib)("param[%d] = %s\n", j, debugstr_w((*pptfd)->pParamDesc[j].Name));
1785
1786                 /* SEEK value = jump to offset,
1787                  * from there jump to the end of record,
1788                  * go back by (j-1) arguments
1789                  */
1790                 MSFT_ReadLEDWords( &paraminfo ,
1791                            sizeof(MSFT_ParameterInfo), pcx,
1792                            recoffset + reclength - ((pFuncRec->nrargs - j - 1)
1793                                                * sizeof(MSFT_ParameterInfo)));
1794                 lpArgTypeDesc =
1795                     & ((*pptfd)->funcdesc.lprgelemdescParam[j].tdesc);
1796
1797                 while ( lpArgTypeDesc != NULL )
1798                 {
1799                     switch ( lpArgTypeDesc->vt )
1800                     {
1801                     case VT_PTR:
1802                         lpArgTypeDesc = lpArgTypeDesc->u.lptdesc;
1803                         break;
1804
1805                     case VT_CARRAY:
1806                         lpArgTypeDesc = & (lpArgTypeDesc->u.lpadesc->tdescElem);
1807                         break;
1808
1809                     case VT_USERDEFINED:
1810                         MSFT_DoRefType(pcx, pTI,
1811                                        lpArgTypeDesc->u.hreftype);
1812
1813                         lpArgTypeDesc = NULL;
1814                         break;
1815
1816                     default:
1817                         lpArgTypeDesc = NULL;
1818                     }
1819                 }
1820             }
1821
1822
1823             /* parameter is the return value! */
1824             if ( paraminfo.Flags & PARAMFLAG_FRETVAL )
1825             {
1826                 TYPEDESC* lpArgTypeDesc;
1827
1828                 (*pptfd)->funcdesc.elemdescFunc =
1829                 (*pptfd)->funcdesc.lprgelemdescParam[j];
1830
1831                 lpArgTypeDesc = & ((*pptfd)->funcdesc.elemdescFunc.tdesc) ;
1832
1833                 while ( lpArgTypeDesc != NULL )
1834                 {
1835                     switch ( lpArgTypeDesc->vt )
1836                     {
1837                     case VT_PTR:
1838                         lpArgTypeDesc = lpArgTypeDesc->u.lptdesc;
1839                         break;
1840                     case VT_CARRAY:
1841                         lpArgTypeDesc =
1842                         & (lpArgTypeDesc->u.lpadesc->tdescElem);
1843
1844                         break;
1845
1846                     case VT_USERDEFINED:
1847                         MSFT_DoRefType(pcx,
1848                                        pTI,
1849                                        lpArgTypeDesc->u.hreftype);
1850
1851                         lpArgTypeDesc = NULL;
1852                         break;
1853
1854                     default:
1855                         lpArgTypeDesc = NULL;
1856                     }
1857                 }
1858             }
1859
1860             /* second time around */
1861             for(j=0;j<pFuncRec->nrargs;j++)
1862             {
1863                 /* default value */
1864                 if ( (PARAMFLAG_FHASDEFAULT &
1865                       (*pptfd)->funcdesc.lprgelemdescParam[j].u.paramdesc.wParamFlags) &&
1866                      ((pFuncRec->FKCCIC) & 0x1000) )
1867                 {
1868                     INT* pInt = (INT *)((char *)pFuncRec +
1869                                    reclength -
1870                                    (pFuncRec->nrargs * 4 + 1) * sizeof(INT) );
1871
1872                     PARAMDESC* pParamDesc = & (*pptfd)->funcdesc.lprgelemdescParam[j].u.paramdesc;
1873
1874                     pParamDesc->pparamdescex = TLB_Alloc(sizeof(PARAMDESCEX));
1875                     pParamDesc->pparamdescex->cBytes = sizeof(PARAMDESCEX);
1876
1877                     MSFT_ReadValue(&(pParamDesc->pparamdescex->varDefaultValue),
1878                         pInt[j], pcx);
1879                 }
1880                 /* custom info */
1881                 if ( nrattributes > 7 + j && pFuncRec->FKCCIC & 0x80 )
1882                 {
1883                     MSFT_CustData(pcx,
1884                                   pFuncRec->OptAttr[7+j],
1885                                   &(*pptfd)->pParamDesc[j].pCustData);
1886                 }
1887            }
1888         }
1889
1890         /* scode is not used: archaic win16 stuff FIXME: right? */
1891         (*pptfd)->funcdesc.cScodes   = 0 ;
1892         (*pptfd)->funcdesc.lprgscode = NULL ;
1893
1894         pptfd      = & ((*pptfd)->next);
1895         recoffset += reclength;
1896     }
1897 }
1898
1899 static void MSFT_DoVars(TLBContext *pcx, ITypeInfoImpl *pTI, int cFuncs,
1900                        int cVars, int offset, TLBVarDesc ** pptvd)
1901 {
1902     int infolen, nameoffset, reclength;
1903     char recbuf[256];
1904     MSFT_VarRecord * pVarRec=(MSFT_VarRecord *) recbuf;
1905     int i;
1906     int recoffset;
1907
1908     TRACE_(typelib)("\n");
1909
1910     MSFT_ReadLEDWords(&infolen,sizeof(INT), pcx, offset);
1911     MSFT_ReadLEDWords(&recoffset,sizeof(INT), pcx, offset + infolen +
1912                       ((cFuncs+cVars)*2+cFuncs + 1)*sizeof(INT));
1913     recoffset += offset+sizeof(INT);
1914     for(i=0;i<cVars;i++){
1915         *pptvd=TLB_Alloc(sizeof(TLBVarDesc));
1916     /* name, eventually add to a hash table */
1917         MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx,
1918                           offset + infolen + (cFuncs + cVars + i + 1) * sizeof(INT));
1919         (*pptvd)->Name=MSFT_ReadName(pcx, nameoffset);
1920     /* read the variable information record */
1921         MSFT_ReadLEDWords(&reclength, sizeof(INT), pcx, recoffset);
1922         reclength &=0xff;
1923         MSFT_ReadLEDWords(pVarRec, reclength - sizeof(INT), pcx, DO_NOT_SEEK);
1924     /* Optional data */
1925         if(reclength >(6*sizeof(INT)) )
1926             (*pptvd)->HelpContext=pVarRec->HelpContext;
1927         if(reclength >(7*sizeof(INT)) )
1928             (*pptvd)->HelpString = MSFT_ReadString(pcx, pVarRec->oHelpString) ;
1929         if(reclength >(8*sizeof(INT)) )
1930         if(reclength >(9*sizeof(INT)) )
1931             (*pptvd)->HelpStringContext=pVarRec->HelpStringContext;
1932     /* fill the VarDesc Structure */
1933         MSFT_ReadLEDWords(&(*pptvd)->vardesc.memid, sizeof(INT), pcx,
1934                           offset + infolen + ( i + 1) * sizeof(INT));
1935         (*pptvd)->vardesc.varkind = pVarRec->VarKind;
1936         (*pptvd)->vardesc.wVarFlags = pVarRec->Flags;
1937         MSFT_GetTdesc(pcx, pVarRec->DataType,
1938             &(*pptvd)->vardesc.elemdescVar.tdesc, pTI);
1939 /*   (*pptvd)->vardesc.lpstrSchema; is reserved (SDK) FIXME?? */
1940         if(pVarRec->VarKind == VAR_CONST ){
1941             (*pptvd)->vardesc.u.lpvarValue=TLB_Alloc(sizeof(VARIANT));
1942             MSFT_ReadValue((*pptvd)->vardesc.u.lpvarValue,
1943                 pVarRec->OffsValue, pcx);
1944         } else
1945             (*pptvd)->vardesc.u.oInst=pVarRec->OffsValue;
1946         pptvd=&((*pptvd)->next);
1947         recoffset += reclength;
1948     }
1949 }
1950 /* fill in data for a hreftype (offset). When the referenced type is contained
1951  * in the typelib, it's just an (file) offset in the type info base dir.
1952  * If comes from import, it's an offset+1 in the ImpInfo table
1953  * */
1954 static void MSFT_DoRefType(TLBContext *pcx, ITypeInfoImpl *pTI,
1955                           int offset)
1956 {
1957     int j;
1958     TLBRefType **ppRefType = &pTI->reflist;
1959
1960     TRACE_(typelib)("TLB context %p, TLB offset %x\n", pcx, offset);
1961
1962     while(*ppRefType) {
1963         if((*ppRefType)->reference == offset)
1964             return;
1965         ppRefType = &(*ppRefType)->next;
1966     }
1967
1968     *ppRefType = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1969                            sizeof(**ppRefType));
1970
1971     if(!MSFT_HREFTYPE_INTHISFILE( offset)) {
1972         /* external typelib */
1973         MSFT_ImpInfo impinfo;
1974         TLBImpLib *pImpLib=(pcx->pLibInfo->pImpLibs);
1975
1976         TRACE_(typelib)("offset %x, masked offset %x\n", offset, offset + (offset & 0xfffffffc));
1977
1978         MSFT_ReadLEDWords(&impinfo, sizeof(impinfo), pcx,
1979                           pcx->pTblDir->pImpInfo.offset + (offset & 0xfffffffc));
1980         for(j=0;pImpLib;j++){   /* search the known offsets of all import libraries */
1981             if(pImpLib->offset==impinfo.oImpFile) break;
1982             pImpLib=pImpLib->next;
1983         }
1984         if(pImpLib){
1985             (*ppRefType)->reference=offset;
1986             (*ppRefType)->pImpTLInfo = pImpLib;
1987             if(impinfo.flags & MSFT_IMPINFO_OFFSET_IS_GUID) {
1988                 MSFT_ReadGuid(&(*ppRefType)->guid, impinfo.oGuid, pcx);
1989                 (*ppRefType)->index = TLB_REF_USE_GUID;
1990             } else
1991                 (*ppRefType)->index = impinfo.oGuid;               
1992         }else{
1993             ERR("Cannot find a reference\n");
1994             (*ppRefType)->reference=-1;
1995             (*ppRefType)->pImpTLInfo=TLB_REF_NOT_FOUND;
1996         }
1997     }else{
1998         /* in this typelib */
1999         (*ppRefType)->index = MSFT_HREFTYPE_INDEX(offset);
2000         (*ppRefType)->reference=offset;
2001         (*ppRefType)->pImpTLInfo=TLB_REF_INTERNAL;
2002     }
2003 }
2004
2005 /* process Implemented Interfaces of a com class */
2006 static void MSFT_DoImplTypes(TLBContext *pcx, ITypeInfoImpl *pTI, int count,
2007                             int offset)
2008 {
2009     int i;
2010     MSFT_RefRecord refrec;
2011     TLBImplType **ppImpl = &pTI->impltypelist;
2012
2013     TRACE_(typelib)("\n");
2014
2015     for(i=0;i<count;i++){
2016         if(offset<0) break; /* paranoia */
2017         *ppImpl=TLB_Alloc(sizeof(**ppImpl));
2018         MSFT_ReadLEDWords(&refrec,sizeof(refrec),pcx,offset+pcx->pTblDir->pRefTab.offset);
2019         MSFT_DoRefType(pcx, pTI, refrec.reftype);
2020         (*ppImpl)->hRef = refrec.reftype;
2021         (*ppImpl)->implflags=refrec.flags;
2022         (*ppImpl)->ctCustData=
2023             MSFT_CustData(pcx, refrec.oCustData, &(*ppImpl)->pCustData);
2024         offset=refrec.onext;
2025         ppImpl=&((*ppImpl)->next);
2026     }
2027 }
2028 /*
2029  * process a typeinfo record
2030  */
2031 static ITypeInfoImpl * MSFT_DoTypeInfo(
2032     TLBContext *pcx,
2033     int count,
2034     ITypeLibImpl * pLibInfo)
2035 {
2036     MSFT_TypeInfoBase tiBase;
2037     ITypeInfoImpl *ptiRet;
2038
2039     TRACE_(typelib)("count=%u\n", count);
2040
2041     ptiRet = (ITypeInfoImpl*) ITypeInfo_Constructor();
2042     MSFT_ReadLEDWords(&tiBase, sizeof(tiBase) ,pcx ,
2043                       pcx->pTblDir->pTypeInfoTab.offset+count*sizeof(tiBase));
2044
2045 /* this is where we are coming from */
2046     ptiRet->pTypeLib = pLibInfo;
2047     ptiRet->index=count;
2048 /* fill in the typeattr fields */
2049     WARN("Assign constructor/destructor memid\n");
2050
2051     MSFT_ReadGuid(&ptiRet->TypeAttr.guid, tiBase.posguid, pcx);
2052     ptiRet->TypeAttr.lcid=pLibInfo->LibAttr.lcid;   /* FIXME: correct? */
2053     ptiRet->TypeAttr.memidConstructor=MEMBERID_NIL ;/* FIXME */
2054     ptiRet->TypeAttr.memidDestructor=MEMBERID_NIL ; /* FIXME */
2055     ptiRet->TypeAttr.lpstrSchema=NULL;              /* reserved */
2056     ptiRet->TypeAttr.cbSizeInstance=tiBase.size;
2057     ptiRet->TypeAttr.typekind=tiBase.typekind & 0xF;
2058     ptiRet->TypeAttr.cFuncs=LOWORD(tiBase.cElement);
2059     ptiRet->TypeAttr.cVars=HIWORD(tiBase.cElement);
2060     ptiRet->TypeAttr.cbAlignment=(tiBase.typekind >> 11 )& 0x1F; /* there are more flags there */
2061     ptiRet->TypeAttr.wTypeFlags=tiBase.flags;
2062     ptiRet->TypeAttr.wMajorVerNum=LOWORD(tiBase.version);
2063     ptiRet->TypeAttr.wMinorVerNum=HIWORD(tiBase.version);
2064     ptiRet->TypeAttr.cImplTypes=tiBase.cImplTypes;
2065     ptiRet->TypeAttr.cbSizeVft=tiBase.cbSizeVft; /* FIXME: this is only the non inherited part */
2066     if(ptiRet->TypeAttr.typekind == TKIND_ALIAS)
2067         MSFT_GetTdesc(pcx, tiBase.datatype1,
2068             &ptiRet->TypeAttr.tdescAlias, ptiRet);
2069
2070 /*  FIXME: */
2071 /*    IDLDESC  idldescType; *//* never saw this one != zero  */
2072
2073 /* name, eventually add to a hash table */
2074     ptiRet->Name=MSFT_ReadName(pcx, tiBase.NameOffset);
2075     TRACE_(typelib)("reading %s\n", debugstr_w(ptiRet->Name));
2076     /* help info */
2077     ptiRet->DocString=MSFT_ReadString(pcx, tiBase.docstringoffs);
2078     ptiRet->dwHelpStringContext=tiBase.helpstringcontext;
2079     ptiRet->dwHelpContext=tiBase.helpcontext;
2080
2081     if (ptiRet->TypeAttr.typekind == TKIND_MODULE)
2082         ptiRet->DllName = MSFT_ReadString(pcx, tiBase.datatype1);
2083
2084 /* note: InfoType's Help file and HelpStringDll come from the containing
2085  * library. Further HelpString and Docstring appear to be the same thing :(
2086  */
2087     /* functions */
2088     if(ptiRet->TypeAttr.cFuncs >0 )
2089         MSFT_DoFuncs(pcx, ptiRet, ptiRet->TypeAttr.cFuncs,
2090                     ptiRet->TypeAttr.cVars,
2091                     tiBase.memoffset, & ptiRet->funclist);
2092     /* variables */
2093     if(ptiRet->TypeAttr.cVars >0 )
2094         MSFT_DoVars(pcx, ptiRet, ptiRet->TypeAttr.cFuncs,
2095                    ptiRet->TypeAttr.cVars,
2096                    tiBase.memoffset, & ptiRet->varlist);
2097     if(ptiRet->TypeAttr.cImplTypes >0 ) {
2098         switch(ptiRet->TypeAttr.typekind)
2099         {
2100         case TKIND_COCLASS:
2101             MSFT_DoImplTypes(pcx, ptiRet, ptiRet->TypeAttr.cImplTypes ,
2102                 tiBase.datatype1);
2103             break;
2104         case TKIND_DISPATCH:
2105             ptiRet->impltypelist=TLB_Alloc(sizeof(TLBImplType));
2106
2107             if (tiBase.datatype1 != -1)
2108             {
2109               MSFT_DoRefType(pcx, ptiRet, tiBase.datatype1);
2110               ptiRet->impltypelist->hRef = tiBase.datatype1;
2111             }
2112             else
2113             { /* FIXME: This is a really bad hack to add IDispatch */
2114               const char* szStdOle = "stdole2.tlb\0";
2115               int   nStdOleLen = strlen(szStdOle);
2116               TLBRefType **ppRef = &ptiRet->reflist;
2117
2118               while(*ppRef) {
2119                 if((*ppRef)->reference == -1)
2120                   break;
2121                 ppRef = &(*ppRef)->next;
2122               }
2123               if(!*ppRef) {
2124                 *ppRef = TLB_Alloc(sizeof(**ppRef));
2125                 (*ppRef)->guid             = IID_IDispatch;
2126                 (*ppRef)->reference        = -1;
2127                 (*ppRef)->index            = TLB_REF_USE_GUID;
2128                 (*ppRef)->pImpTLInfo       = TLB_Alloc(sizeof(TLBImpLib));
2129                 (*ppRef)->pImpTLInfo->guid = IID_StdOle;
2130                 (*ppRef)->pImpTLInfo->name = SysAllocStringLen(NULL,
2131                                                               nStdOleLen  + 1);
2132
2133                 MultiByteToWideChar(CP_ACP,
2134                                     MB_PRECOMPOSED,
2135                                     szStdOle,
2136                                     -1,
2137                                     (*ppRef)->pImpTLInfo->name,
2138                                     SysStringLen((*ppRef)->pImpTLInfo->name));
2139
2140                 (*ppRef)->pImpTLInfo->lcid          = 0;
2141                 (*ppRef)->pImpTLInfo->wVersionMajor = 2;
2142                 (*ppRef)->pImpTLInfo->wVersionMinor = 0;
2143               }
2144             }
2145             break;
2146         default:
2147             ptiRet->impltypelist=TLB_Alloc(sizeof(TLBImplType));
2148             MSFT_DoRefType(pcx, ptiRet, tiBase.datatype1);
2149             ptiRet->impltypelist->hRef = tiBase.datatype1;
2150             break;
2151        }
2152     }
2153     ptiRet->ctCustData=
2154         MSFT_CustData(pcx, tiBase.oCustData, &ptiRet->pCustData);
2155
2156     TRACE_(typelib)("%s guid: %s kind:%s\n",
2157        debugstr_w(ptiRet->Name),
2158        debugstr_guid(&ptiRet->TypeAttr.guid),
2159        typekind_desc[ptiRet->TypeAttr.typekind]);
2160
2161     return ptiRet;
2162 }
2163
2164 /* Because type library parsing has some degree of overhead, and some apps repeatedly load the same
2165  * typelibs over and over, we cache them here. According to MSDN Microsoft have a similar scheme in
2166  * place. This will cause a deliberate memory leak, but generally losing RAM for cycles is an acceptable
2167  * tradeoff here.
2168  */
2169 static ITypeLibImpl *tlb_cache_first;
2170 static CRITICAL_SECTION cache_section;
2171 static CRITICAL_SECTION_DEBUG cache_section_debug =
2172 {
2173     0, 0, &cache_section,
2174     { &cache_section_debug.ProcessLocksList, &cache_section_debug.ProcessLocksList },
2175       0, 0, { (DWORD_PTR)(__FILE__ ": typelib loader cache") }
2176 };
2177 static CRITICAL_SECTION cache_section = { &cache_section_debug, -1, 0, 0, 0, 0 };
2178
2179
2180 /****************************************************************************
2181  *      TLB_ReadTypeLib
2182  *
2183  * find the type of the typelib file and map the typelib resource into
2184  * the memory
2185  */
2186 #define MSFT_SIGNATURE 0x5446534D /* "MSFT" */
2187 #define SLTG_SIGNATURE 0x47544c53 /* "SLTG" */
2188 int TLB_ReadTypeLib(LPCWSTR pszFileName, INT index, ITypeLib2 **ppTypeLib)
2189 {
2190     ITypeLibImpl *entry;
2191     int ret = TYPE_E_CANTLOADLIBRARY;
2192     DWORD dwSignature = 0;
2193     HANDLE hFile;
2194
2195     TRACE_(typelib)("%s:%d\n", debugstr_w(pszFileName), index);
2196
2197     *ppTypeLib = NULL;
2198
2199     /* We look the path up in the typelib cache. If found, we just addref it, and return the pointer. */
2200     EnterCriticalSection(&cache_section);
2201     for (entry = tlb_cache_first; entry != NULL; entry = entry->next)
2202     {
2203         if (!strcmpiW(entry->path, pszFileName) && entry->index == index)
2204         {
2205             TRACE("cache hit\n");
2206             *ppTypeLib = (ITypeLib2*)entry;
2207             ITypeLib_AddRef(*ppTypeLib);
2208             LeaveCriticalSection(&cache_section);
2209             return S_OK;
2210         }
2211     }
2212     LeaveCriticalSection(&cache_section);
2213
2214     /* check the signature of the file */
2215     hFile = CreateFileW( pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
2216     if (INVALID_HANDLE_VALUE != hFile)
2217     {
2218       HANDLE hMapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL );
2219       if (hMapping)
2220       {
2221         LPVOID pBase = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
2222         if(pBase)
2223         {
2224           /* retrieve file size */
2225           DWORD dwTLBLength = GetFileSize(hFile, NULL);
2226
2227           /* first try to load as *.tlb */
2228           dwSignature = FromLEDWord(*((DWORD*) pBase));
2229           if ( dwSignature == MSFT_SIGNATURE)
2230           {
2231             *ppTypeLib = ITypeLib2_Constructor_MSFT(pBase, dwTLBLength);
2232           }
2233           else if ( dwSignature == SLTG_SIGNATURE)
2234           {
2235             *ppTypeLib = ITypeLib2_Constructor_SLTG(pBase, dwTLBLength);
2236           }
2237           UnmapViewOfFile(pBase);
2238         }
2239         CloseHandle(hMapping);
2240       }
2241       CloseHandle(hFile);
2242     }
2243     else
2244     {
2245       TRACE("not found, trying to load %s as library\n", debugstr_w(pszFileName));
2246     }
2247
2248     /* if the file is a DLL or not found, try loading it with LoadLibrary */
2249     if (((WORD)dwSignature == IMAGE_DOS_SIGNATURE) || (dwSignature == 0))
2250     {
2251       /* find the typelibrary resource*/
2252       HINSTANCE hinstDLL = LoadLibraryExW(pszFileName, 0, DONT_RESOLVE_DLL_REFERENCES|
2253                                           LOAD_LIBRARY_AS_DATAFILE|LOAD_WITH_ALTERED_SEARCH_PATH);
2254       if (hinstDLL)
2255       {
2256         static const WCHAR TYPELIBW[] = {'T','Y','P','E','L','I','B',0};
2257         HRSRC hrsrc = FindResourceW(hinstDLL, MAKEINTRESOURCEW(index), TYPELIBW);
2258         if (hrsrc)
2259         {
2260           HGLOBAL hGlobal = LoadResource(hinstDLL, hrsrc);
2261           if (hGlobal)
2262           {
2263             LPVOID pBase = LockResource(hGlobal);
2264             DWORD  dwTLBLength = SizeofResource(hinstDLL, hrsrc);
2265
2266             if (pBase)
2267             {
2268               /* try to load as incore resource */
2269               dwSignature = FromLEDWord(*((DWORD*) pBase));
2270               if ( dwSignature == MSFT_SIGNATURE)
2271               {
2272                   *ppTypeLib = ITypeLib2_Constructor_MSFT(pBase, dwTLBLength);
2273               }
2274               else if ( dwSignature == SLTG_SIGNATURE)
2275               {
2276                   *ppTypeLib = ITypeLib2_Constructor_SLTG(pBase, dwTLBLength);
2277               }
2278               else
2279               {
2280                   FIXME("Header type magic 0x%08lx not supported.\n",dwSignature);
2281               }
2282             }
2283             FreeResource( hGlobal );
2284           }
2285         }
2286         FreeLibrary(hinstDLL);
2287       }
2288     }
2289
2290     if(*ppTypeLib) {
2291         ITypeLibImpl *impl = (ITypeLibImpl*)*ppTypeLib;
2292
2293         TRACE("adding to cache\n");
2294         impl->path = HeapAlloc(GetProcessHeap(), 0, (strlenW(pszFileName)+1) * sizeof(WCHAR));
2295         lstrcpyW(impl->path, pszFileName);
2296         /* We should really canonicalise the path here. */
2297         impl->index = index;
2298
2299         /* FIXME: check if it has added already in the meantime */
2300         EnterCriticalSection(&cache_section);
2301         if ((impl->next = tlb_cache_first) != NULL) impl->next->prev = impl;
2302         impl->prev = NULL;
2303         tlb_cache_first = impl;
2304         LeaveCriticalSection(&cache_section);
2305         ret = S_OK;
2306     } else
2307         ERR("Loading of typelib %s failed with error %ld\n", debugstr_w(pszFileName), GetLastError());
2308
2309     return ret;
2310 }
2311
2312 /*================== ITypeLib(2) Methods ===================================*/
2313
2314 /****************************************************************************
2315  *      ITypeLib2_Constructor_MSFT
2316  *
2317  * loading an MSFT typelib from an in-memory image
2318  */
2319 static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength)
2320 {
2321     TLBContext cx;
2322     long lPSegDir;
2323     MSFT_Header tlbHeader;
2324     MSFT_SegDir tlbSegDir;
2325     ITypeLibImpl * pTypeLibImpl;
2326
2327     TRACE("%p, TLB length = %ld\n", pLib, dwTLBLength);
2328
2329     pTypeLibImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeLibImpl));
2330     if (!pTypeLibImpl) return NULL;
2331
2332     pTypeLibImpl->lpVtbl = &tlbvt;
2333     pTypeLibImpl->lpVtblTypeComp = &tlbtcvt;
2334     pTypeLibImpl->ref = 1;
2335
2336     /* get pointer to beginning of typelib data */
2337     cx.pos = 0;
2338     cx.oStart=0;
2339     cx.mapping = pLib;
2340     cx.pLibInfo = pTypeLibImpl;
2341     cx.length = dwTLBLength;
2342
2343     /* read header */
2344     MSFT_ReadLEDWords((void*)&tlbHeader, sizeof(tlbHeader), &cx, 0);
2345     TRACE("header:\n");
2346     TRACE("\tmagic1=0x%08x ,magic2=0x%08x\n",tlbHeader.magic1,tlbHeader.magic2 );
2347     if (tlbHeader.magic1 != MSFT_SIGNATURE) {
2348         FIXME("Header type magic 0x%08x not supported.\n",tlbHeader.magic1);
2349         return NULL;
2350     }
2351     /* there is a small amount of information here until the next important
2352      * part:
2353      * the segment directory . Try to calculate the amount of data */
2354     lPSegDir = sizeof(tlbHeader) + (tlbHeader.nrtypeinfos)*4 + ((tlbHeader.varflags & HELPDLLFLAG)? 4 :0);
2355
2356     /* now read the segment directory */
2357     TRACE("read segment directory (at %ld)\n",lPSegDir);
2358     MSFT_ReadLEDWords(&tlbSegDir, sizeof(tlbSegDir), &cx, lPSegDir);
2359     cx.pTblDir = &tlbSegDir;
2360
2361     /* just check two entries */
2362     if ( tlbSegDir.pTypeInfoTab.res0c != 0x0F || tlbSegDir.pImpInfo.res0c != 0x0F)
2363     {
2364         ERR("cannot find the table directory, ptr=0x%lx\n",lPSegDir);
2365         HeapFree(GetProcessHeap(),0,pTypeLibImpl);
2366         return NULL;
2367     }
2368
2369     /* now fill our internal data */
2370     /* TLIBATTR fields */
2371     MSFT_ReadGuid(&pTypeLibImpl->LibAttr.guid, tlbHeader.posguid, &cx);
2372
2373     /*    pTypeLibImpl->LibAttr.lcid = tlbHeader.lcid;*/
2374     /* Windows seems to have zero here, is this correct? */
2375     if(SUBLANGID(tlbHeader.lcid) == SUBLANG_NEUTRAL)
2376       pTypeLibImpl->LibAttr.lcid = MAKELCID(MAKELANGID(PRIMARYLANGID(tlbHeader.lcid),0),0);
2377     else
2378       pTypeLibImpl->LibAttr.lcid = 0;
2379
2380     pTypeLibImpl->LibAttr.syskind = tlbHeader.varflags & 0x0f; /* check the mask */
2381     pTypeLibImpl->LibAttr.wMajorVerNum = LOWORD(tlbHeader.version);
2382     pTypeLibImpl->LibAttr.wMinorVerNum = HIWORD(tlbHeader.version);
2383     pTypeLibImpl->LibAttr.wLibFlags = (WORD) tlbHeader.flags & 0xffff;/* check mask */
2384
2385     /* name, eventually add to a hash table */
2386     pTypeLibImpl->Name = MSFT_ReadName(&cx, tlbHeader.NameOffset);
2387
2388     /* help info */
2389     pTypeLibImpl->DocString = MSFT_ReadString(&cx, tlbHeader.helpstring);
2390     pTypeLibImpl->HelpFile = MSFT_ReadString(&cx, tlbHeader.helpfile);
2391
2392     if( tlbHeader.varflags & HELPDLLFLAG)
2393     {
2394             int offset;
2395             MSFT_ReadLEDWords(&offset, sizeof(offset), &cx, sizeof(tlbHeader));
2396             pTypeLibImpl->HelpStringDll = MSFT_ReadString(&cx, offset);
2397     }
2398
2399     pTypeLibImpl->dwHelpContext = tlbHeader.helpstringcontext;
2400
2401     /* custom data */
2402     if(tlbHeader.CustomDataOffset >= 0)
2403     {
2404         pTypeLibImpl->ctCustData = MSFT_CustData(&cx, tlbHeader.CustomDataOffset, &pTypeLibImpl->pCustData);
2405     }
2406
2407     /* fill in typedescriptions */
2408     if(tlbSegDir.pTypdescTab.length > 0)
2409     {
2410         int i, j, cTD = tlbSegDir.pTypdescTab.length / (2*sizeof(INT));
2411         INT16 td[4];
2412         pTypeLibImpl->pTypeDesc = TLB_Alloc( cTD * sizeof(TYPEDESC));
2413         MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pTypdescTab.offset);
2414         for(i=0; i<cTD; )
2415         {
2416             /* FIXME: add several sanity checks here */
2417             pTypeLibImpl->pTypeDesc[i].vt = td[0] & VT_TYPEMASK;
2418             if(td[0] == VT_PTR || td[0] == VT_SAFEARRAY)
2419             {
2420                 /* FIXME: check safearray */
2421                 if(td[3] < 0)
2422                     pTypeLibImpl->pTypeDesc[i].u.lptdesc= & stndTypeDesc[td[2]];
2423                 else
2424                     pTypeLibImpl->pTypeDesc[i].u.lptdesc= & pTypeLibImpl->pTypeDesc[td[2]/8];
2425             }
2426             else if(td[0] == VT_CARRAY)
2427             {
2428                 /* array descr table here */
2429                 pTypeLibImpl->pTypeDesc[i].u.lpadesc = (void *)((int) td[2]);  /* temp store offset in*/
2430             }
2431             else if(td[0] == VT_USERDEFINED)
2432             {
2433                 pTypeLibImpl->pTypeDesc[i].u.hreftype = MAKELONG(td[2],td[3]);
2434             }
2435             if(++i<cTD) MSFT_ReadLEWords(td, sizeof(td), &cx, DO_NOT_SEEK);
2436         }
2437
2438         /* second time around to fill the array subscript info */
2439         for(i=0;i<cTD;i++)
2440         {
2441             if(pTypeLibImpl->pTypeDesc[i].vt != VT_CARRAY) continue;
2442             if(tlbSegDir.pArrayDescriptions.offset>0)
2443             {
2444                 MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pArrayDescriptions.offset + (int) pTypeLibImpl->pTypeDesc[i].u.lpadesc);
2445                 pTypeLibImpl->pTypeDesc[i].u.lpadesc = TLB_Alloc(sizeof(ARRAYDESC)+sizeof(SAFEARRAYBOUND)*(td[3]-1));
2446
2447                 if(td[1]<0)
2448                     pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem.vt = td[0] & VT_TYPEMASK;
2449                 else
2450                     pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem = stndTypeDesc[td[0]/8];
2451
2452                 pTypeLibImpl->pTypeDesc[i].u.lpadesc->cDims = td[2];
2453
2454                 for(j = 0; j<td[2]; j++)
2455                 {
2456                     MSFT_ReadLEDWords(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].cElements,
2457                                       sizeof(INT), &cx, DO_NOT_SEEK);
2458                     MSFT_ReadLEDWords(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].lLbound,
2459                                       sizeof(INT), &cx, DO_NOT_SEEK);
2460                 }
2461             }
2462             else
2463             {
2464                 pTypeLibImpl->pTypeDesc[i].u.lpadesc = NULL;
2465                 ERR("didn't find array description data\n");
2466             }
2467         }
2468     }
2469
2470     /* imported type libs */
2471     if(tlbSegDir.pImpFiles.offset>0)
2472     {
2473         TLBImpLib **ppImpLib = &(pTypeLibImpl->pImpLibs);
2474         int oGuid, offset = tlbSegDir.pImpFiles.offset;
2475         UINT16 size;
2476
2477         while(offset < tlbSegDir.pImpFiles.offset +tlbSegDir.pImpFiles.length)
2478         {
2479             char *name;
2480             DWORD len;
2481
2482             *ppImpLib = TLB_Alloc(sizeof(TLBImpLib));
2483             (*ppImpLib)->offset = offset - tlbSegDir.pImpFiles.offset;
2484             MSFT_ReadLEDWords(&oGuid, sizeof(INT), &cx, offset);
2485
2486             MSFT_ReadLEDWords(&(*ppImpLib)->lcid,         sizeof(LCID),   &cx, DO_NOT_SEEK);
2487             MSFT_ReadLEWords(&(*ppImpLib)->wVersionMajor, sizeof(WORD),   &cx, DO_NOT_SEEK);
2488             MSFT_ReadLEWords(&(*ppImpLib)->wVersionMinor, sizeof(WORD),   &cx, DO_NOT_SEEK);
2489             MSFT_ReadLEWords(& size,                      sizeof(UINT16), &cx, DO_NOT_SEEK);
2490
2491             size >>= 2;
2492             name = TLB_Alloc(size+1);
2493             MSFT_Read(name, size, &cx, DO_NOT_SEEK);
2494             len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0 );
2495             (*ppImpLib)->name = TLB_Alloc(len * sizeof(WCHAR));
2496             MultiByteToWideChar(CP_ACP, 0, name, -1, (*ppImpLib)->name, len );
2497             TLB_Free(name);
2498
2499             MSFT_ReadGuid(&(*ppImpLib)->guid, oGuid, &cx);
2500             offset = (offset + sizeof(INT) + sizeof(DWORD) + sizeof(LCID) + sizeof(UINT16) + size + 3) & ~3;
2501
2502             ppImpLib = &(*ppImpLib)->next;
2503         }
2504     }
2505
2506     /* type info's */
2507     if(tlbHeader.nrtypeinfos >= 0 )
2508     {
2509         /*pTypeLibImpl->TypeInfoCount=tlbHeader.nrtypeinfos; */
2510         ITypeInfoImpl **ppTI = &(pTypeLibImpl->pTypeInfo);
2511         int i;
2512
2513         for(i = 0; i<(int)tlbHeader.nrtypeinfos; i++)
2514         {
2515             *ppTI = MSFT_DoTypeInfo(&cx, i, pTypeLibImpl);
2516
2517             ppTI = &((*ppTI)->next);
2518             (pTypeLibImpl->TypeInfoCount)++;
2519         }
2520     }
2521
2522     TRACE("(%p)\n", pTypeLibImpl);
2523     return (ITypeLib2*) pTypeLibImpl;
2524 }
2525
2526
2527 static BSTR TLB_MultiByteToBSTR(char *ptr)
2528 {
2529     DWORD len;
2530     WCHAR *nameW;
2531     BSTR ret;
2532
2533     len = MultiByteToWideChar(CP_ACP, 0, ptr, -1, NULL, 0);
2534     nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2535     MultiByteToWideChar(CP_ACP, 0, ptr, -1, nameW, len);
2536     ret = SysAllocString(nameW);
2537     HeapFree(GetProcessHeap(), 0, nameW);
2538     return ret;
2539 }
2540
2541 static BOOL TLB_GUIDFromString(char *str, GUID *guid)
2542 {
2543   char b[3];
2544   int i;
2545   short s;
2546
2547   if(sscanf(str, "%lx-%hx-%hx-%hx", &guid->Data1, &guid->Data2, &guid->Data3, &s) != 4) {
2548     FIXME("Can't parse guid %s\n", debugstr_guid(guid));
2549     return FALSE;
2550   }
2551
2552   guid->Data4[0] = s >> 8;
2553   guid->Data4[1] = s & 0xff;
2554
2555   b[2] = '\0';
2556   for(i = 0; i < 6; i++) {
2557     memcpy(b, str + 24 + 2 * i, 2);
2558     guid->Data4[i + 2] = strtol(b, NULL, 16);
2559   }
2560   return TRUE;
2561 }
2562
2563 static WORD SLTG_ReadString(char *ptr, BSTR *pBstr)
2564 {
2565     WORD bytelen;
2566     DWORD len;
2567     WCHAR *nameW;
2568
2569     *pBstr = NULL;
2570     bytelen = *(WORD*)ptr;
2571     if(bytelen == 0xffff) return 2;
2572     len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, NULL, 0);
2573     nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2574     len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, nameW, len);
2575     *pBstr = SysAllocStringLen(nameW, len);
2576     HeapFree(GetProcessHeap(), 0, nameW);
2577     return bytelen + 2;
2578 }
2579
2580 static WORD SLTG_ReadStringA(char *ptr, char **str)
2581 {
2582     WORD bytelen;
2583
2584     *str = NULL;
2585     bytelen = *(WORD*)ptr;
2586     if(bytelen == 0xffff) return 2;
2587     *str = HeapAlloc(GetProcessHeap(), 0, bytelen + 1);
2588     memcpy(*str, ptr + 2, bytelen);
2589     (*str)[bytelen] = '\0';
2590     return bytelen + 2;
2591 }
2592
2593 static DWORD SLTG_ReadLibBlk(LPVOID pLibBlk, ITypeLibImpl *pTypeLibImpl)
2594 {
2595     char *ptr = pLibBlk;
2596     WORD w;
2597
2598     if((w = *(WORD*)ptr) != SLTG_LIBBLK_MAGIC) {
2599         FIXME("libblk magic = %04x\n", w);
2600         return 0;
2601     }
2602
2603     ptr += 6;
2604     if((w = *(WORD*)ptr) != 0xffff) {
2605         FIXME("LibBlk.res06 = %04x. Assumung string and skipping\n", w);
2606         ptr += w;
2607     }
2608     ptr += 2;
2609
2610     ptr += SLTG_ReadString(ptr, &pTypeLibImpl->DocString);
2611
2612     ptr += SLTG_ReadString(ptr, &pTypeLibImpl->HelpFile);
2613
2614     pTypeLibImpl->dwHelpContext = *(DWORD*)ptr;
2615     ptr += 4;
2616
2617     pTypeLibImpl->LibAttr.syskind = *(WORD*)ptr;
2618     ptr += 2;
2619
2620     if(SUBLANGID(*(WORD*)ptr) == SUBLANG_NEUTRAL)
2621         pTypeLibImpl->LibAttr.lcid = MAKELCID(MAKELANGID(PRIMARYLANGID(*(WORD*)ptr),0),0);
2622     else
2623         pTypeLibImpl->LibAttr.lcid = 0;
2624     ptr += 2;
2625
2626     ptr += 4; /* skip res12 */
2627
2628     pTypeLibImpl->LibAttr.wLibFlags = *(WORD*)ptr;
2629     ptr += 2;
2630
2631     pTypeLibImpl->LibAttr.wMajorVerNum = *(WORD*)ptr;
2632     ptr += 2;
2633
2634     pTypeLibImpl->LibAttr.wMinorVerNum = *(WORD*)ptr;
2635     ptr += 2;
2636
2637     memcpy(&pTypeLibImpl->LibAttr.guid, ptr, sizeof(GUID));
2638     ptr += sizeof(GUID);
2639
2640     return ptr - (char*)pLibBlk;
2641 }
2642
2643 static WORD *SLTG_DoType(WORD *pType, char *pBlk, ELEMDESC *pElem)
2644 {
2645     BOOL done = FALSE;
2646     TYPEDESC *pTD = &pElem->tdesc;
2647
2648     /* Handle [in/out] first */
2649     if((*pType & 0xc000) == 0xc000)
2650         pElem->u.paramdesc.wParamFlags = PARAMFLAG_NONE;
2651     else if(*pType & 0x8000)
2652         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN | PARAMFLAG_FOUT;
2653     else if(*pType & 0x4000)
2654         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FOUT;
2655     else
2656         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN;
2657
2658     if(*pType & 0x2000)
2659         pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FLCID;
2660
2661     if(*pType & 0x80)
2662         pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FRETVAL;
2663
2664     while(!done) {
2665         if((*pType & 0xe00) == 0xe00) {
2666             pTD->vt = VT_PTR;
2667             pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2668                                        sizeof(TYPEDESC));
2669             pTD = pTD->u.lptdesc;
2670         }
2671         switch(*pType & 0x7f) {
2672         case VT_PTR:
2673             pTD->vt = VT_PTR;
2674             pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2675                                        sizeof(TYPEDESC));
2676             pTD = pTD->u.lptdesc;
2677             break;
2678
2679         case VT_USERDEFINED:
2680             pTD->vt = VT_USERDEFINED;
2681             pTD->u.hreftype = *(++pType) / 4;
2682             done = TRUE;
2683             break;
2684
2685         case VT_CARRAY:
2686           {
2687             /* *(pType+1) is offset to a SAFEARRAY, *(pType+2) is type of
2688                array */
2689
2690             SAFEARRAY *pSA = (SAFEARRAY *)(pBlk + *(++pType));
2691
2692             pTD->vt = VT_CARRAY;
2693             pTD->u.lpadesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2694                                 sizeof(ARRAYDESC) +
2695                                 (pSA->cDims - 1) * sizeof(SAFEARRAYBOUND));
2696             pTD->u.lpadesc->cDims = pSA->cDims;
2697             memcpy(pTD->u.lpadesc->rgbounds, pSA->rgsabound,
2698                    pSA->cDims * sizeof(SAFEARRAYBOUND));
2699
2700             pTD = &pTD->u.lpadesc->tdescElem;
2701             break;
2702           }
2703
2704         case VT_SAFEARRAY:
2705           {
2706             /* FIXME: *(pType+1) gives an offset to SAFEARRAY, is this
2707                useful? */
2708
2709             pType++;
2710             pTD->vt = VT_SAFEARRAY;
2711             pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2712                                        sizeof(TYPEDESC));
2713             pTD = pTD->u.lptdesc;
2714             break;
2715           }
2716         default:
2717             pTD->vt = *pType & 0x7f;
2718             done = TRUE;
2719             break;
2720         }
2721         pType++;
2722     }
2723     return pType;
2724 }
2725
2726
2727 static void SLTG_DoRefs(SLTG_RefInfo *pRef, ITypeInfoImpl *pTI,
2728                         char *pNameTable)
2729 {
2730     int ref;
2731     char *name;
2732     TLBRefType **ppRefType;
2733
2734     if(pRef->magic != SLTG_REF_MAGIC) {
2735         FIXME("Ref magic = %x\n", pRef->magic);
2736         return;
2737     }
2738     name = ( (char*)(&pRef->names) + pRef->number);
2739
2740     ppRefType = &pTI->reflist;
2741     for(ref = 0; ref < pRef->number >> 3; ref++) {
2742         char *refname;
2743         unsigned int lib_offs, type_num;
2744
2745         *ppRefType = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2746                                sizeof(**ppRefType));
2747
2748         name += SLTG_ReadStringA(name, &refname);
2749         if(sscanf(refname, "*\\R%x*#%x", &lib_offs, &type_num) != 2)
2750             FIXME("Can't sscanf ref\n");
2751         if(lib_offs != 0xffff) {
2752             TLBImpLib **import = &pTI->pTypeLib->pImpLibs;
2753
2754             while(*import) {
2755                 if((*import)->offset == lib_offs)
2756                     break;
2757                 import = &(*import)->next;
2758             }
2759             if(!*import) {
2760                 char fname[MAX_PATH+1];
2761                 int len;
2762
2763                 *import = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2764                                     sizeof(**import));
2765                 (*import)->offset = lib_offs;
2766                 TLB_GUIDFromString( pNameTable + lib_offs + 4,
2767                                     &(*import)->guid);
2768                 if(sscanf(pNameTable + lib_offs + 40, "}#%hd.%hd#%lx#%s",
2769                           &(*import)->wVersionMajor,
2770                           &(*import)->wVersionMinor,
2771                           &(*import)->lcid, fname) != 4) {
2772                   FIXME("can't sscanf ref %s\n",
2773                         pNameTable + lib_offs + 40);
2774                 }
2775                 len = strlen(fname);
2776                 if(fname[len-1] != '#')
2777                     FIXME("fname = %s\n", fname);
2778                 fname[len-1] = '\0';
2779                 (*import)->name = TLB_MultiByteToBSTR(fname);
2780             }
2781             (*ppRefType)->pImpTLInfo = *import;
2782         } else { /* internal ref */
2783           (*ppRefType)->pImpTLInfo = TLB_REF_INTERNAL;
2784         }
2785         (*ppRefType)->reference = ref;
2786         (*ppRefType)->index = type_num;
2787
2788         HeapFree(GetProcessHeap(), 0, refname);
2789         ppRefType = &(*ppRefType)->next;
2790     }
2791     if((BYTE)*name != SLTG_REF_MAGIC)
2792       FIXME("End of ref block magic = %x\n", *name);
2793     dump_TLBRefType(pTI->reflist);
2794 }
2795
2796 static char *SLTG_DoImpls(char *pBlk, ITypeInfoImpl *pTI,
2797                           BOOL OneOnly)
2798 {
2799     SLTG_ImplInfo *info;
2800     TLBImplType **ppImplType = &pTI->impltypelist;
2801     /* I don't really get this structure, usually it's 0x16 bytes
2802        long, but iuser.tlb contains some that are 0x18 bytes long.
2803        That's ok because we can use the next ptr to jump to the next
2804        one. But how do we know the length of the last one?  The WORD
2805        at offs 0x8 might be the clue.  For now I'm just assuming that
2806        the last one is the regular 0x16 bytes. */
2807
2808     info = (SLTG_ImplInfo*)pBlk;
2809     while(1) {
2810         *ppImplType = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2811                                 sizeof(**ppImplType));
2812         (*ppImplType)->hRef = info->ref;
2813         (*ppImplType)->implflags = info->impltypeflags;
2814         pTI->TypeAttr.cImplTypes++;
2815         ppImplType = &(*ppImplType)->next;
2816
2817         if(info->next == 0xffff)
2818             break;
2819         if(OneOnly)
2820             FIXME("Interface inheriting more than one interface\n");
2821         info = (SLTG_ImplInfo*)(pBlk + info->next);
2822     }
2823     info++; /* see comment at top of function */
2824     return (char*)info;
2825 }
2826
2827 static SLTG_TypeInfoTail *SLTG_ProcessCoClass(char *pBlk, ITypeInfoImpl *pTI,
2828                                               char *pNameTable)
2829 {
2830     SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk;
2831     SLTG_MemberHeader *pMemHeader;
2832     char *pFirstItem, *pNextItem;
2833
2834     if(pTIHeader->href_table != 0xffffffff) {
2835         SLTG_DoRefs((SLTG_RefInfo*)(pBlk + pTIHeader->href_table), pTI,
2836                     pNameTable);
2837     }
2838
2839
2840     pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table);
2841
2842     pFirstItem = pNextItem = (char*)(pMemHeader + 1);
2843
2844     if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
2845         pNextItem = SLTG_DoImpls(pFirstItem, pTI, FALSE);
2846     }
2847
2848     return (SLTG_TypeInfoTail*)(pFirstItem + pMemHeader->cbExtra);
2849 }
2850
2851
2852 static SLTG_TypeInfoTail *SLTG_ProcessInterface(char *pBlk, ITypeInfoImpl *pTI,
2853                                                 char *pNameTable)
2854 {
2855     SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk;
2856     SLTG_MemberHeader *pMemHeader;
2857     SLTG_Function *pFunc;
2858     char *pFirstItem, *pNextItem;
2859     TLBFuncDesc **ppFuncDesc = &pTI->funclist;
2860     int num = 0;
2861
2862     if(pTIHeader->href_table != 0xffffffff) {
2863         SLTG_DoRefs((SLTG_RefInfo*)(pBlk + pTIHeader->href_table), pTI,
2864                     pNameTable);
2865     }
2866
2867     pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table);
2868
2869     pFirstItem = pNextItem = (char*)(pMemHeader + 1);
2870
2871     if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
2872         pNextItem = SLTG_DoImpls(pFirstItem, pTI, TRUE);
2873     }
2874
2875     for(pFunc = (SLTG_Function*)pNextItem, num = 1; 1;
2876         pFunc = (SLTG_Function*)(pFirstItem + pFunc->next), num++) {
2877
2878         int param;
2879         WORD *pType, *pArg;
2880
2881         if(pFunc->magic != SLTG_FUNCTION_MAGIC &&
2882            pFunc->magic != SLTG_FUNCTION_WITH_FLAGS_MAGIC) {
2883             FIXME("func magic = %02x\n", pFunc->magic);
2884             return NULL;
2885         }
2886         *ppFuncDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2887                                 sizeof(**ppFuncDesc));
2888         (*ppFuncDesc)->Name = TLB_MultiByteToBSTR(pFunc->name + pNameTable);
2889
2890         (*ppFuncDesc)->funcdesc.memid = pFunc->dispid;
2891         (*ppFuncDesc)->funcdesc.invkind = pFunc->inv >> 4;
2892         (*ppFuncDesc)->funcdesc.callconv = pFunc->nacc & 0x7;
2893         (*ppFuncDesc)->funcdesc.cParams = pFunc->nacc >> 3;
2894         (*ppFuncDesc)->funcdesc.cParamsOpt = (pFunc->retnextopt & 0x7e) >> 1;
2895         (*ppFuncDesc)->funcdesc.oVft = pFunc->vtblpos;
2896
2897         if(pFunc->magic == SLTG_FUNCTION_WITH_FLAGS_MAGIC)
2898             (*ppFuncDesc)->funcdesc.wFuncFlags = pFunc->funcflags;
2899
2900         if(pFunc->retnextopt & 0x80)
2901             pType = &pFunc->rettype;
2902         else
2903             pType = (WORD*)(pFirstItem + pFunc->rettype);
2904
2905
2906         SLTG_DoType(pType, pFirstItem, &(*ppFuncDesc)->funcdesc.elemdescFunc);
2907
2908         (*ppFuncDesc)->funcdesc.lprgelemdescParam =
2909           HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2910                     (*ppFuncDesc)->funcdesc.cParams * sizeof(ELEMDESC));
2911         (*ppFuncDesc)->pParamDesc =
2912           HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2913                     (*ppFuncDesc)->funcdesc.cParams * sizeof(TLBParDesc));
2914
2915         pArg = (WORD*)(pFirstItem + pFunc->arg_off);
2916
2917         for(param = 0; param < (*ppFuncDesc)->funcdesc.cParams; param++) {
2918             char *paramName = pNameTable + *pArg;
2919             BOOL HaveOffs;
2920             /* If arg type follows then paramName points to the 2nd
2921                letter of the name, else the next WORD is an offset to
2922                the arg type and paramName points to the first letter.
2923                So let's take one char off paramName and see if we're
2924                pointing at an alpha-numeric char.  However if *pArg is
2925                0xffff or 0xfffe then the param has no name, the former
2926                meaning that the next WORD is the type, the latter
2927                meaning the the next WORD is an offset to the type. */
2928
2929             HaveOffs = FALSE;
2930             if(*pArg == 0xffff)
2931                 paramName = NULL;
2932             else if(*pArg == 0xfffe) {
2933                 paramName = NULL;
2934                 HaveOffs = TRUE;
2935             }
2936             else if(paramName[-1] && !isalnum(paramName[-1]))
2937                 HaveOffs = TRUE;
2938
2939             pArg++;
2940
2941             if(HaveOffs) { /* the next word is an offset to type */
2942                 pType = (WORD*)(pFirstItem + *pArg);
2943                 SLTG_DoType(pType, pFirstItem,
2944                             &(*ppFuncDesc)->funcdesc.lprgelemdescParam[param]);
2945                 pArg++;
2946             } else {
2947                 if(paramName)
2948                   paramName--;
2949                 pArg = SLTG_DoType(pArg, pFirstItem,
2950                            &(*ppFuncDesc)->funcdesc.lprgelemdescParam[param]);
2951             }
2952
2953             /* Are we an optional param ? */
2954             if((*ppFuncDesc)->funcdesc.cParams - param <=
2955                (*ppFuncDesc)->funcdesc.cParamsOpt)
2956               (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].u.paramdesc.wParamFlags |= PARAMFLAG_FOPT;
2957
2958             if(paramName) {
2959                 (*ppFuncDesc)->pParamDesc[param].Name =
2960                   TLB_MultiByteToBSTR(paramName);
2961             }
2962         }
2963
2964         ppFuncDesc = &((*ppFuncDesc)->next);
2965         if(pFunc->next == 0xffff) break;
2966     }
2967     pTI->TypeAttr.cFuncs = num;
2968     dump_TLBFuncDesc(pTI->funclist);
2969     return (SLTG_TypeInfoTail*)(pFirstItem + pMemHeader->cbExtra);
2970 }
2971
2972 static SLTG_TypeInfoTail *SLTG_ProcessRecord(char *pBlk, ITypeInfoImpl *pTI,
2973                                              char *pNameTable)
2974 {
2975   SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk;
2976   SLTG_MemberHeader *pMemHeader;
2977   SLTG_RecordItem *pItem;
2978   char *pFirstItem;
2979   TLBVarDesc **ppVarDesc = &pTI->varlist;
2980   int num = 0;
2981   WORD *pType;
2982   char buf[300];
2983
2984   pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table);
2985
2986   pFirstItem = (char*)(pMemHeader + 1);
2987   for(pItem = (SLTG_RecordItem *)pFirstItem, num = 1; 1;
2988       pItem = (SLTG_RecordItem *)(pFirstItem + pItem->next), num++) {
2989       if(pItem->magic != SLTG_RECORD_MAGIC) {
2990           FIXME("record magic = %02x\n", pItem->magic);
2991           return NULL;
2992       }
2993       *ppVarDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2994                              sizeof(**ppVarDesc));
2995       (*ppVarDesc)->Name = TLB_MultiByteToBSTR(pItem->name + pNameTable);
2996       (*ppVarDesc)->vardesc.memid = pItem->memid;
2997       (*ppVarDesc)->vardesc.u.oInst = pItem->byte_offs;
2998       (*ppVarDesc)->vardesc.varkind = VAR_PERINSTANCE;
2999
3000       if(pItem->typepos == 0x02)
3001           pType = &pItem->type;
3002       else if(pItem->typepos == 0x00)
3003           pType = (WORD*)(pFirstItem + pItem->type);
3004       else {
3005           FIXME("typepos = %02x\n", pItem->typepos);
3006           break;
3007       }
3008
3009       SLTG_DoType(pType, pFirstItem,
3010                   &(*ppVarDesc)->vardesc.elemdescVar);
3011
3012       /* FIXME("helpcontext, helpstring\n"); */
3013
3014       dump_TypeDesc(&(*ppVarDesc)->vardesc.elemdescVar.tdesc, buf);
3015
3016       ppVarDesc = &((*ppVarDesc)->next);
3017       if(pItem->next == 0xffff) break;
3018   }
3019   pTI->TypeAttr.cVars = num;
3020   return (SLTG_TypeInfoTail*)(pFirstItem + pMemHeader->cbExtra);
3021 }
3022
3023 static SLTG_TypeInfoTail *SLTG_ProcessAlias(char *pBlk, ITypeInfoImpl *pTI,
3024                                            char *pNameTable)
3025 {
3026   SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk;
3027   SLTG_MemberHeader *pMemHeader;
3028   SLTG_AliasItem *pItem;
3029   int i, mustbelast;
3030
3031   pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table);
3032   pItem = (SLTG_AliasItem*)(pMemHeader + 1);
3033
3034   mustbelast = 0;
3035   /* This is used for creating a TYPEDESC chain in case of VT_USERDEFINED */
3036   for (i = 0 ; i<pMemHeader->cbExtra/4 ; i++) {
3037     if (pItem->vt == 0xffff) {
3038       if (i<(pMemHeader->cbExtra/4-1))
3039         FIXME("Endmarker too early in process alias data!\n");
3040       break;
3041     }
3042     if (mustbelast) {
3043       FIXME("Chain extends over last entry?\n");
3044       break;
3045     }
3046     if (pItem->vt == VT_USERDEFINED) {
3047       pTI->TypeAttr.tdescAlias.vt = pItem->vt;
3048       /* guessing here ... */
3049       FIXME("Guessing TKIND_ALIAS of VT_USERDEFINED with hreftype 0x%x\n",pItem->res02);
3050       pTI->TypeAttr.tdescAlias.u.hreftype = pItem->res02;
3051       mustbelast = 1;
3052     } else {
3053       FIXME("alias %d: 0x%x\n",i,pItem->vt);
3054       FIXME("alias %d: 0x%x\n",i,pItem->res02);
3055     }
3056     pItem++;
3057   }
3058   return (SLTG_TypeInfoTail*)((char*)(pMemHeader + 1)+pMemHeader->cbExtra);
3059 }
3060
3061 static SLTG_TypeInfoTail *SLTG_ProcessDispatch(char *pBlk, ITypeInfoImpl *pTI,
3062                                            char *pNameTable)
3063 {
3064   SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk;
3065   SLTG_MemberHeader *pMemHeader;
3066   SLTG_AliasItem *pItem;
3067
3068   pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table);
3069   pItem = (SLTG_AliasItem*)(pMemHeader + 1);
3070   FIXME("memh.cbExtra is %ld\n",pMemHeader->cbExtra);
3071   FIXME("offset 0 0x%x\n",*(WORD*)pItem);
3072   return (SLTG_TypeInfoTail*)((char*)(pMemHeader + 1)+pMemHeader->cbExtra);
3073 }
3074
3075 static SLTG_TypeInfoTail *SLTG_ProcessEnum(char *pBlk, ITypeInfoImpl *pTI,
3076                                            char *pNameTable)
3077 {
3078   SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk;
3079   SLTG_MemberHeader *pMemHeader;
3080   SLTG_EnumItem *pItem;
3081   char *pFirstItem;
3082   TLBVarDesc **ppVarDesc = &pTI->varlist;
3083   int num = 0;
3084
3085   pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table);
3086
3087   pFirstItem = (char*)(pMemHeader + 1);
3088   for(pItem = (SLTG_EnumItem *)pFirstItem, num = 1; 1;
3089       pItem = (SLTG_EnumItem *)(pFirstItem + pItem->next), num++) {
3090       if(pItem->magic != SLTG_ENUMITEM_MAGIC) {
3091           FIXME("enumitem magic = %04x\n", pItem->magic);
3092           return NULL;
3093       }
3094       *ppVarDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3095                              sizeof(**ppVarDesc));
3096       (*ppVarDesc)->Name = TLB_MultiByteToBSTR(pItem->name + pNameTable);
3097       (*ppVarDesc)->vardesc.memid = pItem->memid;
3098       (*ppVarDesc)->vardesc.u.lpvarValue = HeapAlloc(GetProcessHeap(), 0,
3099                                                      sizeof(VARIANT));
3100       V_VT((*ppVarDesc)->vardesc.u.lpvarValue) = VT_INT;
3101       V_UNION((*ppVarDesc)->vardesc.u.lpvarValue, intVal) =
3102         *(INT*)(pItem->value + pFirstItem);
3103       (*ppVarDesc)->vardesc.elemdescVar.tdesc.vt = VT_I4;
3104       (*ppVarDesc)->vardesc.varkind = VAR_CONST;
3105       /* FIXME("helpcontext, helpstring\n"); */
3106
3107       ppVarDesc = &((*ppVarDesc)->next);
3108       if(pItem->next == 0xffff) break;
3109   }
3110   pTI->TypeAttr.cVars = num;
3111   return (SLTG_TypeInfoTail*)(pFirstItem + pMemHeader->cbExtra);
3112 }
3113
3114 /* Because SLTG_OtherTypeInfo is such a painful struct, we make a more
3115    managable copy of it into this */
3116 typedef struct {
3117   WORD small_no;
3118   char *index_name;
3119   char *other_name;
3120   WORD res1a;
3121   WORD name_offs;
3122   WORD more_bytes;
3123   char *extra;
3124   WORD res20;
3125   DWORD helpcontext;
3126   WORD res26;
3127   GUID uuid;
3128 } SLTG_InternalOtherTypeInfo;
3129
3130 /****************************************************************************
3131  *      ITypeLib2_Constructor_SLTG
3132  *
3133  * loading a SLTG typelib from an in-memory image
3134  */
3135 static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength)
3136 {
3137     ITypeLibImpl *pTypeLibImpl;
3138     SLTG_Header *pHeader;
3139     SLTG_BlkEntry *pBlkEntry;
3140     SLTG_Magic *pMagic;
3141     SLTG_Index *pIndex;
3142     SLTG_Pad9 *pPad9;
3143     LPVOID pBlk, pFirstBlk;
3144     SLTG_LibBlk *pLibBlk;
3145     SLTG_InternalOtherTypeInfo *pOtherTypeInfoBlks;
3146     char *pAfterOTIBlks = NULL;
3147     char *pNameTable, *ptr;
3148     int i;
3149     DWORD len, order;
3150     ITypeInfoImpl **ppTypeInfoImpl;
3151
3152     TRACE_(typelib)("%p, TLB length = %ld\n", pLib, dwTLBLength);
3153
3154     pTypeLibImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeLibImpl));
3155     if (!pTypeLibImpl) return NULL;
3156
3157     pTypeLibImpl->lpVtbl = &tlbvt;
3158     pTypeLibImpl->ref = 1;
3159
3160     pHeader = pLib;
3161
3162     TRACE_(typelib)("header:\n");
3163     TRACE_(typelib)("\tmagic=0x%08lx, file blocks = %d\n", pHeader->SLTG_magic,
3164           pHeader->nrOfFileBlks );
3165     if (pHeader->SLTG_magic != SLTG_SIGNATURE) {
3166         FIXME("Header type magic 0x%08lx not supported.\n",
3167               pHeader->SLTG_magic);
3168         return NULL;
3169     }
3170
3171     /* There are pHeader->nrOfFileBlks - 2 TypeInfo records in this typelib */
3172     pTypeLibImpl->TypeInfoCount = pHeader->nrOfFileBlks - 2;
3173
3174     /* This points to pHeader->nrOfFileBlks - 1 of SLTG_BlkEntry */
3175     pBlkEntry = (SLTG_BlkEntry*)(pHeader + 1);
3176
3177     /* Next we have a magic block */
3178     pMagic = (SLTG_Magic*)(pBlkEntry + pHeader->nrOfFileBlks - 1);
3179
3180     /* Let's see if we're still in sync */
3181     if(memcmp(pMagic->CompObj_magic, SLTG_COMPOBJ_MAGIC,
3182               sizeof(SLTG_COMPOBJ_MAGIC))) {
3183         FIXME("CompObj magic = %s\n", pMagic->CompObj_magic);
3184         return NULL;
3185     }
3186     if(memcmp(pMagic->dir_magic, SLTG_DIR_MAGIC,
3187               sizeof(SLTG_DIR_MAGIC))) {
3188         FIXME("dir magic = %s\n", pMagic->dir_magic);
3189         return NULL;
3190     }
3191
3192     pIndex = (SLTG_Index*)(pMagic+1);
3193
3194     pPad9 = (SLTG_Pad9*)(pIndex + pTypeLibImpl->TypeInfoCount);
3195
3196     pFirstBlk = (LPVOID)(pPad9 + 1);
3197
3198     /* We'll set up a ptr to the main library block, which is the last one. */
3199
3200     for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0;
3201           pBlkEntry[order].next != 0;
3202           order = pBlkEntry[order].next - 1, i++) {
3203        pBlk = (char*)pBlk + pBlkEntry[order].len;
3204     }
3205     pLibBlk = pBlk;
3206
3207     len = SLTG_ReadLibBlk(pLibBlk, pTypeLibImpl);
3208
3209     /* Now there's 0x40 bytes of 0xffff with the numbers 0 to TypeInfoCount
3210        interspersed */
3211
3212     len += 0x40;
3213
3214     /* And now TypeInfoCount of SLTG_OtherTypeInfo */
3215
3216     pOtherTypeInfoBlks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3217                                    sizeof(*pOtherTypeInfoBlks) *
3218                                    pTypeLibImpl->TypeInfoCount);
3219
3220
3221     ptr = (char*)pLibBlk + len;
3222
3223     for(i = 0; i < pTypeLibImpl->TypeInfoCount; i++) {
3224         WORD w, extra;
3225         len = 0;
3226
3227         pOtherTypeInfoBlks[i].small_no = *(WORD*)ptr;
3228
3229         w = *(WORD*)(ptr + 2);
3230         if(w != 0xffff) {
3231             len += w;
3232             pOtherTypeInfoBlks[i].index_name = HeapAlloc(GetProcessHeap(),0,
3233                                                          w+1);
3234             memcpy(pOtherTypeInfoBlks[i].index_name, ptr + 4, w);
3235             pOtherTypeInfoBlks[i].index_name[w] = '\0';
3236         }
3237         w = *(WORD*)(ptr + 4 + len);
3238         if(w != 0xffff) {
3239             TRACE_(typelib)("\twith %s\n", debugstr_an(ptr + 6 + len, w));
3240             len += w;
3241             pOtherTypeInfoBlks[i].other_name = HeapAlloc(GetProcessHeap(),0,
3242                                                          w+1);
3243             memcpy(pOtherTypeInfoBlks[i].other_name, ptr + 6 + len, w);
3244             pOtherTypeInfoBlks[i].other_name[w] = '\0';
3245         }
3246         pOtherTypeInfoBlks[i].res1a = *(WORD*)(ptr + len + 6);
3247         pOtherTypeInfoBlks[i].name_offs = *(WORD*)(ptr + len + 8);
3248         extra = pOtherTypeInfoBlks[i].more_bytes = *(WORD*)(ptr + 10 + len);
3249         if(extra) {
3250             pOtherTypeInfoBlks[i].extra = HeapAlloc(GetProcessHeap(),0,
3251                                                     extra);
3252             memcpy(pOtherTypeInfoBlks[i].extra, ptr + 12, extra);
3253             len += extra;
3254         }
3255         pOtherTypeInfoBlks[i].res20 = *(WORD*)(ptr + 12 + len);
3256         pOtherTypeInfoBlks[i].helpcontext = *(DWORD*)(ptr + 14 + len);
3257         pOtherTypeInfoBlks[i].res26 = *(WORD*)(ptr + 18 + len);
3258         memcpy(&pOtherTypeInfoBlks[i].uuid, ptr + 20 + len, sizeof(GUID));
3259         len += sizeof(SLTG_OtherTypeInfo);
3260         ptr += len;
3261     }
3262
3263     pAfterOTIBlks = ptr;
3264
3265     /* Skip this WORD and get the next DWORD */
3266     len = *(DWORD*)(pAfterOTIBlks + 2);
3267
3268     /* Now add this to pLibBLk look at what we're pointing at and
3269        possibly add 0x20, then add 0x216, sprinkle a bit a magic
3270        dust and we should be pointing at the beginning of the name
3271        table */
3272
3273     pNameTable = (char*)pLibBlk + len;
3274
3275    switch(*(WORD*)pNameTable) {
3276    case 0xffff:
3277        break;
3278    case 0x0200:
3279        pNameTable += 0x20;
3280        break;
3281    default:
3282        FIXME("pNameTable jump = %x\n", *(WORD*)pNameTable);
3283        break;
3284    }
3285
3286     pNameTable += 0x216;
3287
3288     pNameTable += 2;
3289
3290     TRACE("Library name is %s\n", pNameTable + pLibBlk->name);
3291
3292     pTypeLibImpl->Name = TLB_MultiByteToBSTR(pNameTable + pLibBlk->name);
3293
3294
3295     /* Hopefully we now have enough ptrs set up to actually read in
3296        some TypeInfos.  It's not clear which order to do them in, so
3297        I'll just follow the links along the BlkEntry chain and read
3298        them in in the order in which they're in the file */
3299
3300     ppTypeInfoImpl = &(pTypeLibImpl->pTypeInfo);
3301
3302     for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0;
3303         pBlkEntry[order].next != 0;
3304         order = pBlkEntry[order].next - 1, i++) {
3305
3306       SLTG_TypeInfoHeader *pTIHeader;
3307       SLTG_TypeInfoTail *pTITail;
3308
3309       if(strcmp(pBlkEntry[order].index_string + (char*)pMagic,
3310                 pOtherTypeInfoBlks[i].index_name)) {
3311         FIXME("Index strings don't match\n");
3312         return NULL;
3313       }
3314
3315       pTIHeader = pBlk;
3316       if(pTIHeader->magic != SLTG_TIHEADER_MAGIC) {
3317         FIXME("TypeInfoHeader magic = %04x\n", pTIHeader->magic);
3318         return NULL;
3319       }
3320       *ppTypeInfoImpl = (ITypeInfoImpl*)ITypeInfo_Constructor();
3321       (*ppTypeInfoImpl)->pTypeLib = pTypeLibImpl;
3322       (*ppTypeInfoImpl)->index = i;
3323       (*ppTypeInfoImpl)->Name = TLB_MultiByteToBSTR(
3324                                              pOtherTypeInfoBlks[i].name_offs +
3325                                              pNameTable);
3326       (*ppTypeInfoImpl)->dwHelpContext = pOtherTypeInfoBlks[i].helpcontext;
3327       memcpy(&((*ppTypeInfoImpl)->TypeAttr.guid), &pOtherTypeInfoBlks[i].uuid,
3328              sizeof(GUID));
3329       (*ppTypeInfoImpl)->TypeAttr.typekind = pTIHeader->typekind;
3330       (*ppTypeInfoImpl)->TypeAttr.wMajorVerNum = pTIHeader->major_version;
3331       (*ppTypeInfoImpl)->TypeAttr.wMinorVerNum = pTIHeader->minor_version;
3332       (*ppTypeInfoImpl)->TypeAttr.wTypeFlags =
3333         (pTIHeader->typeflags1 >> 3) | (pTIHeader->typeflags2 << 5);
3334
3335       if((pTIHeader->typeflags1 & 7) != 2)
3336         FIXME("typeflags1 = %02x\n", pTIHeader->typeflags1);
3337       if(pTIHeader->typeflags3 != 2)
3338         FIXME("typeflags3 = %02x\n", pTIHeader->typeflags3);
3339
3340       TRACE("TypeInfo %s of kind %s guid %s typeflags %04x\n",
3341             debugstr_w((*ppTypeInfoImpl)->Name),
3342             typekind_desc[pTIHeader->typekind],
3343             debugstr_guid(&(*ppTypeInfoImpl)->TypeAttr.guid),
3344             (*ppTypeInfoImpl)->TypeAttr.wTypeFlags);
3345
3346       switch(pTIHeader->typekind) {
3347       case TKIND_ENUM:
3348         pTITail = SLTG_ProcessEnum(pBlk, *ppTypeInfoImpl, pNameTable);
3349         break;
3350
3351       case TKIND_RECORD:
3352         pTITail = SLTG_ProcessRecord(pBlk, *ppTypeInfoImpl, pNameTable);
3353         break;
3354
3355       case TKIND_INTERFACE:
3356         pTITail = SLTG_ProcessInterface(pBlk, *ppTypeInfoImpl, pNameTable);
3357         break;
3358
3359       case TKIND_COCLASS:
3360         pTITail = SLTG_ProcessCoClass(pBlk, *ppTypeInfoImpl, pNameTable);
3361         break;
3362
3363       case TKIND_ALIAS:
3364         pTITail = SLTG_ProcessAlias(pBlk, *ppTypeInfoImpl, pNameTable);
3365         if (pTITail->tdescalias_vt)
3366           (*ppTypeInfoImpl)->TypeAttr.tdescAlias.vt = pTITail->tdescalias_vt;
3367         break;
3368
3369       case TKIND_DISPATCH:
3370         pTITail = SLTG_ProcessDispatch(pBlk, *ppTypeInfoImpl, pNameTable);
3371         break;
3372
3373       default:
3374         FIXME("Not processing typekind %d\n", pTIHeader->typekind);
3375         pTITail = NULL;
3376         break;
3377
3378       }
3379
3380       if(pTITail) { /* could get cFuncs, cVars and cImplTypes from here
3381                        but we've already set those */
3382           (*ppTypeInfoImpl)->TypeAttr.cbAlignment = pTITail->cbAlignment;
3383           (*ppTypeInfoImpl)->TypeAttr.cbSizeInstance = pTITail->cbSizeInstance;
3384           (*ppTypeInfoImpl)->TypeAttr.cbSizeVft = pTITail->cbSizeVft;
3385
3386 #define X(x) TRACE_(typelib)("tt "#x": %x\n",pTITail->res##x);
3387           X(06);
3388           X(08);
3389           X(0a);
3390           X(0c);
3391           X(0e);
3392           X(10);
3393           X(12);
3394           X(16);
3395           X(18);
3396           X(1a);
3397           X(1c);
3398           X(1e);
3399           X(24);
3400           X(26);
3401           X(2a);
3402           X(2c);
3403           X(2e);
3404           X(30);
3405           X(32);
3406           X(34);
3407       }
3408       ppTypeInfoImpl = &((*ppTypeInfoImpl)->next);
3409       pBlk = (char*)pBlk + pBlkEntry[order].len;
3410     }
3411
3412     if(i != pTypeLibImpl->TypeInfoCount) {
3413       FIXME("Somehow processed %d TypeInfos\n", i);
3414       return NULL;
3415     }
3416
3417     HeapFree(GetProcessHeap(), 0, pOtherTypeInfoBlks);
3418     return (ITypeLib2*)pTypeLibImpl;
3419 }
3420
3421 /* ITypeLib::QueryInterface
3422  */
3423 static HRESULT WINAPI ITypeLib2_fnQueryInterface(
3424         ITypeLib2 * iface,
3425         REFIID riid,
3426         VOID **ppvObject)
3427 {
3428     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3429
3430     TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
3431
3432     *ppvObject=NULL;
3433     if(IsEqualIID(riid, &IID_IUnknown) ||
3434        IsEqualIID(riid,&IID_ITypeLib)||
3435        IsEqualIID(riid,&IID_ITypeLib2))
3436     {
3437         *ppvObject = This;
3438     }
3439
3440     if(*ppvObject)
3441     {
3442         ITypeLib2_AddRef(iface);
3443         TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
3444         return S_OK;
3445     }
3446     TRACE("-- Interface: E_NOINTERFACE\n");
3447     return E_NOINTERFACE;
3448 }
3449
3450 /* ITypeLib::AddRef
3451  */
3452 static ULONG WINAPI ITypeLib2_fnAddRef( ITypeLib2 *iface)
3453 {
3454     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3455     ULONG ref = InterlockedIncrement(&This->ref);
3456
3457     TRACE("(%p)->ref was %lu\n",This, ref - 1);
3458
3459     return ref;
3460 }
3461
3462 /* ITypeLib::Release
3463  */
3464 static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface)
3465 {
3466     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3467     ULONG ref = InterlockedDecrement(&This->ref);
3468
3469     TRACE("(%p)->(%lu)\n",This, ref);
3470
3471     if (!ref)
3472     {
3473       /* remove cache entry */
3474       TRACE("removing from cache list\n");
3475       EnterCriticalSection(&cache_section);
3476       if (This->next) This->next->prev = This->prev;
3477       if (This->prev) This->prev->next = This->next;
3478       else tlb_cache_first = This->next;
3479       LeaveCriticalSection(&cache_section);
3480
3481       /* FIXME destroy child objects */
3482       TRACE(" destroying ITypeLib(%p)\n",This);
3483
3484       if (This->Name)
3485       {
3486           SysFreeString(This->Name);
3487           This->Name = NULL;
3488       }
3489
3490       if (This->DocString)
3491       {
3492           SysFreeString(This->DocString);
3493           This->DocString = NULL;
3494       }
3495
3496       if (This->HelpFile)
3497       {
3498           SysFreeString(This->HelpFile);
3499           This->HelpFile = NULL;
3500       }
3501
3502       if (This->HelpStringDll)
3503       {
3504           SysFreeString(This->HelpStringDll);
3505           This->HelpStringDll = NULL;
3506       }
3507
3508       if (This->pTypeInfo) /* can be NULL */
3509           ITypeInfo_Release((ITypeInfo*) This->pTypeInfo);
3510       HeapFree(GetProcessHeap(),0,This);
3511       return 0;
3512     }
3513
3514     return ref;
3515 }
3516
3517 /* ITypeLib::GetTypeInfoCount
3518  *
3519  * Returns the number of type descriptions in the type library
3520  */
3521 static UINT WINAPI ITypeLib2_fnGetTypeInfoCount( ITypeLib2 *iface)
3522 {
3523     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3524     TRACE("(%p)->count is %d\n",This, This->TypeInfoCount);
3525     return This->TypeInfoCount;
3526 }
3527
3528 /* ITypeLib::GetTypeInfo
3529  *
3530  * retrieves the specified type description in the library.
3531  */
3532 static HRESULT WINAPI ITypeLib2_fnGetTypeInfo(
3533     ITypeLib2 *iface,
3534     UINT index,
3535     ITypeInfo **ppTInfo)
3536 {
3537     int i;
3538
3539     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3540     ITypeInfoImpl *pTypeInfo = This->pTypeInfo;
3541
3542     TRACE("(%p)->(index=%d) \n", This, index);
3543
3544     if (!ppTInfo) return E_INVALIDARG;
3545
3546     /* search element n in list */
3547     for(i=0; i < index; i++)
3548     {
3549       pTypeInfo = pTypeInfo->next;
3550       if (!pTypeInfo)
3551       {
3552         TRACE("-- element not found\n");
3553         return TYPE_E_ELEMENTNOTFOUND;
3554       }
3555     }
3556
3557     *ppTInfo = (ITypeInfo *) pTypeInfo;
3558
3559     ITypeInfo_AddRef(*ppTInfo);
3560     TRACE("-- found (%p)\n",*ppTInfo);
3561     return S_OK;
3562 }
3563
3564
3565 /* ITypeLibs::GetTypeInfoType
3566  *
3567  * Retrieves the type of a type description.
3568  */
3569 static HRESULT WINAPI ITypeLib2_fnGetTypeInfoType(
3570     ITypeLib2 *iface,
3571     UINT index,
3572     TYPEKIND *pTKind)
3573 {
3574     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3575     int i;
3576     ITypeInfoImpl *pTInfo = This->pTypeInfo;
3577
3578     TRACE("(%p) index %d \n",This, index);
3579
3580     if(!pTKind) return E_INVALIDARG;
3581
3582     /* search element n in list */
3583     for(i=0; i < index; i++)
3584     {
3585       if(!pTInfo)
3586       {
3587         TRACE("-- element not found\n");
3588         return TYPE_E_ELEMENTNOTFOUND;
3589       }
3590       pTInfo = pTInfo->next;
3591     }
3592
3593     *pTKind = pTInfo->TypeAttr.typekind;
3594     TRACE("-- found Type (%d)\n", *pTKind);
3595     return S_OK;
3596 }
3597
3598 /* ITypeLib::GetTypeInfoOfGuid
3599  *
3600  * Retrieves the type description that corresponds to the specified GUID.
3601  *
3602  */
3603 static HRESULT WINAPI ITypeLib2_fnGetTypeInfoOfGuid(
3604     ITypeLib2 *iface,
3605     REFGUID guid,
3606     ITypeInfo **ppTInfo)
3607 {
3608     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3609     ITypeInfoImpl *pTypeInfo = This->pTypeInfo; /* head of list */
3610
3611     TRACE("(%p)\n\tguid:\t%s)\n",This,debugstr_guid(guid));
3612
3613     if (!pTypeInfo) return TYPE_E_ELEMENTNOTFOUND;
3614
3615     /* search linked list for guid */
3616     while( !IsEqualIID(guid,&pTypeInfo->TypeAttr.guid) )
3617     {
3618       pTypeInfo = pTypeInfo->next;
3619
3620       if (!pTypeInfo)
3621       {
3622         /* end of list reached */
3623         TRACE("-- element not found\n");
3624         return TYPE_E_ELEMENTNOTFOUND;
3625       }
3626     }
3627
3628     TRACE("-- found (%p, %s)\n",
3629           pTypeInfo,
3630           debugstr_w(pTypeInfo->Name));
3631
3632     *ppTInfo = (ITypeInfo*)pTypeInfo;
3633     ITypeInfo_AddRef(*ppTInfo);
3634     return S_OK;
3635 }
3636
3637 /* ITypeLib::GetLibAttr
3638  *
3639  * Retrieves the structure that contains the library's attributes.
3640  *
3641  */
3642 static HRESULT WINAPI ITypeLib2_fnGetLibAttr(
3643         ITypeLib2 *iface,
3644         LPTLIBATTR *ppTLibAttr)
3645 {
3646     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3647     TRACE("(%p)\n",This);
3648     *ppTLibAttr = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppTLibAttr));
3649     memcpy(*ppTLibAttr, &This->LibAttr, sizeof(**ppTLibAttr));
3650     return S_OK;
3651 }
3652
3653 /* ITypeLib::GetTypeComp
3654  *
3655  * Enables a client compiler to bind to a library's types, variables,
3656  * constants, and global functions.
3657  *
3658  */
3659 static HRESULT WINAPI ITypeLib2_fnGetTypeComp(
3660         ITypeLib2 *iface,
3661         ITypeComp **ppTComp)
3662 {
3663     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3664
3665     TRACE("(%p)->(%p)\n",This,ppTComp);
3666     *ppTComp = (ITypeComp *)&This->lpVtblTypeComp;
3667     ITypeComp_AddRef(*ppTComp);
3668
3669     return S_OK;
3670 }
3671
3672 /* ITypeLib::GetDocumentation
3673  *
3674  * Retrieves the library's documentation string, the complete Help file name
3675  * and path, and the context identifier for the library Help topic in the Help
3676  * file.
3677  *
3678  * On a successful return all non-null BSTR pointers will have been set,
3679  * possibly to NULL.
3680  */
3681 static HRESULT WINAPI ITypeLib2_fnGetDocumentation(
3682     ITypeLib2 *iface,
3683     INT index,
3684     BSTR *pBstrName,
3685     BSTR *pBstrDocString,
3686     DWORD *pdwHelpContext,
3687     BSTR *pBstrHelpFile)
3688 {
3689     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3690
3691     HRESULT result = E_INVALIDARG;
3692
3693     ITypeInfo *pTInfo;
3694
3695
3696     TRACE("(%p) index %d Name(%p) DocString(%p) HelpContext(%p) HelpFile(%p)\n",
3697         This, index,
3698         pBstrName, pBstrDocString,
3699         pdwHelpContext, pBstrHelpFile);
3700
3701     if(index<0)
3702     {
3703         /* documentation for the typelib */
3704         if(pBstrName)
3705         {
3706             if (This->Name)
3707             {
3708                 if(!(*pBstrName = SysAllocString(This->Name)))
3709                     goto memerr1;
3710             }
3711             else
3712                 *pBstrName = NULL;
3713         }
3714         if(pBstrDocString)
3715         {
3716             if (This->DocString)
3717             {
3718                 if(!(*pBstrDocString = SysAllocString(This->DocString)))
3719                     goto memerr2;
3720             }
3721             else if (This->Name)
3722             {
3723                 if(!(*pBstrDocString = SysAllocString(This->Name)))
3724                     goto memerr2;
3725             }
3726             else
3727                 *pBstrDocString = NULL;
3728         }
3729         if(pdwHelpContext)
3730         {
3731             *pdwHelpContext = This->dwHelpContext;
3732         }
3733         if(pBstrHelpFile)
3734         {
3735             if (This->HelpFile)
3736             {
3737                 if(!(*pBstrHelpFile = SysAllocString(This->HelpFile)))
3738                     goto memerr3;
3739             }
3740             else
3741                 *pBstrHelpFile = NULL;
3742         }
3743
3744         result = S_OK;
3745     }
3746     else
3747     {
3748         /* for a typeinfo */
3749         result = ITypeLib2_fnGetTypeInfo(iface, index, &pTInfo);
3750
3751         if(SUCCEEDED(result))
3752         {
3753             result = ITypeInfo_GetDocumentation(pTInfo,
3754                                           MEMBERID_NIL,
3755                                           pBstrName,
3756                                           pBstrDocString,
3757                                           pdwHelpContext, pBstrHelpFile);
3758
3759             ITypeInfo_Release(pTInfo);
3760         }
3761     }
3762     return result;
3763 memerr3:
3764     if (pBstrDocString) SysFreeString (*pBstrDocString);
3765 memerr2:
3766     if (pBstrName) SysFreeString (*pBstrName);
3767 memerr1:
3768     return STG_E_INSUFFICIENTMEMORY;
3769 }
3770
3771 /* ITypeLib::IsName
3772  *
3773  * Indicates whether a passed-in string contains the name of a type or member
3774  * described in the library.
3775  *
3776  */
3777 static HRESULT WINAPI ITypeLib2_fnIsName(
3778         ITypeLib2 *iface,
3779         LPOLESTR szNameBuf,
3780         ULONG lHashVal,
3781         BOOL *pfName)
3782 {
3783     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3784     ITypeInfoImpl *pTInfo;
3785     TLBFuncDesc *pFInfo;
3786     TLBVarDesc *pVInfo;
3787     int i;
3788     UINT nNameBufLen = (lstrlenW(szNameBuf)+1)*sizeof(WCHAR);
3789
3790     TRACE("(%p)->(%s,%08lx,%p)\n", This, debugstr_w(szNameBuf), lHashVal,
3791           pfName);
3792
3793     *pfName=TRUE;
3794     for(pTInfo=This->pTypeInfo;pTInfo;pTInfo=pTInfo->next){
3795         if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
3796         for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
3797             if(!memcmp(szNameBuf,pFInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
3798             for(i=0;i<pFInfo->funcdesc.cParams;i++)
3799                 if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name, nNameBufLen))
3800                     goto ITypeLib2_fnIsName_exit;
3801         }
3802         for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next)
3803             if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
3804
3805     }
3806     *pfName=FALSE;
3807
3808 ITypeLib2_fnIsName_exit:
3809     TRACE("(%p)slow! search for %s: %s found!\n", This,
3810           debugstr_w(szNameBuf), *pfName?"NOT":"");
3811
3812     return S_OK;
3813 }
3814
3815 /* ITypeLib::FindName
3816  *
3817  * Finds occurrences of a type description in a type library. This may be used
3818  * to quickly verify that a name exists in a type library.
3819  *
3820  */
3821 static HRESULT WINAPI ITypeLib2_fnFindName(
3822         ITypeLib2 *iface,
3823         LPOLESTR szNameBuf,
3824         ULONG lHashVal,
3825         ITypeInfo **ppTInfo,
3826         MEMBERID *rgMemId,
3827         UINT16 *pcFound)
3828 {
3829     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3830     ITypeInfoImpl *pTInfo;
3831     TLBFuncDesc *pFInfo;
3832     TLBVarDesc *pVInfo;
3833     int i,j = 0;
3834     UINT nNameBufLen = (lstrlenW(szNameBuf)+1)*sizeof(WCHAR);
3835
3836     for(pTInfo=This->pTypeInfo;pTInfo && j<*pcFound; pTInfo=pTInfo->next){
3837         if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit;
3838         for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
3839             if(!memcmp(szNameBuf,pFInfo->Name,nNameBufLen)) goto ITypeLib2_fnFindName_exit;
3840             for(i=0;i<pFInfo->funcdesc.cParams;i++) {
3841                 if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name,nNameBufLen))
3842                     goto ITypeLib2_fnFindName_exit;
3843             }
3844         }
3845         for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next)
3846             if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit;
3847         continue;
3848 ITypeLib2_fnFindName_exit:
3849         ITypeInfo_AddRef((ITypeInfo*)pTInfo);
3850         ppTInfo[j]=(LPTYPEINFO)pTInfo;
3851         j++;
3852     }
3853     TRACE("(%p)slow! search for %d with %s: found %d TypeInfo's!\n",
3854           This, *pcFound, debugstr_w(szNameBuf), j);
3855
3856     *pcFound=j;
3857
3858     return S_OK;
3859 }
3860
3861 /* ITypeLib::ReleaseTLibAttr
3862  *
3863  * Releases the TLIBATTR originally obtained from ITypeLib::GetLibAttr.
3864  *
3865  */
3866 static VOID WINAPI ITypeLib2_fnReleaseTLibAttr(
3867         ITypeLib2 *iface,
3868         TLIBATTR *pTLibAttr)
3869 {
3870     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3871     TRACE("freeing (%p)\n",This);
3872     HeapFree(GetProcessHeap(),0,pTLibAttr);
3873
3874 }
3875
3876 /* ITypeLib2::GetCustData
3877  *
3878  * gets the custom data
3879  */
3880 static HRESULT WINAPI ITypeLib2_fnGetCustData(
3881         ITypeLib2 * iface,
3882         REFGUID guid,
3883         VARIANT *pVarVal)
3884 {
3885     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3886     TLBCustData *pCData;
3887
3888     for(pCData=This->pCustData; pCData; pCData = pCData->next)
3889     {
3890       if( IsEqualIID(guid, &pCData->guid)) break;
3891     }
3892
3893     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
3894
3895     if(pCData)
3896     {
3897         VariantInit( pVarVal);
3898         VariantCopy( pVarVal, &pCData->data);
3899         return S_OK;
3900     }
3901     return E_INVALIDARG;  /* FIXME: correct? */
3902 }
3903
3904 /* ITypeLib2::GetLibStatistics
3905  *
3906  * Returns statistics about a type library that are required for efficient
3907  * sizing of hash tables.
3908  *
3909  */
3910 static HRESULT WINAPI ITypeLib2_fnGetLibStatistics(
3911         ITypeLib2 * iface,
3912         ULONG *pcUniqueNames,
3913         ULONG *pcchUniqueNames)
3914 {
3915     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3916
3917     FIXME("(%p): stub!\n", This);
3918
3919     if(pcUniqueNames) *pcUniqueNames=1;
3920     if(pcchUniqueNames) *pcchUniqueNames=1;
3921     return S_OK;
3922 }
3923
3924 /* ITypeLib2::GetDocumentation2
3925  *
3926  * Retrieves the library's documentation string, the complete Help file name
3927  * and path, the localization context to use, and the context ID for the
3928  * library Help topic in the Help file.
3929  *
3930  */
3931 static HRESULT WINAPI ITypeLib2_fnGetDocumentation2(
3932         ITypeLib2 * iface,
3933         INT index,
3934         LCID lcid,
3935         BSTR *pbstrHelpString,
3936         DWORD *pdwHelpStringContext,
3937         BSTR *pbstrHelpStringDll)
3938 {
3939     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3940     HRESULT result;
3941     ITypeInfo *pTInfo;
3942
3943     FIXME("(%p) index %d lcid %ld half implemented stub!\n", This, index, lcid);
3944
3945     /* the help string should be obtained from the helpstringdll,
3946      * using the _DLLGetDocumentation function, based on the supplied
3947      * lcid. Nice to do sometime...
3948      */
3949     if(index<0)
3950     {
3951       /* documentation for the typelib */
3952       if(pbstrHelpString)
3953         *pbstrHelpString=SysAllocString(This->DocString);
3954       if(pdwHelpStringContext)
3955         *pdwHelpStringContext=This->dwHelpContext;
3956       if(pbstrHelpStringDll)
3957         *pbstrHelpStringDll=SysAllocString(This->HelpStringDll);
3958
3959       result = S_OK;
3960     }
3961     else
3962     {
3963       /* for a typeinfo */
3964       result=ITypeLib2_GetTypeInfo(iface, index, &pTInfo);
3965
3966       if(SUCCEEDED(result))
3967       {
3968         ITypeInfo2 * pTInfo2;
3969         result = ITypeInfo_QueryInterface(pTInfo,
3970                                           &IID_ITypeInfo2,
3971                                           (LPVOID*) &pTInfo2);
3972
3973         if(SUCCEEDED(result))
3974         {
3975           result = ITypeInfo2_GetDocumentation2(pTInfo2,
3976                                            MEMBERID_NIL,
3977                                            lcid,
3978                                            pbstrHelpString,
3979                                            pdwHelpStringContext,
3980                                            pbstrHelpStringDll);
3981
3982           ITypeInfo2_Release(pTInfo2);
3983         }
3984
3985         ITypeInfo_Release(pTInfo);
3986       }
3987     }
3988     return result;
3989 }
3990
3991 /* ITypeLib2::GetAllCustData
3992  *
3993  * Gets all custom data items for the library.
3994  *
3995  */
3996 static HRESULT WINAPI ITypeLib2_fnGetAllCustData(
3997         ITypeLib2 * iface,
3998         CUSTDATA *pCustData)
3999 {
4000     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4001     TLBCustData *pCData;
4002     int i;
4003     TRACE("(%p) returning %d items\n", This, This->ctCustData);
4004     pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
4005     if(pCustData->prgCustData ){
4006         pCustData->cCustData=This->ctCustData;
4007         for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
4008             pCustData->prgCustData[i].guid=pCData->guid;
4009             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
4010         }
4011     }else{
4012         ERR(" OUT OF MEMORY! \n");
4013         return E_OUTOFMEMORY;
4014     }
4015     return S_OK;
4016 }
4017
4018 static const ITypeLib2Vtbl tlbvt = {
4019     ITypeLib2_fnQueryInterface,
4020     ITypeLib2_fnAddRef,
4021     ITypeLib2_fnRelease,
4022     ITypeLib2_fnGetTypeInfoCount,
4023     ITypeLib2_fnGetTypeInfo,
4024     ITypeLib2_fnGetTypeInfoType,
4025     ITypeLib2_fnGetTypeInfoOfGuid,
4026     ITypeLib2_fnGetLibAttr,
4027     ITypeLib2_fnGetTypeComp,
4028     ITypeLib2_fnGetDocumentation,
4029     ITypeLib2_fnIsName,
4030     ITypeLib2_fnFindName,
4031     ITypeLib2_fnReleaseTLibAttr,
4032
4033     ITypeLib2_fnGetCustData,
4034     ITypeLib2_fnGetLibStatistics,
4035     ITypeLib2_fnGetDocumentation2,
4036     ITypeLib2_fnGetAllCustData
4037  };
4038
4039
4040 static HRESULT WINAPI ITypeLibComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
4041 {
4042     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4043
4044     return ITypeLib2_QueryInterface((ITypeLib *)This, riid, ppv);
4045 }
4046
4047 static ULONG WINAPI ITypeLibComp_fnAddRef(ITypeComp * iface)
4048 {
4049     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4050
4051     return ITypeLib2_AddRef((ITypeLib2 *)This);
4052 }
4053
4054 static ULONG WINAPI ITypeLibComp_fnRelease(ITypeComp * iface)
4055 {
4056     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4057
4058     return ITypeLib2_Release((ITypeLib2 *)This);
4059 }
4060
4061 static HRESULT WINAPI ITypeLibComp_fnBind(
4062     ITypeComp * iface,
4063     OLECHAR * szName,
4064     ULONG lHash,
4065     WORD wFlags,
4066     ITypeInfo ** ppTInfo,
4067     DESCKIND * pDescKind,
4068     BINDPTR * pBindPtr)
4069 {
4070     FIXME("(%s, %lx, 0x%x, %p, %p, %p): stub\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
4071     return E_NOTIMPL;
4072 }
4073
4074 static HRESULT WINAPI ITypeLibComp_fnBindType(
4075     ITypeComp * iface,
4076     OLECHAR * szName,
4077     ULONG lHash,
4078     ITypeInfo ** ppTInfo,
4079     ITypeComp ** ppTComp)
4080 {
4081     FIXME("(%s, %lx, %p, %p): stub\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
4082     return E_NOTIMPL;
4083 }
4084
4085 static const ITypeCompVtbl tlbtcvt =
4086 {
4087
4088     ITypeLibComp_fnQueryInterface,
4089     ITypeLibComp_fnAddRef,
4090     ITypeLibComp_fnRelease,
4091
4092     ITypeLibComp_fnBind,
4093     ITypeLibComp_fnBindType
4094 };
4095
4096 /*================== ITypeInfo(2) Methods ===================================*/
4097 static ITypeInfo2 * WINAPI ITypeInfo_Constructor(void)
4098 {
4099     ITypeInfoImpl * pTypeInfoImpl;
4100
4101     pTypeInfoImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeInfoImpl));
4102     if (pTypeInfoImpl)
4103     {
4104       pTypeInfoImpl->lpVtbl = &tinfvt;
4105       pTypeInfoImpl->lpVtblTypeComp = &tcompvt;
4106       pTypeInfoImpl->ref=1;
4107     }
4108     TRACE("(%p)\n", pTypeInfoImpl);
4109     return (ITypeInfo2*) pTypeInfoImpl;
4110 }
4111
4112 /* ITypeInfo::QueryInterface
4113  */
4114 static HRESULT WINAPI ITypeInfo_fnQueryInterface(
4115         ITypeInfo2 *iface,
4116         REFIID riid,
4117         VOID **ppvObject)
4118 {
4119     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4120
4121     TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
4122
4123     *ppvObject=NULL;
4124     if(IsEqualIID(riid, &IID_IUnknown) ||
4125             IsEqualIID(riid,&IID_ITypeInfo)||
4126             IsEqualIID(riid,&IID_ITypeInfo2))
4127         *ppvObject = This;
4128
4129     if(*ppvObject){
4130         ITypeInfo_AddRef(iface);
4131         TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
4132         return S_OK;
4133     }
4134     TRACE("-- Interface: E_NOINTERFACE\n");
4135     return E_NOINTERFACE;
4136 }
4137
4138 /* ITypeInfo::AddRef
4139  */
4140 static ULONG WINAPI ITypeInfo_fnAddRef( ITypeInfo2 *iface)
4141 {
4142     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4143     ULONG ref = InterlockedIncrement(&This->ref);
4144
4145     ITypeLib2_AddRef((ITypeLib2*)This->pTypeLib);
4146
4147     TRACE("(%p)->ref is %lu\n",This, ref);
4148     return ref;
4149 }
4150
4151 /* ITypeInfo::Release
4152  */
4153 static ULONG WINAPI ITypeInfo_fnRelease(ITypeInfo2 *iface)
4154 {
4155     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4156     ULONG ref = InterlockedDecrement(&This->ref);
4157
4158     TRACE("(%p)->(%lu)\n",This, ref);
4159
4160     if (ref)   {
4161       /* We don't release ITypeLib when ref=0 because
4162          it means that function is called by ITypeLib2_Release */
4163       ITypeLib2_Release((ITypeLib2*)This->pTypeLib);
4164     } else   {
4165       FIXME("destroy child objects\n");
4166
4167       TRACE("destroying ITypeInfo(%p)\n",This);
4168       if (This->Name)
4169       {
4170           SysFreeString(This->Name);
4171           This->Name = 0;
4172       }
4173
4174       if (This->DocString)
4175       {
4176           SysFreeString(This->DocString);
4177           This->DocString = 0;
4178       }
4179
4180       if (This->DllName)
4181       {
4182           SysFreeString(This->DllName);
4183           This->DllName = 0;
4184       }
4185
4186       if (This->next)
4187       {
4188         ITypeInfo_Release((ITypeInfo*)This->next);
4189       }
4190
4191       HeapFree(GetProcessHeap(),0,This);
4192       return 0;
4193     }
4194     return ref;
4195 }
4196
4197 /* ITypeInfo::GetTypeAttr
4198  *
4199  * Retrieves a TYPEATTR structure that contains the attributes of the type
4200  * description.
4201  *
4202  */
4203 static HRESULT WINAPI ITypeInfo_fnGetTypeAttr( ITypeInfo2 *iface,
4204         LPTYPEATTR  *ppTypeAttr)
4205 {
4206     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4207     TRACE("(%p)\n",This);
4208     *ppTypeAttr = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppTypeAttr));
4209     memcpy(*ppTypeAttr, &This->TypeAttr, sizeof(**ppTypeAttr));
4210
4211     if(This->TypeAttr.typekind == TKIND_ALIAS) /* need to deep copy typedesc */
4212         copy_typedesc(&(*ppTypeAttr)->tdescAlias, &This->TypeAttr.tdescAlias);
4213
4214     if((*ppTypeAttr)->typekind == TKIND_DISPATCH) {
4215         (*ppTypeAttr)->cFuncs = (*ppTypeAttr)->cbSizeVft / 4; /* This should include all the inherited
4216                                                                  funcs */
4217         (*ppTypeAttr)->cbSizeVft = 28; /* This is always the size of IDispatch's vtbl */
4218         (*ppTypeAttr)->wTypeFlags &= ~TYPEFLAG_FOLEAUTOMATION;
4219     }
4220     return S_OK;
4221 }
4222
4223 /* ITypeInfo::GetTypeComp
4224  *
4225  * Retrieves the ITypeComp interface for the type description, which enables a
4226  * client compiler to bind to the type description's members.
4227  *
4228  */
4229 static HRESULT WINAPI ITypeInfo_fnGetTypeComp( ITypeInfo2 *iface,
4230         ITypeComp  * *ppTComp)
4231 {
4232     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4233
4234     TRACE("(%p)->(%p) stub!\n", This, ppTComp);
4235
4236     *ppTComp = (ITypeComp *)&This->lpVtblTypeComp;
4237     ITypeComp_AddRef(*ppTComp);
4238     return S_OK;
4239 }
4240
4241 /* ITypeInfo::GetFuncDesc
4242  *
4243  * Retrieves the FUNCDESC structure that contains information about a
4244  * specified function.
4245  *
4246  */
4247 static HRESULT WINAPI ITypeInfo_fnGetFuncDesc( ITypeInfo2 *iface, UINT index,
4248         LPFUNCDESC  *ppFuncDesc)
4249 {
4250     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4251     int i;
4252     TLBFuncDesc * pFDesc;
4253     TRACE("(%p) index %d\n", This, index);
4254     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++, pFDesc=pFDesc->next)
4255         ;
4256     if(pFDesc){
4257         /* FIXME: must do a copy here */
4258         *ppFuncDesc=&pFDesc->funcdesc;
4259         return S_OK;
4260     }
4261     return E_INVALIDARG;
4262 }
4263
4264 /* ITypeInfo::GetVarDesc
4265  *
4266  * Retrieves a VARDESC structure that describes the specified variable.
4267  *
4268  */
4269 static HRESULT WINAPI ITypeInfo_fnGetVarDesc( ITypeInfo2 *iface, UINT index,
4270         LPVARDESC  *ppVarDesc)
4271 {
4272     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4273     int i;
4274     TLBVarDesc * pVDesc;
4275     TRACE("(%p) index %d\n", This, index);
4276     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next)
4277         ;
4278     if(pVDesc){
4279         /* FIXME: must do a copy here */
4280         *ppVarDesc=&pVDesc->vardesc;
4281         return S_OK;
4282     }
4283     return E_INVALIDARG;
4284 }
4285
4286 /* ITypeInfo_GetNames
4287  *
4288  * Retrieves the variable with the specified member ID (or the name of the
4289  * property or method and its parameters) that correspond to the specified
4290  * function ID.
4291  */
4292 static HRESULT WINAPI ITypeInfo_fnGetNames( ITypeInfo2 *iface, MEMBERID memid,
4293         BSTR  *rgBstrNames, UINT cMaxNames, UINT  *pcNames)
4294 {
4295     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4296     TLBFuncDesc * pFDesc;
4297     TLBVarDesc * pVDesc;
4298     int i;
4299     TRACE("(%p) memid=0x%08lx Maxname=%d\n", This, memid, cMaxNames);
4300     for(pFDesc=This->funclist; pFDesc && pFDesc->funcdesc.memid != memid; pFDesc=pFDesc->next);
4301     if(pFDesc)
4302     {
4303       /* function found, now return function and parameter names */
4304       for(i=0; i<cMaxNames && i <= pFDesc->funcdesc.cParams; i++)
4305       {
4306         if(!i)
4307           *rgBstrNames=SysAllocString(pFDesc->Name);
4308         else
4309           rgBstrNames[i]=SysAllocString(pFDesc->pParamDesc[i-1].Name);
4310       }
4311       *pcNames=i;
4312     }
4313     else
4314     {
4315       for(pVDesc=This->varlist; pVDesc && pVDesc->vardesc.memid != memid; pVDesc=pVDesc->next);
4316       if(pVDesc)
4317       {
4318         *rgBstrNames=SysAllocString(pVDesc->Name);
4319         *pcNames=1;
4320       }
4321       else
4322       {
4323         if(This->TypeAttr.cImplTypes &&
4324            (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
4325           /* recursive search */
4326           ITypeInfo *pTInfo;
4327           HRESULT result;
4328           result=ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef,
4329                                           &pTInfo);
4330           if(SUCCEEDED(result))
4331           {
4332             result=ITypeInfo_GetNames(pTInfo, memid, rgBstrNames, cMaxNames, pcNames);
4333             ITypeInfo_Release(pTInfo);
4334             return result;
4335           }
4336           WARN("Could not search inherited interface!\n");
4337         }
4338         else
4339         {
4340           WARN("no names found\n");
4341         }
4342         *pcNames=0;
4343         return TYPE_E_ELEMENTNOTFOUND;
4344       }
4345     }
4346     return S_OK;
4347 }
4348
4349
4350 /* ITypeInfo::GetRefTypeOfImplType
4351  *
4352  * If a type description describes a COM class, it retrieves the type
4353  * description of the implemented interface types. For an interface,
4354  * GetRefTypeOfImplType returns the type information for inherited interfaces,
4355  * if any exist.
4356  *
4357  */
4358 static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType(
4359         ITypeInfo2 *iface,
4360         UINT index,
4361         HREFTYPE  *pRefType)
4362 {
4363     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4364     int i;
4365     HRESULT hr = S_OK;
4366     TLBImplType *pImpl = This->impltypelist;
4367
4368     TRACE("(%p) index %d\n", This, index);
4369     if (TRACE_ON(ole)) dump_TypeInfo(This);
4370
4371     if(index==(UINT)-1)
4372     {
4373       /* only valid on dual interfaces;
4374          retrieve the associated TKIND_INTERFACE handle for the current TKIND_DISPATCH
4375       */
4376       if( This->TypeAttr.typekind != TKIND_DISPATCH) return E_INVALIDARG;
4377
4378       if (This->TypeAttr.wTypeFlags & TYPEFLAG_FDISPATCHABLE &&
4379           This->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL )
4380       {
4381         *pRefType = -1;
4382       }
4383       else
4384       {
4385         hr = TYPE_E_ELEMENTNOTFOUND;
4386       }
4387     }
4388     else
4389     {
4390       /* get element n from linked list */
4391       for(i=0; pImpl && i<index; i++)
4392       {
4393         pImpl = pImpl->next;
4394       }
4395
4396       if (pImpl)
4397         *pRefType = pImpl->hRef;
4398       else
4399         hr = TYPE_E_ELEMENTNOTFOUND;
4400     }
4401
4402     if(TRACE_ON(ole))
4403     {
4404         if(SUCCEEDED(hr))
4405             TRACE("SUCCESS -- hRef = 0x%08lx\n", *pRefType );
4406         else
4407             TRACE("FAILURE -- hresult = 0x%08lx\n", hr);
4408     }
4409
4410     return hr;
4411 }
4412
4413 /* ITypeInfo::GetImplTypeFlags
4414  *
4415  * Retrieves the IMPLTYPEFLAGS enumeration for one implemented interface
4416  * or base interface in a type description.
4417  */
4418 static HRESULT WINAPI ITypeInfo_fnGetImplTypeFlags( ITypeInfo2 *iface,
4419         UINT index, INT  *pImplTypeFlags)
4420 {
4421     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4422     int i;
4423     TLBImplType *pImpl;
4424
4425     TRACE("(%p) index %d\n", This, index);
4426     for(i=0, pImpl=This->impltypelist; i<index && pImpl;
4427         i++, pImpl=pImpl->next)
4428         ;
4429     if(i==index && pImpl){
4430         *pImplTypeFlags=pImpl->implflags;
4431         return S_OK;
4432     }
4433     *pImplTypeFlags=0;
4434     return TYPE_E_ELEMENTNOTFOUND;
4435 }
4436
4437 /* GetIDsOfNames
4438  * Maps between member names and member IDs, and parameter names and
4439  * parameter IDs.
4440  */
4441 static HRESULT WINAPI ITypeInfo_fnGetIDsOfNames( ITypeInfo2 *iface,
4442         LPOLESTR  *rgszNames, UINT cNames, MEMBERID  *pMemId)
4443 {
4444     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4445     TLBFuncDesc * pFDesc;
4446     TLBVarDesc * pVDesc;
4447     HRESULT ret=S_OK;
4448
4449     TRACE("(%p) Name %s cNames %d\n", This, debugstr_w(*rgszNames),
4450             cNames);
4451     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next) {
4452         int i, j;
4453         if(!lstrcmpiW(*rgszNames, pFDesc->Name)) {
4454             if(cNames) *pMemId=pFDesc->funcdesc.memid;
4455             for(i=1; i < cNames; i++){
4456                 for(j=0; j<pFDesc->funcdesc.cParams; j++)
4457                     if(!lstrcmpiW(rgszNames[i],pFDesc->pParamDesc[j].Name))
4458                             break;
4459                 if( j<pFDesc->funcdesc.cParams)
4460                     pMemId[i]=j;
4461                 else
4462                    ret=DISP_E_UNKNOWNNAME;
4463             };
4464             return ret;
4465         }
4466     }
4467     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) {
4468         if(!lstrcmpiW(*rgszNames, pVDesc->Name)) {
4469             if(cNames) *pMemId=pVDesc->vardesc.memid;
4470             return ret;
4471         }
4472     }
4473     /* not found, see if this is and interface with an inheritance */
4474     if(This->TypeAttr.cImplTypes &&
4475        (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
4476         /* recursive search */
4477         ITypeInfo *pTInfo;
4478         ret=ITypeInfo_GetRefTypeInfo(iface,
4479                 This->impltypelist->hRef, &pTInfo);
4480         if(SUCCEEDED(ret)){
4481             ret=ITypeInfo_GetIDsOfNames(pTInfo, rgszNames, cNames, pMemId );
4482             ITypeInfo_Release(pTInfo);
4483             return ret;
4484         }
4485         WARN("Could not search inherited interface!\n");
4486     } else
4487         WARN("no names found\n");
4488     return DISP_E_UNKNOWNNAME;
4489 }
4490
4491 /* ITypeInfo::Invoke
4492  *
4493  * Invokes a method, or accesses a property of an object, that implements the
4494  * interface described by the type description.
4495  */
4496 DWORD
4497 _invoke(FARPROC func,CALLCONV callconv, int nrargs, DWORD *args) {
4498     DWORD res;
4499
4500     if (TRACE_ON(ole)) {
4501         int i;
4502         TRACE("Calling %p(",func);
4503         for (i=0;i<nrargs;i++) TRACE("%08lx,",args[i]);
4504         TRACE(")\n");
4505     }
4506
4507     switch (callconv) {
4508     case CC_STDCALL:
4509
4510         switch (nrargs) {
4511         case 0:
4512                 res = func();
4513                 break;
4514         case 1:
4515                 res = func(args[0]);
4516                 break;
4517         case 2:
4518                 res = func(args[0],args[1]);
4519                 break;
4520         case 3:
4521                 res = func(args[0],args[1],args[2]);
4522                 break;
4523         case 4:
4524                 res = func(args[0],args[1],args[2],args[3]);
4525                 break;
4526         case 5:
4527                 res = func(args[0],args[1],args[2],args[3],args[4]);
4528                 break;
4529         case 6:
4530                 res = func(args[0],args[1],args[2],args[3],args[4],args[5]);
4531                 break;
4532         case 7:
4533                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
4534                 break;
4535         case 8:
4536                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]);
4537                 break;
4538         case 9:
4539                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]);
4540                 break;
4541         case 10:
4542                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9]);
4543                 break;
4544         case 11:
4545                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10]);
4546                 break;
4547         case 12:
4548                 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]);
4549                 break;
4550         case 13:
4551                 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]);
4552                 break;
4553         case 14:
4554                 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]);
4555                 break;
4556         default:
4557                 FIXME("unsupported number of arguments %d in stdcall\n",nrargs);
4558                 res = -1;
4559                 break;
4560         }
4561         break;
4562     default:
4563         FIXME("unsupported calling convention %d\n",callconv);
4564         res = -1;
4565         break;
4566     }
4567     TRACE("returns %08lx\n",res);
4568     return res;
4569 }
4570
4571 extern int _argsize(DWORD vt);
4572
4573 /****************************************************************************
4574  * Helper functions for Dispcall / Invoke, which copies one variant
4575  * with target type onto the argument stack.
4576  */
4577 static HRESULT
4578 _copy_arg(      ITypeInfo2 *tinfo, TYPEDESC *tdesc,
4579                 DWORD *argpos, VARIANT *arg, VARTYPE vt
4580 ) {
4581     UINT arglen = _argsize(vt)*sizeof(DWORD);
4582     VARIANT     va;
4583
4584     if ((vt==VT_PTR) && tdesc && (tdesc->u.lptdesc->vt == VT_VARIANT)) {
4585         memcpy(argpos,&arg,sizeof(void*));
4586         return S_OK;
4587     }
4588
4589     if (V_VT(arg) == vt) {
4590         memcpy(argpos, &V_I4(arg), arglen);
4591         return S_OK;
4592     }
4593
4594     if (V_ISARRAY(arg) && (vt == VT_SAFEARRAY)) {
4595         memcpy(argpos, &V_ARRAY(arg), sizeof(SAFEARRAY*));
4596         return S_OK;
4597     }
4598
4599     if (vt == VT_VARIANT) {
4600         memcpy(argpos, arg, arglen);
4601         return S_OK;
4602     }
4603     /* Deref BYREF vars if there is need */
4604     if(V_ISBYREF(arg) && ((V_VT(arg) & ~VT_BYREF)==vt)) {
4605         memcpy(argpos,(void*)V_I4(arg), arglen);
4606         return S_OK;
4607     }
4608     if (vt==VT_UNKNOWN && V_VT(arg)==VT_DISPATCH) {
4609         /* in this context, if the type lib specifies IUnknown*, giving an
4610            IDispatch* is correct; so, don't invoke VariantChangeType */
4611         memcpy(argpos,&V_I4(arg), arglen);
4612         return S_OK;
4613     }
4614     if ((vt == VT_PTR) && tdesc)
4615         return _copy_arg(tinfo, tdesc->u.lptdesc, argpos, arg, tdesc->u.lptdesc->vt);
4616
4617     if ((vt == VT_USERDEFINED) && tdesc && tinfo) {
4618         ITypeInfo       *tinfo2 = NULL;
4619         TYPEATTR        *tattr = NULL;
4620         HRESULT         hres;
4621
4622         hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
4623         if (hres) {
4624             FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED, "
4625                   "while coercing from vt 0x%x. Copying 4 byte.\n",
4626                   tdesc->u.hreftype,V_VT(arg));
4627             memcpy(argpos, &V_I4(arg), 4);
4628             return S_OK;
4629         }
4630         hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr);
4631         if( hres )
4632         {
4633             ERR("GetTypeAttr failed\n");
4634             ITypeInfo_Release(tinfo2);
4635             return hres;
4636         }
4637         switch (tattr->typekind) {
4638         case TKIND_ENUM:
4639           switch ( V_VT( arg ) ) {
4640           case VT_I2:
4641              *argpos = V_I2(arg);
4642              hres = S_OK;
4643              break;
4644           case VT_I4:
4645              memcpy(argpos, &V_I4(arg), 4);
4646              hres = S_OK;
4647              break;
4648           case VT_BYREF|VT_I4:
4649              memcpy(argpos, V_I4REF(arg), 4);
4650              hres = S_OK;
4651              break;
4652           default:
4653              FIXME("vt 0x%x -> TKIND_ENUM unhandled.\n",V_VT(arg));
4654              hres = E_FAIL;
4655              break;
4656           }
4657           break;
4658
4659         case TKIND_ALIAS:
4660             tdesc = &(tattr->tdescAlias);
4661             hres = _copy_arg((ITypeInfo2*)tinfo2, tdesc, argpos, arg, tdesc->vt);
4662             break;
4663
4664         case TKIND_INTERFACE:
4665             if (V_VT(arg) == VT_DISPATCH) {
4666                 IDispatch *disp;
4667                 if (IsEqualIID(&IID_IDispatch,&(tattr->guid))) {
4668                     memcpy(argpos, &V_DISPATCH(arg), 4);
4669                     hres = S_OK;
4670                     break;
4671                 }
4672                 hres=IUnknown_QueryInterface(V_DISPATCH(arg),
4673                                              &IID_IDispatch,(LPVOID*)&disp);
4674                 if (SUCCEEDED(hres)) {
4675                     memcpy(argpos,&disp,4);
4676                     IUnknown_Release(V_DISPATCH(arg));
4677                     hres = S_OK;
4678                     break;
4679                 }
4680                 FIXME("Failed to query IDispatch interface from %s while "
4681                      "converting to VT_DISPATCH!\n",debugstr_guid(&(tattr->guid)));
4682                 hres = E_FAIL;
4683                 break;
4684             }
4685             if (V_VT(arg) == VT_UNKNOWN) {
4686                 memcpy(argpos, &V_UNKNOWN(arg), 4);
4687                 hres = S_OK;
4688                 break;
4689             }
4690             FIXME("vt 0x%x -> TKIND_INTERFACE(%s) unhandled\n",
4691                   V_VT(arg),debugstr_guid(&(tattr->guid)));
4692             hres = E_FAIL;
4693             break;
4694
4695         case TKIND_DISPATCH:
4696             if (V_VT(arg) == VT_DISPATCH) {
4697                 memcpy(argpos, &V_DISPATCH(arg), 4);
4698                 hres = S_OK;
4699             }
4700             else {
4701                 hres = E_FAIL;
4702                 FIXME("TKIND_DISPATCH unhandled for target vt 0x%x.\n",V_VT(arg));
4703             }
4704             break;
4705         case TKIND_RECORD:
4706             FIXME("TKIND_RECORD unhandled.\n");
4707             hres = E_FAIL;
4708             break;
4709         default:
4710             FIXME("TKIND %d unhandled.\n",tattr->typekind);
4711             hres = E_FAIL;
4712             break;
4713         }
4714         ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
4715         ITypeInfo_Release(tinfo2);
4716         return hres;
4717     }
4718
4719     VariantInit(&va);
4720     if (VariantChangeType(&va,arg,0,vt)==S_OK) {
4721         memcpy(argpos,&V_I4(&va), arglen);
4722         FIXME("Should not use VariantChangeType here."
4723               " (conversion from 0x%x -> 0x%x) %08lx\n",
4724                 V_VT(arg), vt, *argpos
4725         );
4726         return S_OK;
4727     }
4728     ERR("Set arg to disparg type 0x%x vs 0x%x\n",V_VT(arg),vt);
4729     return E_FAIL;
4730 }
4731
4732 static HRESULT userdefined_to_variantvt(ITypeInfo *tinfo, TYPEDESC *tdesc, VARTYPE *vt)
4733 {
4734     HRESULT hr = S_OK;
4735     ITypeInfo *tinfo2 = NULL;
4736     TYPEATTR *tattr = NULL;
4737
4738     hr = ITypeInfo_GetRefTypeInfo(tinfo, tdesc->u.hreftype, &tinfo2);
4739     if (hr)
4740     {
4741         ERR("Could not get typeinfo of hreftype %lx for VT_USERDEFINED, "
4742             "hr = 0x%08lx\n",
4743               tdesc->u.hreftype, hr);
4744         return hr;
4745     }
4746     hr = ITypeInfo_GetTypeAttr(tinfo2, &tattr);
4747     if (hr)
4748     {
4749         ERR("ITypeInfo_GetTypeAttr failed, hr = 0x%08lx\n", hr);
4750         ITypeInfo_Release(tinfo2);
4751         return hr;
4752     }
4753
4754     switch (tattr->typekind)
4755     {
4756     case TKIND_ENUM:
4757         *vt |= VT_INT;
4758         break;
4759
4760     case TKIND_ALIAS:
4761         tdesc = &tattr->tdescAlias;
4762         hr = typedescvt_to_variantvt(tinfo2, &tattr->tdescAlias, vt);
4763         break;
4764
4765     case TKIND_INTERFACE:
4766         if (IsEqualIID(&IID_IDispatch, &tattr->guid))
4767            *vt |= VT_DISPATCH;
4768         else
4769            *vt |= VT_UNKNOWN;
4770         break;
4771
4772     case TKIND_DISPATCH:
4773         *vt |= VT_DISPATCH;
4774         break;
4775
4776     case TKIND_RECORD:
4777         FIXME("TKIND_RECORD unhandled.\n");
4778         hr = E_NOTIMPL;
4779         break;
4780
4781     case TKIND_UNION:
4782         FIXME("TKIND_RECORD unhandled.\n");
4783         hr = E_NOTIMPL;
4784         break;
4785
4786     default:
4787         FIXME("TKIND %d unhandled.\n",tattr->typekind);
4788         hr = E_NOTIMPL;
4789         break;
4790     }
4791     ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
4792     ITypeInfo_Release(tinfo2);
4793     return hr;
4794 }
4795
4796 static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, TYPEDESC *tdesc, VARTYPE *vt)
4797 {
4798     HRESULT hr = S_OK;
4799
4800     /* enforce only one level of pointer indirection */
4801     if (!(*vt & VT_BYREF) && (tdesc->vt == VT_PTR))
4802     {
4803         tdesc = tdesc->u.lptdesc;
4804
4805         /* munch VT_PTR -> VT_USERDEFINED(interface) into VT_UNKNOWN or
4806          * VT_DISPATCH and VT_PTR -> VT_PTR -> VT_USERDEFINED(interface) into 
4807          * VT_BYREF|VT_DISPATCH or VT_BYREF|VT_UNKNOWN */
4808         if ((tdesc->vt == VT_USERDEFINED) ||
4809             ((tdesc->vt == VT_PTR) && (tdesc->u.lptdesc->vt == VT_USERDEFINED)))
4810         {
4811             VARTYPE vt_userdefined = 0;
4812             TYPEDESC *tdesc_userdefined = tdesc;
4813             if (tdesc->vt == VT_PTR)
4814             {
4815                 vt_userdefined = VT_BYREF;
4816                 tdesc_userdefined = tdesc->u.lptdesc;
4817             }
4818             hr = userdefined_to_variantvt(tinfo, tdesc_userdefined, &vt_userdefined);
4819             if ((hr == S_OK) && 
4820                 (((vt_userdefined & VT_TYPEMASK) == VT_UNKNOWN) ||
4821                  ((vt_userdefined & VT_TYPEMASK) == VT_DISPATCH)))
4822             {
4823                 *vt |= vt_userdefined;
4824                 return S_OK;
4825             }
4826         }
4827         *vt = VT_BYREF;
4828     }
4829
4830     switch (tdesc->vt)
4831     {
4832     case VT_HRESULT:
4833         *vt |= VT_ERROR;
4834         break;
4835     case VT_USERDEFINED:
4836         hr = userdefined_to_variantvt(tinfo, tdesc, vt);
4837         break;
4838     case VT_PTR:
4839         ERR("cannot convert VT_PTR into variant VT\n");
4840         hr = E_FAIL;
4841         break;
4842     default:
4843         *vt |= tdesc->vt;
4844         break;
4845     }
4846     return hr;
4847 }
4848
4849 /***********************************************************************
4850  *              DispCallFunc (OLEAUT32.@)
4851  */
4852 HRESULT WINAPI
4853 DispCallFunc(
4854     void* pvInstance, ULONG oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals,
4855     VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult
4856 ) {
4857     int i, argsize, argspos;
4858     DWORD *args;
4859     HRESULT hres;
4860
4861     TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
4862         pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg, pvargResult, V_VT(pvargResult)
4863     );
4864     /* DispCallFunc is only used to invoke methods belonging to an IDispatch-derived COM interface.
4865     So we need to add a first parameter to the list of arguments, to supply the interface pointer */
4866     argsize = 1;
4867     for (i=0;i<cActuals;i++) {
4868         TRACE("arg %d: type %d, size %d\n",i,prgvt[i],_argsize(prgvt[i]));
4869         dump_Variant(prgpvarg[i]);
4870         argsize += _argsize(prgvt[i]);
4871     }
4872     args = HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*argsize);
4873     args[0] = (DWORD)pvInstance;      /* this is the fake IDispatch interface pointer */
4874     argspos = 1;
4875     for (i=0;i<cActuals;i++) {
4876         VARIANT *arg = prgpvarg[i];
4877         TRACE("Storing arg %d (%d as %d)\n",i,V_VT(arg),prgvt[i]);
4878         _copy_arg(NULL, NULL, &args[argspos], arg, prgvt[i]);
4879         argspos += _argsize(prgvt[i]);
4880     }
4881
4882     if(pvargResult!=NULL && V_VT(pvargResult)==VT_EMPTY)
4883     {
4884         _invoke((*(FARPROC**)pvInstance)[oVft/4],cc,argsize,args);
4885         hres=S_OK;
4886     }
4887     else
4888     {
4889         FIXME("Do not know how to handle pvargResult %p. Expect crash ...\n",pvargResult);
4890         hres = _invoke((*(FARPROC**)pvInstance)[oVft/4],cc,argsize,args);
4891         FIXME("Method returned %lx\n",hres);
4892     }
4893     HeapFree(GetProcessHeap(),0,args);
4894     return hres;
4895 }
4896
4897 static HRESULT WINAPI ITypeInfo_fnInvoke(
4898     ITypeInfo2 *iface,
4899     VOID  *pIUnk,
4900     MEMBERID memid,
4901     UINT16 dwFlags,
4902     DISPPARAMS  *pDispParams,
4903     VARIANT  *pVarResult,
4904     EXCEPINFO  *pExcepInfo,
4905     UINT  *pArgErr)
4906 {
4907     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4908     int i;
4909     unsigned int func_index, var_index;
4910     TYPEKIND type_kind;
4911     HRESULT hres;
4912
4913     TRACE("(%p)(%p,id=%ld,flags=0x%08x,%p,%p,%p,%p) partial stub!\n",
4914       This,pIUnk,memid,dwFlags,pDispParams,pVarResult,pExcepInfo,pArgErr
4915     );
4916     dump_DispParms(pDispParams);
4917
4918     hres = ITypeInfo2_GetFuncIndexOfMemId(iface, memid, dwFlags, &func_index);
4919     if (SUCCEEDED(hres)) {
4920         FUNCDESC *func_desc;
4921
4922         hres = ITypeInfo2_GetFuncDesc(iface, func_index, &func_desc);
4923         if(FAILED(hres)) return hres;
4924         if (TRACE_ON(ole))
4925         {
4926             TRACE("invoking:\n");
4927             dump_FUNCDESC(func_desc);
4928         }
4929         
4930         switch (func_desc->funckind) {
4931         case FUNC_PUREVIRTUAL:
4932         case FUNC_VIRTUAL: {
4933             DWORD res;
4934             int   numargs, numargs2, argspos, args2pos;
4935             DWORD *args , *args2;
4936             VARIANT *rgvarg = HeapAlloc(GetProcessHeap(), 0, sizeof(VARIANT) * func_desc->cParams);
4937             memcpy(rgvarg,pDispParams->rgvarg,sizeof(VARIANT)*pDispParams->cArgs);
4938
4939             hres = S_OK;
4940             numargs = 1; /* sizeof(thisptr) */
4941             numargs2 = 0;
4942             for (i = 0; i < func_desc->cParams; i++) {
4943                 TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc;
4944
4945                 numargs += _argsize(tdesc->vt);
4946                 if (i>=pDispParams->cArgs) { /* arguments to return */
4947                     if (tdesc->vt == VT_PTR) {
4948                         numargs2        += _argsize(tdesc->u.lptdesc->vt);
4949                     } else {
4950                         FIXME("The variant type here should have been VT_PTR, not vt %d\n", tdesc->vt);
4951                         numargs2        += _argsize(tdesc->vt);
4952                     }
4953                 }
4954             }
4955
4956             args = HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*numargs);
4957             args2 = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD)*numargs2);
4958
4959             args[0] = (DWORD)pIUnk;
4960             argspos = 1; args2pos = 0;
4961             for (i = 0; i < func_desc->cParams; i++) {
4962                 ELEMDESC *elemdesc = &(func_desc->lprgelemdescParam[i]);
4963                 TYPEDESC *tdesc = &(elemdesc->tdesc);
4964                 USHORT paramFlags = elemdesc->u.paramdesc.wParamFlags;
4965                 int arglen = _argsize(tdesc->vt);
4966
4967                 if (i<pDispParams->cArgs) {
4968                     VARIANT *arg = &rgvarg[pDispParams->cArgs-i-1];
4969
4970                     if (paramFlags & PARAMFLAG_FOPT) {
4971                         if(i < func_desc->cParams - func_desc->cParamsOpt)
4972                             ERR("Parameter has PARAMFLAG_FOPT flag but is not one of last cParamOpt parameters\n");
4973                         if(V_VT(arg) == VT_EMPTY
4974                           || ((V_ISBYREF(arg)) && !V_BYREF(arg))) {
4975                                /* FIXME: Documentation says that we do this when parameter is left unspecified.
4976                                          How to determine it? */
4977
4978                             if(paramFlags & PARAMFLAG_FHASDEFAULT)
4979                                 FIXME("PARAMFLAG_FHASDEFAULT flag not supported\n");
4980                             V_VT(arg) = VT_ERROR;
4981                             V_ERROR(arg) = DISP_E_PARAMNOTFOUND;
4982                             arglen = _argsize(VT_ERROR);
4983                         }
4984                     }
4985                     hres = _copy_arg(iface, tdesc, &args[argspos], arg, tdesc->vt);
4986                     if (FAILED(hres)) goto func_fail;
4987                     argspos += arglen;
4988                 } else if (paramFlags & PARAMFLAG_FOPT) {
4989                     VARIANT *arg = &rgvarg[i];
4990
4991                     if (i < func_desc->cParams - func_desc->cParamsOpt)
4992                         ERR("Parameter has PARAMFLAG_FOPT flag but is not one of last cParamOpt parameters\n");
4993                     if (paramFlags & PARAMFLAG_FHASDEFAULT)
4994                         FIXME("PARAMFLAG_FHASDEFAULT flag not supported\n");
4995
4996                     V_VT(arg) = VT_ERROR;
4997                     V_ERROR(arg) = DISP_E_PARAMNOTFOUND;
4998                     arglen = _argsize(VT_ERROR);
4999                     hres = _copy_arg(iface, tdesc, &args[argspos], arg, tdesc->vt);
5000                     if (FAILED(hres)) goto func_fail;
5001                     argspos += arglen;
5002                 } else {
5003                     if (tdesc->vt == VT_PTR)
5004                         arglen = _argsize(tdesc->u.lptdesc->vt);
5005                     else
5006                         FIXME("set %d to pointer for get (type is %d)\n",i,tdesc->vt);
5007
5008                     /* Supply pointers for the rest, so propertyget works*/
5009                     args[argspos] = (DWORD)&args2[args2pos];
5010
5011                     /* If pointer to variant, pass reference it. */
5012                     if ((tdesc->vt == VT_PTR) &&
5013                         (tdesc->u.lptdesc->vt == VT_VARIANT) &&
5014                         pVarResult
5015                     )
5016                         args[argspos]= (DWORD)pVarResult;
5017                     argspos     += 1;
5018                     args2pos    += arglen;
5019                 }
5020             }
5021             if (func_desc->cParamsOpt < 0)
5022                 FIXME("Does not support optional parameters (%d)\n", func_desc->cParamsOpt);
5023
5024             res = _invoke((*(FARPROC**)pIUnk)[func_desc->oVft/4],
5025                     func_desc->callconv,
5026                     numargs,
5027                     args
5028             );
5029
5030             if (pVarResult) {
5031                 for (i = 0; i < func_desc->cParams; i++) {
5032                     USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
5033                     if (wParamFlags & PARAMFLAG_FRETVAL) {
5034                         ELEMDESC *elemdesc = &func_desc->lprgelemdescParam[i];
5035                         TYPEDESC *tdesc = &elemdesc->tdesc;
5036                         VARIANTARG varresult;
5037                         V_VT(&varresult) = 0;
5038                         hres = typedescvt_to_variantvt((ITypeInfo *)iface, tdesc, &V_VT(&varresult));
5039                         if (hres)
5040                             break;
5041                         /* FIXME: this is really messy - we should keep the
5042                          * args in VARIANTARGs rather than a DWORD array */
5043                         memcpy(&V_UI4(&varresult), &args[i+1], sizeof(DWORD));
5044                         if (TRACE_ON(ole))
5045                         {
5046                             TRACE("varresult: ");
5047                             dump_Variant(&varresult);
5048                         }
5049                         hres = VariantCopyInd(pVarResult, &varresult);
5050                         /* free data stored in varresult. Note that
5051                          * VariantClear doesn't do what we want because we are
5052                          * working with byref types. */
5053                         /* FIXME: clear safearrays, bstrs, records and
5054                          * variants here too */
5055                         if ((V_VT(&varresult) == (VT_UNKNOWN | VT_BYREF)) ||
5056                             (V_VT(&varresult) == (VT_DISPATCH | VT_BYREF)))
5057                             IUnknown_Release(*V_UNKNOWNREF(&varresult));
5058                         break;
5059                     }
5060                 }
5061             }
5062
5063             if ((func_desc->elemdescFunc.tdesc.vt == VT_HRESULT) && FAILED(res)) {
5064                 WARN("invoked function failed with error 0x%08lx\n", res);
5065                 hres = DISP_E_EXCEPTION;
5066                 if (pExcepInfo) pExcepInfo->scode = res;
5067             }
5068 func_fail:
5069             HeapFree(GetProcessHeap(), 0, rgvarg);
5070             HeapFree(GetProcessHeap(),0,args2);
5071             HeapFree(GetProcessHeap(),0,args);
5072             break;
5073         }
5074         case FUNC_DISPATCH:  {
5075            IDispatch *disp;
5076
5077            hres = IUnknown_QueryInterface((LPUNKNOWN)pIUnk,&IID_IDispatch,(LPVOID*)&disp);
5078            if (SUCCEEDED(hres)) {
5079                FIXME("Calling Invoke in IDispatch iface. untested!\n");
5080                hres = IDispatch_Invoke(
5081                                      disp,memid,&IID_NULL,LOCALE_USER_DEFAULT,dwFlags,pDispParams,
5082                                      pVarResult,pExcepInfo,pArgErr
5083                                      );
5084                if (FAILED(hres))
5085                    FIXME("IDispatch::Invoke failed with %08lx. (Could be not a real error?)\n", hres);
5086                IDispatch_Release(disp);
5087            } else
5088                FIXME("FUNC_DISPATCH used on object without IDispatch iface?\n");
5089            break;
5090         }
5091         default:
5092             FIXME("Unknown function invocation type %d\n", func_desc->funckind);
5093             hres = E_FAIL;
5094             break;
5095         }
5096
5097         ITypeInfo2_ReleaseFuncDesc(iface, func_desc);
5098         return hres;
5099
5100     } else if(SUCCEEDED(hres = ITypeInfo2_GetVarIndexOfMemId(iface, memid, &var_index))) {
5101         VARDESC *var_desc;
5102
5103         hres = ITypeInfo2_GetVarDesc(iface, var_index, &var_desc);
5104         if(FAILED(hres)) return hres;
5105         
5106         FIXME("varseek: Found memid, but variable-based invoking not supported\n");
5107         dump_VARDESC(var_desc);
5108         ITypeInfo2_ReleaseVarDesc(iface, var_desc);
5109         return E_NOTIMPL;
5110     }
5111
5112     /* not found, look for it in inherited interfaces */
5113     ITypeInfo2_GetTypeKind(iface, &type_kind);
5114     if(type_kind == TKIND_INTERFACE || type_kind == TKIND_DISPATCH) {
5115         HREFTYPE ref_type;
5116         if(SUCCEEDED(ITypeInfo2_GetRefTypeOfImplType(iface, 0, &ref_type))) {
5117             /* recursive search */
5118             ITypeInfo *pTInfo;
5119             hres = ITypeInfo_GetRefTypeInfo(iface, ref_type, &pTInfo);
5120             if(SUCCEEDED(hres)){
5121                 hres = ITypeInfo_Invoke(pTInfo,pIUnk,memid,dwFlags,pDispParams,pVarResult,pExcepInfo,pArgErr);
5122                 ITypeInfo_Release(pTInfo);
5123                 return hres;
5124             }
5125             WARN("Could not search inherited interface!\n");
5126         }
5127     }
5128     ERR("did not find member id %08lx, flags %d!\n", memid, dwFlags);
5129     return DISP_E_MEMBERNOTFOUND;
5130 }
5131
5132 /* ITypeInfo::GetDocumentation
5133  *
5134  * Retrieves the documentation string, the complete Help file name and path,
5135  * and the context ID for the Help topic for a specified type description.
5136  *
5137  * (Can be tested by the Visual Basic Editor in Word for instance.)
5138  */
5139 static HRESULT WINAPI ITypeInfo_fnGetDocumentation( ITypeInfo2 *iface,
5140         MEMBERID memid, BSTR  *pBstrName, BSTR  *pBstrDocString,
5141         DWORD  *pdwHelpContext, BSTR  *pBstrHelpFile)
5142 {
5143     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5144     TLBFuncDesc * pFDesc;
5145     TLBVarDesc * pVDesc;
5146     TRACE("(%p) memid %ld Name(%p) DocString(%p)"
5147           " HelpContext(%p) HelpFile(%p)\n",
5148         This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
5149     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
5150         if(pBstrName)
5151             *pBstrName=SysAllocString(This->Name);
5152         if(pBstrDocString)
5153             *pBstrDocString=SysAllocString(This->DocString);
5154         if(pdwHelpContext)
5155             *pdwHelpContext=This->dwHelpContext;
5156         if(pBstrHelpFile)
5157             *pBstrHelpFile=SysAllocString(This->DocString);/* FIXME */
5158         return S_OK;
5159     }else {/* for a member */
5160     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
5161         if(pFDesc->funcdesc.memid==memid){
5162           if(pBstrName)
5163             *pBstrName = SysAllocString(pFDesc->Name);
5164           if(pBstrDocString)
5165             *pBstrDocString=SysAllocString(pFDesc->HelpString);
5166           if(pdwHelpContext)
5167             *pdwHelpContext=pFDesc->helpcontext;
5168           return S_OK;
5169         }
5170     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
5171         if(pVDesc->vardesc.memid==memid){
5172             if(pBstrName)
5173               *pBstrName = SysAllocString(pVDesc->Name);
5174             if(pBstrDocString)
5175               *pBstrDocString=SysAllocString(pVDesc->HelpString);
5176             if(pdwHelpContext)
5177               *pdwHelpContext=pVDesc->HelpContext;
5178             return S_OK;
5179         }
5180     }
5181     WARN("member %ld not found\n", memid);
5182     return TYPE_E_ELEMENTNOTFOUND;
5183 }
5184
5185 /*  ITypeInfo::GetDllEntry
5186  *
5187  * Retrieves a description or specification of an entry point for a function
5188  * in a DLL.
5189  */
5190 static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid,
5191         INVOKEKIND invKind, BSTR  *pBstrDllName, BSTR  *pBstrName,
5192         WORD  *pwOrdinal)
5193 {
5194     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5195     TLBFuncDesc *pFDesc;
5196
5197     TRACE("(%p)->(memid %lx, %d, %p, %p, %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
5198
5199     if (pBstrDllName) *pBstrDllName = NULL;
5200     if (pBstrName) *pBstrName = NULL;
5201     if (pwOrdinal) *pwOrdinal = 0;
5202
5203     if (This->TypeAttr.typekind != TKIND_MODULE)
5204         return TYPE_E_BADMODULEKIND;
5205
5206     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
5207         if(pFDesc->funcdesc.memid==memid){
5208             dump_TypeInfo(This);
5209             dump_TLBFuncDescOne(pFDesc);
5210
5211             if (pBstrDllName)
5212                 *pBstrDllName = SysAllocString(This->DllName);
5213
5214             if (HIWORD(pFDesc->Entry) && (pFDesc->Entry != (void*)-1)) {
5215                 if (pBstrName)
5216                     *pBstrName = SysAllocString(pFDesc->Entry);
5217                 if (pwOrdinal)
5218                     *pwOrdinal = -1;
5219                 return S_OK;
5220             }
5221             if (pBstrName)
5222                 *pBstrName = NULL;
5223             if (pwOrdinal)
5224                 *pwOrdinal = (DWORD)pFDesc->Entry;
5225             return S_OK;
5226         }
5227     return TYPE_E_ELEMENTNOTFOUND;
5228 }
5229
5230 /* ITypeInfo::GetRefTypeInfo
5231  *
5232  * If a type description references other type descriptions, it retrieves
5233  * the referenced type descriptions.
5234  */
5235 static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo(
5236         ITypeInfo2 *iface,
5237         HREFTYPE hRefType,
5238         ITypeInfo  **ppTInfo)
5239 {
5240     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5241     HRESULT result = E_FAIL;
5242
5243     if (hRefType == -1 &&
5244         (((ITypeInfoImpl*) This)->TypeAttr.typekind   == TKIND_DISPATCH) &&
5245         (((ITypeInfoImpl*) This)->TypeAttr.wTypeFlags &  TYPEFLAG_FDUAL))
5246     {
5247           /* when we meet a DUAL dispinterface, we must create the interface
5248           * version of it.
5249           */
5250           ITypeInfoImpl* pTypeInfoImpl = (ITypeInfoImpl*) ITypeInfo_Constructor();
5251
5252
5253           /* the interface version contains the same information as the dispinterface
5254            * copy the contents of the structs.
5255            */
5256           *pTypeInfoImpl = *This;
5257           pTypeInfoImpl->ref = 1;
5258
5259           /* change the type to interface */
5260           pTypeInfoImpl->TypeAttr.typekind = TKIND_INTERFACE;
5261
5262           *ppTInfo = (ITypeInfo*) pTypeInfoImpl;
5263
5264           ITypeInfo_AddRef((ITypeInfo*) pTypeInfoImpl);
5265
5266           result = S_OK;
5267
5268     } else {
5269         TLBRefType *pRefType;
5270         for(pRefType = This->reflist; pRefType; pRefType = pRefType->next) {
5271             if(pRefType->reference == hRefType)
5272                 break;
5273         }
5274         if(!pRefType)
5275           FIXME("Can't find pRefType for ref %lx\n", hRefType);
5276         if(pRefType && hRefType != -1) {
5277             ITypeLib *pTLib = NULL;
5278
5279             if(pRefType->pImpTLInfo == TLB_REF_INTERNAL) {
5280                 UINT Index;
5281                 result = ITypeInfo_GetContainingTypeLib(iface, &pTLib, &Index);
5282             } else {
5283                 if(pRefType->pImpTLInfo->pImpTypeLib) {
5284                     TRACE("typeinfo in imported typelib that is already loaded\n");
5285                     pTLib = (ITypeLib*)pRefType->pImpTLInfo->pImpTypeLib;
5286                     ITypeLib2_AddRef((ITypeLib*) pTLib);
5287                     result = S_OK;
5288                 } else {
5289                     TRACE("typeinfo in imported typelib that isn't already loaded\n");
5290                     result = LoadRegTypeLib( &pRefType->pImpTLInfo->guid,
5291                                              pRefType->pImpTLInfo->wVersionMajor,
5292                                              pRefType->pImpTLInfo->wVersionMinor,
5293                                              pRefType->pImpTLInfo->lcid,
5294                                              &pTLib);
5295
5296                     if(!SUCCEEDED(result)) {
5297                         BSTR libnam=SysAllocString(pRefType->pImpTLInfo->name);
5298                         result=LoadTypeLib(libnam, &pTLib);
5299                         SysFreeString(libnam);
5300                     }
5301                     if(SUCCEEDED(result)) {
5302                         pRefType->pImpTLInfo->pImpTypeLib = (ITypeLibImpl*)pTLib;
5303                         ITypeLib2_AddRef(pTLib);
5304                     }
5305                 }
5306             }
5307             if(SUCCEEDED(result)) {
5308                 if(pRefType->index == TLB_REF_USE_GUID)
5309                     result = ITypeLib2_GetTypeInfoOfGuid(pTLib,
5310                                                          &pRefType->guid,
5311                                                          ppTInfo);
5312                 else
5313                     result = ITypeLib2_GetTypeInfo(pTLib, pRefType->index,
5314                                                    ppTInfo);
5315             }
5316             if (pTLib != NULL)
5317                 ITypeLib2_Release(pTLib);
5318         }
5319     }
5320
5321     TRACE("(%p) hreftype 0x%04lx loaded %s (%p)\n", This, hRefType,
5322           SUCCEEDED(result)? "SUCCESS":"FAILURE", *ppTInfo);
5323     return result;
5324 }
5325
5326 /* ITypeInfo::AddressOfMember
5327  *
5328  * Retrieves the addresses of static functions or variables, such as those
5329  * defined in a DLL.
5330  */
5331 static HRESULT WINAPI ITypeInfo_fnAddressOfMember( ITypeInfo2 *iface,
5332         MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
5333 {
5334     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5335     FIXME("(%p) stub!\n", This);
5336     return S_OK;
5337 }
5338
5339 /* ITypeInfo::CreateInstance
5340  *
5341  * Creates a new instance of a type that describes a component object class
5342  * (coclass).
5343  */
5344 static HRESULT WINAPI ITypeInfo_fnCreateInstance( ITypeInfo2 *iface,
5345         IUnknown *pUnk, REFIID riid, VOID  **ppvObj)
5346 {
5347     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5348     FIXME("(%p) stub!\n", This);
5349     return S_OK;
5350 }
5351
5352 /* ITypeInfo::GetMops
5353  *
5354  * Retrieves marshalling information.
5355  */
5356 static HRESULT WINAPI ITypeInfo_fnGetMops( ITypeInfo2 *iface, MEMBERID memid,
5357                                 BSTR  *pBstrMops)
5358 {
5359     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5360     FIXME("(%p) stub!\n", This);
5361     return S_OK;
5362 }
5363
5364 /* ITypeInfo::GetContainingTypeLib
5365  *
5366  * Retrieves the containing type library and the index of the type description
5367  * within that type library.
5368  */
5369 static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( ITypeInfo2 *iface,
5370         ITypeLib  * *ppTLib, UINT  *pIndex)
5371 {
5372     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5373     
5374     /* If a pointer is null, we simply ignore it, the ATL in particular passes pIndex as 0 */
5375     if (pIndex) {
5376       *pIndex=This->index;
5377       TRACE("returning pIndex=%d\n", *pIndex);
5378     }
5379     
5380     if (ppTLib) {
5381       *ppTLib=(LPTYPELIB )(This->pTypeLib);
5382       ITypeLib2_AddRef(*ppTLib);
5383       TRACE("returning ppTLib=%p\n", *ppTLib);
5384     }
5385     
5386     return S_OK;
5387 }
5388
5389 /* ITypeInfo::ReleaseTypeAttr
5390  *
5391  * Releases a TYPEATTR previously returned by GetTypeAttr.
5392  *
5393  */
5394 static void WINAPI ITypeInfo_fnReleaseTypeAttr( ITypeInfo2 *iface,
5395         TYPEATTR* pTypeAttr)
5396 {
5397     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5398     TRACE("(%p)->(%p)\n", This, pTypeAttr);
5399     if(This->TypeAttr.typekind == TKIND_ALIAS)
5400         free_deep_typedesc(&pTypeAttr->tdescAlias);
5401     HeapFree(GetProcessHeap(), 0, pTypeAttr);
5402 }
5403
5404 /* ITypeInfo::ReleaseFuncDesc
5405  *
5406  * Releases a FUNCDESC previously returned by GetFuncDesc. *
5407  */
5408 static void WINAPI ITypeInfo_fnReleaseFuncDesc(
5409         ITypeInfo2 *iface,
5410         FUNCDESC *pFuncDesc)
5411 {
5412     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5413     TRACE("(%p)->(%p)\n", This, pFuncDesc);
5414 }
5415
5416 /* ITypeInfo::ReleaseVarDesc
5417  *
5418  * Releases a VARDESC previously returned by GetVarDesc.
5419  */
5420 static void WINAPI ITypeInfo_fnReleaseVarDesc( ITypeInfo2 *iface,
5421         VARDESC *pVarDesc)
5422 {
5423     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5424     TRACE("(%p)->(%p)\n", This, pVarDesc);
5425 }
5426
5427 /* ITypeInfo2::GetTypeKind
5428  *
5429  * Returns the TYPEKIND enumeration quickly, without doing any allocations.
5430  *
5431  */
5432 static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo2 * iface,
5433     TYPEKIND *pTypeKind)
5434 {
5435     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5436     *pTypeKind=This->TypeAttr.typekind;
5437     TRACE("(%p) type 0x%0x\n", This,*pTypeKind);
5438     return S_OK;
5439 }
5440
5441 /* ITypeInfo2::GetTypeFlags
5442  *
5443  * Returns the type flags without any allocations. This returns a DWORD type
5444  * flag, which expands the type flags without growing the TYPEATTR (type
5445  * attribute).
5446  *
5447  */
5448 static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo2 *iface, ULONG *pTypeFlags)
5449 {
5450     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5451     *pTypeFlags=This->TypeAttr.wTypeFlags;
5452     TRACE("(%p) flags 0x%lx\n", This,*pTypeFlags);
5453     return S_OK;
5454 }
5455
5456 /* ITypeInfo2::GetFuncIndexOfMemId
5457  * Binds to a specific member based on a known DISPID, where the member name
5458  * is not known (for example, when binding to a default member).
5459  *
5460  */
5461 static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo2 * iface,
5462     MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex)
5463 {
5464     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5465     TLBFuncDesc *pFuncInfo;
5466     int i;
5467     HRESULT result;
5468
5469     for(i = 0, pFuncInfo = This->funclist; pFuncInfo; i++, pFuncInfo=pFuncInfo->next)
5470         if(memid == pFuncInfo->funcdesc.memid && (invKind & pFuncInfo->funcdesc.invkind))
5471             break;
5472     if(pFuncInfo) {
5473         *pFuncIndex = i;
5474         result = S_OK;
5475     } else
5476         result = TYPE_E_ELEMENTNOTFOUND;
5477
5478     TRACE("(%p) memid 0x%08lx invKind 0x%04x -> %s\n", This,
5479           memid, invKind, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
5480     return result;
5481 }
5482
5483 /* TypeInfo2::GetVarIndexOfMemId
5484  *
5485  * Binds to a specific member based on a known DISPID, where the member name
5486  * is not known (for example, when binding to a default member).
5487  *
5488  */
5489 static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( ITypeInfo2 * iface,
5490     MEMBERID memid, UINT *pVarIndex)
5491 {
5492     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5493     TLBVarDesc *pVarInfo;
5494     int i;
5495     HRESULT result;
5496     for(i=0, pVarInfo=This->varlist; pVarInfo &&
5497             memid != pVarInfo->vardesc.memid; i++, pVarInfo=pVarInfo->next)
5498         ;
5499     if(pVarInfo) {
5500         *pVarIndex = i;
5501         result = S_OK;
5502     } else
5503         result = TYPE_E_ELEMENTNOTFOUND;
5504
5505     TRACE("(%p) memid 0x%08lx -> %s\n", This,
5506           memid, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
5507     return result;
5508 }
5509
5510 /* ITypeInfo2::GetCustData
5511  *
5512  * Gets the custom data
5513  */
5514 static HRESULT WINAPI ITypeInfo2_fnGetCustData(
5515         ITypeInfo2 * iface,
5516         REFGUID guid,
5517         VARIANT *pVarVal)
5518 {
5519     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5520     TLBCustData *pCData;
5521
5522     for(pCData=This->pCustData; pCData; pCData = pCData->next)
5523         if( IsEqualIID(guid, &pCData->guid)) break;
5524
5525     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
5526
5527     if(pCData)
5528     {
5529         VariantInit( pVarVal);
5530         VariantCopy( pVarVal, &pCData->data);
5531         return S_OK;
5532     }
5533     return E_INVALIDARG;  /* FIXME: correct? */
5534 }
5535
5536 /* ITypeInfo2::GetFuncCustData
5537  *
5538  * Gets the custom data
5539  */
5540 static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData(
5541         ITypeInfo2 * iface,
5542         UINT index,
5543         REFGUID guid,
5544         VARIANT *pVarVal)
5545 {
5546     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5547     TLBCustData *pCData=NULL;
5548     TLBFuncDesc * pFDesc;
5549     int i;
5550     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
5551             pFDesc=pFDesc->next);
5552
5553     if(pFDesc)
5554         for(pCData=pFDesc->pCustData; pCData; pCData = pCData->next)
5555             if( IsEqualIID(guid, &pCData->guid)) break;
5556
5557     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
5558
5559     if(pCData){
5560         VariantInit( pVarVal);
5561         VariantCopy( pVarVal, &pCData->data);
5562         return S_OK;
5563     }
5564     return E_INVALIDARG;  /* FIXME: correct? */
5565 }
5566
5567 /* ITypeInfo2::GetParamCustData
5568  *
5569  * Gets the custom data
5570  */
5571 static HRESULT WINAPI ITypeInfo2_fnGetParamCustData(
5572         ITypeInfo2 * iface,
5573         UINT indexFunc,
5574         UINT indexParam,
5575         REFGUID guid,
5576         VARIANT *pVarVal)
5577 {
5578     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5579     TLBCustData *pCData=NULL;
5580     TLBFuncDesc * pFDesc;
5581     int i;
5582
5583     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,pFDesc=pFDesc->next);
5584
5585     if(pFDesc && indexParam >=0 && indexParam<pFDesc->funcdesc.cParams)
5586         for(pCData=pFDesc->pParamDesc[indexParam].pCustData; pCData;
5587                 pCData = pCData->next)
5588             if( IsEqualIID(guid, &pCData->guid)) break;
5589
5590     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
5591
5592     if(pCData)
5593     {
5594         VariantInit( pVarVal);
5595         VariantCopy( pVarVal, &pCData->data);
5596         return S_OK;
5597     }
5598     return E_INVALIDARG;  /* FIXME: correct? */
5599 }
5600
5601 /* ITypeInfo2::GetVarCustData
5602  *
5603  * Gets the custom data
5604  */
5605 static HRESULT WINAPI ITypeInfo2_fnGetVarCustData(
5606         ITypeInfo2 * iface,
5607         UINT index,
5608         REFGUID guid,
5609         VARIANT *pVarVal)
5610 {
5611     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5612     TLBCustData *pCData=NULL;
5613     TLBVarDesc * pVDesc;
5614     int i;
5615
5616     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next);
5617
5618     if(pVDesc)
5619     {
5620       for(pCData=pVDesc->pCustData; pCData; pCData = pCData->next)
5621       {
5622         if( IsEqualIID(guid, &pCData->guid)) break;
5623       }
5624     }
5625
5626     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
5627
5628     if(pCData)
5629     {
5630         VariantInit( pVarVal);
5631         VariantCopy( pVarVal, &pCData->data);
5632         return S_OK;
5633     }
5634     return E_INVALIDARG;  /* FIXME: correct? */
5635 }
5636
5637 /* ITypeInfo2::GetImplCustData
5638  *
5639  * Gets the custom data
5640  */
5641 static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData(
5642         ITypeInfo2 * iface,
5643         UINT index,
5644         REFGUID guid,
5645         VARIANT *pVarVal)
5646 {
5647     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5648     TLBCustData *pCData=NULL;
5649     TLBImplType * pRDesc;
5650     int i;
5651
5652     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++, pRDesc=pRDesc->next);
5653
5654     if(pRDesc)
5655     {
5656       for(pCData=pRDesc->pCustData; pCData; pCData = pCData->next)
5657       {
5658         if( IsEqualIID(guid, &pCData->guid)) break;
5659       }
5660     }
5661
5662     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
5663
5664     if(pCData)
5665     {
5666         VariantInit( pVarVal);
5667         VariantCopy( pVarVal, &pCData->data);
5668         return S_OK;
5669     }
5670     return E_INVALIDARG;  /* FIXME: correct? */
5671 }
5672
5673 /* ITypeInfo2::GetDocumentation2
5674  *
5675  * Retrieves the documentation string, the complete Help file name and path,
5676  * the localization context to use, and the context ID for the library Help
5677  * topic in the Help file.
5678  *
5679  */
5680 static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2(
5681         ITypeInfo2 * iface,
5682         MEMBERID memid,
5683         LCID lcid,
5684         BSTR *pbstrHelpString,
5685         DWORD *pdwHelpStringContext,
5686         BSTR *pbstrHelpStringDll)
5687 {
5688     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5689     TLBFuncDesc * pFDesc;
5690     TLBVarDesc * pVDesc;
5691     TRACE("(%p) memid %ld lcid(0x%lx)  HelpString(%p) "
5692           "HelpStringContext(%p) HelpStringDll(%p)\n",
5693           This, memid, lcid, pbstrHelpString, pdwHelpStringContext,
5694           pbstrHelpStringDll );
5695     /* the help string should be obtained from the helpstringdll,
5696      * using the _DLLGetDocumentation function, based on the supplied
5697      * lcid. Nice to do sometime...
5698      */
5699     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
5700         if(pbstrHelpString)
5701             *pbstrHelpString=SysAllocString(This->Name);
5702         if(pdwHelpStringContext)
5703             *pdwHelpStringContext=This->dwHelpStringContext;
5704         if(pbstrHelpStringDll)
5705             *pbstrHelpStringDll=
5706                 SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
5707         return S_OK;
5708     }else {/* for a member */
5709     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
5710         if(pFDesc->funcdesc.memid==memid){
5711              if(pbstrHelpString)
5712                 *pbstrHelpString=SysAllocString(pFDesc->HelpString);
5713             if(pdwHelpStringContext)
5714                 *pdwHelpStringContext=pFDesc->HelpStringContext;
5715             if(pbstrHelpStringDll)
5716                 *pbstrHelpStringDll=
5717                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
5718         return S_OK;
5719     }
5720     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
5721         if(pVDesc->vardesc.memid==memid){
5722              if(pbstrHelpString)
5723                 *pbstrHelpString=SysAllocString(pVDesc->HelpString);
5724             if(pdwHelpStringContext)
5725                 *pdwHelpStringContext=pVDesc->HelpStringContext;
5726             if(pbstrHelpStringDll)
5727                 *pbstrHelpStringDll=
5728                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
5729             return S_OK;
5730         }
5731     }
5732     return TYPE_E_ELEMENTNOTFOUND;
5733 }
5734
5735 /* ITypeInfo2::GetAllCustData
5736  *
5737  * Gets all custom data items for the Type info.
5738  *
5739  */
5740 static HRESULT WINAPI ITypeInfo2_fnGetAllCustData(
5741         ITypeInfo2 * iface,
5742         CUSTDATA *pCustData)
5743 {
5744     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5745     TLBCustData *pCData;
5746     int i;
5747
5748     TRACE("(%p) returning %d items\n", This, This->ctCustData);
5749
5750     pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
5751     if(pCustData->prgCustData ){
5752         pCustData->cCustData=This->ctCustData;
5753         for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
5754             pCustData->prgCustData[i].guid=pCData->guid;
5755             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
5756         }
5757     }else{
5758         ERR(" OUT OF MEMORY! \n");
5759         return E_OUTOFMEMORY;
5760     }
5761     return S_OK;
5762 }
5763
5764 /* ITypeInfo2::GetAllFuncCustData
5765  *
5766  * Gets all custom data items for the specified Function
5767  *
5768  */
5769 static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData(
5770         ITypeInfo2 * iface,
5771         UINT index,
5772         CUSTDATA *pCustData)
5773 {
5774     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5775     TLBCustData *pCData;
5776     TLBFuncDesc * pFDesc;
5777     int i;
5778     TRACE("(%p) index %d\n", This, index);
5779     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
5780             pFDesc=pFDesc->next)
5781         ;
5782     if(pFDesc){
5783         pCustData->prgCustData =
5784             TLB_Alloc(pFDesc->ctCustData * sizeof(CUSTDATAITEM));
5785         if(pCustData->prgCustData ){
5786             pCustData->cCustData=pFDesc->ctCustData;
5787             for(i=0, pCData=pFDesc->pCustData; pCData; i++,
5788                     pCData = pCData->next){
5789                 pCustData->prgCustData[i].guid=pCData->guid;
5790                 VariantCopy(& pCustData->prgCustData[i].varValue,
5791                         & pCData->data);
5792             }
5793         }else{
5794             ERR(" OUT OF MEMORY! \n");
5795             return E_OUTOFMEMORY;
5796         }
5797         return S_OK;
5798     }
5799     return TYPE_E_ELEMENTNOTFOUND;
5800 }
5801
5802 /* ITypeInfo2::GetAllParamCustData
5803  *
5804  * Gets all custom data items for the Functions
5805  *
5806  */
5807 static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo2 * iface,
5808     UINT indexFunc, UINT indexParam, CUSTDATA *pCustData)
5809 {
5810     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5811     TLBCustData *pCData=NULL;
5812     TLBFuncDesc * pFDesc;
5813     int i;
5814     TRACE("(%p) index %d\n", This, indexFunc);
5815     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,
5816             pFDesc=pFDesc->next)
5817         ;
5818     if(pFDesc && indexParam >=0 && indexParam<pFDesc->funcdesc.cParams){
5819         pCustData->prgCustData =
5820             TLB_Alloc(pFDesc->pParamDesc[indexParam].ctCustData *
5821                     sizeof(CUSTDATAITEM));
5822         if(pCustData->prgCustData ){
5823             pCustData->cCustData=pFDesc->pParamDesc[indexParam].ctCustData;
5824             for(i=0, pCData=pFDesc->pParamDesc[indexParam].pCustData;
5825                     pCData; i++, pCData = pCData->next){
5826                 pCustData->prgCustData[i].guid=pCData->guid;
5827                 VariantCopy(& pCustData->prgCustData[i].varValue,
5828                         & pCData->data);
5829             }
5830         }else{
5831             ERR(" OUT OF MEMORY! \n");
5832             return E_OUTOFMEMORY;
5833         }
5834         return S_OK;
5835     }
5836     return TYPE_E_ELEMENTNOTFOUND;
5837 }
5838
5839 /* ITypeInfo2::GetAllVarCustData
5840  *
5841  * Gets all custom data items for the specified Variable
5842  *
5843  */
5844 static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo2 * iface,
5845     UINT index, CUSTDATA *pCustData)
5846 {
5847     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5848     TLBCustData *pCData;
5849     TLBVarDesc * pVDesc;
5850     int i;
5851     TRACE("(%p) index %d\n", This, index);
5852     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++,
5853             pVDesc=pVDesc->next)
5854         ;
5855     if(pVDesc){
5856         pCustData->prgCustData =
5857             TLB_Alloc(pVDesc->ctCustData * sizeof(CUSTDATAITEM));
5858         if(pCustData->prgCustData ){
5859             pCustData->cCustData=pVDesc->ctCustData;
5860             for(i=0, pCData=pVDesc->pCustData; pCData; i++,
5861                     pCData = pCData->next){
5862                 pCustData->prgCustData[i].guid=pCData->guid;
5863                 VariantCopy(& pCustData->prgCustData[i].varValue,
5864                         & pCData->data);
5865             }
5866         }else{
5867             ERR(" OUT OF MEMORY! \n");
5868             return E_OUTOFMEMORY;
5869         }
5870         return S_OK;
5871     }
5872     return TYPE_E_ELEMENTNOTFOUND;
5873 }
5874
5875 /* ITypeInfo2::GetAllImplCustData
5876  *
5877  * Gets all custom data items for the specified implementation type
5878  *
5879  */
5880 static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData(
5881         ITypeInfo2 * iface,
5882         UINT index,
5883         CUSTDATA *pCustData)
5884 {
5885     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5886     TLBCustData *pCData;
5887     TLBImplType * pRDesc;
5888     int i;
5889     TRACE("(%p) index %d\n", This, index);
5890     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++,
5891             pRDesc=pRDesc->next)
5892         ;
5893     if(pRDesc){
5894         pCustData->prgCustData =
5895             TLB_Alloc(pRDesc->ctCustData * sizeof(CUSTDATAITEM));
5896         if(pCustData->prgCustData ){
5897             pCustData->cCustData=pRDesc->ctCustData;
5898             for(i=0, pCData=pRDesc->pCustData; pCData; i++,
5899                     pCData = pCData->next){
5900                 pCustData->prgCustData[i].guid=pCData->guid;
5901                 VariantCopy(& pCustData->prgCustData[i].varValue,
5902                         & pCData->data);
5903             }
5904         }else{
5905             ERR(" OUT OF MEMORY! \n");
5906             return E_OUTOFMEMORY;
5907         }
5908         return S_OK;
5909     }
5910     return TYPE_E_ELEMENTNOTFOUND;
5911 }
5912
5913 static const ITypeInfo2Vtbl tinfvt =
5914 {
5915
5916     ITypeInfo_fnQueryInterface,
5917     ITypeInfo_fnAddRef,
5918     ITypeInfo_fnRelease,
5919
5920     ITypeInfo_fnGetTypeAttr,
5921     ITypeInfo_fnGetTypeComp,
5922     ITypeInfo_fnGetFuncDesc,
5923     ITypeInfo_fnGetVarDesc,
5924     ITypeInfo_fnGetNames,
5925     ITypeInfo_fnGetRefTypeOfImplType,
5926     ITypeInfo_fnGetImplTypeFlags,
5927     ITypeInfo_fnGetIDsOfNames,
5928     ITypeInfo_fnInvoke,
5929     ITypeInfo_fnGetDocumentation,
5930     ITypeInfo_fnGetDllEntry,
5931     ITypeInfo_fnGetRefTypeInfo,
5932     ITypeInfo_fnAddressOfMember,
5933     ITypeInfo_fnCreateInstance,
5934     ITypeInfo_fnGetMops,
5935     ITypeInfo_fnGetContainingTypeLib,
5936     ITypeInfo_fnReleaseTypeAttr,
5937     ITypeInfo_fnReleaseFuncDesc,
5938     ITypeInfo_fnReleaseVarDesc,
5939
5940     ITypeInfo2_fnGetTypeKind,
5941     ITypeInfo2_fnGetTypeFlags,
5942     ITypeInfo2_fnGetFuncIndexOfMemId,
5943     ITypeInfo2_fnGetVarIndexOfMemId,
5944     ITypeInfo2_fnGetCustData,
5945     ITypeInfo2_fnGetFuncCustData,
5946     ITypeInfo2_fnGetParamCustData,
5947     ITypeInfo2_fnGetVarCustData,
5948     ITypeInfo2_fnGetImplTypeCustData,
5949     ITypeInfo2_fnGetDocumentation2,
5950     ITypeInfo2_fnGetAllCustData,
5951     ITypeInfo2_fnGetAllFuncCustData,
5952     ITypeInfo2_fnGetAllParamCustData,
5953     ITypeInfo2_fnGetAllVarCustData,
5954     ITypeInfo2_fnGetAllImplTypeCustData,
5955 };
5956
5957 /******************************************************************************
5958  * CreateDispTypeInfo [OLEAUT32.31]
5959  *
5960  * Build type information for an object so it can be called through an
5961  * IDispatch interface.
5962  *
5963  * RETURNS
5964  *  Success: S_OK. pptinfo contains the created ITypeInfo object.
5965  *  Failure: E_INVALIDARG, if one or more arguments is invalid.
5966  *
5967  * NOTES
5968  *  This call allows an objects methods to be accessed through IDispatch, by
5969  *  building an ITypeInfo object that IDispatch can use to call through.
5970  */
5971 HRESULT WINAPI CreateDispTypeInfo(
5972         INTERFACEDATA *pidata, /* [I] Description of the interface to build type info for */
5973         LCID lcid, /* [I] Locale Id */
5974         ITypeInfo **pptinfo) /* [O] Destination for created ITypeInfo object */
5975 {
5976     ITypeInfoImpl *pTIImpl;
5977     int param, func;
5978     TLBFuncDesc **ppFuncDesc;
5979
5980     pTIImpl = (ITypeInfoImpl*)ITypeInfo_Constructor();
5981     pTIImpl->pTypeLib = NULL;
5982     pTIImpl->index = 0;
5983     pTIImpl->Name = NULL;
5984     pTIImpl->dwHelpContext = -1;
5985     memset(&pTIImpl->TypeAttr.guid, 0, sizeof(GUID));
5986     pTIImpl->TypeAttr.lcid = lcid;
5987     pTIImpl->TypeAttr.typekind = TKIND_COCLASS;
5988     pTIImpl->TypeAttr.wMajorVerNum = 0;
5989     pTIImpl->TypeAttr.wMinorVerNum = 0;
5990     pTIImpl->TypeAttr.cbAlignment = 2;
5991     pTIImpl->TypeAttr.cbSizeInstance = -1;
5992     pTIImpl->TypeAttr.cbSizeVft = -1;
5993     pTIImpl->TypeAttr.cFuncs = 0;
5994     pTIImpl->TypeAttr.cImplTypes = 1;
5995     pTIImpl->TypeAttr.cVars = 0;
5996     pTIImpl->TypeAttr.wTypeFlags = 0;
5997
5998     ppFuncDesc = &pTIImpl->funclist;
5999     for(func = 0; func < pidata->cMembers; func++) {
6000         METHODDATA *md = pidata->pmethdata + func;
6001         *ppFuncDesc = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppFuncDesc));
6002         (*ppFuncDesc)->Name = SysAllocString(md->szName);
6003         (*ppFuncDesc)->funcdesc.memid = md->dispid;
6004         (*ppFuncDesc)->funcdesc.invkind = md->wFlags;
6005         (*ppFuncDesc)->funcdesc.callconv = md->cc;
6006         (*ppFuncDesc)->funcdesc.cParams = md->cArgs;
6007         (*ppFuncDesc)->funcdesc.cParamsOpt = 0;
6008         (*ppFuncDesc)->funcdesc.oVft = md->iMeth;
6009         (*ppFuncDesc)->funcdesc.wFuncFlags = 0; /*??*/
6010         (*ppFuncDesc)->funcdesc.elemdescFunc.tdesc.vt = md->vtReturn;
6011         (*ppFuncDesc)->funcdesc.lprgelemdescParam = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6012                                                               md->cArgs * sizeof(ELEMDESC));
6013         (*ppFuncDesc)->pParamDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6014                                               md->cArgs * sizeof(TLBParDesc));
6015         for(param = 0; param < md->cArgs; param++) {
6016             (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].tdesc.vt = md->ppdata[param].vt;
6017             (*ppFuncDesc)->pParamDesc[param].Name = SysAllocString(md->ppdata[param].szName);
6018         }
6019         ppFuncDesc = &(*ppFuncDesc)->next;
6020     }        
6021     *pptinfo = (ITypeInfo*)pTIImpl;
6022     return S_OK;
6023
6024 }
6025
6026 static HRESULT WINAPI ITypeComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
6027 {
6028     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
6029
6030     return ITypeInfo_QueryInterface((ITypeInfo *)This, riid, ppv);
6031 }
6032
6033 static ULONG WINAPI ITypeComp_fnAddRef(ITypeComp * iface)
6034 {
6035     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
6036
6037     return ITypeInfo_AddRef((ITypeInfo *)This);
6038 }
6039
6040 static ULONG WINAPI ITypeComp_fnRelease(ITypeComp * iface)
6041 {
6042     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
6043
6044     return ITypeInfo_Release((ITypeInfo *)This);
6045 }
6046
6047 static HRESULT WINAPI ITypeComp_fnBind(
6048     ITypeComp * iface,
6049     OLECHAR * szName,
6050     ULONG lHash,
6051     WORD wFlags,
6052     ITypeInfo ** ppTInfo,
6053     DESCKIND * pDescKind,
6054     BINDPTR * pBindPtr)
6055 {
6056     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
6057     TLBFuncDesc * pFDesc;
6058     TLBVarDesc * pVDesc;
6059
6060     TRACE("(%s, %lx, 0x%x, %p, %p, %p)\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
6061
6062     for(pFDesc = This->funclist; pFDesc; pFDesc = pFDesc->next)
6063         if (pFDesc->funcdesc.invkind & wFlags)
6064             if (!strcmpW(pFDesc->Name, szName)) {
6065                 break;
6066             }
6067
6068     if (pFDesc)
6069     {
6070         *pDescKind = DESCKIND_FUNCDESC;
6071         pBindPtr->lpfuncdesc = &pFDesc->funcdesc;
6072         *ppTInfo = (ITypeInfo *)&This->lpVtbl;
6073         return S_OK;
6074     } else {
6075         if (!(wFlags & ~(INVOKE_PROPERTYGET)))
6076         {
6077             for(pVDesc = This->varlist; pVDesc; pVDesc = pVDesc->next) {
6078                 if (!strcmpW(pVDesc->Name, szName)) {
6079                     *pDescKind = DESCKIND_VARDESC;
6080                     pBindPtr->lpvardesc = &pVDesc->vardesc;
6081                     *ppTInfo = (ITypeInfo *)&This->lpVtbl;
6082                     return S_OK;
6083                 }
6084             }
6085         }
6086     }
6087     /* not found, look for it in inherited interfaces */
6088     if (This->TypeAttr.cImplTypes &&
6089         (This->TypeAttr.typekind == TKIND_INTERFACE || This->TypeAttr.typekind == TKIND_DISPATCH)) {
6090         /* recursive search */
6091         ITypeInfo *pTInfo;
6092         ITypeComp *pTComp;
6093         HRESULT hr;
6094         hr=ITypeInfo_GetRefTypeInfo((ITypeInfo *)&This->lpVtbl, This->impltypelist->hRef, &pTInfo);
6095         if (SUCCEEDED(hr))
6096         {
6097             hr = ITypeInfo_GetTypeComp(pTInfo,&pTComp);
6098             ITypeInfo_Release(pTInfo);
6099         }
6100         if (SUCCEEDED(hr))
6101         {
6102             hr = ITypeComp_Bind(pTComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
6103             ITypeComp_Release(pTComp);
6104             return hr;
6105         }
6106         WARN("Could not search inherited interface!\n");
6107     }
6108     ERR("did not find member with name %s, flags 0x%x!\n", debugstr_w(szName), wFlags);
6109     *pDescKind = DESCKIND_NONE;
6110     pBindPtr->lpfuncdesc = NULL;
6111     *ppTInfo = NULL;
6112     return DISP_E_MEMBERNOTFOUND;
6113 }
6114
6115 static HRESULT WINAPI ITypeComp_fnBindType(
6116     ITypeComp * iface,
6117     OLECHAR * szName,
6118     ULONG lHash,
6119     ITypeInfo ** ppTInfo,
6120     ITypeComp ** ppTComp)
6121 {
6122     TRACE("(%s, %lx, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
6123
6124     /* strange behaviour (does nothing) but like the
6125      * original */
6126
6127     if (!ppTInfo || !ppTComp)
6128         return E_POINTER;
6129
6130     *ppTInfo = NULL;
6131     *ppTComp = NULL;
6132
6133     return S_OK;
6134 }
6135
6136 static const ITypeCompVtbl tcompvt =
6137 {
6138
6139     ITypeComp_fnQueryInterface,
6140     ITypeComp_fnAddRef,
6141     ITypeComp_fnRelease,
6142
6143     ITypeComp_fnBind,
6144     ITypeComp_fnBindType
6145 };