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