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