Put the UI update code for cabinet file into a separate function.
[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, { (DWORD_PTR)(__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_(typelib)("%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_(typelib)("header:\n");
3146     TRACE_(typelib)("\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_(typelib)("\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_(typelib)("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             {
3691                 if(!(*pBstrName = SysAllocString(This->Name)))
3692                     goto memerr1;
3693             }
3694             else
3695                 *pBstrName = NULL;
3696         }
3697         if(pBstrDocString)
3698         {
3699             if (This->DocString)
3700             {
3701                 if(!(*pBstrDocString = SysAllocString(This->DocString)))
3702                     goto memerr2;
3703             }
3704             else if (This->Name)
3705             {
3706                 if(!(*pBstrDocString = SysAllocString(This->Name)))
3707                     goto memerr2;
3708             }
3709             else
3710                 *pBstrDocString = NULL;
3711         }
3712         if(pdwHelpContext)
3713         {
3714             *pdwHelpContext = This->dwHelpContext;
3715         }
3716         if(pBstrHelpFile)
3717         {
3718             if (This->HelpFile)
3719             {
3720                 if(!(*pBstrHelpFile = SysAllocString(This->HelpFile)))
3721                     goto memerr3;
3722             }
3723             else
3724                 *pBstrHelpFile = NULL;
3725         }
3726
3727         result = S_OK;
3728     }
3729     else
3730     {
3731         /* for a typeinfo */
3732         result = ITypeLib2_fnGetTypeInfo(iface, index, &pTInfo);
3733
3734         if(SUCCEEDED(result))
3735         {
3736             result = ITypeInfo_GetDocumentation(pTInfo,
3737                                           MEMBERID_NIL,
3738                                           pBstrName,
3739                                           pBstrDocString,
3740                                           pdwHelpContext, pBstrHelpFile);
3741
3742             ITypeInfo_Release(pTInfo);
3743         }
3744     }
3745     return result;
3746 memerr3:
3747     if (pBstrDocString) SysFreeString (*pBstrDocString);
3748 memerr2:
3749     if (pBstrName) SysFreeString (*pBstrName);
3750 memerr1:
3751     return STG_E_INSUFFICIENTMEMORY;
3752 }
3753
3754 /* ITypeLib::IsName
3755  *
3756  * Indicates whether a passed-in string contains the name of a type or member
3757  * described in the library.
3758  *
3759  */
3760 static HRESULT WINAPI ITypeLib2_fnIsName(
3761         ITypeLib2 *iface,
3762         LPOLESTR szNameBuf,
3763         ULONG lHashVal,
3764         BOOL *pfName)
3765 {
3766     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3767     ITypeInfoImpl *pTInfo;
3768     TLBFuncDesc *pFInfo;
3769     TLBVarDesc *pVInfo;
3770     int i;
3771     UINT nNameBufLen = (lstrlenW(szNameBuf)+1)*sizeof(WCHAR);
3772
3773     TRACE("(%p)->(%s,%08lx,%p)\n", This, debugstr_w(szNameBuf), lHashVal,
3774           pfName);
3775
3776     *pfName=TRUE;
3777     for(pTInfo=This->pTypeInfo;pTInfo;pTInfo=pTInfo->next){
3778         if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
3779         for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
3780             if(!memcmp(szNameBuf,pFInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
3781             for(i=0;i<pFInfo->funcdesc.cParams;i++)
3782                 if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name, nNameBufLen))
3783                     goto ITypeLib2_fnIsName_exit;
3784         }
3785         for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next)
3786             if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
3787
3788     }
3789     *pfName=FALSE;
3790
3791 ITypeLib2_fnIsName_exit:
3792     TRACE("(%p)slow! search for %s: %s found!\n", This,
3793           debugstr_w(szNameBuf), *pfName?"NOT":"");
3794
3795     return S_OK;
3796 }
3797
3798 /* ITypeLib::FindName
3799  *
3800  * Finds occurrences of a type description in a type library. This may be used
3801  * to quickly verify that a name exists in a type library.
3802  *
3803  */
3804 static HRESULT WINAPI ITypeLib2_fnFindName(
3805         ITypeLib2 *iface,
3806         LPOLESTR szNameBuf,
3807         ULONG lHashVal,
3808         ITypeInfo **ppTInfo,
3809         MEMBERID *rgMemId,
3810         UINT16 *pcFound)
3811 {
3812     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3813     ITypeInfoImpl *pTInfo;
3814     TLBFuncDesc *pFInfo;
3815     TLBVarDesc *pVInfo;
3816     int i,j = 0;
3817     UINT nNameBufLen = (lstrlenW(szNameBuf)+1)*sizeof(WCHAR);
3818
3819     for(pTInfo=This->pTypeInfo;pTInfo && j<*pcFound; pTInfo=pTInfo->next){
3820         if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit;
3821         for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
3822             if(!memcmp(szNameBuf,pFInfo->Name,nNameBufLen)) goto ITypeLib2_fnFindName_exit;
3823             for(i=0;i<pFInfo->funcdesc.cParams;i++) {
3824                 if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name,nNameBufLen))
3825                     goto ITypeLib2_fnFindName_exit;
3826             }
3827         }
3828         for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next)
3829             if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit;
3830         continue;
3831 ITypeLib2_fnFindName_exit:
3832         ITypeInfo_AddRef((ITypeInfo*)pTInfo);
3833         ppTInfo[j]=(LPTYPEINFO)pTInfo;
3834         j++;
3835     }
3836     TRACE("(%p)slow! search for %d with %s: found %d TypeInfo's!\n",
3837           This, *pcFound, debugstr_w(szNameBuf), j);
3838
3839     *pcFound=j;
3840
3841     return S_OK;
3842 }
3843
3844 /* ITypeLib::ReleaseTLibAttr
3845  *
3846  * Releases the TLIBATTR originally obtained from ITypeLib::GetLibAttr.
3847  *
3848  */
3849 static VOID WINAPI ITypeLib2_fnReleaseTLibAttr(
3850         ITypeLib2 *iface,
3851         TLIBATTR *pTLibAttr)
3852 {
3853     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3854     TRACE("freeing (%p)\n",This);
3855     HeapFree(GetProcessHeap(),0,pTLibAttr);
3856
3857 }
3858
3859 /* ITypeLib2::GetCustData
3860  *
3861  * gets the custom data
3862  */
3863 static HRESULT WINAPI ITypeLib2_fnGetCustData(
3864         ITypeLib2 * iface,
3865         REFGUID guid,
3866         VARIANT *pVarVal)
3867 {
3868     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3869     TLBCustData *pCData;
3870
3871     for(pCData=This->pCustData; pCData; pCData = pCData->next)
3872     {
3873       if( IsEqualIID(guid, &pCData->guid)) break;
3874     }
3875
3876     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
3877
3878     if(pCData)
3879     {
3880         VariantInit( pVarVal);
3881         VariantCopy( pVarVal, &pCData->data);
3882         return S_OK;
3883     }
3884     return E_INVALIDARG;  /* FIXME: correct? */
3885 }
3886
3887 /* ITypeLib2::GetLibStatistics
3888  *
3889  * Returns statistics about a type library that are required for efficient
3890  * sizing of hash tables.
3891  *
3892  */
3893 static HRESULT WINAPI ITypeLib2_fnGetLibStatistics(
3894         ITypeLib2 * iface,
3895         ULONG *pcUniqueNames,
3896         ULONG *pcchUniqueNames)
3897 {
3898     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3899
3900     FIXME("(%p): stub!\n", This);
3901
3902     if(pcUniqueNames) *pcUniqueNames=1;
3903     if(pcchUniqueNames) *pcchUniqueNames=1;
3904     return S_OK;
3905 }
3906
3907 /* ITypeLib2::GetDocumentation2
3908  *
3909  * Retrieves the library's documentation string, the complete Help file name
3910  * and path, the localization context to use, and the context ID for the
3911  * library Help topic in the Help file.
3912  *
3913  */
3914 static HRESULT WINAPI ITypeLib2_fnGetDocumentation2(
3915         ITypeLib2 * iface,
3916         INT index,
3917         LCID lcid,
3918         BSTR *pbstrHelpString,
3919         DWORD *pdwHelpStringContext,
3920         BSTR *pbstrHelpStringDll)
3921 {
3922     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3923     HRESULT result;
3924     ITypeInfo *pTInfo;
3925
3926     FIXME("(%p) index %d lcid %ld half implemented stub!\n", This, index, lcid);
3927
3928     /* the help string should be obtained from the helpstringdll,
3929      * using the _DLLGetDocumentation function, based on the supplied
3930      * lcid. Nice to do sometime...
3931      */
3932     if(index<0)
3933     {
3934       /* documentation for the typelib */
3935       if(pbstrHelpString)
3936         *pbstrHelpString=SysAllocString(This->DocString);
3937       if(pdwHelpStringContext)
3938         *pdwHelpStringContext=This->dwHelpContext;
3939       if(pbstrHelpStringDll)
3940         *pbstrHelpStringDll=SysAllocString(This->HelpStringDll);
3941
3942       result = S_OK;
3943     }
3944     else
3945     {
3946       /* for a typeinfo */
3947       result=ITypeLib2_GetTypeInfo(iface, index, &pTInfo);
3948
3949       if(SUCCEEDED(result))
3950       {
3951         ITypeInfo2 * pTInfo2;
3952         result = ITypeInfo_QueryInterface(pTInfo,
3953                                           &IID_ITypeInfo2,
3954                                           (LPVOID*) &pTInfo2);
3955
3956         if(SUCCEEDED(result))
3957         {
3958           result = ITypeInfo2_GetDocumentation2(pTInfo2,
3959                                            MEMBERID_NIL,
3960                                            lcid,
3961                                            pbstrHelpString,
3962                                            pdwHelpStringContext,
3963                                            pbstrHelpStringDll);
3964
3965           ITypeInfo2_Release(pTInfo2);
3966         }
3967
3968         ITypeInfo_Release(pTInfo);
3969       }
3970     }
3971     return result;
3972 }
3973
3974 /* ITypeLib2::GetAllCustData
3975  *
3976  * Gets all custom data items for the library.
3977  *
3978  */
3979 static HRESULT WINAPI ITypeLib2_fnGetAllCustData(
3980         ITypeLib2 * iface,
3981         CUSTDATA *pCustData)
3982 {
3983     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3984     TLBCustData *pCData;
3985     int i;
3986     TRACE("(%p) returning %d items\n", This, This->ctCustData);
3987     pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
3988     if(pCustData->prgCustData ){
3989         pCustData->cCustData=This->ctCustData;
3990         for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
3991             pCustData->prgCustData[i].guid=pCData->guid;
3992             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
3993         }
3994     }else{
3995         ERR(" OUT OF MEMORY! \n");
3996         return E_OUTOFMEMORY;
3997     }
3998     return S_OK;
3999 }
4000
4001 static const ITypeLib2Vtbl tlbvt = {
4002     ITypeLib2_fnQueryInterface,
4003     ITypeLib2_fnAddRef,
4004     ITypeLib2_fnRelease,
4005     ITypeLib2_fnGetTypeInfoCount,
4006     ITypeLib2_fnGetTypeInfo,
4007     ITypeLib2_fnGetTypeInfoType,
4008     ITypeLib2_fnGetTypeInfoOfGuid,
4009     ITypeLib2_fnGetLibAttr,
4010     ITypeLib2_fnGetTypeComp,
4011     ITypeLib2_fnGetDocumentation,
4012     ITypeLib2_fnIsName,
4013     ITypeLib2_fnFindName,
4014     ITypeLib2_fnReleaseTLibAttr,
4015
4016     ITypeLib2_fnGetCustData,
4017     ITypeLib2_fnGetLibStatistics,
4018     ITypeLib2_fnGetDocumentation2,
4019     ITypeLib2_fnGetAllCustData
4020  };
4021
4022
4023 static HRESULT WINAPI ITypeLibComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
4024 {
4025     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4026
4027     return ITypeLib2_QueryInterface((ITypeLib *)This, riid, ppv);
4028 }
4029
4030 static ULONG WINAPI ITypeLibComp_fnAddRef(ITypeComp * iface)
4031 {
4032     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4033
4034     return ITypeLib2_AddRef((ITypeLib2 *)This);
4035 }
4036
4037 static ULONG WINAPI ITypeLibComp_fnRelease(ITypeComp * iface)
4038 {
4039     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4040
4041     return ITypeLib2_Release((ITypeLib2 *)This);
4042 }
4043
4044 static HRESULT WINAPI ITypeLibComp_fnBind(
4045     ITypeComp * iface,
4046     OLECHAR * szName,
4047     ULONG lHash,
4048     WORD wFlags,
4049     ITypeInfo ** ppTInfo,
4050     DESCKIND * pDescKind,
4051     BINDPTR * pBindPtr)
4052 {
4053     FIXME("(%s, %lx, 0x%x, %p, %p, %p): stub\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
4054     return E_NOTIMPL;
4055 }
4056
4057 static HRESULT WINAPI ITypeLibComp_fnBindType(
4058     ITypeComp * iface,
4059     OLECHAR * szName,
4060     ULONG lHash,
4061     ITypeInfo ** ppTInfo,
4062     ITypeComp ** ppTComp)
4063 {
4064     FIXME("(%s, %lx, %p, %p): stub\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
4065     return E_NOTIMPL;
4066 }
4067
4068 static const ITypeCompVtbl tlbtcvt =
4069 {
4070
4071     ITypeLibComp_fnQueryInterface,
4072     ITypeLibComp_fnAddRef,
4073     ITypeLibComp_fnRelease,
4074
4075     ITypeLibComp_fnBind,
4076     ITypeLibComp_fnBindType
4077 };
4078
4079 /*================== ITypeInfo(2) Methods ===================================*/
4080 static ITypeInfo2 * WINAPI ITypeInfo_Constructor(void)
4081 {
4082     ITypeInfoImpl * pTypeInfoImpl;
4083
4084     pTypeInfoImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeInfoImpl));
4085     if (pTypeInfoImpl)
4086     {
4087       pTypeInfoImpl->lpVtbl = &tinfvt;
4088       pTypeInfoImpl->lpVtblTypeComp = &tcompvt;
4089       pTypeInfoImpl->ref=1;
4090     }
4091     TRACE("(%p)\n", pTypeInfoImpl);
4092     return (ITypeInfo2*) pTypeInfoImpl;
4093 }
4094
4095 /* ITypeInfo::QueryInterface
4096  */
4097 static HRESULT WINAPI ITypeInfo_fnQueryInterface(
4098         ITypeInfo2 *iface,
4099         REFIID riid,
4100         VOID **ppvObject)
4101 {
4102     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4103
4104     TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
4105
4106     *ppvObject=NULL;
4107     if(IsEqualIID(riid, &IID_IUnknown) ||
4108             IsEqualIID(riid,&IID_ITypeInfo)||
4109             IsEqualIID(riid,&IID_ITypeInfo2))
4110         *ppvObject = This;
4111
4112     if(*ppvObject){
4113         ITypeInfo_AddRef(iface);
4114         TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
4115         return S_OK;
4116     }
4117     TRACE("-- Interface: E_NOINTERFACE\n");
4118     return E_NOINTERFACE;
4119 }
4120
4121 /* ITypeInfo::AddRef
4122  */
4123 static ULONG WINAPI ITypeInfo_fnAddRef( ITypeInfo2 *iface)
4124 {
4125     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4126     ULONG ref = InterlockedIncrement(&This->ref);
4127
4128     ITypeLib2_AddRef((ITypeLib2*)This->pTypeLib);
4129
4130     TRACE("(%p)->ref is %lu\n",This, ref);
4131     return ref;
4132 }
4133
4134 /* ITypeInfo::Release
4135  */
4136 static ULONG WINAPI ITypeInfo_fnRelease(ITypeInfo2 *iface)
4137 {
4138     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4139     ULONG ref = InterlockedDecrement(&This->ref);
4140
4141     TRACE("(%p)->(%lu)\n",This, ref);
4142
4143     if (ref)   {
4144       /* We don't release ITypeLib when ref=0 because
4145          it means that function is called by ITypeLib2_Release */
4146       ITypeLib2_Release((ITypeLib2*)This->pTypeLib);
4147     } else   {
4148       FIXME("destroy child objects\n");
4149
4150       TRACE("destroying ITypeInfo(%p)\n",This);
4151       if (This->Name)
4152       {
4153           SysFreeString(This->Name);
4154           This->Name = 0;
4155       }
4156
4157       if (This->DocString)
4158       {
4159           SysFreeString(This->DocString);
4160           This->DocString = 0;
4161       }
4162
4163       if (This->next)
4164       {
4165         ITypeInfo_Release((ITypeInfo*)This->next);
4166       }
4167
4168       HeapFree(GetProcessHeap(),0,This);
4169       return 0;
4170     }
4171     return ref;
4172 }
4173
4174 /* ITypeInfo::GetTypeAttr
4175  *
4176  * Retrieves a TYPEATTR structure that contains the attributes of the type
4177  * description.
4178  *
4179  */
4180 static HRESULT WINAPI ITypeInfo_fnGetTypeAttr( ITypeInfo2 *iface,
4181         LPTYPEATTR  *ppTypeAttr)
4182 {
4183     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4184     TRACE("(%p)\n",This);
4185     *ppTypeAttr = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppTypeAttr));
4186     memcpy(*ppTypeAttr, &This->TypeAttr, sizeof(**ppTypeAttr));
4187
4188     if(This->TypeAttr.typekind == TKIND_ALIAS) /* need to deep copy typedesc */
4189         copy_typedesc(&(*ppTypeAttr)->tdescAlias, &This->TypeAttr.tdescAlias);
4190
4191     if((*ppTypeAttr)->typekind == TKIND_DISPATCH) {
4192         (*ppTypeAttr)->cFuncs = (*ppTypeAttr)->cbSizeVft / 4; /* This should include all the inherited
4193                                                                  funcs */
4194         (*ppTypeAttr)->cbSizeVft = 28; /* This is always the size of IDispatch's vtbl */
4195         (*ppTypeAttr)->wTypeFlags &= ~TYPEFLAG_FOLEAUTOMATION;
4196     }
4197     return S_OK;
4198 }
4199
4200 /* ITypeInfo::GetTypeComp
4201  *
4202  * Retrieves the ITypeComp interface for the type description, which enables a
4203  * client compiler to bind to the type description's members.
4204  *
4205  */
4206 static HRESULT WINAPI ITypeInfo_fnGetTypeComp( ITypeInfo2 *iface,
4207         ITypeComp  * *ppTComp)
4208 {
4209     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4210
4211     TRACE("(%p)->(%p) stub!\n", This, ppTComp);
4212
4213     *ppTComp = (ITypeComp *)&This->lpVtblTypeComp;
4214     ITypeComp_AddRef(*ppTComp);
4215     return S_OK;
4216 }
4217
4218 /* ITypeInfo::GetFuncDesc
4219  *
4220  * Retrieves the FUNCDESC structure that contains information about a
4221  * specified function.
4222  *
4223  */
4224 static HRESULT WINAPI ITypeInfo_fnGetFuncDesc( ITypeInfo2 *iface, UINT index,
4225         LPFUNCDESC  *ppFuncDesc)
4226 {
4227     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4228     int i;
4229     TLBFuncDesc * pFDesc;
4230     TRACE("(%p) index %d\n", This, index);
4231     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++, pFDesc=pFDesc->next)
4232         ;
4233     if(pFDesc){
4234         /* FIXME: must do a copy here */
4235         *ppFuncDesc=&pFDesc->funcdesc;
4236         return S_OK;
4237     }
4238     return E_INVALIDARG;
4239 }
4240
4241 /* ITypeInfo::GetVarDesc
4242  *
4243  * Retrieves a VARDESC structure that describes the specified variable.
4244  *
4245  */
4246 static HRESULT WINAPI ITypeInfo_fnGetVarDesc( ITypeInfo2 *iface, UINT index,
4247         LPVARDESC  *ppVarDesc)
4248 {
4249     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4250     int i;
4251     TLBVarDesc * pVDesc;
4252     TRACE("(%p) index %d\n", This, index);
4253     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next)
4254         ;
4255     if(pVDesc){
4256         /* FIXME: must do a copy here */
4257         *ppVarDesc=&pVDesc->vardesc;
4258         return S_OK;
4259     }
4260     return E_INVALIDARG;
4261 }
4262
4263 /* ITypeInfo_GetNames
4264  *
4265  * Retrieves the variable with the specified member ID (or the name of the
4266  * property or method and its parameters) that correspond to the specified
4267  * function ID.
4268  */
4269 static HRESULT WINAPI ITypeInfo_fnGetNames( ITypeInfo2 *iface, MEMBERID memid,
4270         BSTR  *rgBstrNames, UINT cMaxNames, UINT  *pcNames)
4271 {
4272     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4273     TLBFuncDesc * pFDesc;
4274     TLBVarDesc * pVDesc;
4275     int i;
4276     TRACE("(%p) memid=0x%08lx Maxname=%d\n", This, memid, cMaxNames);
4277     for(pFDesc=This->funclist; pFDesc && pFDesc->funcdesc.memid != memid; pFDesc=pFDesc->next);
4278     if(pFDesc)
4279     {
4280       /* function found, now return function and parameter names */
4281       for(i=0; i<cMaxNames && i <= pFDesc->funcdesc.cParams; i++)
4282       {
4283         if(!i)
4284           *rgBstrNames=SysAllocString(pFDesc->Name);
4285         else
4286           rgBstrNames[i]=SysAllocString(pFDesc->pParamDesc[i-1].Name);
4287       }
4288       *pcNames=i;
4289     }
4290     else
4291     {
4292       for(pVDesc=This->varlist; pVDesc && pVDesc->vardesc.memid != memid; pVDesc=pVDesc->next);
4293       if(pVDesc)
4294       {
4295         *rgBstrNames=SysAllocString(pVDesc->Name);
4296         *pcNames=1;
4297       }
4298       else
4299       {
4300         if(This->TypeAttr.cImplTypes &&
4301            (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
4302           /* recursive search */
4303           ITypeInfo *pTInfo;
4304           HRESULT result;
4305           result=ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef,
4306                                           &pTInfo);
4307           if(SUCCEEDED(result))
4308           {
4309             result=ITypeInfo_GetNames(pTInfo, memid, rgBstrNames, cMaxNames, pcNames);
4310             ITypeInfo_Release(pTInfo);
4311             return result;
4312           }
4313           WARN("Could not search inherited interface!\n");
4314         }
4315         else
4316         {
4317           WARN("no names found\n");
4318         }
4319         *pcNames=0;
4320         return TYPE_E_ELEMENTNOTFOUND;
4321       }
4322     }
4323     return S_OK;
4324 }
4325
4326
4327 /* ITypeInfo::GetRefTypeOfImplType
4328  *
4329  * If a type description describes a COM class, it retrieves the type
4330  * description of the implemented interface types. For an interface,
4331  * GetRefTypeOfImplType returns the type information for inherited interfaces,
4332  * if any exist.
4333  *
4334  */
4335 static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType(
4336         ITypeInfo2 *iface,
4337         UINT index,
4338         HREFTYPE  *pRefType)
4339 {
4340     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4341     int i;
4342     HRESULT hr = S_OK;
4343     TLBImplType *pImpl = This->impltypelist;
4344
4345     TRACE("(%p) index %d\n", This, index);
4346     if (TRACE_ON(ole)) dump_TypeInfo(This);
4347
4348     if(index==(UINT)-1)
4349     {
4350       /* only valid on dual interfaces;
4351          retrieve the associated TKIND_INTERFACE handle for the current TKIND_DISPATCH
4352       */
4353       if( This->TypeAttr.typekind != TKIND_DISPATCH) return E_INVALIDARG;
4354
4355       if (This->TypeAttr.wTypeFlags & TYPEFLAG_FDISPATCHABLE &&
4356           This->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL )
4357       {
4358         *pRefType = -1;
4359       }
4360       else
4361       {
4362         hr = TYPE_E_ELEMENTNOTFOUND;
4363       }
4364     }
4365     else
4366     {
4367       /* get element n from linked list */
4368       for(i=0; pImpl && i<index; i++)
4369       {
4370         pImpl = pImpl->next;
4371       }
4372
4373       if (pImpl)
4374         *pRefType = pImpl->hRef;
4375       else
4376         hr = TYPE_E_ELEMENTNOTFOUND;
4377     }
4378
4379     if(TRACE_ON(ole))
4380     {
4381         if(SUCCEEDED(hr))
4382             TRACE("SUCCESS -- hRef = 0x%08lx\n", *pRefType );
4383         else
4384             TRACE("FAILURE -- hresult = 0x%08lx\n", hr);
4385     }
4386
4387     return hr;
4388 }
4389
4390 /* ITypeInfo::GetImplTypeFlags
4391  *
4392  * Retrieves the IMPLTYPEFLAGS enumeration for one implemented interface
4393  * or base interface in a type description.
4394  */
4395 static HRESULT WINAPI ITypeInfo_fnGetImplTypeFlags( ITypeInfo2 *iface,
4396         UINT index, INT  *pImplTypeFlags)
4397 {
4398     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4399     int i;
4400     TLBImplType *pImpl;
4401
4402     TRACE("(%p) index %d\n", This, index);
4403     for(i=0, pImpl=This->impltypelist; i<index && pImpl;
4404         i++, pImpl=pImpl->next)
4405         ;
4406     if(i==index && pImpl){
4407         *pImplTypeFlags=pImpl->implflags;
4408         return S_OK;
4409     }
4410     *pImplTypeFlags=0;
4411     return TYPE_E_ELEMENTNOTFOUND;
4412 }
4413
4414 /* GetIDsOfNames
4415  * Maps between member names and member IDs, and parameter names and
4416  * parameter IDs.
4417  */
4418 static HRESULT WINAPI ITypeInfo_fnGetIDsOfNames( ITypeInfo2 *iface,
4419         LPOLESTR  *rgszNames, UINT cNames, MEMBERID  *pMemId)
4420 {
4421     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4422     TLBFuncDesc * pFDesc;
4423     TLBVarDesc * pVDesc;
4424     HRESULT ret=S_OK;
4425
4426     TRACE("(%p) Name %s cNames %d\n", This, debugstr_w(*rgszNames),
4427             cNames);
4428     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next) {
4429         int i, j;
4430         if(!lstrcmpiW(*rgszNames, pFDesc->Name)) {
4431             if(cNames) *pMemId=pFDesc->funcdesc.memid;
4432             for(i=1; i < cNames; i++){
4433                 for(j=0; j<pFDesc->funcdesc.cParams; j++)
4434                     if(!lstrcmpiW(rgszNames[i],pFDesc->pParamDesc[j].Name))
4435                             break;
4436                 if( j<pFDesc->funcdesc.cParams)
4437                     pMemId[i]=j;
4438                 else
4439                    ret=DISP_E_UNKNOWNNAME;
4440             };
4441             return ret;
4442         }
4443     }
4444     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) {
4445         if(!lstrcmpiW(*rgszNames, pVDesc->Name)) {
4446             if(cNames) *pMemId=pVDesc->vardesc.memid;
4447             return ret;
4448         }
4449     }
4450     /* not found, see if this is and interface with an inheritance */
4451     if(This->TypeAttr.cImplTypes &&
4452        (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
4453         /* recursive search */
4454         ITypeInfo *pTInfo;
4455         ret=ITypeInfo_GetRefTypeInfo(iface,
4456                 This->impltypelist->hRef, &pTInfo);
4457         if(SUCCEEDED(ret)){
4458             ret=ITypeInfo_GetIDsOfNames(pTInfo, rgszNames, cNames, pMemId );
4459             ITypeInfo_Release(pTInfo);
4460             return ret;
4461         }
4462         WARN("Could not search inherited interface!\n");
4463     } else
4464         WARN("no names found\n");
4465     return DISP_E_UNKNOWNNAME;
4466 }
4467
4468 /* ITypeInfo::Invoke
4469  *
4470  * Invokes a method, or accesses a property of an object, that implements the
4471  * interface described by the type description.
4472  */
4473 DWORD
4474 _invoke(FARPROC func,CALLCONV callconv, int nrargs, DWORD *args) {
4475     DWORD res;
4476
4477     if (TRACE_ON(ole)) {
4478         int i;
4479         TRACE("Calling %p(",func);
4480         for (i=0;i<nrargs;i++) TRACE("%08lx,",args[i]);
4481         TRACE(")\n");
4482     }
4483
4484     switch (callconv) {
4485     case CC_STDCALL:
4486
4487         switch (nrargs) {
4488         case 0:
4489                 res = func();
4490                 break;
4491         case 1:
4492                 res = func(args[0]);
4493                 break;
4494         case 2:
4495                 res = func(args[0],args[1]);
4496                 break;
4497         case 3:
4498                 res = func(args[0],args[1],args[2]);
4499                 break;
4500         case 4:
4501                 res = func(args[0],args[1],args[2],args[3]);
4502                 break;
4503         case 5:
4504                 res = func(args[0],args[1],args[2],args[3],args[4]);
4505                 break;
4506         case 6:
4507                 res = func(args[0],args[1],args[2],args[3],args[4],args[5]);
4508                 break;
4509         case 7:
4510                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
4511                 break;
4512         case 8:
4513                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]);
4514                 break;
4515         case 9:
4516                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]);
4517                 break;
4518         case 10:
4519                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9]);
4520                 break;
4521         case 11:
4522                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10]);
4523                 break;
4524         case 12:
4525                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11]);
4526                 break;
4527         case 13:
4528                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12]);
4529                 break;
4530         case 14:
4531                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13]);
4532                 break;
4533         default:
4534                 FIXME("unsupported number of arguments %d in stdcall\n",nrargs);
4535                 res = -1;
4536                 break;
4537         }
4538         break;
4539     default:
4540         FIXME("unsupported calling convention %d\n",callconv);
4541         res = -1;
4542         break;
4543     }
4544     TRACE("returns %08lx\n",res);
4545     return res;
4546 }
4547
4548 extern int _argsize(DWORD vt);
4549
4550 /****************************************************************************
4551  * Helper functions for Dispcall / Invoke, which copies one variant
4552  * with target type onto the argument stack.
4553  */
4554 static HRESULT
4555 _copy_arg(      ITypeInfo2 *tinfo, TYPEDESC *tdesc,
4556                 DWORD *argpos, VARIANT *arg, VARTYPE vt
4557 ) {
4558     UINT arglen = _argsize(vt)*sizeof(DWORD);
4559     VARIANT     va;
4560
4561     if ((vt==VT_PTR) && tdesc && (tdesc->u.lptdesc->vt == VT_VARIANT)) {
4562         memcpy(argpos,&arg,sizeof(void*));
4563         return S_OK;
4564     }
4565
4566     if (V_VT(arg) == vt) {
4567         memcpy(argpos, &V_I4(arg), arglen);
4568         return S_OK;
4569     }
4570
4571     if (V_ISARRAY(arg) && (vt == VT_SAFEARRAY)) {
4572         memcpy(argpos, &V_ARRAY(arg), sizeof(SAFEARRAY*));
4573         return S_OK;
4574     }
4575
4576     if (vt == VT_VARIANT) {
4577         memcpy(argpos, arg, arglen);
4578         return S_OK;
4579     }
4580     /* Deref BYREF vars if there is need */
4581     if(V_ISBYREF(arg) && ((V_VT(arg) & ~VT_BYREF)==vt)) {
4582         memcpy(argpos,(void*)V_I4(arg), arglen);
4583         return S_OK;
4584     }
4585     if (vt==VT_UNKNOWN && V_VT(arg)==VT_DISPATCH) {
4586         /* in this context, if the type lib specifies IUnknown*, giving an
4587            IDispatch* is correct; so, don't invoke VariantChangeType */
4588         memcpy(argpos,&V_I4(arg), arglen);
4589         return S_OK;
4590     }
4591     if ((vt == VT_PTR) && tdesc)
4592         return _copy_arg(tinfo, tdesc->u.lptdesc, argpos, arg, tdesc->u.lptdesc->vt);
4593
4594     if ((vt == VT_USERDEFINED) && tdesc && tinfo) {
4595         ITypeInfo       *tinfo2 = NULL;
4596         TYPEATTR        *tattr = NULL;
4597         HRESULT         hres;
4598
4599         hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
4600         if (hres) {
4601             FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED, "
4602                   "while coercing from vt 0x%x. Copying 4 byte.\n",
4603                   tdesc->u.hreftype,V_VT(arg));
4604             memcpy(argpos, &V_I4(arg), 4);
4605             return S_OK;
4606         }
4607         hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr);
4608         if( hres )
4609         {
4610             ERR("GetTypeAttr failed\n");
4611             ITypeInfo_Release(tinfo2);
4612             return hres;
4613         }
4614         switch (tattr->typekind) {
4615         case TKIND_ENUM:
4616           switch ( V_VT( arg ) ) {
4617           case VT_I2:
4618              *argpos = V_I2(arg);
4619              hres = S_OK;
4620              break;
4621           case VT_I4:
4622              memcpy(argpos, &V_I4(arg), 4);
4623              hres = S_OK;
4624              break;
4625           case VT_BYREF|VT_I4:
4626              memcpy(argpos, V_I4REF(arg), 4);
4627              hres = S_OK;
4628              break;
4629           default:
4630              FIXME("vt 0x%x -> TKIND_ENUM unhandled.\n",V_VT(arg));
4631              hres = E_FAIL;
4632              break;
4633           }
4634           break;
4635
4636         case TKIND_ALIAS:
4637             tdesc = &(tattr->tdescAlias);
4638             hres = _copy_arg((ITypeInfo2*)tinfo2, tdesc, argpos, arg, tdesc->vt);
4639             break;
4640
4641         case TKIND_INTERFACE:
4642             if (V_VT(arg) == VT_DISPATCH) {
4643                 IDispatch *disp;
4644                 if (IsEqualIID(&IID_IDispatch,&(tattr->guid))) {
4645                     memcpy(argpos, &V_DISPATCH(arg), 4);
4646                     hres = S_OK;
4647                     break;
4648                 }
4649                 hres=IUnknown_QueryInterface(V_DISPATCH(arg),
4650                                              &IID_IDispatch,(LPVOID*)&disp);
4651                 if (SUCCEEDED(hres)) {
4652                     memcpy(argpos,&disp,4);
4653                     IUnknown_Release(V_DISPATCH(arg));
4654                     hres = S_OK;
4655                     break;
4656                 }
4657                 FIXME("Failed to query IDispatch interface from %s while "
4658                      "converting to VT_DISPATCH!\n",debugstr_guid(&(tattr->guid)));
4659                 hres = E_FAIL;
4660                 break;
4661             }
4662             if (V_VT(arg) == VT_UNKNOWN) {
4663                 memcpy(argpos, &V_UNKNOWN(arg), 4);
4664                 hres = S_OK;
4665                 break;
4666             }
4667             FIXME("vt 0x%x -> TKIND_INTERFACE(%s) unhandled\n",
4668                   V_VT(arg),debugstr_guid(&(tattr->guid)));
4669             hres = E_FAIL;
4670             break;
4671
4672         case TKIND_DISPATCH:
4673             if (V_VT(arg) == VT_DISPATCH) {
4674                 memcpy(argpos, &V_DISPATCH(arg), 4);
4675                 hres = S_OK;
4676             }
4677             else {
4678                 hres = E_FAIL;
4679                 FIXME("TKIND_DISPATCH unhandled for target vt 0x%x.\n",V_VT(arg));
4680             }
4681             break;
4682         case TKIND_RECORD:
4683             FIXME("TKIND_RECORD unhandled.\n");
4684             hres = E_FAIL;
4685             break;
4686         default:
4687             FIXME("TKIND %d unhandled.\n",tattr->typekind);
4688             hres = E_FAIL;
4689             break;
4690         }
4691         ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
4692         ITypeInfo_Release(tinfo2);
4693         return hres;
4694     }
4695
4696     VariantInit(&va);
4697     if (VariantChangeType(&va,arg,0,vt)==S_OK) {
4698         memcpy(argpos,&V_I4(&va), arglen);
4699         FIXME("Should not use VariantChangeType here."
4700               " (conversion from 0x%x -> 0x%x) %08lx\n",
4701                 V_VT(arg), vt, *argpos
4702         );
4703         return S_OK;
4704     }
4705     ERR("Set arg to disparg type 0x%x vs 0x%x\n",V_VT(arg),vt);
4706     return E_FAIL;
4707 }
4708
4709 static HRESULT userdefined_to_variantvt(ITypeInfo *tinfo, TYPEDESC *tdesc, VARTYPE *vt)
4710 {
4711     HRESULT hr = S_OK;
4712     ITypeInfo *tinfo2 = NULL;
4713     TYPEATTR *tattr = NULL;
4714
4715     hr = ITypeInfo_GetRefTypeInfo(tinfo, tdesc->u.hreftype, &tinfo2);
4716     if (hr)
4717     {
4718         ERR("Could not get typeinfo of hreftype %lx for VT_USERDEFINED, "
4719             "hr = 0x%08lx\n",
4720               tdesc->u.hreftype, hr);
4721         return hr;
4722     }
4723     hr = ITypeInfo_GetTypeAttr(tinfo2, &tattr);
4724     if (hr)
4725     {
4726         ERR("ITypeInfo_GetTypeAttr failed, hr = 0x%08lx\n", hr);
4727         ITypeInfo_Release(tinfo2);
4728         return hr;
4729     }
4730
4731     switch (tattr->typekind)
4732     {
4733     case TKIND_ENUM:
4734         *vt |= VT_INT;
4735         break;
4736
4737     case TKIND_ALIAS:
4738         tdesc = &tattr->tdescAlias;
4739         hr = typedescvt_to_variantvt(tinfo2, &tattr->tdescAlias, vt);
4740         break;
4741
4742     case TKIND_INTERFACE:
4743         if (IsEqualIID(&IID_IDispatch, &tattr->guid))
4744            *vt |= VT_DISPATCH;
4745         else
4746            *vt |= VT_UNKNOWN;
4747         break;
4748
4749     case TKIND_DISPATCH:
4750         *vt |= VT_DISPATCH;
4751         break;
4752
4753     case TKIND_RECORD:
4754         FIXME("TKIND_RECORD unhandled.\n");
4755         hr = E_NOTIMPL;
4756         break;
4757
4758     case TKIND_UNION:
4759         FIXME("TKIND_RECORD unhandled.\n");
4760         hr = E_NOTIMPL;
4761         break;
4762
4763     default:
4764         FIXME("TKIND %d unhandled.\n",tattr->typekind);
4765         hr = E_NOTIMPL;
4766         break;
4767     }
4768     ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
4769     ITypeInfo_Release(tinfo2);
4770     return hr;
4771 }
4772
4773 static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, TYPEDESC *tdesc, VARTYPE *vt)
4774 {
4775     HRESULT hr = S_OK;
4776
4777     /* enforce only one level of pointer indirection */
4778     if (!(*vt & VT_BYREF) && (tdesc->vt == VT_PTR))
4779     {
4780         tdesc = tdesc->u.lptdesc;
4781
4782         /* munch VT_PTR -> VT_USERDEFINED(interface) into VT_UNKNOWN or
4783          * VT_DISPATCH and VT_PTR -> VT_PTR -> VT_USERDEFINED(interface) into 
4784          * VT_BYREF|VT_DISPATCH or VT_BYREF|VT_UNKNOWN */
4785         if ((tdesc->vt == VT_USERDEFINED) ||
4786             ((tdesc->vt == VT_PTR) && (tdesc->u.lptdesc->vt == VT_USERDEFINED)))
4787         {
4788             VARTYPE vt_userdefined = 0;
4789             TYPEDESC *tdesc_userdefined = tdesc;
4790             if (tdesc->vt == VT_PTR)
4791             {
4792                 vt_userdefined = VT_BYREF;
4793                 tdesc_userdefined = tdesc->u.lptdesc;
4794             }
4795             hr = userdefined_to_variantvt(tinfo, tdesc_userdefined, &vt_userdefined);
4796             if ((hr == S_OK) && 
4797                 (((vt_userdefined & VT_TYPEMASK) == VT_UNKNOWN) ||
4798                  ((vt_userdefined & VT_TYPEMASK) == VT_DISPATCH)))
4799             {
4800                 *vt |= vt_userdefined;
4801                 return S_OK;
4802             }
4803         }
4804         *vt = VT_BYREF;
4805     }
4806
4807     switch (tdesc->vt)
4808     {
4809     case VT_HRESULT:
4810         *vt |= VT_ERROR;
4811         break;
4812     case VT_USERDEFINED:
4813         hr = userdefined_to_variantvt(tinfo, tdesc, vt);
4814         break;
4815     case VT_PTR:
4816         ERR("cannot convert VT_PTR into variant VT\n");
4817         hr = E_FAIL;
4818         break;
4819     default:
4820         *vt |= tdesc->vt;
4821         break;
4822     }
4823     return hr;
4824 }
4825
4826 /***********************************************************************
4827  *              DispCallFunc (OLEAUT32.@)
4828  */
4829 HRESULT WINAPI
4830 DispCallFunc(
4831     void* pvInstance, ULONG oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals,
4832     VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult
4833 ) {
4834     int i, argsize, argspos;
4835     DWORD *args;
4836     HRESULT hres;
4837
4838     TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
4839         pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg, pvargResult, V_VT(pvargResult)
4840     );
4841     /* DispCallFunc is only used to invoke methods belonging to an IDispatch-derived COM interface.
4842     So we need to add a first parameter to the list of arguments, to supply the interface pointer */
4843     argsize = 1;
4844     for (i=0;i<cActuals;i++) {
4845         TRACE("arg %d: type %d, size %d\n",i,prgvt[i],_argsize(prgvt[i]));
4846         dump_Variant(prgpvarg[i]);
4847         argsize += _argsize(prgvt[i]);
4848     }
4849     args = HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*argsize);
4850     args[0] = (DWORD)pvInstance;      /* this is the fake IDispatch interface pointer */
4851     argspos = 1;
4852     for (i=0;i<cActuals;i++) {
4853         VARIANT *arg = prgpvarg[i];
4854         TRACE("Storing arg %d (%d as %d)\n",i,V_VT(arg),prgvt[i]);
4855         _copy_arg(NULL, NULL, &args[argspos], arg, prgvt[i]);
4856         argspos += _argsize(prgvt[i]);
4857     }
4858
4859     if(pvargResult!=NULL && V_VT(pvargResult)==VT_EMPTY)
4860     {
4861         _invoke((*(FARPROC**)pvInstance)[oVft/4],cc,argsize,args);
4862         hres=S_OK;
4863     }
4864     else
4865     {
4866         FIXME("Do not know how to handle pvargResult %p. Expect crash ...\n",pvargResult);
4867         hres = _invoke((*(FARPROC**)pvInstance)[oVft/4],cc,argsize,args);
4868         FIXME("Method returned %lx\n",hres);
4869     }
4870     HeapFree(GetProcessHeap(),0,args);
4871     return hres;
4872 }
4873
4874 static HRESULT WINAPI ITypeInfo_fnInvoke(
4875     ITypeInfo2 *iface,
4876     VOID  *pIUnk,
4877     MEMBERID memid,
4878     UINT16 dwFlags,
4879     DISPPARAMS  *pDispParams,
4880     VARIANT  *pVarResult,
4881     EXCEPINFO  *pExcepInfo,
4882     UINT  *pArgErr)
4883 {
4884     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4885     int i;
4886     unsigned int func_index, var_index;
4887     TYPEKIND type_kind;
4888     HRESULT hres;
4889
4890     TRACE("(%p)(%p,id=%ld,flags=0x%08x,%p,%p,%p,%p) partial stub!\n",
4891       This,pIUnk,memid,dwFlags,pDispParams,pVarResult,pExcepInfo,pArgErr
4892     );
4893     dump_DispParms(pDispParams);
4894
4895     hres = ITypeInfo2_GetFuncIndexOfMemId(iface, memid, dwFlags, &func_index);
4896     if (SUCCEEDED(hres)) {
4897         FUNCDESC *func_desc;
4898
4899         hres = ITypeInfo2_GetFuncDesc(iface, func_index, &func_desc);
4900         if(FAILED(hres)) return hres;
4901         if (TRACE_ON(ole))
4902         {
4903             TRACE("invoking:\n");
4904             dump_FUNCDESC(func_desc);
4905         }
4906         
4907         switch (func_desc->funckind) {
4908         case FUNC_PUREVIRTUAL:
4909         case FUNC_VIRTUAL: {
4910             DWORD res;
4911             int   numargs, numargs2, argspos, args2pos;
4912             DWORD *args , *args2;
4913             VARIANT *rgvarg = HeapAlloc(GetProcessHeap(), 0, sizeof(VARIANT) * func_desc->cParams);
4914             memcpy(rgvarg,pDispParams->rgvarg,sizeof(VARIANT)*pDispParams->cArgs);
4915
4916             hres = S_OK;
4917             numargs = 1; /* sizeof(thisptr) */
4918             numargs2 = 0;
4919             for (i = 0; i < func_desc->cParams; i++) {
4920                 TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc;
4921
4922                 numargs += _argsize(tdesc->vt);
4923                 if (i>=pDispParams->cArgs) { /* arguments to return */
4924                     if (tdesc->vt == VT_PTR) {
4925                         numargs2        += _argsize(tdesc->u.lptdesc->vt);
4926                     } else {
4927                         FIXME("The variant type here should have been VT_PTR, not vt %d\n", tdesc->vt);
4928                         numargs2        += _argsize(tdesc->vt);
4929                     }
4930                 }
4931             }
4932
4933             args = HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*numargs);
4934             args2 = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD)*numargs2);
4935
4936             args[0] = (DWORD)pIUnk;
4937             argspos = 1; args2pos = 0;
4938             for (i = 0; i < func_desc->cParams; i++) {
4939                 ELEMDESC *elemdesc = &(func_desc->lprgelemdescParam[i]);
4940                 TYPEDESC *tdesc = &(elemdesc->tdesc);
4941                 USHORT paramFlags = elemdesc->u.paramdesc.wParamFlags;
4942                 int arglen = _argsize(tdesc->vt);
4943
4944                 if (i<pDispParams->cArgs) {
4945                     VARIANT *arg = &rgvarg[pDispParams->cArgs-i-1];
4946
4947                     if (paramFlags & PARAMFLAG_FOPT) {
4948                         if(i < func_desc->cParams - func_desc->cParamsOpt)
4949                             ERR("Parameter has PARAMFLAG_FOPT flag but is not one of last cParamOpt parameters\n");
4950                         if(V_VT(arg) == VT_EMPTY
4951                           || ((V_ISBYREF(arg)) && !V_BYREF(arg))) {
4952                                /* FIXME: Documentation says that we do this when parameter is left unspecified.
4953                                          How to determine it? */
4954
4955                             if(paramFlags & PARAMFLAG_FHASDEFAULT)
4956                                 FIXME("PARAMFLAG_FHASDEFAULT flag not supported\n");
4957                             V_VT(arg) = VT_ERROR;
4958                             V_ERROR(arg) = DISP_E_PARAMNOTFOUND;
4959                             arglen = _argsize(VT_ERROR);
4960                         }
4961                     }
4962                     hres = _copy_arg(iface, tdesc, &args[argspos], arg, tdesc->vt);
4963                     if (FAILED(hres)) goto func_fail;
4964                     argspos += arglen;
4965                 } else if (paramFlags & PARAMFLAG_FOPT) {
4966                     VARIANT *arg = &rgvarg[i];
4967
4968                     if (i < func_desc->cParams - func_desc->cParamsOpt)
4969                         ERR("Parameter has PARAMFLAG_FOPT flag but is not one of last cParamOpt parameters\n");
4970                     if (paramFlags & PARAMFLAG_FHASDEFAULT)
4971                         FIXME("PARAMFLAG_FHASDEFAULT flag not supported\n");
4972
4973                     V_VT(arg) = VT_ERROR;
4974                     V_ERROR(arg) = DISP_E_PARAMNOTFOUND;
4975                     arglen = _argsize(VT_ERROR);
4976                     hres = _copy_arg(iface, tdesc, &args[argspos], arg, tdesc->vt);
4977                     if (FAILED(hres)) goto func_fail;
4978                     argspos += arglen;
4979                 } else {
4980                     if (tdesc->vt == VT_PTR)
4981                         arglen = _argsize(tdesc->u.lptdesc->vt);
4982                     else
4983                         FIXME("set %d to pointer for get (type is %d)\n",i,tdesc->vt);
4984
4985                     /* Supply pointers for the rest, so propertyget works*/
4986                     args[argspos] = (DWORD)&args2[args2pos];
4987
4988                     /* If pointer to variant, pass reference it. */
4989                     if ((tdesc->vt == VT_PTR) &&
4990                         (tdesc->u.lptdesc->vt == VT_VARIANT) &&
4991                         pVarResult
4992                     )
4993                         args[argspos]= (DWORD)pVarResult;
4994                     argspos     += 1;
4995                     args2pos    += arglen;
4996                 }
4997             }
4998             if (func_desc->cParamsOpt < 0)
4999                 FIXME("Does not support optional parameters (%d)\n", func_desc->cParamsOpt);
5000
5001             res = _invoke((*(FARPROC**)pIUnk)[func_desc->oVft/4],
5002                     func_desc->callconv,
5003                     numargs,
5004                     args
5005             );
5006
5007             if (pVarResult) {
5008                 for (i = 0; i < func_desc->cParams; i++) {
5009                     USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
5010                     if (wParamFlags & PARAMFLAG_FRETVAL) {
5011                         ELEMDESC *elemdesc = &func_desc->lprgelemdescParam[i];
5012                         TYPEDESC *tdesc = &elemdesc->tdesc;
5013                         VARIANTARG varresult;
5014                         V_VT(&varresult) = 0;
5015                         hres = typedescvt_to_variantvt((ITypeInfo *)iface, tdesc, &V_VT(&varresult));
5016                         if (hres)
5017                             break;
5018                         /* FIXME: this is really messy - we should keep the
5019                          * args in VARIANTARGs rather than a DWORD array */
5020                         memcpy(&V_UI4(&varresult), &args[i+1], sizeof(DWORD));
5021                         if (TRACE_ON(ole))
5022                         {
5023                             TRACE("varresult: ");
5024                             dump_Variant(&varresult);
5025                         }
5026                         hres = VariantCopyInd(pVarResult, &varresult);
5027                         /* free data stored in varresult. Note that
5028                          * VariantClear doesn't do what we want because we are
5029                          * working with byref types. */
5030                         /* FIXME: clear safearrays, bstrs, records and
5031                          * variants here too */
5032                         if ((V_VT(&varresult) == (VT_UNKNOWN | VT_BYREF)) ||
5033                             (V_VT(&varresult) == (VT_DISPATCH | VT_BYREF)))
5034                             IUnknown_Release(*V_UNKNOWNREF(&varresult));
5035                         break;
5036                     }
5037                 }
5038             }
5039
5040             if ((func_desc->elemdescFunc.tdesc.vt == VT_HRESULT) && FAILED(res)) {
5041                 WARN("invoked function failed with error 0x%08lx\n", res);
5042                 hres = DISP_E_EXCEPTION;
5043                 if (pExcepInfo) pExcepInfo->scode = res;
5044             }
5045 func_fail:
5046             HeapFree(GetProcessHeap(), 0, rgvarg);
5047             HeapFree(GetProcessHeap(),0,args2);
5048             HeapFree(GetProcessHeap(),0,args);
5049             break;
5050         }
5051         case FUNC_DISPATCH:  {
5052            IDispatch *disp;
5053
5054            hres = IUnknown_QueryInterface((LPUNKNOWN)pIUnk,&IID_IDispatch,(LPVOID*)&disp);
5055            if (SUCCEEDED(hres)) {
5056                FIXME("Calling Invoke in IDispatch iface. untested!\n");
5057                hres = IDispatch_Invoke(
5058                                      disp,memid,&IID_NULL,LOCALE_USER_DEFAULT,dwFlags,pDispParams,
5059                                      pVarResult,pExcepInfo,pArgErr
5060                                      );
5061                if (FAILED(hres))
5062                    FIXME("IDispatch::Invoke failed with %08lx. (Could be not a real error?)\n", hres);
5063                IDispatch_Release(disp);
5064            } else
5065                FIXME("FUNC_DISPATCH used on object without IDispatch iface?\n");
5066            break;
5067         }
5068         default:
5069             FIXME("Unknown function invocation type %d\n", func_desc->funckind);
5070             hres = E_FAIL;
5071             break;
5072         }
5073
5074         ITypeInfo2_ReleaseFuncDesc(iface, func_desc);
5075         return hres;
5076
5077     } else if(SUCCEEDED(hres = ITypeInfo2_GetVarIndexOfMemId(iface, memid, &var_index))) {
5078         VARDESC *var_desc;
5079
5080         hres = ITypeInfo2_GetVarDesc(iface, var_index, &var_desc);
5081         if(FAILED(hres)) return hres;
5082         
5083         FIXME("varseek: Found memid, but variable-based invoking not supported\n");
5084         dump_VARDESC(var_desc);
5085         ITypeInfo2_ReleaseVarDesc(iface, var_desc);
5086         return E_NOTIMPL;
5087     }
5088
5089     /* not found, look for it in inherited interfaces */
5090     ITypeInfo2_GetTypeKind(iface, &type_kind);
5091     if(type_kind == TKIND_INTERFACE || type_kind == TKIND_DISPATCH) {
5092         HREFTYPE ref_type;
5093         if(SUCCEEDED(ITypeInfo2_GetRefTypeOfImplType(iface, 0, &ref_type))) {
5094             /* recursive search */
5095             ITypeInfo *pTInfo;
5096             hres = ITypeInfo_GetRefTypeInfo(iface, ref_type, &pTInfo);
5097             if(SUCCEEDED(hres)){
5098                 hres = ITypeInfo_Invoke(pTInfo,pIUnk,memid,dwFlags,pDispParams,pVarResult,pExcepInfo,pArgErr);
5099                 ITypeInfo_Release(pTInfo);
5100                 return hres;
5101             }
5102             WARN("Could not search inherited interface!\n");
5103         }
5104     }
5105     ERR("did not find member id %08lx, flags %d!\n", memid, dwFlags);
5106     return DISP_E_MEMBERNOTFOUND;
5107 }
5108
5109 /* ITypeInfo::GetDocumentation
5110  *
5111  * Retrieves the documentation string, the complete Help file name and path,
5112  * and the context ID for the Help topic for a specified type description.
5113  *
5114  * (Can be tested by the Visual Basic Editor in Word for instance.)
5115  */
5116 static HRESULT WINAPI ITypeInfo_fnGetDocumentation( ITypeInfo2 *iface,
5117         MEMBERID memid, BSTR  *pBstrName, BSTR  *pBstrDocString,
5118         DWORD  *pdwHelpContext, BSTR  *pBstrHelpFile)
5119 {
5120     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5121     TLBFuncDesc * pFDesc;
5122     TLBVarDesc * pVDesc;
5123     TRACE("(%p) memid %ld Name(%p) DocString(%p)"
5124           " HelpContext(%p) HelpFile(%p)\n",
5125         This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
5126     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
5127         if(pBstrName)
5128             *pBstrName=SysAllocString(This->Name);
5129         if(pBstrDocString)
5130             *pBstrDocString=SysAllocString(This->DocString);
5131         if(pdwHelpContext)
5132             *pdwHelpContext=This->dwHelpContext;
5133         if(pBstrHelpFile)
5134             *pBstrHelpFile=SysAllocString(This->DocString);/* FIXME */
5135         return S_OK;
5136     }else {/* for a member */
5137     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
5138         if(pFDesc->funcdesc.memid==memid){
5139           if(pBstrName)
5140             *pBstrName = SysAllocString(pFDesc->Name);
5141           if(pBstrDocString)
5142             *pBstrDocString=SysAllocString(pFDesc->HelpString);
5143           if(pdwHelpContext)
5144             *pdwHelpContext=pFDesc->helpcontext;
5145           return S_OK;
5146         }
5147     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
5148         if(pVDesc->vardesc.memid==memid){
5149             if(pBstrName)
5150               *pBstrName = SysAllocString(pVDesc->Name);
5151             if(pBstrDocString)
5152               *pBstrDocString=SysAllocString(pVDesc->HelpString);
5153             if(pdwHelpContext)
5154               *pdwHelpContext=pVDesc->HelpContext;
5155             return S_OK;
5156         }
5157     }
5158     WARN("member %ld not found\n", memid);
5159     return TYPE_E_ELEMENTNOTFOUND;
5160 }
5161
5162 /*  ITypeInfo::GetDllEntry
5163  *
5164  * Retrieves a description or specification of an entry point for a function
5165  * in a DLL.
5166  */
5167 static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid,
5168         INVOKEKIND invKind, BSTR  *pBstrDllName, BSTR  *pBstrName,
5169         WORD  *pwOrdinal)
5170 {
5171     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5172     TLBFuncDesc *pFDesc;
5173
5174     FIXME("(%p, memid %lx, %d, %p, %p, %p), partial stub!\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
5175
5176     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
5177         if(pFDesc->funcdesc.memid==memid){
5178             dump_TypeInfo(This);
5179             dump_TLBFuncDescOne(pFDesc);
5180
5181             /* FIXME: This is wrong, but how do you find that out? */
5182             if (pBstrDllName) {
5183                 static const WCHAR oleaut32W[] = {'O','L','E','A','U','T','3','2','.','D','L','L',0};
5184                 *pBstrDllName = SysAllocString(oleaut32W);
5185             }
5186
5187             if (HIWORD(pFDesc->Entry) && (pFDesc->Entry != (void*)-1)) {
5188                 if (pBstrName)
5189                     *pBstrName = SysAllocString(pFDesc->Entry);
5190                 if (pwOrdinal)
5191                     *pwOrdinal = -1;
5192                 return S_OK;
5193             }
5194             if (pBstrName)
5195                 *pBstrName = NULL;
5196             if (pwOrdinal)
5197                 *pwOrdinal = (DWORD)pFDesc->Entry;
5198             return S_OK;
5199         }
5200     return E_FAIL;
5201 }
5202
5203 /* ITypeInfo::GetRefTypeInfo
5204  *
5205  * If a type description references other type descriptions, it retrieves
5206  * the referenced type descriptions.
5207  */
5208 static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo(
5209         ITypeInfo2 *iface,
5210         HREFTYPE hRefType,
5211         ITypeInfo  **ppTInfo)
5212 {
5213     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5214     HRESULT result = E_FAIL;
5215
5216     if (hRefType == -1 &&
5217         (((ITypeInfoImpl*) This)->TypeAttr.typekind   == TKIND_DISPATCH) &&
5218         (((ITypeInfoImpl*) This)->TypeAttr.wTypeFlags &  TYPEFLAG_FDUAL))
5219     {
5220           /* when we meet a DUAL dispinterface, we must create the interface
5221           * version of it.
5222           */
5223           ITypeInfoImpl* pTypeInfoImpl = (ITypeInfoImpl*) ITypeInfo_Constructor();
5224
5225
5226           /* the interface version contains the same information as the dispinterface
5227            * copy the contents of the structs.
5228            */
5229           *pTypeInfoImpl = *This;
5230           pTypeInfoImpl->ref = 1;
5231
5232           /* change the type to interface */
5233           pTypeInfoImpl->TypeAttr.typekind = TKIND_INTERFACE;
5234
5235           *ppTInfo = (ITypeInfo*) pTypeInfoImpl;
5236
5237           ITypeInfo_AddRef((ITypeInfo*) pTypeInfoImpl);
5238
5239           result = S_OK;
5240
5241     } else {
5242         TLBRefType *pRefType;
5243         for(pRefType = This->reflist; pRefType; pRefType = pRefType->next) {
5244             if(pRefType->reference == hRefType)
5245                 break;
5246         }
5247         if(!pRefType)
5248           FIXME("Can't find pRefType for ref %lx\n", hRefType);
5249         if(pRefType && hRefType != -1) {
5250             ITypeLib *pTLib = NULL;
5251
5252             if(pRefType->pImpTLInfo == TLB_REF_INTERNAL) {
5253                 UINT Index;
5254                 result = ITypeInfo_GetContainingTypeLib(iface, &pTLib, &Index);
5255             } else {
5256                 if(pRefType->pImpTLInfo->pImpTypeLib) {
5257                     TRACE("typeinfo in imported typelib that is already loaded\n");
5258                     pTLib = (ITypeLib*)pRefType->pImpTLInfo->pImpTypeLib;
5259                     ITypeLib2_AddRef((ITypeLib*) pTLib);
5260                     result = S_OK;
5261                 } else {
5262                     TRACE("typeinfo in imported typelib that isn't already loaded\n");
5263                     result = LoadRegTypeLib( &pRefType->pImpTLInfo->guid,
5264                                              pRefType->pImpTLInfo->wVersionMajor,
5265                                              pRefType->pImpTLInfo->wVersionMinor,
5266                                              pRefType->pImpTLInfo->lcid,
5267                                              &pTLib);
5268
5269                     if(!SUCCEEDED(result)) {
5270                         BSTR libnam=SysAllocString(pRefType->pImpTLInfo->name);
5271                         result=LoadTypeLib(libnam, &pTLib);
5272                         SysFreeString(libnam);
5273                     }
5274                     if(SUCCEEDED(result)) {
5275                         pRefType->pImpTLInfo->pImpTypeLib = (ITypeLibImpl*)pTLib;
5276                         ITypeLib2_AddRef(pTLib);
5277                     }
5278                 }
5279             }
5280             if(SUCCEEDED(result)) {
5281                 if(pRefType->index == TLB_REF_USE_GUID)
5282                     result = ITypeLib2_GetTypeInfoOfGuid(pTLib,
5283                                                          &pRefType->guid,
5284                                                          ppTInfo);
5285                 else
5286                     result = ITypeLib2_GetTypeInfo(pTLib, pRefType->index,
5287                                                    ppTInfo);
5288             }
5289             if (pTLib != NULL)
5290                 ITypeLib2_Release(pTLib);
5291         }
5292     }
5293
5294     TRACE("(%p) hreftype 0x%04lx loaded %s (%p)\n", This, hRefType,
5295           SUCCEEDED(result)? "SUCCESS":"FAILURE", *ppTInfo);
5296     return result;
5297 }
5298
5299 /* ITypeInfo::AddressOfMember
5300  *
5301  * Retrieves the addresses of static functions or variables, such as those
5302  * defined in a DLL.
5303  */
5304 static HRESULT WINAPI ITypeInfo_fnAddressOfMember( ITypeInfo2 *iface,
5305         MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
5306 {
5307     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5308     FIXME("(%p) stub!\n", This);
5309     return S_OK;
5310 }
5311
5312 /* ITypeInfo::CreateInstance
5313  *
5314  * Creates a new instance of a type that describes a component object class
5315  * (coclass).
5316  */
5317 static HRESULT WINAPI ITypeInfo_fnCreateInstance( ITypeInfo2 *iface,
5318         IUnknown *pUnk, REFIID riid, VOID  **ppvObj)
5319 {
5320     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5321     FIXME("(%p) stub!\n", This);
5322     return S_OK;
5323 }
5324
5325 /* ITypeInfo::GetMops
5326  *
5327  * Retrieves marshalling information.
5328  */
5329 static HRESULT WINAPI ITypeInfo_fnGetMops( ITypeInfo2 *iface, MEMBERID memid,
5330                                 BSTR  *pBstrMops)
5331 {
5332     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5333     FIXME("(%p) stub!\n", This);
5334     return S_OK;
5335 }
5336
5337 /* ITypeInfo::GetContainingTypeLib
5338  *
5339  * Retrieves the containing type library and the index of the type description
5340  * within that type library.
5341  */
5342 static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( ITypeInfo2 *iface,
5343         ITypeLib  * *ppTLib, UINT  *pIndex)
5344 {
5345     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5346     
5347     /* If a pointer is null, we simply ignore it, the ATL in particular passes pIndex as 0 */
5348     if (pIndex) {
5349       *pIndex=This->index;
5350       TRACE("returning pIndex=%d\n", *pIndex);
5351     }
5352     
5353     if (ppTLib) {
5354       *ppTLib=(LPTYPELIB )(This->pTypeLib);
5355       ITypeLib2_AddRef(*ppTLib);
5356       TRACE("returning ppTLib=%p\n", *ppTLib);
5357     }
5358     
5359     return S_OK;
5360 }
5361
5362 /* ITypeInfo::ReleaseTypeAttr
5363  *
5364  * Releases a TYPEATTR previously returned by GetTypeAttr.
5365  *
5366  */
5367 static void WINAPI ITypeInfo_fnReleaseTypeAttr( ITypeInfo2 *iface,
5368         TYPEATTR* pTypeAttr)
5369 {
5370     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5371     TRACE("(%p)->(%p)\n", This, pTypeAttr);
5372     if(This->TypeAttr.typekind == TKIND_ALIAS)
5373         free_deep_typedesc(&pTypeAttr->tdescAlias);
5374     HeapFree(GetProcessHeap(), 0, pTypeAttr);
5375 }
5376
5377 /* ITypeInfo::ReleaseFuncDesc
5378  *
5379  * Releases a FUNCDESC previously returned by GetFuncDesc. *
5380  */
5381 static void WINAPI ITypeInfo_fnReleaseFuncDesc(
5382         ITypeInfo2 *iface,
5383         FUNCDESC *pFuncDesc)
5384 {
5385     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5386     TRACE("(%p)->(%p)\n", This, pFuncDesc);
5387 }
5388
5389 /* ITypeInfo::ReleaseVarDesc
5390  *
5391  * Releases a VARDESC previously returned by GetVarDesc.
5392  */
5393 static void WINAPI ITypeInfo_fnReleaseVarDesc( ITypeInfo2 *iface,
5394         VARDESC *pVarDesc)
5395 {
5396     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5397     TRACE("(%p)->(%p)\n", This, pVarDesc);
5398 }
5399
5400 /* ITypeInfo2::GetTypeKind
5401  *
5402  * Returns the TYPEKIND enumeration quickly, without doing any allocations.
5403  *
5404  */
5405 static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo2 * iface,
5406     TYPEKIND *pTypeKind)
5407 {
5408     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5409     *pTypeKind=This->TypeAttr.typekind;
5410     TRACE("(%p) type 0x%0x\n", This,*pTypeKind);
5411     return S_OK;
5412 }
5413
5414 /* ITypeInfo2::GetTypeFlags
5415  *
5416  * Returns the type flags without any allocations. This returns a DWORD type
5417  * flag, which expands the type flags without growing the TYPEATTR (type
5418  * attribute).
5419  *
5420  */
5421 static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo2 *iface, ULONG *pTypeFlags)
5422 {
5423     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5424     *pTypeFlags=This->TypeAttr.wTypeFlags;
5425     TRACE("(%p) flags 0x%lx\n", This,*pTypeFlags);
5426     return S_OK;
5427 }
5428
5429 /* ITypeInfo2::GetFuncIndexOfMemId
5430  * Binds to a specific member based on a known DISPID, where the member name
5431  * is not known (for example, when binding to a default member).
5432  *
5433  */
5434 static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo2 * iface,
5435     MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex)
5436 {
5437     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5438     TLBFuncDesc *pFuncInfo;
5439     int i;
5440     HRESULT result;
5441
5442     for(i = 0, pFuncInfo = This->funclist; pFuncInfo; i++, pFuncInfo=pFuncInfo->next)
5443         if(memid == pFuncInfo->funcdesc.memid && (invKind & pFuncInfo->funcdesc.invkind))
5444             break;
5445     if(pFuncInfo) {
5446         *pFuncIndex = i;
5447         result = S_OK;
5448     } else
5449         result = TYPE_E_ELEMENTNOTFOUND;
5450
5451     TRACE("(%p) memid 0x%08lx invKind 0x%04x -> %s\n", This,
5452           memid, invKind, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
5453     return result;
5454 }
5455
5456 /* TypeInfo2::GetVarIndexOfMemId
5457  *
5458  * Binds to a specific member based on a known DISPID, where the member name
5459  * is not known (for example, when binding to a default member).
5460  *
5461  */
5462 static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( ITypeInfo2 * iface,
5463     MEMBERID memid, UINT *pVarIndex)
5464 {
5465     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5466     TLBVarDesc *pVarInfo;
5467     int i;
5468     HRESULT result;
5469     for(i=0, pVarInfo=This->varlist; pVarInfo &&
5470             memid != pVarInfo->vardesc.memid; i++, pVarInfo=pVarInfo->next)
5471         ;
5472     if(pVarInfo) {
5473         *pVarIndex = i;
5474         result = S_OK;
5475     } else
5476         result = TYPE_E_ELEMENTNOTFOUND;
5477
5478     TRACE("(%p) memid 0x%08lx -> %s\n", This,
5479           memid, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
5480     return result;
5481 }
5482
5483 /* ITypeInfo2::GetCustData
5484  *
5485  * Gets the custom data
5486  */
5487 static HRESULT WINAPI ITypeInfo2_fnGetCustData(
5488         ITypeInfo2 * iface,
5489         REFGUID guid,
5490         VARIANT *pVarVal)
5491 {
5492     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5493     TLBCustData *pCData;
5494
5495     for(pCData=This->pCustData; pCData; pCData = pCData->next)
5496         if( IsEqualIID(guid, &pCData->guid)) break;
5497
5498     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
5499
5500     if(pCData)
5501     {
5502         VariantInit( pVarVal);
5503         VariantCopy( pVarVal, &pCData->data);
5504         return S_OK;
5505     }
5506     return E_INVALIDARG;  /* FIXME: correct? */
5507 }
5508
5509 /* ITypeInfo2::GetFuncCustData
5510  *
5511  * Gets the custom data
5512  */
5513 static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData(
5514         ITypeInfo2 * iface,
5515         UINT index,
5516         REFGUID guid,
5517         VARIANT *pVarVal)
5518 {
5519     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5520     TLBCustData *pCData=NULL;
5521     TLBFuncDesc * pFDesc;
5522     int i;
5523     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
5524             pFDesc=pFDesc->next);
5525
5526     if(pFDesc)
5527         for(pCData=pFDesc->pCustData; pCData; pCData = pCData->next)
5528             if( IsEqualIID(guid, &pCData->guid)) break;
5529
5530     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
5531
5532     if(pCData){
5533         VariantInit( pVarVal);
5534         VariantCopy( pVarVal, &pCData->data);
5535         return S_OK;
5536     }
5537     return E_INVALIDARG;  /* FIXME: correct? */
5538 }
5539
5540 /* ITypeInfo2::GetParamCustData
5541  *
5542  * Gets the custom data
5543  */
5544 static HRESULT WINAPI ITypeInfo2_fnGetParamCustData(
5545         ITypeInfo2 * iface,
5546         UINT indexFunc,
5547         UINT indexParam,
5548         REFGUID guid,
5549         VARIANT *pVarVal)
5550 {
5551     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5552     TLBCustData *pCData=NULL;
5553     TLBFuncDesc * pFDesc;
5554     int i;
5555
5556     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,pFDesc=pFDesc->next);
5557
5558     if(pFDesc && indexParam >=0 && indexParam<pFDesc->funcdesc.cParams)
5559         for(pCData=pFDesc->pParamDesc[indexParam].pCustData; pCData;
5560                 pCData = pCData->next)
5561             if( IsEqualIID(guid, &pCData->guid)) break;
5562
5563     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
5564
5565     if(pCData)
5566     {
5567         VariantInit( pVarVal);
5568         VariantCopy( pVarVal, &pCData->data);
5569         return S_OK;
5570     }
5571     return E_INVALIDARG;  /* FIXME: correct? */
5572 }
5573
5574 /* ITypeInfo2::GetVarCustData
5575  *
5576  * Gets the custom data
5577  */
5578 static HRESULT WINAPI ITypeInfo2_fnGetVarCustData(
5579         ITypeInfo2 * iface,
5580         UINT index,
5581         REFGUID guid,
5582         VARIANT *pVarVal)
5583 {
5584     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5585     TLBCustData *pCData=NULL;
5586     TLBVarDesc * pVDesc;
5587     int i;
5588
5589     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next);
5590
5591     if(pVDesc)
5592     {
5593       for(pCData=pVDesc->pCustData; pCData; pCData = pCData->next)
5594       {
5595         if( IsEqualIID(guid, &pCData->guid)) break;
5596       }
5597     }
5598
5599     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
5600
5601     if(pCData)
5602     {
5603         VariantInit( pVarVal);
5604         VariantCopy( pVarVal, &pCData->data);
5605         return S_OK;
5606     }
5607     return E_INVALIDARG;  /* FIXME: correct? */
5608 }
5609
5610 /* ITypeInfo2::GetImplCustData
5611  *
5612  * Gets the custom data
5613  */
5614 static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData(
5615         ITypeInfo2 * iface,
5616         UINT index,
5617         REFGUID guid,
5618         VARIANT *pVarVal)
5619 {
5620     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5621     TLBCustData *pCData=NULL;
5622     TLBImplType * pRDesc;
5623     int i;
5624
5625     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++, pRDesc=pRDesc->next);
5626
5627     if(pRDesc)
5628     {
5629       for(pCData=pRDesc->pCustData; pCData; pCData = pCData->next)
5630       {
5631         if( IsEqualIID(guid, &pCData->guid)) break;
5632       }
5633     }
5634
5635     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
5636
5637     if(pCData)
5638     {
5639         VariantInit( pVarVal);
5640         VariantCopy( pVarVal, &pCData->data);
5641         return S_OK;
5642     }
5643     return E_INVALIDARG;  /* FIXME: correct? */
5644 }
5645
5646 /* ITypeInfo2::GetDocumentation2
5647  *
5648  * Retrieves the documentation string, the complete Help file name and path,
5649  * the localization context to use, and the context ID for the library Help
5650  * topic in the Help file.
5651  *
5652  */
5653 static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2(
5654         ITypeInfo2 * iface,
5655         MEMBERID memid,
5656         LCID lcid,
5657         BSTR *pbstrHelpString,
5658         DWORD *pdwHelpStringContext,
5659         BSTR *pbstrHelpStringDll)
5660 {
5661     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5662     TLBFuncDesc * pFDesc;
5663     TLBVarDesc * pVDesc;
5664     TRACE("(%p) memid %ld lcid(0x%lx)  HelpString(%p) "
5665           "HelpStringContext(%p) HelpStringDll(%p)\n",
5666           This, memid, lcid, pbstrHelpString, pdwHelpStringContext,
5667           pbstrHelpStringDll );
5668     /* the help string should be obtained from the helpstringdll,
5669      * using the _DLLGetDocumentation function, based on the supplied
5670      * lcid. Nice to do sometime...
5671      */
5672     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
5673         if(pbstrHelpString)
5674             *pbstrHelpString=SysAllocString(This->Name);
5675         if(pdwHelpStringContext)
5676             *pdwHelpStringContext=This->dwHelpStringContext;
5677         if(pbstrHelpStringDll)
5678             *pbstrHelpStringDll=
5679                 SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
5680         return S_OK;
5681     }else {/* for a member */
5682     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
5683         if(pFDesc->funcdesc.memid==memid){
5684              if(pbstrHelpString)
5685                 *pbstrHelpString=SysAllocString(pFDesc->HelpString);
5686             if(pdwHelpStringContext)
5687                 *pdwHelpStringContext=pFDesc->HelpStringContext;
5688             if(pbstrHelpStringDll)
5689                 *pbstrHelpStringDll=
5690                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
5691         return S_OK;
5692     }
5693     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
5694         if(pVDesc->vardesc.memid==memid){
5695              if(pbstrHelpString)
5696                 *pbstrHelpString=SysAllocString(pVDesc->HelpString);
5697             if(pdwHelpStringContext)
5698                 *pdwHelpStringContext=pVDesc->HelpStringContext;
5699             if(pbstrHelpStringDll)
5700                 *pbstrHelpStringDll=
5701                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
5702             return S_OK;
5703         }
5704     }
5705     return TYPE_E_ELEMENTNOTFOUND;
5706 }
5707
5708 /* ITypeInfo2::GetAllCustData
5709  *
5710  * Gets all custom data items for the Type info.
5711  *
5712  */
5713 static HRESULT WINAPI ITypeInfo2_fnGetAllCustData(
5714         ITypeInfo2 * iface,
5715         CUSTDATA *pCustData)
5716 {
5717     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5718     TLBCustData *pCData;
5719     int i;
5720
5721     TRACE("(%p) returning %d items\n", This, This->ctCustData);
5722
5723     pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
5724     if(pCustData->prgCustData ){
5725         pCustData->cCustData=This->ctCustData;
5726         for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
5727             pCustData->prgCustData[i].guid=pCData->guid;
5728             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
5729         }
5730     }else{
5731         ERR(" OUT OF MEMORY! \n");
5732         return E_OUTOFMEMORY;
5733     }
5734     return S_OK;
5735 }
5736
5737 /* ITypeInfo2::GetAllFuncCustData
5738  *
5739  * Gets all custom data items for the specified Function
5740  *
5741  */
5742 static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData(
5743         ITypeInfo2 * iface,
5744         UINT index,
5745         CUSTDATA *pCustData)
5746 {
5747     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5748     TLBCustData *pCData;
5749     TLBFuncDesc * pFDesc;
5750     int i;
5751     TRACE("(%p) index %d\n", This, index);
5752     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
5753             pFDesc=pFDesc->next)
5754         ;
5755     if(pFDesc){
5756         pCustData->prgCustData =
5757             TLB_Alloc(pFDesc->ctCustData * sizeof(CUSTDATAITEM));
5758         if(pCustData->prgCustData ){
5759             pCustData->cCustData=pFDesc->ctCustData;
5760             for(i=0, pCData=pFDesc->pCustData; pCData; i++,
5761                     pCData = pCData->next){
5762                 pCustData->prgCustData[i].guid=pCData->guid;
5763                 VariantCopy(& pCustData->prgCustData[i].varValue,
5764                         & pCData->data);
5765             }
5766         }else{
5767             ERR(" OUT OF MEMORY! \n");
5768             return E_OUTOFMEMORY;
5769         }
5770         return S_OK;
5771     }
5772     return TYPE_E_ELEMENTNOTFOUND;
5773 }
5774
5775 /* ITypeInfo2::GetAllParamCustData
5776  *
5777  * Gets all custom data items for the Functions
5778  *
5779  */
5780 static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo2 * iface,
5781     UINT indexFunc, UINT indexParam, CUSTDATA *pCustData)
5782 {
5783     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5784     TLBCustData *pCData=NULL;
5785     TLBFuncDesc * pFDesc;
5786     int i;
5787     TRACE("(%p) index %d\n", This, indexFunc);
5788     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,
5789             pFDesc=pFDesc->next)
5790         ;
5791     if(pFDesc && indexParam >=0 && indexParam<pFDesc->funcdesc.cParams){
5792         pCustData->prgCustData =
5793             TLB_Alloc(pFDesc->pParamDesc[indexParam].ctCustData *
5794                     sizeof(CUSTDATAITEM));
5795         if(pCustData->prgCustData ){
5796             pCustData->cCustData=pFDesc->pParamDesc[indexParam].ctCustData;
5797             for(i=0, pCData=pFDesc->pParamDesc[indexParam].pCustData;
5798                     pCData; i++, pCData = pCData->next){
5799                 pCustData->prgCustData[i].guid=pCData->guid;
5800                 VariantCopy(& pCustData->prgCustData[i].varValue,
5801                         & pCData->data);
5802             }
5803         }else{
5804             ERR(" OUT OF MEMORY! \n");
5805             return E_OUTOFMEMORY;
5806         }
5807         return S_OK;
5808     }
5809     return TYPE_E_ELEMENTNOTFOUND;
5810 }
5811
5812 /* ITypeInfo2::GetAllVarCustData
5813  *
5814  * Gets all custom data items for the specified Variable
5815  *
5816  */
5817 static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo2 * iface,
5818     UINT index, CUSTDATA *pCustData)
5819 {
5820     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5821     TLBCustData *pCData;
5822     TLBVarDesc * pVDesc;
5823     int i;
5824     TRACE("(%p) index %d\n", This, index);
5825     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++,
5826             pVDesc=pVDesc->next)
5827         ;
5828     if(pVDesc){
5829         pCustData->prgCustData =
5830             TLB_Alloc(pVDesc->ctCustData * sizeof(CUSTDATAITEM));
5831         if(pCustData->prgCustData ){
5832             pCustData->cCustData=pVDesc->ctCustData;
5833             for(i=0, pCData=pVDesc->pCustData; pCData; i++,
5834                     pCData = pCData->next){
5835                 pCustData->prgCustData[i].guid=pCData->guid;
5836                 VariantCopy(& pCustData->prgCustData[i].varValue,
5837                         & pCData->data);
5838             }
5839         }else{
5840             ERR(" OUT OF MEMORY! \n");
5841             return E_OUTOFMEMORY;
5842         }
5843         return S_OK;
5844     }
5845     return TYPE_E_ELEMENTNOTFOUND;
5846 }
5847
5848 /* ITypeInfo2::GetAllImplCustData
5849  *
5850  * Gets all custom data items for the specified implementation type
5851  *
5852  */
5853 static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData(
5854         ITypeInfo2 * iface,
5855         UINT index,
5856         CUSTDATA *pCustData)
5857 {
5858     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5859     TLBCustData *pCData;
5860     TLBImplType * pRDesc;
5861     int i;
5862     TRACE("(%p) index %d\n", This, index);
5863     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++,
5864             pRDesc=pRDesc->next)
5865         ;
5866     if(pRDesc){
5867         pCustData->prgCustData =
5868             TLB_Alloc(pRDesc->ctCustData * sizeof(CUSTDATAITEM));
5869         if(pCustData->prgCustData ){
5870             pCustData->cCustData=pRDesc->ctCustData;
5871             for(i=0, pCData=pRDesc->pCustData; pCData; i++,
5872                     pCData = pCData->next){
5873                 pCustData->prgCustData[i].guid=pCData->guid;
5874                 VariantCopy(& pCustData->prgCustData[i].varValue,
5875                         & pCData->data);
5876             }
5877         }else{
5878             ERR(" OUT OF MEMORY! \n");
5879             return E_OUTOFMEMORY;
5880         }
5881         return S_OK;
5882     }
5883     return TYPE_E_ELEMENTNOTFOUND;
5884 }
5885
5886 static const ITypeInfo2Vtbl tinfvt =
5887 {
5888
5889     ITypeInfo_fnQueryInterface,
5890     ITypeInfo_fnAddRef,
5891     ITypeInfo_fnRelease,
5892
5893     ITypeInfo_fnGetTypeAttr,
5894     ITypeInfo_fnGetTypeComp,
5895     ITypeInfo_fnGetFuncDesc,
5896     ITypeInfo_fnGetVarDesc,
5897     ITypeInfo_fnGetNames,
5898     ITypeInfo_fnGetRefTypeOfImplType,
5899     ITypeInfo_fnGetImplTypeFlags,
5900     ITypeInfo_fnGetIDsOfNames,
5901     ITypeInfo_fnInvoke,
5902     ITypeInfo_fnGetDocumentation,
5903     ITypeInfo_fnGetDllEntry,
5904     ITypeInfo_fnGetRefTypeInfo,
5905     ITypeInfo_fnAddressOfMember,
5906     ITypeInfo_fnCreateInstance,
5907     ITypeInfo_fnGetMops,
5908     ITypeInfo_fnGetContainingTypeLib,
5909     ITypeInfo_fnReleaseTypeAttr,
5910     ITypeInfo_fnReleaseFuncDesc,
5911     ITypeInfo_fnReleaseVarDesc,
5912
5913     ITypeInfo2_fnGetTypeKind,
5914     ITypeInfo2_fnGetTypeFlags,
5915     ITypeInfo2_fnGetFuncIndexOfMemId,
5916     ITypeInfo2_fnGetVarIndexOfMemId,
5917     ITypeInfo2_fnGetCustData,
5918     ITypeInfo2_fnGetFuncCustData,
5919     ITypeInfo2_fnGetParamCustData,
5920     ITypeInfo2_fnGetVarCustData,
5921     ITypeInfo2_fnGetImplTypeCustData,
5922     ITypeInfo2_fnGetDocumentation2,
5923     ITypeInfo2_fnGetAllCustData,
5924     ITypeInfo2_fnGetAllFuncCustData,
5925     ITypeInfo2_fnGetAllParamCustData,
5926     ITypeInfo2_fnGetAllVarCustData,
5927     ITypeInfo2_fnGetAllImplTypeCustData,
5928 };
5929
5930 /******************************************************************************
5931  * CreateDispTypeInfo [OLEAUT32.31]
5932  *
5933  * Build type information for an object so it can be called through an
5934  * IDispatch interface.
5935  *
5936  * RETURNS
5937  *  Success: S_OK. pptinfo contains the created ITypeInfo object.
5938  *  Failure: E_INVALIDARG, if one or more arguments is invalid.
5939  *
5940  * NOTES
5941  *  This call allows an objects methods to be accessed through IDispatch, by
5942  *  building an ITypeInfo object that IDispatch can use to call through.
5943  */
5944 HRESULT WINAPI CreateDispTypeInfo(
5945         INTERFACEDATA *pidata, /* [I] Description of the interface to build type info for */
5946         LCID lcid, /* [I] Locale Id */
5947         ITypeInfo **pptinfo) /* [O] Destination for created ITypeInfo object */
5948 {
5949     ITypeInfoImpl *pTIImpl;
5950     int param, func;
5951     TLBFuncDesc **ppFuncDesc;
5952
5953     pTIImpl = (ITypeInfoImpl*)ITypeInfo_Constructor();
5954     pTIImpl->pTypeLib = NULL;
5955     pTIImpl->index = 0;
5956     pTIImpl->Name = NULL;
5957     pTIImpl->dwHelpContext = -1;
5958     memset(&pTIImpl->TypeAttr.guid, 0, sizeof(GUID));
5959     pTIImpl->TypeAttr.lcid = lcid;
5960     pTIImpl->TypeAttr.typekind = TKIND_COCLASS;
5961     pTIImpl->TypeAttr.wMajorVerNum = 0;
5962     pTIImpl->TypeAttr.wMinorVerNum = 0;
5963     pTIImpl->TypeAttr.cbAlignment = 2;
5964     pTIImpl->TypeAttr.cbSizeInstance = -1;
5965     pTIImpl->TypeAttr.cbSizeVft = -1;
5966     pTIImpl->TypeAttr.cFuncs = 0;
5967     pTIImpl->TypeAttr.cImplTypes = 1;
5968     pTIImpl->TypeAttr.cVars = 0;
5969     pTIImpl->TypeAttr.wTypeFlags = 0;
5970
5971     ppFuncDesc = &pTIImpl->funclist;
5972     for(func = 0; func < pidata->cMembers; func++) {
5973         METHODDATA *md = pidata->pmethdata + func;
5974         *ppFuncDesc = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppFuncDesc));
5975         (*ppFuncDesc)->Name = SysAllocString(md->szName);
5976         (*ppFuncDesc)->funcdesc.memid = md->dispid;
5977         (*ppFuncDesc)->funcdesc.invkind = md->wFlags;
5978         (*ppFuncDesc)->funcdesc.callconv = md->cc;
5979         (*ppFuncDesc)->funcdesc.cParams = md->cArgs;
5980         (*ppFuncDesc)->funcdesc.cParamsOpt = 0;
5981         (*ppFuncDesc)->funcdesc.oVft = md->iMeth;
5982         (*ppFuncDesc)->funcdesc.wFuncFlags = 0; /*??*/
5983         (*ppFuncDesc)->funcdesc.elemdescFunc.tdesc.vt = md->vtReturn;
5984         (*ppFuncDesc)->funcdesc.lprgelemdescParam = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5985                                                               md->cArgs * sizeof(ELEMDESC));
5986         (*ppFuncDesc)->pParamDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5987                                               md->cArgs * sizeof(TLBParDesc));
5988         for(param = 0; param < md->cArgs; param++) {
5989             (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].tdesc.vt = md->ppdata[param].vt;
5990             (*ppFuncDesc)->pParamDesc[param].Name = SysAllocString(md->ppdata[param].szName);
5991         }
5992         ppFuncDesc = &(*ppFuncDesc)->next;
5993     }        
5994     *pptinfo = (ITypeInfo*)pTIImpl;
5995     return S_OK;
5996
5997 }
5998
5999 static HRESULT WINAPI ITypeComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
6000 {
6001     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
6002
6003     return ITypeInfo_QueryInterface((ITypeInfo *)This, riid, ppv);
6004 }
6005
6006 static ULONG WINAPI ITypeComp_fnAddRef(ITypeComp * iface)
6007 {
6008     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
6009
6010     return ITypeInfo_AddRef((ITypeInfo *)This);
6011 }
6012
6013 static ULONG WINAPI ITypeComp_fnRelease(ITypeComp * iface)
6014 {
6015     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
6016
6017     return ITypeInfo_Release((ITypeInfo *)This);
6018 }
6019
6020 static HRESULT WINAPI ITypeComp_fnBind(
6021     ITypeComp * iface,
6022     OLECHAR * szName,
6023     ULONG lHash,
6024     WORD wFlags,
6025     ITypeInfo ** ppTInfo,
6026     DESCKIND * pDescKind,
6027     BINDPTR * pBindPtr)
6028 {
6029     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
6030     TLBFuncDesc * pFDesc;
6031     TLBVarDesc * pVDesc;
6032
6033     TRACE("(%s, %lx, 0x%x, %p, %p, %p)\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
6034
6035     for(pFDesc = This->funclist; pFDesc; pFDesc = pFDesc->next)
6036         if (pFDesc->funcdesc.invkind & wFlags)
6037             if (!strcmpW(pFDesc->Name, szName)) {
6038                 break;
6039             }
6040
6041     if (pFDesc)
6042     {
6043         *pDescKind = DESCKIND_FUNCDESC;
6044         pBindPtr->lpfuncdesc = &pFDesc->funcdesc;
6045         *ppTInfo = (ITypeInfo *)&This->lpVtbl;
6046         return S_OK;
6047     } else {
6048         if (!(wFlags & ~(INVOKE_PROPERTYGET)))
6049         {
6050             for(pVDesc = This->varlist; pVDesc; pVDesc = pVDesc->next) {
6051                 if (!strcmpW(pVDesc->Name, szName)) {
6052                     *pDescKind = DESCKIND_VARDESC;
6053                     pBindPtr->lpvardesc = &pVDesc->vardesc;
6054                     *ppTInfo = (ITypeInfo *)&This->lpVtbl;
6055                     return S_OK;
6056                 }
6057             }
6058         }
6059     }
6060     /* not found, look for it in inherited interfaces */
6061     if (This->TypeAttr.cImplTypes &&
6062         (This->TypeAttr.typekind == TKIND_INTERFACE || This->TypeAttr.typekind == TKIND_DISPATCH)) {
6063         /* recursive search */
6064         ITypeInfo *pTInfo;
6065         ITypeComp *pTComp;
6066         HRESULT hr;
6067         hr=ITypeInfo_GetRefTypeInfo((ITypeInfo *)&This->lpVtbl, This->impltypelist->hRef, &pTInfo);
6068         if (SUCCEEDED(hr))
6069         {
6070             hr = ITypeInfo_GetTypeComp(pTInfo,&pTComp);
6071             ITypeInfo_Release(pTInfo);
6072         }
6073         if (SUCCEEDED(hr))
6074         {
6075             hr = ITypeComp_Bind(pTComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
6076             ITypeComp_Release(pTComp);
6077             return hr;
6078         }
6079         WARN("Could not search inherited interface!\n");
6080     }
6081     ERR("did not find member with name %s, flags 0x%x!\n", debugstr_w(szName), wFlags);
6082     *pDescKind = DESCKIND_NONE;
6083     pBindPtr->lpfuncdesc = NULL;
6084     *ppTInfo = NULL;
6085     return DISP_E_MEMBERNOTFOUND;
6086 }
6087
6088 static HRESULT WINAPI ITypeComp_fnBindType(
6089     ITypeComp * iface,
6090     OLECHAR * szName,
6091     ULONG lHash,
6092     ITypeInfo ** ppTInfo,
6093     ITypeComp ** ppTComp)
6094 {
6095     TRACE("(%s, %lx, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
6096
6097     /* strange behaviour (does nothing) but like the
6098      * original */
6099
6100     if (!ppTInfo || !ppTComp)
6101         return E_POINTER;
6102
6103     *ppTInfo = NULL;
6104     *ppTComp = NULL;
6105
6106     return S_OK;
6107 }
6108
6109 static const ITypeCompVtbl tcompvt =
6110 {
6111
6112     ITypeComp_fnQueryInterface,
6113     ITypeComp_fnAddRef,
6114     ITypeComp_fnRelease,
6115
6116     ITypeComp_fnBind,
6117     ITypeComp_fnBindType
6118 };