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