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