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