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