oleaut: Only allocate memory once for each array needed for the
[wine] / dlls / oleaut32 / typelib.c
1 /*
2  *      TYPELIB
3  *
4  *      Copyright 1997  Marcus Meissner
5  *                    1999  Rein Klazes
6  *                    2000  Francois Jacques
7  *                    2001  Huw D M Davies for CodeWeavers
8  *                    2005  Robert Shearman, for CodeWeavers
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  *
24  * --------------------------------------------------------------------------------------
25  * Known problems (2000, Francois Jacques)
26  *
27  * - Tested using OLEVIEW (Platform SDK tool) only.
28  *
29  * - dual interface dispinterfaces. vtable-interface ITypeInfo instances are
30  *   creating by doing a straight copy of the dispinterface instance and just changing
31  *   its typekind. Pointed structures aren't copied - only the address of the pointers.
32  *   So when you release the dispinterface, you delete the vtable-interface structures
33  *   as well... fortunately, clean up of structures is not implemented.
34  *
35  * - locale stuff is partially implemented but hasn't been tested.
36  *
37  * - typelib file is still read in its entirety, but it is released now.
38  * - some garbage is read from function names on some very rare occasions.
39  *
40  * --------------------------------------------------------------------------------------
41  *  Known problems left from previous implementation (1999, Rein Klazes) :
42  *
43  * -. Data structures are straightforward, but slow for look-ups.
44  * -. (related) nothing is hashed
45  * -. there are a number of stubs in ITypeLib and ITypeInfo interfaces. Most
46  *      of them I don't know yet how to implement them.
47  * -. Most error return values are just guessed not checked with windows
48  *      behaviour.
49  * -. didn't bother with a c++ interface
50  * -. lousy fatal error handling
51  * -. some methods just return pointers to internal data structures, this is
52  *      partly laziness, partly I want to check how windows does it.
53  *
54  */
55
56 #include "config.h"
57 #include "wine/port.h"
58
59 #include <stdlib.h>
60 #include <string.h>
61 #include <stdarg.h>
62 #include <stdio.h>
63 #include <ctype.h>
64
65 #define COBJMACROS
66 #define NONAMELESSUNION
67 #define NONAMELESSSTRUCT
68
69 #include "winerror.h"
70 #include "windef.h"
71 #include "winbase.h"
72 #include "winnls.h"
73 #include "winreg.h"
74 #include "winuser.h"
75
76 #include "wine/unicode.h"
77 #include "objbase.h"
78 #include "typelib.h"
79 #include "wine/debug.h"
80 #include "variant.h"
81
82 WINE_DEFAULT_DEBUG_CHANNEL(ole);
83 WINE_DECLARE_DEBUG_CHANNEL(typelib);
84
85 /* The OLE Automation ProxyStub Interface Class (aka Typelib Marshaler) */
86 const GUID CLSID_PSOAInterface = { 0x00020424, 0, 0, { 0xC0, 0, 0, 0, 0, 0, 0, 0x46 } };
87
88 static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, const 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   MESSAGE("%s(%u)\n", debugstr_w(pfd->Name), pfd->funcdesc.cParams);
1149   for (i=0;i<pfd->funcdesc.cParams;i++)
1150       MESSAGE("\tparm%d: %s\n",i,debugstr_w(pfd->pParamDesc[i].Name));
1151
1152
1153   dump_FUNCDESC(&(pfd->funcdesc));
1154
1155   MESSAGE("\thelpstring: %s\n", debugstr_w(pfd->HelpString));
1156   MESSAGE("\tentry: %s\n", debugstr_w(pfd->Entry));
1157 }
1158 static void dump_TLBFuncDesc(const TLBFuncDesc * pfd)
1159 {
1160         while (pfd)
1161         {
1162           dump_TLBFuncDescOne(pfd);
1163           pfd = pfd->next;
1164         };
1165 }
1166 static void dump_TLBVarDesc(const TLBVarDesc * pvd)
1167 {
1168         while (pvd)
1169         {
1170           TRACE_(typelib)("%s\n", debugstr_w(pvd->Name));
1171           pvd = pvd->next;
1172         };
1173 }
1174
1175 static void dump_TLBImpLib(const TLBImpLib *import)
1176 {
1177     TRACE_(typelib)("%s %s\n", debugstr_guid(&(import->guid)),
1178                     debugstr_w(import->name));
1179     TRACE_(typelib)("v%d.%d lcid=%lx offset=%x\n", import->wVersionMajor,
1180                     import->wVersionMinor, import->lcid, import->offset);
1181 }
1182
1183 static void dump_TLBRefType(const TLBRefType * prt)
1184 {
1185         while (prt)
1186         {
1187           TRACE_(typelib)("href:0x%08lx\n", prt->reference);
1188           if(prt->index == -1)
1189             TRACE_(typelib)("%s\n", debugstr_guid(&(prt->guid)));
1190           else
1191             TRACE_(typelib)("type no: %d\n", prt->index);
1192
1193           if(prt->pImpTLInfo != TLB_REF_INTERNAL &&
1194              prt->pImpTLInfo != TLB_REF_NOT_FOUND) {
1195               TRACE_(typelib)("in lib\n");
1196               dump_TLBImpLib(prt->pImpTLInfo);
1197           }
1198           prt = prt->next;
1199         };
1200 }
1201
1202 static void dump_TLBImplType(const TLBImplType * impl)
1203 {
1204     while (impl) {
1205         TRACE_(typelib)(
1206                 "implementing/inheriting interface hRef = %lx implflags %x\n",
1207                 impl->hRef, impl->implflags);
1208         impl = impl->next;
1209     }
1210 }
1211
1212 void dump_Variant(const VARIANT * pvar)
1213 {
1214     SYSTEMTIME st;
1215
1216     TRACE("%p->{%s%s", pvar, debugstr_VT(pvar), debugstr_VF(pvar));
1217
1218     if (pvar)
1219     {
1220       if (V_ISBYREF(pvar) || V_TYPE(pvar) == VT_UNKNOWN ||
1221           V_TYPE(pvar) == VT_DISPATCH || V_TYPE(pvar) == VT_RECORD)
1222       {
1223         TRACE(",%p", V_BYREF(pvar));
1224       }
1225       else if (V_ISARRAY(pvar) || V_ISVECTOR(pvar))
1226       {
1227         TRACE(",FIXME");
1228       }
1229       else switch (V_TYPE(pvar))
1230       {
1231       case VT_I1:   TRACE(",%d", V_I1(pvar)); break;
1232       case VT_UI1:  TRACE(",%d", V_UI1(pvar)); break;
1233       case VT_I2:   TRACE(",%d", V_I2(pvar)); break;
1234       case VT_UI2:  TRACE(",%d", V_UI2(pvar)); break;
1235       case VT_INT:
1236       case VT_I4:   TRACE(",%ld", V_I4(pvar)); break;
1237       case VT_UINT:
1238       case VT_UI4:  TRACE(",%ld", V_UI4(pvar)); break;
1239       case VT_I8:   TRACE(",0x%08lx,0x%08lx", (ULONG)(V_I8(pvar) >> 32),
1240                           (ULONG)(V_I8(pvar) & 0xffffffff)); break;
1241       case VT_UI8:  TRACE(",0x%08lx,0x%08lx", (ULONG)(V_UI8(pvar) >> 32),
1242                           (ULONG)(V_UI8(pvar) & 0xffffffff)); break;
1243       case VT_R4:   TRACE(",%3.3e", V_R4(pvar)); break;
1244       case VT_R8:   TRACE(",%3.3e", V_R8(pvar)); break;
1245       case VT_BOOL: TRACE(",%s", V_BOOL(pvar) ? "TRUE" : "FALSE"); break;
1246       case VT_BSTR: TRACE(",%s", debugstr_w(V_BSTR(pvar))); break;
1247       case VT_CY:   TRACE(",0x%08lx,0x%08lx", V_CY(pvar).s.Hi,
1248                            V_CY(pvar).s.Lo); break;
1249       case VT_DATE:
1250         if(!VariantTimeToSystemTime(V_DATE(pvar), &st))
1251           TRACE(",<invalid>");
1252         else
1253           TRACE(",%04d/%02d/%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay,
1254                 st.wHour, st.wMinute, st.wSecond);
1255         break;
1256       case VT_ERROR:
1257       case VT_VOID:
1258       case VT_USERDEFINED:
1259       case VT_EMPTY:
1260       case VT_NULL:  break;
1261       default:       TRACE(",?"); break;
1262       }
1263     }
1264     TRACE("}\n");
1265 }
1266
1267 static void dump_DispParms(const DISPPARAMS * pdp)
1268 {
1269     int index = 0;
1270
1271     TRACE("args=%u named args=%u\n", pdp->cArgs, pdp->cNamedArgs);
1272
1273     while (index < pdp->cArgs)
1274     {
1275         dump_Variant( &pdp->rgvarg[index] );
1276         ++index;
1277     }
1278 }
1279
1280 static void dump_TypeInfo(const ITypeInfoImpl * pty)
1281 {
1282     TRACE("%p ref=%lu\n", pty, pty->ref);
1283     TRACE("%s %s\n", debugstr_w(pty->Name), debugstr_w(pty->DocString));
1284     TRACE("attr:%s\n", debugstr_guid(&(pty->TypeAttr.guid)));
1285     TRACE("kind:%s\n", typekind_desc[pty->TypeAttr.typekind]);
1286     TRACE("fct:%u var:%u impl:%u\n",
1287       pty->TypeAttr.cFuncs, pty->TypeAttr.cVars, pty->TypeAttr.cImplTypes);
1288     TRACE("wTypeFlags: 0x%04x\n", pty->TypeAttr.wTypeFlags);
1289     TRACE("parent tlb:%p index in TLB:%u\n",pty->pTypeLib, pty->index);
1290     if (pty->TypeAttr.typekind == TKIND_MODULE) TRACE("dllname:%s\n", debugstr_w(pty->DllName));
1291     if (TRACE_ON(ole))
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     if (TRACE_ON(typelib))
2972         dump_TLBFuncDesc(pTI->funclist);
2973     return (SLTG_TypeInfoTail*)(pFirstItem + pMemHeader->cbExtra);
2974 }
2975
2976 static SLTG_TypeInfoTail *SLTG_ProcessRecord(char *pBlk, ITypeInfoImpl *pTI,
2977                                              char *pNameTable)
2978 {
2979   SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk;
2980   SLTG_MemberHeader *pMemHeader;
2981   SLTG_RecordItem *pItem;
2982   char *pFirstItem;
2983   TLBVarDesc **ppVarDesc = &pTI->varlist;
2984   int num = 0;
2985   WORD *pType;
2986   char buf[300];
2987
2988   pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table);
2989
2990   pFirstItem = (char*)(pMemHeader + 1);
2991   for(pItem = (SLTG_RecordItem *)pFirstItem, num = 1; 1;
2992       pItem = (SLTG_RecordItem *)(pFirstItem + pItem->next), num++) {
2993       if(pItem->magic != SLTG_RECORD_MAGIC) {
2994           FIXME("record magic = %02x\n", pItem->magic);
2995           return NULL;
2996       }
2997       *ppVarDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2998                              sizeof(**ppVarDesc));
2999       (*ppVarDesc)->Name = TLB_MultiByteToBSTR(pItem->name + pNameTable);
3000       (*ppVarDesc)->vardesc.memid = pItem->memid;
3001       (*ppVarDesc)->vardesc.u.oInst = pItem->byte_offs;
3002       (*ppVarDesc)->vardesc.varkind = VAR_PERINSTANCE;
3003
3004       if(pItem->typepos == 0x02)
3005           pType = &pItem->type;
3006       else if(pItem->typepos == 0x00)
3007           pType = (WORD*)(pFirstItem + pItem->type);
3008       else {
3009           FIXME("typepos = %02x\n", pItem->typepos);
3010           break;
3011       }
3012
3013       SLTG_DoType(pType, pFirstItem,
3014                   &(*ppVarDesc)->vardesc.elemdescVar);
3015
3016       /* FIXME("helpcontext, helpstring\n"); */
3017
3018       dump_TypeDesc(&(*ppVarDesc)->vardesc.elemdescVar.tdesc, buf);
3019
3020       ppVarDesc = &((*ppVarDesc)->next);
3021       if(pItem->next == 0xffff) break;
3022   }
3023   pTI->TypeAttr.cVars = num;
3024   return (SLTG_TypeInfoTail*)(pFirstItem + pMemHeader->cbExtra);
3025 }
3026
3027 static SLTG_TypeInfoTail *SLTG_ProcessAlias(char *pBlk, ITypeInfoImpl *pTI,
3028                                            char *pNameTable)
3029 {
3030   SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk;
3031   SLTG_MemberHeader *pMemHeader;
3032   SLTG_AliasItem *pItem;
3033   int i, mustbelast;
3034
3035   pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table);
3036   pItem = (SLTG_AliasItem*)(pMemHeader + 1);
3037
3038   mustbelast = 0;
3039   /* This is used for creating a TYPEDESC chain in case of VT_USERDEFINED */
3040   for (i = 0 ; i<pMemHeader->cbExtra/4 ; i++) {
3041     if (pItem->vt == 0xffff) {
3042       if (i<(pMemHeader->cbExtra/4-1))
3043         FIXME("Endmarker too early in process alias data!\n");
3044       break;
3045     }
3046     if (mustbelast) {
3047       FIXME("Chain extends over last entry?\n");
3048       break;
3049     }
3050     if (pItem->vt == VT_USERDEFINED) {
3051       pTI->TypeAttr.tdescAlias.vt = pItem->vt;
3052       /* guessing here ... */
3053       FIXME("Guessing TKIND_ALIAS of VT_USERDEFINED with hreftype 0x%x\n",pItem->res02);
3054       pTI->TypeAttr.tdescAlias.u.hreftype = pItem->res02;
3055       mustbelast = 1;
3056     } else {
3057       FIXME("alias %d: 0x%x\n",i,pItem->vt);
3058       FIXME("alias %d: 0x%x\n",i,pItem->res02);
3059     }
3060     pItem++;
3061   }
3062   return (SLTG_TypeInfoTail*)((char*)(pMemHeader + 1)+pMemHeader->cbExtra);
3063 }
3064
3065 static SLTG_TypeInfoTail *SLTG_ProcessDispatch(char *pBlk, ITypeInfoImpl *pTI,
3066                                            char *pNameTable)
3067 {
3068   SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk;
3069   SLTG_MemberHeader *pMemHeader;
3070   SLTG_AliasItem *pItem;
3071
3072   pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table);
3073   pItem = (SLTG_AliasItem*)(pMemHeader + 1);
3074   FIXME("memh.cbExtra is %ld\n",pMemHeader->cbExtra);
3075   FIXME("offset 0 0x%x\n",*(WORD*)pItem);
3076   return (SLTG_TypeInfoTail*)((char*)(pMemHeader + 1)+pMemHeader->cbExtra);
3077 }
3078
3079 static SLTG_TypeInfoTail *SLTG_ProcessEnum(char *pBlk, ITypeInfoImpl *pTI,
3080                                            char *pNameTable)
3081 {
3082   SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk;
3083   SLTG_MemberHeader *pMemHeader;
3084   SLTG_EnumItem *pItem;
3085   char *pFirstItem;
3086   TLBVarDesc **ppVarDesc = &pTI->varlist;
3087   int num = 0;
3088
3089   pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table);
3090
3091   pFirstItem = (char*)(pMemHeader + 1);
3092   for(pItem = (SLTG_EnumItem *)pFirstItem, num = 1; 1;
3093       pItem = (SLTG_EnumItem *)(pFirstItem + pItem->next), num++) {
3094       if(pItem->magic != SLTG_ENUMITEM_MAGIC) {
3095           FIXME("enumitem magic = %04x\n", pItem->magic);
3096           return NULL;
3097       }
3098       *ppVarDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3099                              sizeof(**ppVarDesc));
3100       (*ppVarDesc)->Name = TLB_MultiByteToBSTR(pItem->name + pNameTable);
3101       (*ppVarDesc)->vardesc.memid = pItem->memid;
3102       (*ppVarDesc)->vardesc.u.lpvarValue = HeapAlloc(GetProcessHeap(), 0,
3103                                                      sizeof(VARIANT));
3104       V_VT((*ppVarDesc)->vardesc.u.lpvarValue) = VT_INT;
3105       V_UNION((*ppVarDesc)->vardesc.u.lpvarValue, intVal) =
3106         *(INT*)(pItem->value + pFirstItem);
3107       (*ppVarDesc)->vardesc.elemdescVar.tdesc.vt = VT_I4;
3108       (*ppVarDesc)->vardesc.varkind = VAR_CONST;
3109       /* FIXME("helpcontext, helpstring\n"); */
3110
3111       ppVarDesc = &((*ppVarDesc)->next);
3112       if(pItem->next == 0xffff) break;
3113   }
3114   pTI->TypeAttr.cVars = num;
3115   return (SLTG_TypeInfoTail*)(pFirstItem + pMemHeader->cbExtra);
3116 }
3117
3118 /* Because SLTG_OtherTypeInfo is such a painful struct, we make a more
3119    managable copy of it into this */
3120 typedef struct {
3121   WORD small_no;
3122   char *index_name;
3123   char *other_name;
3124   WORD res1a;
3125   WORD name_offs;
3126   WORD more_bytes;
3127   char *extra;
3128   WORD res20;
3129   DWORD helpcontext;
3130   WORD res26;
3131   GUID uuid;
3132 } SLTG_InternalOtherTypeInfo;
3133
3134 /****************************************************************************
3135  *      ITypeLib2_Constructor_SLTG
3136  *
3137  * loading a SLTG typelib from an in-memory image
3138  */
3139 static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength)
3140 {
3141     ITypeLibImpl *pTypeLibImpl;
3142     SLTG_Header *pHeader;
3143     SLTG_BlkEntry *pBlkEntry;
3144     SLTG_Magic *pMagic;
3145     SLTG_Index *pIndex;
3146     SLTG_Pad9 *pPad9;
3147     LPVOID pBlk, pFirstBlk;
3148     SLTG_LibBlk *pLibBlk;
3149     SLTG_InternalOtherTypeInfo *pOtherTypeInfoBlks;
3150     char *pAfterOTIBlks = NULL;
3151     char *pNameTable, *ptr;
3152     int i;
3153     DWORD len, order;
3154     ITypeInfoImpl **ppTypeInfoImpl;
3155
3156     TRACE_(typelib)("%p, TLB length = %ld\n", pLib, dwTLBLength);
3157
3158     pTypeLibImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeLibImpl));
3159     if (!pTypeLibImpl) return NULL;
3160
3161     pTypeLibImpl->lpVtbl = &tlbvt;
3162     pTypeLibImpl->ref = 1;
3163
3164     pHeader = pLib;
3165
3166     TRACE_(typelib)("header:\n");
3167     TRACE_(typelib)("\tmagic=0x%08lx, file blocks = %d\n", pHeader->SLTG_magic,
3168           pHeader->nrOfFileBlks );
3169     if (pHeader->SLTG_magic != SLTG_SIGNATURE) {
3170         FIXME("Header type magic 0x%08lx not supported.\n",
3171               pHeader->SLTG_magic);
3172         return NULL;
3173     }
3174
3175     /* There are pHeader->nrOfFileBlks - 2 TypeInfo records in this typelib */
3176     pTypeLibImpl->TypeInfoCount = pHeader->nrOfFileBlks - 2;
3177
3178     /* This points to pHeader->nrOfFileBlks - 1 of SLTG_BlkEntry */
3179     pBlkEntry = (SLTG_BlkEntry*)(pHeader + 1);
3180
3181     /* Next we have a magic block */
3182     pMagic = (SLTG_Magic*)(pBlkEntry + pHeader->nrOfFileBlks - 1);
3183
3184     /* Let's see if we're still in sync */
3185     if(memcmp(pMagic->CompObj_magic, SLTG_COMPOBJ_MAGIC,
3186               sizeof(SLTG_COMPOBJ_MAGIC))) {
3187         FIXME("CompObj magic = %s\n", pMagic->CompObj_magic);
3188         return NULL;
3189     }
3190     if(memcmp(pMagic->dir_magic, SLTG_DIR_MAGIC,
3191               sizeof(SLTG_DIR_MAGIC))) {
3192         FIXME("dir magic = %s\n", pMagic->dir_magic);
3193         return NULL;
3194     }
3195
3196     pIndex = (SLTG_Index*)(pMagic+1);
3197
3198     pPad9 = (SLTG_Pad9*)(pIndex + pTypeLibImpl->TypeInfoCount);
3199
3200     pFirstBlk = (LPVOID)(pPad9 + 1);
3201
3202     /* We'll set up a ptr to the main library block, which is the last one. */
3203
3204     for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0;
3205           pBlkEntry[order].next != 0;
3206           order = pBlkEntry[order].next - 1, i++) {
3207        pBlk = (char*)pBlk + pBlkEntry[order].len;
3208     }
3209     pLibBlk = pBlk;
3210
3211     len = SLTG_ReadLibBlk(pLibBlk, pTypeLibImpl);
3212
3213     /* Now there's 0x40 bytes of 0xffff with the numbers 0 to TypeInfoCount
3214        interspersed */
3215
3216     len += 0x40;
3217
3218     /* And now TypeInfoCount of SLTG_OtherTypeInfo */
3219
3220     pOtherTypeInfoBlks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3221                                    sizeof(*pOtherTypeInfoBlks) *
3222                                    pTypeLibImpl->TypeInfoCount);
3223
3224
3225     ptr = (char*)pLibBlk + len;
3226
3227     for(i = 0; i < pTypeLibImpl->TypeInfoCount; i++) {
3228         WORD w, extra;
3229         len = 0;
3230
3231         pOtherTypeInfoBlks[i].small_no = *(WORD*)ptr;
3232
3233         w = *(WORD*)(ptr + 2);
3234         if(w != 0xffff) {
3235             len += w;
3236             pOtherTypeInfoBlks[i].index_name = HeapAlloc(GetProcessHeap(),0,
3237                                                          w+1);
3238             memcpy(pOtherTypeInfoBlks[i].index_name, ptr + 4, w);
3239             pOtherTypeInfoBlks[i].index_name[w] = '\0';
3240         }
3241         w = *(WORD*)(ptr + 4 + len);
3242         if(w != 0xffff) {
3243             TRACE_(typelib)("\twith %s\n", debugstr_an(ptr + 6 + len, w));
3244             len += w;
3245             pOtherTypeInfoBlks[i].other_name = HeapAlloc(GetProcessHeap(),0,
3246                                                          w+1);
3247             memcpy(pOtherTypeInfoBlks[i].other_name, ptr + 6 + len, w);
3248             pOtherTypeInfoBlks[i].other_name[w] = '\0';
3249         }
3250         pOtherTypeInfoBlks[i].res1a = *(WORD*)(ptr + len + 6);
3251         pOtherTypeInfoBlks[i].name_offs = *(WORD*)(ptr + len + 8);
3252         extra = pOtherTypeInfoBlks[i].more_bytes = *(WORD*)(ptr + 10 + len);
3253         if(extra) {
3254             pOtherTypeInfoBlks[i].extra = HeapAlloc(GetProcessHeap(),0,
3255                                                     extra);
3256             memcpy(pOtherTypeInfoBlks[i].extra, ptr + 12, extra);
3257             len += extra;
3258         }
3259         pOtherTypeInfoBlks[i].res20 = *(WORD*)(ptr + 12 + len);
3260         pOtherTypeInfoBlks[i].helpcontext = *(DWORD*)(ptr + 14 + len);
3261         pOtherTypeInfoBlks[i].res26 = *(WORD*)(ptr + 18 + len);
3262         memcpy(&pOtherTypeInfoBlks[i].uuid, ptr + 20 + len, sizeof(GUID));
3263         len += sizeof(SLTG_OtherTypeInfo);
3264         ptr += len;
3265     }
3266
3267     pAfterOTIBlks = ptr;
3268
3269     /* Skip this WORD and get the next DWORD */
3270     len = *(DWORD*)(pAfterOTIBlks + 2);
3271
3272     /* Now add this to pLibBLk look at what we're pointing at and
3273        possibly add 0x20, then add 0x216, sprinkle a bit a magic
3274        dust and we should be pointing at the beginning of the name
3275        table */
3276
3277     pNameTable = (char*)pLibBlk + len;
3278
3279    switch(*(WORD*)pNameTable) {
3280    case 0xffff:
3281        break;
3282    case 0x0200:
3283        pNameTable += 0x20;
3284        break;
3285    default:
3286        FIXME("pNameTable jump = %x\n", *(WORD*)pNameTable);
3287        break;
3288    }
3289
3290     pNameTable += 0x216;
3291
3292     pNameTable += 2;
3293
3294     TRACE("Library name is %s\n", pNameTable + pLibBlk->name);
3295
3296     pTypeLibImpl->Name = TLB_MultiByteToBSTR(pNameTable + pLibBlk->name);
3297
3298
3299     /* Hopefully we now have enough ptrs set up to actually read in
3300        some TypeInfos.  It's not clear which order to do them in, so
3301        I'll just follow the links along the BlkEntry chain and read
3302        them in in the order in which they're in the file */
3303
3304     ppTypeInfoImpl = &(pTypeLibImpl->pTypeInfo);
3305
3306     for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0;
3307         pBlkEntry[order].next != 0;
3308         order = pBlkEntry[order].next - 1, i++) {
3309
3310       SLTG_TypeInfoHeader *pTIHeader;
3311       SLTG_TypeInfoTail *pTITail;
3312
3313       if(strcmp(pBlkEntry[order].index_string + (char*)pMagic,
3314                 pOtherTypeInfoBlks[i].index_name)) {
3315         FIXME("Index strings don't match\n");
3316         return NULL;
3317       }
3318
3319       pTIHeader = pBlk;
3320       if(pTIHeader->magic != SLTG_TIHEADER_MAGIC) {
3321         FIXME("TypeInfoHeader magic = %04x\n", pTIHeader->magic);
3322         return NULL;
3323       }
3324       *ppTypeInfoImpl = (ITypeInfoImpl*)ITypeInfo_Constructor();
3325       (*ppTypeInfoImpl)->pTypeLib = pTypeLibImpl;
3326       (*ppTypeInfoImpl)->index = i;
3327       (*ppTypeInfoImpl)->Name = TLB_MultiByteToBSTR(
3328                                              pOtherTypeInfoBlks[i].name_offs +
3329                                              pNameTable);
3330       (*ppTypeInfoImpl)->dwHelpContext = pOtherTypeInfoBlks[i].helpcontext;
3331       memcpy(&((*ppTypeInfoImpl)->TypeAttr.guid), &pOtherTypeInfoBlks[i].uuid,
3332              sizeof(GUID));
3333       (*ppTypeInfoImpl)->TypeAttr.typekind = pTIHeader->typekind;
3334       (*ppTypeInfoImpl)->TypeAttr.wMajorVerNum = pTIHeader->major_version;
3335       (*ppTypeInfoImpl)->TypeAttr.wMinorVerNum = pTIHeader->minor_version;
3336       (*ppTypeInfoImpl)->TypeAttr.wTypeFlags =
3337         (pTIHeader->typeflags1 >> 3) | (pTIHeader->typeflags2 << 5);
3338
3339       if((pTIHeader->typeflags1 & 7) != 2)
3340         FIXME("typeflags1 = %02x\n", pTIHeader->typeflags1);
3341       if(pTIHeader->typeflags3 != 2)
3342         FIXME("typeflags3 = %02x\n", pTIHeader->typeflags3);
3343
3344       TRACE("TypeInfo %s of kind %s guid %s typeflags %04x\n",
3345             debugstr_w((*ppTypeInfoImpl)->Name),
3346             typekind_desc[pTIHeader->typekind],
3347             debugstr_guid(&(*ppTypeInfoImpl)->TypeAttr.guid),
3348             (*ppTypeInfoImpl)->TypeAttr.wTypeFlags);
3349
3350       switch(pTIHeader->typekind) {
3351       case TKIND_ENUM:
3352         pTITail = SLTG_ProcessEnum(pBlk, *ppTypeInfoImpl, pNameTable);
3353         break;
3354
3355       case TKIND_RECORD:
3356         pTITail = SLTG_ProcessRecord(pBlk, *ppTypeInfoImpl, pNameTable);
3357         break;
3358
3359       case TKIND_INTERFACE:
3360         pTITail = SLTG_ProcessInterface(pBlk, *ppTypeInfoImpl, pNameTable);
3361         break;
3362
3363       case TKIND_COCLASS:
3364         pTITail = SLTG_ProcessCoClass(pBlk, *ppTypeInfoImpl, pNameTable);
3365         break;
3366
3367       case TKIND_ALIAS:
3368         pTITail = SLTG_ProcessAlias(pBlk, *ppTypeInfoImpl, pNameTable);
3369         if (pTITail->tdescalias_vt)
3370           (*ppTypeInfoImpl)->TypeAttr.tdescAlias.vt = pTITail->tdescalias_vt;
3371         break;
3372
3373       case TKIND_DISPATCH:
3374         pTITail = SLTG_ProcessDispatch(pBlk, *ppTypeInfoImpl, pNameTable);
3375         break;
3376
3377       default:
3378         FIXME("Not processing typekind %d\n", pTIHeader->typekind);
3379         pTITail = NULL;
3380         break;
3381
3382       }
3383
3384       if(pTITail) { /* could get cFuncs, cVars and cImplTypes from here
3385                        but we've already set those */
3386           (*ppTypeInfoImpl)->TypeAttr.cbAlignment = pTITail->cbAlignment;
3387           (*ppTypeInfoImpl)->TypeAttr.cbSizeInstance = pTITail->cbSizeInstance;
3388           (*ppTypeInfoImpl)->TypeAttr.cbSizeVft = pTITail->cbSizeVft;
3389
3390 #define X(x) TRACE_(typelib)("tt "#x": %x\n",pTITail->res##x);
3391           X(06);
3392           X(08);
3393           X(0a);
3394           X(0c);
3395           X(0e);
3396           X(10);
3397           X(12);
3398           X(16);
3399           X(18);
3400           X(1a);
3401           X(1c);
3402           X(1e);
3403           X(24);
3404           X(26);
3405           X(2a);
3406           X(2c);
3407           X(2e);
3408           X(30);
3409           X(32);
3410           X(34);
3411       }
3412       ppTypeInfoImpl = &((*ppTypeInfoImpl)->next);
3413       pBlk = (char*)pBlk + pBlkEntry[order].len;
3414     }
3415
3416     if(i != pTypeLibImpl->TypeInfoCount) {
3417       FIXME("Somehow processed %d TypeInfos\n", i);
3418       return NULL;
3419     }
3420
3421     HeapFree(GetProcessHeap(), 0, pOtherTypeInfoBlks);
3422     return (ITypeLib2*)pTypeLibImpl;
3423 }
3424
3425 /* ITypeLib::QueryInterface
3426  */
3427 static HRESULT WINAPI ITypeLib2_fnQueryInterface(
3428         ITypeLib2 * iface,
3429         REFIID riid,
3430         VOID **ppvObject)
3431 {
3432     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3433
3434     TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
3435
3436     *ppvObject=NULL;
3437     if(IsEqualIID(riid, &IID_IUnknown) ||
3438        IsEqualIID(riid,&IID_ITypeLib)||
3439        IsEqualIID(riid,&IID_ITypeLib2))
3440     {
3441         *ppvObject = This;
3442     }
3443
3444     if(*ppvObject)
3445     {
3446         ITypeLib2_AddRef(iface);
3447         TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
3448         return S_OK;
3449     }
3450     TRACE("-- Interface: E_NOINTERFACE\n");
3451     return E_NOINTERFACE;
3452 }
3453
3454 /* ITypeLib::AddRef
3455  */
3456 static ULONG WINAPI ITypeLib2_fnAddRef( ITypeLib2 *iface)
3457 {
3458     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3459     ULONG ref = InterlockedIncrement(&This->ref);
3460
3461     TRACE("(%p)->ref was %lu\n",This, ref - 1);
3462
3463     return ref;
3464 }
3465
3466 /* ITypeLib::Release
3467  */
3468 static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface)
3469 {
3470     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3471     ULONG ref = InterlockedDecrement(&This->ref);
3472
3473     TRACE("(%p)->(%lu)\n",This, ref);
3474
3475     if (!ref)
3476     {
3477       /* remove cache entry */
3478       TRACE("removing from cache list\n");
3479       EnterCriticalSection(&cache_section);
3480       if (This->next) This->next->prev = This->prev;
3481       if (This->prev) This->prev->next = This->next;
3482       else tlb_cache_first = This->next;
3483       LeaveCriticalSection(&cache_section);
3484
3485       /* FIXME destroy child objects */
3486       TRACE(" destroying ITypeLib(%p)\n",This);
3487
3488       if (This->Name)
3489       {
3490           SysFreeString(This->Name);
3491           This->Name = NULL;
3492       }
3493
3494       if (This->DocString)
3495       {
3496           SysFreeString(This->DocString);
3497           This->DocString = NULL;
3498       }
3499
3500       if (This->HelpFile)
3501       {
3502           SysFreeString(This->HelpFile);
3503           This->HelpFile = NULL;
3504       }
3505
3506       if (This->HelpStringDll)
3507       {
3508           SysFreeString(This->HelpStringDll);
3509           This->HelpStringDll = NULL;
3510       }
3511
3512       if (This->pTypeInfo) /* can be NULL */
3513           ITypeInfo_Release((ITypeInfo*) This->pTypeInfo);
3514       HeapFree(GetProcessHeap(),0,This);
3515       return 0;
3516     }
3517
3518     return ref;
3519 }
3520
3521 /* ITypeLib::GetTypeInfoCount
3522  *
3523  * Returns the number of type descriptions in the type library
3524  */
3525 static UINT WINAPI ITypeLib2_fnGetTypeInfoCount( ITypeLib2 *iface)
3526 {
3527     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3528     TRACE("(%p)->count is %d\n",This, This->TypeInfoCount);
3529     return This->TypeInfoCount;
3530 }
3531
3532 /* ITypeLib::GetTypeInfo
3533  *
3534  * retrieves the specified type description in the library.
3535  */
3536 static HRESULT WINAPI ITypeLib2_fnGetTypeInfo(
3537     ITypeLib2 *iface,
3538     UINT index,
3539     ITypeInfo **ppTInfo)
3540 {
3541     int i;
3542
3543     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3544     ITypeInfoImpl *pTypeInfo = This->pTypeInfo;
3545
3546     TRACE("(%p)->(index=%d)\n", This, index);
3547
3548     if (!ppTInfo) return E_INVALIDARG;
3549
3550     /* search element n in list */
3551     for(i=0; i < index; i++)
3552     {
3553       pTypeInfo = pTypeInfo->next;
3554       if (!pTypeInfo)
3555       {
3556         TRACE("-- element not found\n");
3557         return TYPE_E_ELEMENTNOTFOUND;
3558       }
3559     }
3560
3561     *ppTInfo = (ITypeInfo *) pTypeInfo;
3562
3563     ITypeInfo_AddRef(*ppTInfo);
3564     TRACE("-- found (%p)\n",*ppTInfo);
3565     return S_OK;
3566 }
3567
3568
3569 /* ITypeLibs::GetTypeInfoType
3570  *
3571  * Retrieves the type of a type description.
3572  */
3573 static HRESULT WINAPI ITypeLib2_fnGetTypeInfoType(
3574     ITypeLib2 *iface,
3575     UINT index,
3576     TYPEKIND *pTKind)
3577 {
3578     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3579     int i;
3580     ITypeInfoImpl *pTInfo = This->pTypeInfo;
3581
3582     TRACE("(%p) index %d\n", This, index);
3583
3584     if(!pTKind) return E_INVALIDARG;
3585
3586     /* search element n in list */
3587     for(i=0; i < index; i++)
3588     {
3589       if(!pTInfo)
3590       {
3591         TRACE("-- element not found\n");
3592         return TYPE_E_ELEMENTNOTFOUND;
3593       }
3594       pTInfo = pTInfo->next;
3595     }
3596
3597     *pTKind = pTInfo->TypeAttr.typekind;
3598     TRACE("-- found Type (%d)\n", *pTKind);
3599     return S_OK;
3600 }
3601
3602 /* ITypeLib::GetTypeInfoOfGuid
3603  *
3604  * Retrieves the type description that corresponds to the specified GUID.
3605  *
3606  */
3607 static HRESULT WINAPI ITypeLib2_fnGetTypeInfoOfGuid(
3608     ITypeLib2 *iface,
3609     REFGUID guid,
3610     ITypeInfo **ppTInfo)
3611 {
3612     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3613     ITypeInfoImpl *pTypeInfo = This->pTypeInfo; /* head of list */
3614
3615     TRACE("(%p)\n\tguid:\t%s)\n",This,debugstr_guid(guid));
3616
3617     if (!pTypeInfo)
3618     {
3619         WARN("-- element not found\n");
3620         return TYPE_E_ELEMENTNOTFOUND;
3621     }
3622
3623     /* search linked list for guid */
3624     while( !IsEqualIID(guid,&pTypeInfo->TypeAttr.guid) )
3625     {
3626       pTypeInfo = pTypeInfo->next;
3627
3628       if (!pTypeInfo)
3629       {
3630         /* end of list reached */
3631         WARN("-- element not found\n");
3632         return TYPE_E_ELEMENTNOTFOUND;
3633       }
3634     }
3635
3636     TRACE("-- found (%p, %s)\n",
3637           pTypeInfo,
3638           debugstr_w(pTypeInfo->Name));
3639
3640     *ppTInfo = (ITypeInfo*)pTypeInfo;
3641     ITypeInfo_AddRef(*ppTInfo);
3642     return S_OK;
3643 }
3644
3645 /* ITypeLib::GetLibAttr
3646  *
3647  * Retrieves the structure that contains the library's attributes.
3648  *
3649  */
3650 static HRESULT WINAPI ITypeLib2_fnGetLibAttr(
3651         ITypeLib2 *iface,
3652         LPTLIBATTR *ppTLibAttr)
3653 {
3654     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3655     TRACE("(%p)\n",This);
3656     *ppTLibAttr = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppTLibAttr));
3657     memcpy(*ppTLibAttr, &This->LibAttr, sizeof(**ppTLibAttr));
3658     return S_OK;
3659 }
3660
3661 /* ITypeLib::GetTypeComp
3662  *
3663  * Enables a client compiler to bind to a library's types, variables,
3664  * constants, and global functions.
3665  *
3666  */
3667 static HRESULT WINAPI ITypeLib2_fnGetTypeComp(
3668         ITypeLib2 *iface,
3669         ITypeComp **ppTComp)
3670 {
3671     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3672
3673     TRACE("(%p)->(%p)\n",This,ppTComp);
3674     *ppTComp = (ITypeComp *)&This->lpVtblTypeComp;
3675     ITypeComp_AddRef(*ppTComp);
3676
3677     return S_OK;
3678 }
3679
3680 /* ITypeLib::GetDocumentation
3681  *
3682  * Retrieves the library's documentation string, the complete Help file name
3683  * and path, and the context identifier for the library Help topic in the Help
3684  * file.
3685  *
3686  * On a successful return all non-null BSTR pointers will have been set,
3687  * possibly to NULL.
3688  */
3689 static HRESULT WINAPI ITypeLib2_fnGetDocumentation(
3690     ITypeLib2 *iface,
3691     INT index,
3692     BSTR *pBstrName,
3693     BSTR *pBstrDocString,
3694     DWORD *pdwHelpContext,
3695     BSTR *pBstrHelpFile)
3696 {
3697     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3698
3699     HRESULT result = E_INVALIDARG;
3700
3701     ITypeInfo *pTInfo;
3702
3703
3704     TRACE("(%p) index %d Name(%p) DocString(%p) HelpContext(%p) HelpFile(%p)\n",
3705         This, index,
3706         pBstrName, pBstrDocString,
3707         pdwHelpContext, pBstrHelpFile);
3708
3709     if(index<0)
3710     {
3711         /* documentation for the typelib */
3712         if(pBstrName)
3713         {
3714             if (This->Name)
3715             {
3716                 if(!(*pBstrName = SysAllocString(This->Name)))
3717                     goto memerr1;
3718             }
3719             else
3720                 *pBstrName = NULL;
3721         }
3722         if(pBstrDocString)
3723         {
3724             if (This->DocString)
3725             {
3726                 if(!(*pBstrDocString = SysAllocString(This->DocString)))
3727                     goto memerr2;
3728             }
3729             else if (This->Name)
3730             {
3731                 if(!(*pBstrDocString = SysAllocString(This->Name)))
3732                     goto memerr2;
3733             }
3734             else
3735                 *pBstrDocString = NULL;
3736         }
3737         if(pdwHelpContext)
3738         {
3739             *pdwHelpContext = This->dwHelpContext;
3740         }
3741         if(pBstrHelpFile)
3742         {
3743             if (This->HelpFile)
3744             {
3745                 if(!(*pBstrHelpFile = SysAllocString(This->HelpFile)))
3746                     goto memerr3;
3747             }
3748             else
3749                 *pBstrHelpFile = NULL;
3750         }
3751
3752         result = S_OK;
3753     }
3754     else
3755     {
3756         /* for a typeinfo */
3757         result = ITypeLib2_fnGetTypeInfo(iface, index, &pTInfo);
3758
3759         if(SUCCEEDED(result))
3760         {
3761             result = ITypeInfo_GetDocumentation(pTInfo,
3762                                           MEMBERID_NIL,
3763                                           pBstrName,
3764                                           pBstrDocString,
3765                                           pdwHelpContext, pBstrHelpFile);
3766
3767             ITypeInfo_Release(pTInfo);
3768         }
3769     }
3770     return result;
3771 memerr3:
3772     if (pBstrDocString) SysFreeString (*pBstrDocString);
3773 memerr2:
3774     if (pBstrName) SysFreeString (*pBstrName);
3775 memerr1:
3776     return STG_E_INSUFFICIENTMEMORY;
3777 }
3778
3779 /* ITypeLib::IsName
3780  *
3781  * Indicates whether a passed-in string contains the name of a type or member
3782  * described in the library.
3783  *
3784  */
3785 static HRESULT WINAPI ITypeLib2_fnIsName(
3786         ITypeLib2 *iface,
3787         LPOLESTR szNameBuf,
3788         ULONG lHashVal,
3789         BOOL *pfName)
3790 {
3791     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3792     ITypeInfoImpl *pTInfo;
3793     TLBFuncDesc *pFInfo;
3794     TLBVarDesc *pVInfo;
3795     int i;
3796     UINT nNameBufLen = (lstrlenW(szNameBuf)+1)*sizeof(WCHAR);
3797
3798     TRACE("(%p)->(%s,%08lx,%p)\n", This, debugstr_w(szNameBuf), lHashVal,
3799           pfName);
3800
3801     *pfName=TRUE;
3802     for(pTInfo=This->pTypeInfo;pTInfo;pTInfo=pTInfo->next){
3803         if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
3804         for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
3805             if(!memcmp(szNameBuf,pFInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
3806             for(i=0;i<pFInfo->funcdesc.cParams;i++)
3807                 if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name, nNameBufLen))
3808                     goto ITypeLib2_fnIsName_exit;
3809         }
3810         for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next)
3811             if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
3812
3813     }
3814     *pfName=FALSE;
3815
3816 ITypeLib2_fnIsName_exit:
3817     TRACE("(%p)slow! search for %s: %s found!\n", This,
3818           debugstr_w(szNameBuf), *pfName?"NOT":"");
3819
3820     return S_OK;
3821 }
3822
3823 /* ITypeLib::FindName
3824  *
3825  * Finds occurrences of a type description in a type library. This may be used
3826  * to quickly verify that a name exists in a type library.
3827  *
3828  */
3829 static HRESULT WINAPI ITypeLib2_fnFindName(
3830         ITypeLib2 *iface,
3831         LPOLESTR szNameBuf,
3832         ULONG lHashVal,
3833         ITypeInfo **ppTInfo,
3834         MEMBERID *rgMemId,
3835         UINT16 *pcFound)
3836 {
3837     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3838     ITypeInfoImpl *pTInfo;
3839     TLBFuncDesc *pFInfo;
3840     TLBVarDesc *pVInfo;
3841     int i,j = 0;
3842     UINT nNameBufLen = (lstrlenW(szNameBuf)+1)*sizeof(WCHAR);
3843
3844     for(pTInfo=This->pTypeInfo;pTInfo && j<*pcFound; pTInfo=pTInfo->next){
3845         if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit;
3846         for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
3847             if(!memcmp(szNameBuf,pFInfo->Name,nNameBufLen)) goto ITypeLib2_fnFindName_exit;
3848             for(i=0;i<pFInfo->funcdesc.cParams;i++) {
3849                 if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name,nNameBufLen))
3850                     goto ITypeLib2_fnFindName_exit;
3851             }
3852         }
3853         for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next)
3854             if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit;
3855         continue;
3856 ITypeLib2_fnFindName_exit:
3857         ITypeInfo_AddRef((ITypeInfo*)pTInfo);
3858         ppTInfo[j]=(LPTYPEINFO)pTInfo;
3859         j++;
3860     }
3861     TRACE("(%p)slow! search for %d with %s: found %d TypeInfo's!\n",
3862           This, *pcFound, debugstr_w(szNameBuf), j);
3863
3864     *pcFound=j;
3865
3866     return S_OK;
3867 }
3868
3869 /* ITypeLib::ReleaseTLibAttr
3870  *
3871  * Releases the TLIBATTR originally obtained from ITypeLib::GetLibAttr.
3872  *
3873  */
3874 static VOID WINAPI ITypeLib2_fnReleaseTLibAttr(
3875         ITypeLib2 *iface,
3876         TLIBATTR *pTLibAttr)
3877 {
3878     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3879     TRACE("freeing (%p)\n",This);
3880     HeapFree(GetProcessHeap(),0,pTLibAttr);
3881
3882 }
3883
3884 /* ITypeLib2::GetCustData
3885  *
3886  * gets the custom data
3887  */
3888 static HRESULT WINAPI ITypeLib2_fnGetCustData(
3889         ITypeLib2 * iface,
3890         REFGUID guid,
3891         VARIANT *pVarVal)
3892 {
3893     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3894     TLBCustData *pCData;
3895
3896     for(pCData=This->pCustData; pCData; pCData = pCData->next)
3897     {
3898       if( IsEqualIID(guid, &pCData->guid)) break;
3899     }
3900
3901     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
3902
3903     if(pCData)
3904     {
3905         VariantInit( pVarVal);
3906         VariantCopy( pVarVal, &pCData->data);
3907         return S_OK;
3908     }
3909     return E_INVALIDARG;  /* FIXME: correct? */
3910 }
3911
3912 /* ITypeLib2::GetLibStatistics
3913  *
3914  * Returns statistics about a type library that are required for efficient
3915  * sizing of hash tables.
3916  *
3917  */
3918 static HRESULT WINAPI ITypeLib2_fnGetLibStatistics(
3919         ITypeLib2 * iface,
3920         ULONG *pcUniqueNames,
3921         ULONG *pcchUniqueNames)
3922 {
3923     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3924
3925     FIXME("(%p): stub!\n", This);
3926
3927     if(pcUniqueNames) *pcUniqueNames=1;
3928     if(pcchUniqueNames) *pcchUniqueNames=1;
3929     return S_OK;
3930 }
3931
3932 /* ITypeLib2::GetDocumentation2
3933  *
3934  * Retrieves the library's documentation string, the complete Help file name
3935  * and path, the localization context to use, and the context ID for the
3936  * library Help topic in the Help file.
3937  *
3938  */
3939 static HRESULT WINAPI ITypeLib2_fnGetDocumentation2(
3940         ITypeLib2 * iface,
3941         INT index,
3942         LCID lcid,
3943         BSTR *pbstrHelpString,
3944         DWORD *pdwHelpStringContext,
3945         BSTR *pbstrHelpStringDll)
3946 {
3947     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3948     HRESULT result;
3949     ITypeInfo *pTInfo;
3950
3951     FIXME("(%p) index %d lcid %ld half implemented stub!\n", This, index, lcid);
3952
3953     /* the help string should be obtained from the helpstringdll,
3954      * using the _DLLGetDocumentation function, based on the supplied
3955      * lcid. Nice to do sometime...
3956      */
3957     if(index<0)
3958     {
3959       /* documentation for the typelib */
3960       if(pbstrHelpString)
3961         *pbstrHelpString=SysAllocString(This->DocString);
3962       if(pdwHelpStringContext)
3963         *pdwHelpStringContext=This->dwHelpContext;
3964       if(pbstrHelpStringDll)
3965         *pbstrHelpStringDll=SysAllocString(This->HelpStringDll);
3966
3967       result = S_OK;
3968     }
3969     else
3970     {
3971       /* for a typeinfo */
3972       result=ITypeLib2_GetTypeInfo(iface, index, &pTInfo);
3973
3974       if(SUCCEEDED(result))
3975       {
3976         ITypeInfo2 * pTInfo2;
3977         result = ITypeInfo_QueryInterface(pTInfo,
3978                                           &IID_ITypeInfo2,
3979                                           (LPVOID*) &pTInfo2);
3980
3981         if(SUCCEEDED(result))
3982         {
3983           result = ITypeInfo2_GetDocumentation2(pTInfo2,
3984                                            MEMBERID_NIL,
3985                                            lcid,
3986                                            pbstrHelpString,
3987                                            pdwHelpStringContext,
3988                                            pbstrHelpStringDll);
3989
3990           ITypeInfo2_Release(pTInfo2);
3991         }
3992
3993         ITypeInfo_Release(pTInfo);
3994       }
3995     }
3996     return result;
3997 }
3998
3999 /* ITypeLib2::GetAllCustData
4000  *
4001  * Gets all custom data items for the library.
4002  *
4003  */
4004 static HRESULT WINAPI ITypeLib2_fnGetAllCustData(
4005         ITypeLib2 * iface,
4006         CUSTDATA *pCustData)
4007 {
4008     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4009     TLBCustData *pCData;
4010     int i;
4011     TRACE("(%p) returning %d items\n", This, This->ctCustData);
4012     pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
4013     if(pCustData->prgCustData ){
4014         pCustData->cCustData=This->ctCustData;
4015         for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
4016             pCustData->prgCustData[i].guid=pCData->guid;
4017             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
4018         }
4019     }else{
4020         ERR(" OUT OF MEMORY!\n");
4021         return E_OUTOFMEMORY;
4022     }
4023     return S_OK;
4024 }
4025
4026 static const ITypeLib2Vtbl tlbvt = {
4027     ITypeLib2_fnQueryInterface,
4028     ITypeLib2_fnAddRef,
4029     ITypeLib2_fnRelease,
4030     ITypeLib2_fnGetTypeInfoCount,
4031     ITypeLib2_fnGetTypeInfo,
4032     ITypeLib2_fnGetTypeInfoType,
4033     ITypeLib2_fnGetTypeInfoOfGuid,
4034     ITypeLib2_fnGetLibAttr,
4035     ITypeLib2_fnGetTypeComp,
4036     ITypeLib2_fnGetDocumentation,
4037     ITypeLib2_fnIsName,
4038     ITypeLib2_fnFindName,
4039     ITypeLib2_fnReleaseTLibAttr,
4040
4041     ITypeLib2_fnGetCustData,
4042     ITypeLib2_fnGetLibStatistics,
4043     ITypeLib2_fnGetDocumentation2,
4044     ITypeLib2_fnGetAllCustData
4045  };
4046
4047
4048 static HRESULT WINAPI ITypeLibComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
4049 {
4050     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4051
4052     return ITypeLib2_QueryInterface((ITypeLib *)This, riid, ppv);
4053 }
4054
4055 static ULONG WINAPI ITypeLibComp_fnAddRef(ITypeComp * iface)
4056 {
4057     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4058
4059     return ITypeLib2_AddRef((ITypeLib2 *)This);
4060 }
4061
4062 static ULONG WINAPI ITypeLibComp_fnRelease(ITypeComp * iface)
4063 {
4064     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4065
4066     return ITypeLib2_Release((ITypeLib2 *)This);
4067 }
4068
4069 static HRESULT WINAPI ITypeLibComp_fnBind(
4070     ITypeComp * iface,
4071     OLECHAR * szName,
4072     ULONG lHash,
4073     WORD wFlags,
4074     ITypeInfo ** ppTInfo,
4075     DESCKIND * pDescKind,
4076     BINDPTR * pBindPtr)
4077 {
4078     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4079     ITypeInfoImpl *pTypeInfo;
4080
4081     TRACE("(%s, 0x%lx, 0x%x, %p, %p, %p)\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
4082
4083     *pDescKind = DESCKIND_NONE;
4084     pBindPtr->lptcomp = NULL;
4085     *ppTInfo = NULL;
4086
4087     for (pTypeInfo = This->pTypeInfo; pTypeInfo; pTypeInfo = pTypeInfo->next)
4088     {
4089         TRACE("testing %s\n", debugstr_w(pTypeInfo->Name));
4090
4091         /* FIXME: check wFlags here? */
4092         /* FIXME: we should use a hash table to look this info up using lHash
4093          * instead of an O(n) search */
4094         if ((pTypeInfo->TypeAttr.typekind == TKIND_ENUM) ||
4095             (pTypeInfo->TypeAttr.typekind == TKIND_MODULE))
4096         {
4097             if (pTypeInfo->Name && !strcmpW(pTypeInfo->Name, szName))
4098             {
4099                 *pDescKind = DESCKIND_TYPECOMP;
4100                 pBindPtr->lptcomp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4101                 ITypeComp_AddRef(pBindPtr->lptcomp);
4102                 TRACE("module or enum: %s\n", debugstr_w(szName));
4103                 return S_OK;
4104             }
4105         }
4106
4107         if ((pTypeInfo->TypeAttr.typekind == TKIND_MODULE) ||
4108             (pTypeInfo->TypeAttr.typekind == TKIND_ENUM))
4109         {
4110             ITypeComp *pSubTypeComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4111             HRESULT hr;
4112
4113             hr = ITypeComp_Bind(pSubTypeComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
4114             if (SUCCEEDED(hr) && (*pDescKind != DESCKIND_NONE))
4115             {
4116                 TRACE("found in module or in enum: %s\n", debugstr_w(szName));
4117                 return S_OK;
4118             }
4119         }
4120
4121         if ((pTypeInfo->TypeAttr.typekind == TKIND_COCLASS) &&
4122             (pTypeInfo->TypeAttr.wTypeFlags & TYPEFLAG_FAPPOBJECT))
4123         {
4124             ITypeComp *pSubTypeComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4125             HRESULT hr;
4126             ITypeInfo *subtypeinfo;
4127             BINDPTR subbindptr;
4128             DESCKIND subdesckind;
4129
4130             hr = ITypeComp_Bind(pSubTypeComp, szName, lHash, wFlags,
4131                 &subtypeinfo, &subdesckind, &subbindptr);
4132             if (SUCCEEDED(hr) && (subdesckind != DESCKIND_NONE))
4133             {
4134                 TYPEDESC tdesc_appobject =
4135                 {
4136                     {
4137                         (TYPEDESC *)pTypeInfo->hreftype
4138                     },
4139                     VT_USERDEFINED
4140                 };
4141                 const VARDESC vardesc_appobject =
4142                 {
4143                     -2,         /* memid */
4144                     NULL,       /* lpstrSchema */
4145                     {
4146                         0       /* oInst */
4147                     },
4148                     {
4149                                 /* ELEMDESC */
4150                         {
4151                                 /* TYPEDESC */
4152                                 {
4153                                     &tdesc_appobject
4154                                 },
4155                                 VT_PTR
4156                         },
4157                     },
4158                     0,          /* wVarFlags */
4159                     VAR_STATIC  /* varkind */
4160                 };
4161
4162                 TRACE("found in implicit app object: %s\n", debugstr_w(szName));
4163
4164                 /* cleanup things filled in by Bind call so we can put our
4165                  * application object data in there instead */
4166                 switch (subdesckind)
4167                 {
4168                 case DESCKIND_FUNCDESC:
4169                     ITypeInfo_ReleaseFuncDesc(subtypeinfo, subbindptr.lpfuncdesc);
4170                     break;
4171                 case DESCKIND_VARDESC:
4172                     ITypeInfo_ReleaseVarDesc(subtypeinfo, subbindptr.lpvardesc);
4173                     break;
4174                 default:
4175                     break;
4176                 }
4177                 if (subtypeinfo) ITypeInfo_Release(subtypeinfo);
4178
4179                 if (pTypeInfo->hreftype == -1)
4180                     FIXME("no hreftype for interface %p\n", pTypeInfo);
4181
4182                 hr = TLB_AllocAndInitVarDesc(&vardesc_appobject, &pBindPtr->lpvardesc);
4183                 if (FAILED(hr))
4184                     return hr;
4185
4186                 *pDescKind = DESCKIND_IMPLICITAPPOBJ;
4187                 *ppTInfo = (ITypeInfo *)pTypeInfo;
4188                 ITypeInfo_AddRef(*ppTInfo);
4189                 return S_OK;
4190             }
4191         }
4192     }
4193
4194     TRACE("name not found %s\n", debugstr_w(szName));
4195     return S_OK;
4196 }
4197
4198 static HRESULT WINAPI ITypeLibComp_fnBindType(
4199     ITypeComp * iface,
4200     OLECHAR * szName,
4201     ULONG lHash,
4202     ITypeInfo ** ppTInfo,
4203     ITypeComp ** ppTComp)
4204 {
4205     FIXME("(%s, %lx, %p, %p): stub\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
4206     return E_NOTIMPL;
4207 }
4208
4209 static const ITypeCompVtbl tlbtcvt =
4210 {
4211
4212     ITypeLibComp_fnQueryInterface,
4213     ITypeLibComp_fnAddRef,
4214     ITypeLibComp_fnRelease,
4215
4216     ITypeLibComp_fnBind,
4217     ITypeLibComp_fnBindType
4218 };
4219
4220 /*================== ITypeInfo(2) Methods ===================================*/
4221 static ITypeInfo2 * WINAPI ITypeInfo_Constructor(void)
4222 {
4223     ITypeInfoImpl * pTypeInfoImpl;
4224
4225     pTypeInfoImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeInfoImpl));
4226     if (pTypeInfoImpl)
4227     {
4228       pTypeInfoImpl->lpVtbl = &tinfvt;
4229       pTypeInfoImpl->lpVtblTypeComp = &tcompvt;
4230       pTypeInfoImpl->ref=1;
4231       pTypeInfoImpl->hreftype = -1;
4232     }
4233     TRACE("(%p)\n", pTypeInfoImpl);
4234     return (ITypeInfo2*) pTypeInfoImpl;
4235 }
4236
4237 /* ITypeInfo::QueryInterface
4238  */
4239 static HRESULT WINAPI ITypeInfo_fnQueryInterface(
4240         ITypeInfo2 *iface,
4241         REFIID riid,
4242         VOID **ppvObject)
4243 {
4244     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4245
4246     TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
4247
4248     *ppvObject=NULL;
4249     if(IsEqualIID(riid, &IID_IUnknown) ||
4250             IsEqualIID(riid,&IID_ITypeInfo)||
4251             IsEqualIID(riid,&IID_ITypeInfo2))
4252         *ppvObject = This;
4253
4254     if(*ppvObject){
4255         ITypeInfo_AddRef(iface);
4256         TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
4257         return S_OK;
4258     }
4259     TRACE("-- Interface: E_NOINTERFACE\n");
4260     return E_NOINTERFACE;
4261 }
4262
4263 /* ITypeInfo::AddRef
4264  */
4265 static ULONG WINAPI ITypeInfo_fnAddRef( ITypeInfo2 *iface)
4266 {
4267     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4268     ULONG ref = InterlockedIncrement(&This->ref);
4269
4270     ITypeLib2_AddRef((ITypeLib2*)This->pTypeLib);
4271
4272     TRACE("(%p)->ref is %lu\n",This, ref);
4273     return ref;
4274 }
4275
4276 /* ITypeInfo::Release
4277  */
4278 static ULONG WINAPI ITypeInfo_fnRelease(ITypeInfo2 *iface)
4279 {
4280     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4281     ULONG ref = InterlockedDecrement(&This->ref);
4282
4283     TRACE("(%p)->(%lu)\n",This, ref);
4284
4285     if (ref)   {
4286       /* We don't release ITypeLib when ref=0 because
4287          it means that function is called by ITypeLib2_Release */
4288       ITypeLib2_Release((ITypeLib2*)This->pTypeLib);
4289     } else   {
4290       static int once = 0;
4291       if (!once)
4292       {
4293           once = 1;
4294           FIXME("destroy child objects\n");
4295       }
4296
4297       TRACE("destroying ITypeInfo(%p)\n",This);
4298       if (This->Name)
4299       {
4300           SysFreeString(This->Name);
4301           This->Name = 0;
4302       }
4303
4304       if (This->DocString)
4305       {
4306           SysFreeString(This->DocString);
4307           This->DocString = 0;
4308       }
4309
4310       if (This->DllName)
4311       {
4312           SysFreeString(This->DllName);
4313           This->DllName = 0;
4314       }
4315
4316       if (This->next)
4317       {
4318         ITypeInfo_Release((ITypeInfo*)This->next);
4319       }
4320
4321       HeapFree(GetProcessHeap(),0,This);
4322       return 0;
4323     }
4324     return ref;
4325 }
4326
4327 /* ITypeInfo::GetTypeAttr
4328  *
4329  * Retrieves a TYPEATTR structure that contains the attributes of the type
4330  * description.
4331  *
4332  */
4333 static HRESULT WINAPI ITypeInfo_fnGetTypeAttr( ITypeInfo2 *iface,
4334         LPTYPEATTR  *ppTypeAttr)
4335 {
4336     const ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4337     SIZE_T size;
4338
4339     TRACE("(%p)\n",This);
4340
4341     size = sizeof(**ppTypeAttr);
4342     if (This->TypeAttr.typekind == TKIND_ALIAS)
4343         size += TLB_SizeTypeDesc(&This->TypeAttr.tdescAlias, FALSE);
4344
4345     *ppTypeAttr = HeapAlloc(GetProcessHeap(), 0, size);
4346     if (!*ppTypeAttr)
4347         return E_OUTOFMEMORY;
4348
4349     memcpy(*ppTypeAttr, &This->TypeAttr, sizeof(**ppTypeAttr));
4350
4351     if (This->TypeAttr.typekind == TKIND_ALIAS)
4352         TLB_CopyTypeDesc(&(*ppTypeAttr)->tdescAlias,
4353             &This->TypeAttr.tdescAlias, (void *)(*ppTypeAttr + 1));
4354
4355     if((*ppTypeAttr)->typekind == TKIND_DISPATCH) {
4356         (*ppTypeAttr)->cFuncs = (*ppTypeAttr)->cbSizeVft / 4; /* This should include all the inherited
4357                                                                  funcs */
4358         (*ppTypeAttr)->cbSizeVft = 28; /* This is always the size of IDispatch's vtbl */
4359         (*ppTypeAttr)->wTypeFlags &= ~TYPEFLAG_FOLEAUTOMATION;
4360     }
4361     return S_OK;
4362 }
4363
4364 /* ITypeInfo::GetTypeComp
4365  *
4366  * Retrieves the ITypeComp interface for the type description, which enables a
4367  * client compiler to bind to the type description's members.
4368  *
4369  */
4370 static HRESULT WINAPI ITypeInfo_fnGetTypeComp( ITypeInfo2 *iface,
4371         ITypeComp  * *ppTComp)
4372 {
4373     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4374
4375     TRACE("(%p)->(%p) stub!\n", This, ppTComp);
4376
4377     *ppTComp = (ITypeComp *)&This->lpVtblTypeComp;
4378     ITypeComp_AddRef(*ppTComp);
4379     return S_OK;
4380 }
4381
4382 static SIZE_T TLB_SizeElemDesc( const ELEMDESC *elemdesc )
4383 {
4384     SIZE_T size = TLB_SizeTypeDesc(&elemdesc->tdesc, FALSE);
4385     if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
4386         size += sizeof(*elemdesc->u.paramdesc.pparamdescex);
4387     return size;
4388 }
4389
4390 static HRESULT TLB_CopyElemDesc( const ELEMDESC *src, ELEMDESC *dest, char **buffer )
4391 {
4392     memcpy(dest, src, sizeof(ELEMDESC));
4393     *buffer = TLB_CopyTypeDesc(&dest->tdesc, &src->tdesc, *buffer);
4394     if (src->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
4395     {
4396         const PARAMDESCEX *pparamdescex_src = src->u.paramdesc.pparamdescex;
4397         PARAMDESCEX *pparamdescex_dest = dest->u.paramdesc.pparamdescex = (PARAMDESCEX *)*buffer;
4398         *buffer += sizeof(PARAMDESCEX);
4399         memcpy(pparamdescex_dest, pparamdescex_src, sizeof(PARAMDESCEX));
4400         VariantInit(&pparamdescex_dest->varDefaultValue);
4401         return VariantCopy(&pparamdescex_dest->varDefaultValue, 
4402                            (VARIANTARG *)&pparamdescex_src->varDefaultValue);
4403     }
4404     else
4405         dest->u.paramdesc.pparamdescex = NULL;
4406     return S_OK;
4407 }
4408
4409 static void TLB_FreeElemDesc( ELEMDESC *elemdesc )
4410 {
4411     if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
4412         VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue);
4413 }
4414
4415 static HRESULT TLB_AllocAndInitFuncDesc( const FUNCDESC *src, FUNCDESC **dest_ptr, BOOL dispinterface )
4416 {
4417     FUNCDESC *dest;
4418     char *buffer;
4419     SIZE_T size = sizeof(*src);
4420     SHORT i;
4421     HRESULT hr;
4422
4423     size += sizeof(*src->lprgscode) * src->cScodes;
4424     size += TLB_SizeElemDesc(&src->elemdescFunc);
4425     for (i = 0; i < src->cParams; i++)
4426     {
4427         size += sizeof(ELEMDESC);
4428         size += TLB_SizeElemDesc(&src->lprgelemdescParam[i]);
4429     }
4430
4431     dest = (FUNCDESC *)SysAllocStringByteLen(NULL, size);
4432     if (!dest) return E_OUTOFMEMORY;
4433
4434     memcpy(dest, src, sizeof(FUNCDESC));
4435     buffer = (char *)(dest + 1);
4436
4437     dest->lprgscode = (SCODE *)buffer;
4438     memcpy(dest->lprgscode, src->lprgscode, sizeof(*src->lprgscode) * src->cScodes);
4439     buffer += sizeof(*src->lprgscode) * src->cScodes;
4440
4441     hr = TLB_CopyElemDesc(&src->elemdescFunc, &dest->elemdescFunc, &buffer);
4442     if (FAILED(hr))
4443     {
4444         SysFreeString((BSTR)dest);
4445         return hr;
4446     }
4447
4448     dest->lprgelemdescParam = (ELEMDESC *)buffer;
4449     buffer += sizeof(ELEMDESC) * src->cParams;
4450     for (i = 0; i < src->cParams; i++)
4451     {
4452         hr = TLB_CopyElemDesc(&src->lprgelemdescParam[i], &dest->lprgelemdescParam[i], &buffer);
4453         if (FAILED(hr))
4454             break;
4455     }
4456     if (FAILED(hr))
4457     {
4458         /* undo the above actions */
4459         for (i = i - 1; i >= 0; i--)
4460             TLB_FreeElemDesc(&dest->lprgelemdescParam[i]);
4461         TLB_FreeElemDesc(&dest->elemdescFunc);
4462         SysFreeString((BSTR)dest);
4463         return hr;
4464     }
4465
4466     /* special treatment for dispinterfaces: this makes functions appear
4467      * to return their [retval] value when it is really returning an
4468      * HRESULT */
4469     if (dispinterface && dest->elemdescFunc.tdesc.vt == VT_HRESULT)
4470     {
4471         if (dest->cParams &&
4472             (dest->lprgelemdescParam[dest->cParams - 1].u.paramdesc.wParamFlags & PARAMFLAG_FRETVAL))
4473         {
4474             ELEMDESC *elemdesc = &dest->lprgelemdescParam[dest->cParams - 1];
4475             if (elemdesc->tdesc.vt != VT_PTR)
4476             {
4477                 ERR("elemdesc should have started with VT_PTR instead of:\n");
4478                 if (ERR_ON(ole))
4479                     dump_ELEMDESC(elemdesc);
4480                 return E_UNEXPECTED;
4481             }
4482
4483             /* copy last parameter to the return value. we are using a flat
4484              * buffer so there is no danger of leaking memory in
4485              * elemdescFunc */
4486             dest->elemdescFunc.tdesc = *elemdesc->tdesc.u.lptdesc;
4487
4488             /* remove the last parameter */
4489             dest->cParams--;
4490         }
4491         else
4492             /* otherwise this function is made to appear to have no return
4493              * value */
4494             dest->elemdescFunc.tdesc.vt = VT_VOID;
4495
4496     }
4497
4498     *dest_ptr = dest;
4499     return S_OK;
4500 }
4501
4502 HRESULT ITypeInfoImpl_GetInternalFuncDesc( ITypeInfo *iface, UINT index, const FUNCDESC **ppFuncDesc )
4503 {
4504     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4505     const TLBFuncDesc *pFDesc;
4506     int i;
4507
4508     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++, pFDesc=pFDesc->next)
4509         ;
4510
4511     if (pFDesc)
4512     {
4513         *ppFuncDesc = &pFDesc->funcdesc;
4514         return S_OK;
4515     }
4516
4517     return E_INVALIDARG;
4518 }
4519
4520 /* ITypeInfo::GetFuncDesc
4521  *
4522  * Retrieves the FUNCDESC structure that contains information about a
4523  * specified function.
4524  *
4525  */
4526 static HRESULT WINAPI ITypeInfo_fnGetFuncDesc( ITypeInfo2 *iface, UINT index,
4527         LPFUNCDESC  *ppFuncDesc)
4528 {
4529     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4530     const FUNCDESC *internal_funcdesc;
4531     HRESULT hr;
4532
4533     TRACE("(%p) index %d\n", This, index);
4534
4535     hr = ITypeInfoImpl_GetInternalFuncDesc((ITypeInfo *)iface, index, &internal_funcdesc);
4536     if (FAILED(hr))
4537         return hr;
4538
4539     return TLB_AllocAndInitFuncDesc(
4540         internal_funcdesc,
4541         ppFuncDesc,
4542         This->TypeAttr.typekind == TKIND_DISPATCH);
4543 }
4544
4545 static HRESULT TLB_AllocAndInitVarDesc( const VARDESC *src, VARDESC **dest_ptr )
4546 {
4547     VARDESC *dest;
4548     char *buffer;
4549     SIZE_T size = sizeof(*src);
4550     HRESULT hr;
4551
4552     if (src->lpstrSchema) size += (strlenW(src->lpstrSchema) + 1) * sizeof(WCHAR);
4553     if (src->varkind == VAR_CONST)
4554         size += sizeof(VARIANT);
4555     size += TLB_SizeElemDesc(&src->elemdescVar);
4556
4557     dest = (VARDESC *)SysAllocStringByteLen(NULL, size);
4558     if (!dest) return E_OUTOFMEMORY;
4559
4560     *dest = *src;
4561     buffer = (char *)(dest + 1);
4562     if (src->lpstrSchema)
4563     {
4564         int len;
4565         dest->lpstrSchema = (LPOLESTR)buffer;
4566         len = strlenW(src->lpstrSchema);
4567         memcpy(dest->lpstrSchema, src->lpstrSchema, (len + 1) * sizeof(WCHAR));
4568         buffer += (len + 1) * sizeof(WCHAR);
4569     }
4570
4571     if (src->varkind == VAR_CONST)
4572     {
4573         HRESULT hr;
4574
4575         dest->u.lpvarValue = (VARIANT *)buffer;
4576         *dest->u.lpvarValue = *src->u.lpvarValue;
4577         buffer += sizeof(VARIANT);
4578         VariantInit(dest->u.lpvarValue);
4579         hr = VariantCopy(dest->u.lpvarValue, src->u.lpvarValue);
4580         if (FAILED(hr))
4581         {
4582             SysFreeString((BSTR)dest_ptr);
4583             return hr;
4584         }
4585     }
4586     hr = TLB_CopyElemDesc(&src->elemdescVar, &dest->elemdescVar, &buffer);
4587     if (FAILED(hr))
4588     {
4589         if (src->varkind == VAR_CONST)
4590             VariantClear(dest->u.lpvarValue);
4591         SysFreeString((BSTR)dest);
4592         return hr;
4593     }
4594     *dest_ptr = dest;
4595     return S_OK;
4596 }
4597
4598 /* ITypeInfo::GetVarDesc
4599  *
4600  * Retrieves a VARDESC structure that describes the specified variable.
4601  *
4602  */
4603 static HRESULT WINAPI ITypeInfo_fnGetVarDesc( ITypeInfo2 *iface, UINT index,
4604         LPVARDESC  *ppVarDesc)
4605 {
4606     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4607     int i;
4608     const TLBVarDesc *pVDesc;
4609
4610     TRACE("(%p) index %d\n", This, index);
4611
4612     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next)
4613         ;
4614
4615     if (pVDesc)
4616         return TLB_AllocAndInitVarDesc(&pVDesc->vardesc, ppVarDesc);
4617
4618     return E_INVALIDARG;
4619 }
4620
4621 /* ITypeInfo_GetNames
4622  *
4623  * Retrieves the variable with the specified member ID (or the name of the
4624  * property or method and its parameters) that correspond to the specified
4625  * function ID.
4626  */
4627 static HRESULT WINAPI ITypeInfo_fnGetNames( ITypeInfo2 *iface, MEMBERID memid,
4628         BSTR  *rgBstrNames, UINT cMaxNames, UINT  *pcNames)
4629 {
4630     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4631     const TLBFuncDesc *pFDesc;
4632     const TLBVarDesc *pVDesc;
4633     int i;
4634     TRACE("(%p) memid=0x%08lx Maxname=%d\n", This, memid, cMaxNames);
4635     for(pFDesc=This->funclist; pFDesc && pFDesc->funcdesc.memid != memid; pFDesc=pFDesc->next);
4636     if(pFDesc)
4637     {
4638       /* function found, now return function and parameter names */
4639       for(i=0; i<cMaxNames && i <= pFDesc->funcdesc.cParams; i++)
4640       {
4641         if(!i)
4642           *rgBstrNames=SysAllocString(pFDesc->Name);
4643         else
4644           rgBstrNames[i]=SysAllocString(pFDesc->pParamDesc[i-1].Name);
4645       }
4646       *pcNames=i;
4647     }
4648     else
4649     {
4650       for(pVDesc=This->varlist; pVDesc && pVDesc->vardesc.memid != memid; pVDesc=pVDesc->next);
4651       if(pVDesc)
4652       {
4653         *rgBstrNames=SysAllocString(pVDesc->Name);
4654         *pcNames=1;
4655       }
4656       else
4657       {
4658         if(This->TypeAttr.cImplTypes &&
4659            (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
4660           /* recursive search */
4661           ITypeInfo *pTInfo;
4662           HRESULT result;
4663           result=ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef,
4664                                           &pTInfo);
4665           if(SUCCEEDED(result))
4666           {
4667             result=ITypeInfo_GetNames(pTInfo, memid, rgBstrNames, cMaxNames, pcNames);
4668             ITypeInfo_Release(pTInfo);
4669             return result;
4670           }
4671           WARN("Could not search inherited interface!\n");
4672         }
4673         else
4674         {
4675           WARN("no names found\n");
4676         }
4677         *pcNames=0;
4678         return TYPE_E_ELEMENTNOTFOUND;
4679       }
4680     }
4681     return S_OK;
4682 }
4683
4684
4685 /* ITypeInfo::GetRefTypeOfImplType
4686  *
4687  * If a type description describes a COM class, it retrieves the type
4688  * description of the implemented interface types. For an interface,
4689  * GetRefTypeOfImplType returns the type information for inherited interfaces,
4690  * if any exist.
4691  *
4692  */
4693 static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType(
4694         ITypeInfo2 *iface,
4695         UINT index,
4696         HREFTYPE  *pRefType)
4697 {
4698     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4699     int i;
4700     HRESULT hr = S_OK;
4701     const TLBImplType *pImpl = This->impltypelist;
4702
4703     TRACE("(%p) index %d\n", This, index);
4704     if (TRACE_ON(ole)) dump_TypeInfo(This);
4705
4706     if(index==(UINT)-1)
4707     {
4708       /* only valid on dual interfaces;
4709          retrieve the associated TKIND_INTERFACE handle for the current TKIND_DISPATCH
4710       */
4711       if( This->TypeAttr.typekind != TKIND_DISPATCH) return E_INVALIDARG;
4712
4713       if (This->TypeAttr.wTypeFlags & TYPEFLAG_FDISPATCHABLE &&
4714           This->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL )
4715       {
4716         *pRefType = -1;
4717       }
4718       else
4719       {
4720         hr = TYPE_E_ELEMENTNOTFOUND;
4721       }
4722     }
4723     else
4724     {
4725       /* get element n from linked list */
4726       for(i=0; pImpl && i<index; i++)
4727       {
4728         pImpl = pImpl->next;
4729       }
4730
4731       if (pImpl)
4732         *pRefType = pImpl->hRef;
4733       else
4734         hr = TYPE_E_ELEMENTNOTFOUND;
4735     }
4736
4737     if(TRACE_ON(ole))
4738     {
4739         if(SUCCEEDED(hr))
4740             TRACE("SUCCESS -- hRef = 0x%08lx\n", *pRefType );
4741         else
4742             TRACE("FAILURE -- hresult = 0x%08lx\n", hr);
4743     }
4744
4745     return hr;
4746 }
4747
4748 /* ITypeInfo::GetImplTypeFlags
4749  *
4750  * Retrieves the IMPLTYPEFLAGS enumeration for one implemented interface
4751  * or base interface in a type description.
4752  */
4753 static HRESULT WINAPI ITypeInfo_fnGetImplTypeFlags( ITypeInfo2 *iface,
4754         UINT index, INT  *pImplTypeFlags)
4755 {
4756     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4757     int i;
4758     TLBImplType *pImpl;
4759
4760     TRACE("(%p) index %d\n", This, index);
4761     for(i=0, pImpl=This->impltypelist; i<index && pImpl;
4762         i++, pImpl=pImpl->next)
4763         ;
4764     if(i==index && pImpl){
4765         *pImplTypeFlags=pImpl->implflags;
4766         return S_OK;
4767     }
4768     *pImplTypeFlags=0;
4769     return TYPE_E_ELEMENTNOTFOUND;
4770 }
4771
4772 /* GetIDsOfNames
4773  * Maps between member names and member IDs, and parameter names and
4774  * parameter IDs.
4775  */
4776 static HRESULT WINAPI ITypeInfo_fnGetIDsOfNames( ITypeInfo2 *iface,
4777         LPOLESTR  *rgszNames, UINT cNames, MEMBERID  *pMemId)
4778 {
4779     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4780     const TLBFuncDesc *pFDesc;
4781     const TLBVarDesc *pVDesc;
4782     HRESULT ret=S_OK;
4783     int i;
4784
4785     TRACE("(%p) Name %s cNames %d\n", This, debugstr_w(*rgszNames),
4786             cNames);
4787
4788     /* init out parameters in case of failure */
4789     for (i = 0; i < cNames; i++)
4790         pMemId[i] = MEMBERID_NIL;
4791
4792     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next) {
4793         int j;
4794         if(!lstrcmpiW(*rgszNames, pFDesc->Name)) {
4795             if(cNames) *pMemId=pFDesc->funcdesc.memid;
4796             for(i=1; i < cNames; i++){
4797                 for(j=0; j<pFDesc->funcdesc.cParams; j++)
4798                     if(!lstrcmpiW(rgszNames[i],pFDesc->pParamDesc[j].Name))
4799                             break;
4800                 if( j<pFDesc->funcdesc.cParams)
4801                     pMemId[i]=j;
4802                 else
4803                    ret=DISP_E_UNKNOWNNAME;
4804             };
4805             TRACE("-- 0x%08lx\n", ret);
4806             return ret;
4807         }
4808     }
4809     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) {
4810         if(!lstrcmpiW(*rgszNames, pVDesc->Name)) {
4811             if(cNames) *pMemId=pVDesc->vardesc.memid;
4812             return ret;
4813         }
4814     }
4815     /* not found, see if this is and interface with an inheritance */
4816     if(This->TypeAttr.cImplTypes &&
4817        (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
4818         /* recursive search */
4819         ITypeInfo *pTInfo;
4820         ret=ITypeInfo_GetRefTypeInfo(iface,
4821                 This->impltypelist->hRef, &pTInfo);
4822         if(SUCCEEDED(ret)){
4823             ret=ITypeInfo_GetIDsOfNames(pTInfo, rgszNames, cNames, pMemId );
4824             ITypeInfo_Release(pTInfo);
4825             return ret;
4826         }
4827         WARN("Could not search inherited interface!\n");
4828     } else
4829         WARN("no names found\n");
4830     return DISP_E_UNKNOWNNAME;
4831 }
4832
4833 /* ITypeInfo::Invoke
4834  *
4835  * Invokes a method, or accesses a property of an object, that implements the
4836  * interface described by the type description.
4837  */
4838 DWORD
4839 _invoke(FARPROC func,CALLCONV callconv, int nrargs, DWORD *args) {
4840     DWORD res;
4841
4842     if (TRACE_ON(ole)) {
4843         int i;
4844         TRACE("Calling %p(",func);
4845         for (i=0;i<nrargs;i++) TRACE("%08lx,",args[i]);
4846         TRACE(")\n");
4847     }
4848
4849     switch (callconv) {
4850     case CC_STDCALL:
4851
4852         switch (nrargs) {
4853         case 0:
4854                 res = func();
4855                 break;
4856         case 1:
4857                 res = func(args[0]);
4858                 break;
4859         case 2:
4860                 res = func(args[0],args[1]);
4861                 break;
4862         case 3:
4863                 res = func(args[0],args[1],args[2]);
4864                 break;
4865         case 4:
4866                 res = func(args[0],args[1],args[2],args[3]);
4867                 break;
4868         case 5:
4869                 res = func(args[0],args[1],args[2],args[3],args[4]);
4870                 break;
4871         case 6:
4872                 res = func(args[0],args[1],args[2],args[3],args[4],args[5]);
4873                 break;
4874         case 7:
4875                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
4876                 break;
4877         case 8:
4878                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]);
4879                 break;
4880         case 9:
4881                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]);
4882                 break;
4883         case 10:
4884                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9]);
4885                 break;
4886         case 11:
4887                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10]);
4888                 break;
4889         case 12:
4890                 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]);
4891                 break;
4892         case 13:
4893                 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]);
4894                 break;
4895         case 14:
4896                 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]);
4897                 break;
4898         case 15:
4899                 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],args[14]);
4900                 break;
4901         case 16:
4902                 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],args[14],args[15]);
4903                 break;
4904         case 17:
4905                 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],args[14],args[15],args[16]);
4906                 break;
4907         case 18:
4908                 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],args[14],args[15],args[16],args[17]);
4909                 break;
4910         case 19:
4911                 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],args[14],args[15],args[16],args[17],args[18]);
4912                 break;
4913         case 20:
4914                 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],args[14],args[15],args[16],args[17],args[18],args[19]);
4915                 break;
4916         case 21:
4917                 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],args[14],args[15],args[16],args[17],args[18],args[19],args[20]);
4918                 break;
4919         case 22:
4920                 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],args[14],args[15],args[16],args[17],args[18],args[19],args[20],args[21]);
4921                 break;
4922         case 23:
4923                 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],args[14],args[15],args[16],args[17],args[18],args[19],args[20],args[21],args[22]);
4924                 break;
4925         default:
4926                 FIXME("unsupported number of arguments %d in stdcall\n",nrargs);
4927                 res = -1;
4928                 break;
4929         }
4930         break;
4931     default:
4932         FIXME("unsupported calling convention %d\n",callconv);
4933         res = -1;
4934         break;
4935     }
4936     TRACE("returns %08lx\n",res);
4937     return res;
4938 }
4939
4940 extern int _argsize(DWORD vt);
4941
4942 static HRESULT userdefined_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
4943 {
4944     HRESULT hr = S_OK;
4945     ITypeInfo *tinfo2 = NULL;
4946     TYPEATTR *tattr = NULL;
4947
4948     hr = ITypeInfo_GetRefTypeInfo(tinfo, tdesc->u.hreftype, &tinfo2);
4949     if (hr)
4950     {
4951         ERR("Could not get typeinfo of hreftype %lx for VT_USERDEFINED, "
4952             "hr = 0x%08lx\n",
4953               tdesc->u.hreftype, hr);
4954         return hr;
4955     }
4956     hr = ITypeInfo_GetTypeAttr(tinfo2, &tattr);
4957     if (hr)
4958     {
4959         ERR("ITypeInfo_GetTypeAttr failed, hr = 0x%08lx\n", hr);
4960         ITypeInfo_Release(tinfo2);
4961         return hr;
4962     }
4963
4964     switch (tattr->typekind)
4965     {
4966     case TKIND_ENUM:
4967         *vt |= VT_I4;
4968         break;
4969
4970     case TKIND_ALIAS:
4971         tdesc = &tattr->tdescAlias;
4972         hr = typedescvt_to_variantvt(tinfo2, &tattr->tdescAlias, vt);
4973         break;
4974
4975     case TKIND_INTERFACE:
4976         if (IsEqualIID(&IID_IDispatch, &tattr->guid))
4977            *vt |= VT_DISPATCH;
4978         else
4979            *vt |= VT_UNKNOWN;
4980         break;
4981
4982     case TKIND_DISPATCH:
4983         *vt |= VT_DISPATCH;
4984         break;
4985
4986     case TKIND_RECORD:
4987         FIXME("TKIND_RECORD unhandled.\n");
4988         hr = E_NOTIMPL;
4989         break;
4990
4991     case TKIND_UNION:
4992         FIXME("TKIND_RECORD unhandled.\n");
4993         hr = E_NOTIMPL;
4994         break;
4995
4996     default:
4997         FIXME("TKIND %d unhandled.\n",tattr->typekind);
4998         hr = E_NOTIMPL;
4999         break;
5000     }
5001     ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
5002     ITypeInfo_Release(tinfo2);
5003     return hr;
5004 }
5005
5006 static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
5007 {
5008     HRESULT hr = S_OK;
5009
5010     /* enforce only one level of pointer indirection */
5011     if (!(*vt & VT_BYREF) && !(*vt & VT_ARRAY) && (tdesc->vt == VT_PTR))
5012     {
5013         tdesc = tdesc->u.lptdesc;
5014
5015         /* munch VT_PTR -> VT_USERDEFINED(interface) into VT_UNKNOWN or
5016          * VT_DISPATCH and VT_PTR -> VT_PTR -> VT_USERDEFINED(interface) into 
5017          * VT_BYREF|VT_DISPATCH or VT_BYREF|VT_UNKNOWN */
5018         if ((tdesc->vt == VT_USERDEFINED) ||
5019             ((tdesc->vt == VT_PTR) && (tdesc->u.lptdesc->vt == VT_USERDEFINED)))
5020         {
5021             VARTYPE vt_userdefined = 0;
5022             const TYPEDESC *tdesc_userdefined = tdesc;
5023             if (tdesc->vt == VT_PTR)
5024             {
5025                 vt_userdefined = VT_BYREF;
5026                 tdesc_userdefined = tdesc->u.lptdesc;
5027             }
5028             hr = userdefined_to_variantvt(tinfo, tdesc_userdefined, &vt_userdefined);
5029             if ((hr == S_OK) && 
5030                 (((vt_userdefined & VT_TYPEMASK) == VT_UNKNOWN) ||
5031                  ((vt_userdefined & VT_TYPEMASK) == VT_DISPATCH)))
5032             {
5033                 *vt |= vt_userdefined;
5034                 return S_OK;
5035             }
5036         }
5037         *vt = VT_BYREF;
5038     }
5039
5040     switch (tdesc->vt)
5041     {
5042     case VT_HRESULT:
5043         *vt |= VT_ERROR;
5044         break;
5045     case VT_USERDEFINED:
5046         hr = userdefined_to_variantvt(tinfo, tdesc, vt);
5047         break;
5048     case VT_VOID:
5049     case VT_CARRAY:
5050     case VT_PTR:
5051     case VT_LPSTR:
5052     case VT_LPWSTR:
5053         ERR("cannot convert type %d into variant VT\n", tdesc->vt);
5054         hr = DISP_E_BADVARTYPE;
5055         break;
5056     case VT_SAFEARRAY:
5057         *vt |= VT_ARRAY;
5058         hr = typedescvt_to_variantvt(tinfo, tdesc->u.lptdesc, vt);
5059         break;
5060     default:
5061         *vt |= tdesc->vt;
5062         break;
5063     }
5064     return hr;
5065 }
5066
5067 /***********************************************************************
5068  *              DispCallFunc (OLEAUT32.@)
5069  *
5070  * Invokes a function of the specifed calling convention, passing the
5071  * specified arguments and returns the result.
5072  *
5073  * PARAMS
5074  *  pvInstance  [I] Optional pointer to the instance whose function to invoke.
5075  *  oVft        [I] The offset in the vtable. See notes.
5076  *  cc          [I] Calling convention of the function to call.
5077  *  vtReturn    [I] The return type of the function.
5078  *  cActuals    [I] Number of parameters.
5079  *  prgvt       [I] The types of the parameters to pass. This is used for sizing only.
5080  *  prgpvarg    [I] The arguments to pass.
5081  *  pvargResult [O] The return value of the function. Can be NULL.
5082  *
5083  * RETURNS
5084  *  Success: S_OK.
5085  *  Failure: HRESULT code.
5086  *
5087  * NOTES
5088  *  The HRESULT return value of this function is not affected by the return
5089  *  value of the user supplied function, which is returned in pvargResult.
5090  *
5091  *  If pvInstance is NULL then a non-object function is to be called and oVft
5092  *  is the address of the function to call.
5093  *
5094  * The cc parameter can be one of the following values:
5095  *|CC_FASTCALL
5096  *|CC_CDECL
5097  *|CC_PASCAL
5098  *|CC_STDCALL
5099  *|CC_FPFASTCALL
5100  *|CC_SYSCALL
5101  *|CC_MPWCDECL
5102  *|CC_MPWPASCAL
5103  *
5104  * BUGS
5105  *  Native accepts arguments in the reverse order. I.e. the first item in the
5106  *  prgpvarg array is the last argument in the C/C++ declaration of the
5107  *  function to be called.
5108  */
5109 HRESULT WINAPI
5110 DispCallFunc(
5111     void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals,
5112     VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult)
5113 {
5114     int i, argsize, argspos;
5115     DWORD *args;
5116     HRESULT hres;
5117
5118     TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
5119         pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
5120         pvargResult, V_VT(pvargResult));
5121
5122     argsize = 0;
5123     if (pvInstance)
5124         argsize++; /* for This pointer */
5125
5126     for (i=0;i<cActuals;i++)
5127     {
5128         TRACE("arg %d: type %d, size %d\n",i,prgvt[i],_argsize(prgvt[i]));
5129         dump_Variant(prgpvarg[i]);
5130         argsize += _argsize(prgvt[i]);
5131     }
5132     args = HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*argsize);
5133
5134     argspos = 0;
5135     if (pvInstance)
5136     {
5137         args[0] = (DWORD)pvInstance; /* the This pointer is always the first parameter */
5138         argspos++;
5139     }
5140
5141     for (i=0;i<cActuals;i++)
5142     {
5143         VARIANT *arg = prgpvarg[i];
5144         TRACE("Storing arg %d (%d as %d)\n",i,V_VT(arg),prgvt[i]);
5145         memcpy(&args[argspos], &V_NONE(arg), _argsize(prgvt[i]) * sizeof(DWORD));
5146         argspos += _argsize(prgvt[i]);
5147     }
5148
5149     if (pvInstance)
5150     {
5151         FARPROC *vtable = *(FARPROC**)pvInstance;
5152         hres = _invoke(vtable[oVft/sizeof(void *)], cc, argsize, args);
5153     }
5154     else
5155         /* if we aren't invoking an object then the function pointer is stored
5156          * in oVft */
5157         hres = _invoke((FARPROC)oVft, cc, argsize, args);
5158
5159     if (pvargResult && (vtReturn != VT_EMPTY))
5160     {
5161         TRACE("Method returned 0x%08lx\n",hres);
5162         V_VT(pvargResult) = vtReturn;
5163         V_UI4(pvargResult) = hres;
5164     }
5165
5166     HeapFree(GetProcessHeap(),0,args);
5167     return S_OK;
5168 }
5169
5170 #define INVBUF_ELEMENT_SIZE \
5171     (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *) + sizeof(VARTYPE))
5172 #define INVBUF_GET_ARG_ARRAY(buffer, params) \
5173     ((VARIANTARG *)(buffer))
5174 #define INVBUF_GET_MISSING_ARG_ARRAY(buffer, params) \
5175     ((VARIANTARG *)((char *)(buffer) + sizeof(VARIANTARG) * (params)))
5176 #define INVBUF_GET_ARG_PTR_ARRAY(buffer, params) \
5177     ((VARIANTARG **)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG)) * (params)))
5178 #define INVBUF_GET_ARG_TYPE_ARRAY(buffer, params) \
5179     ((VARTYPE *)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *)) * (params)))
5180
5181 static HRESULT WINAPI ITypeInfo_fnInvoke(
5182     ITypeInfo2 *iface,
5183     VOID  *pIUnk,
5184     MEMBERID memid,
5185     UINT16 wFlags,
5186     DISPPARAMS  *pDispParams,
5187     VARIANT  *pVarResult,
5188     EXCEPINFO  *pExcepInfo,
5189     UINT  *pArgErr)
5190 {
5191     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5192     int i;
5193     unsigned int var_index;
5194     TYPEKIND type_kind;
5195     HRESULT hres;
5196     const TLBFuncDesc *pFuncInfo;
5197
5198     TRACE("(%p)(%p,id=%ld,flags=0x%08x,%p,%p,%p,%p)\n",
5199       This,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr
5200     );
5201     dump_DispParms(pDispParams);
5202
5203     /* we do this instead of using GetFuncDesc since it will return a fake
5204      * FUNCDESC for dispinterfaces and we want the real function description */
5205     for (pFuncInfo = This->funclist; pFuncInfo; pFuncInfo=pFuncInfo->next)
5206         if (memid == pFuncInfo->funcdesc.memid && (wFlags & pFuncInfo->funcdesc.invkind))
5207             break;
5208
5209     if (pFuncInfo) {
5210         const FUNCDESC *func_desc = &pFuncInfo->funcdesc;
5211
5212         if (TRACE_ON(ole))
5213         {
5214             TRACE("invoking:\n");
5215             dump_TLBFuncDescOne(pFuncInfo);
5216         }
5217         
5218         switch (func_desc->funckind) {
5219         case FUNC_PUREVIRTUAL:
5220         case FUNC_VIRTUAL: {
5221             void *buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INVBUF_ELEMENT_SIZE * func_desc->cParams);
5222             VARIANT varresult;
5223             VARIANT retval; /* pointer for storing byref retvals in */
5224             VARIANTARG **prgpvarg = INVBUF_GET_ARG_PTR_ARRAY(buffer, func_desc->cParams);
5225             VARIANTARG *rgvarg = INVBUF_GET_ARG_ARRAY(buffer, func_desc->cParams);
5226             VARTYPE *rgvt = INVBUF_GET_ARG_TYPE_ARRAY(buffer, func_desc->cParams);
5227
5228             hres = S_OK;
5229             for (i = 0; i < func_desc->cParams; i++)
5230             {
5231                 TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc;
5232                 hres = typedescvt_to_variantvt((ITypeInfo *)iface, tdesc, &rgvt[i]);
5233                 if (FAILED(hres))
5234                     goto func_fail;
5235             }
5236
5237             TRACE("changing args\n");
5238             for (i = 0; i < func_desc->cParams; i++)
5239             {
5240                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
5241
5242                 if (wParamFlags & PARAMFLAG_FRETVAL)
5243                 {
5244                     /* note: this check is placed so that if the caller passes
5245                      * in a VARIANTARG for the retval we just ignore it, like
5246                      * native does */
5247                     if (i == func_desc->cParams - 1)
5248                     {
5249                         VARIANTARG *arg;
5250                         arg = prgpvarg[i] = &rgvarg[i];
5251                         memset(arg, 0, sizeof(*arg));
5252                         V_VT(arg) = rgvt[i];
5253                         memset(&retval, 0, sizeof(retval));
5254                         V_BYREF(arg) = &retval;
5255                     }
5256                     else
5257                     {
5258                         ERR("[retval] parameter must be the last parameter of the method (%d/%d)\n", i, func_desc->cParams);
5259                         hres = E_UNEXPECTED;
5260                         break;
5261                     }
5262                 }
5263                 else if (i < pDispParams->cArgs)
5264                 {
5265                     V_VT(&rgvarg[i]) = V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1 - i]);
5266                     dump_Variant(&pDispParams->rgvarg[pDispParams->cArgs - 1 - i]);
5267                     /* FIXME: this doesn't work for VT_BYREF arguments if
5268                      * they are not the same type as in the paramdesc */
5269                     hres = VariantChangeType(&rgvarg[i], &pDispParams->rgvarg[pDispParams->cArgs - 1 - i], 0, rgvt[i]);
5270                     if (FAILED(hres))
5271                     {
5272                         ERR("failed to convert param %d to vt %d\n", i, rgvt[i]);
5273                         break;
5274                     }
5275                     V_VT(&rgvarg[i]) = rgvt[i];
5276                     prgpvarg[i] = &rgvarg[i];
5277                 }
5278                 else if (wParamFlags & PARAMFLAG_FOPT)
5279                 {
5280                     VARIANTARG *arg;
5281                     arg = prgpvarg[i] = &rgvarg[i];
5282                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
5283                     {
5284                         hres = VariantCopy(arg, &func_desc->lprgelemdescParam[i].u.paramdesc.pparamdescex->varDefaultValue);
5285                         if (FAILED(hres))
5286                             break;
5287                     }
5288                     else
5289                     {
5290                         VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
5291                         V_VT(arg) = VT_VARIANT | VT_BYREF;
5292                         V_VARIANTREF(arg) = &missing_arg[i];
5293                         V_VT(V_VARIANTREF(arg)) = VT_ERROR;
5294                         V_ERROR(V_VARIANTREF(arg)) = DISP_E_PARAMNOTFOUND;
5295                     }
5296                 }
5297                 else
5298                 {
5299                     hres = DISP_E_BADPARAMCOUNT;
5300                     break;
5301                 }
5302             }
5303             if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
5304             if (func_desc->cParamsOpt < 0)
5305             {
5306                 FIXME("Does not support safearray optional parameters\n");
5307                 hres = DISP_E_BADPARAMCOUNT;
5308                 goto func_fail; /* FIXME: we don't free changed types here */
5309             }
5310
5311             V_VT(&varresult) = 0;
5312             hres = typedescvt_to_variantvt((ITypeInfo *)iface, &func_desc->elemdescFunc.tdesc, &V_VT(&varresult));
5313             if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
5314
5315             hres = DispCallFunc(pIUnk, func_desc->oVft, func_desc->callconv,
5316                                 V_VT(&varresult), func_desc->cParams, rgvt,
5317                                 prgpvarg, &varresult);
5318
5319             for (i = 0; i < func_desc->cParams; i++)
5320             {
5321                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
5322                 if (wParamFlags & PARAMFLAG_FRETVAL)
5323                 {
5324                     if (TRACE_ON(ole))
5325                     {
5326                         TRACE("[retval] value: ");
5327                         dump_Variant(prgpvarg[i]);
5328                     }
5329
5330                     if (pVarResult)
5331                         /* deref return value */
5332                         hres = VariantCopyInd(pVarResult, prgpvarg[i]);
5333
5334                     /* free data stored in varresult. Note that
5335                      * VariantClear doesn't do what we want because we are
5336                      * working with byref types. */
5337                     /* FIXME: clear safearrays, bstrs, records and
5338                      * variants here too */
5339                     if ((V_VT(prgpvarg[i]) == (VT_UNKNOWN | VT_BYREF)) ||
5340                          (V_VT(prgpvarg[i]) == (VT_DISPATCH | VT_BYREF)))
5341                     {
5342                         if(*V_UNKNOWNREF(prgpvarg[i]))
5343                             IUnknown_Release(*V_UNKNOWNREF(prgpvarg[i]));
5344                     }
5345                     break;
5346                 }
5347                 else if (i < pDispParams->cArgs)
5348                 {
5349                     if (wParamFlags & PARAMFLAG_FOUT)
5350                     {
5351                         hres = VariantChangeType(&pDispParams->rgvarg[pDispParams->cArgs - 1 - i],
5352                                                  &rgvarg[i], 0,
5353                                                  V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1 - i]));
5354                         if (FAILED(hres))
5355                         {
5356                             ERR("failed to convert param %d to vt %d\n", i,
5357                                 V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1 - i]));
5358                             break;
5359                         }
5360                     }
5361                     VariantClear(&rgvarg[i]);
5362                 }
5363                 else if (wParamFlags & PARAMFLAG_FOPT)
5364                 {
5365                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
5366                         VariantClear(&rgvarg[i]);
5367                 }
5368             }
5369
5370             if ((V_VT(&varresult) == VT_ERROR) && FAILED(V_ERROR(&varresult)))
5371             {
5372                 WARN("invoked function failed with error 0x%08lx\n", V_ERROR(&varresult));
5373                 hres = DISP_E_EXCEPTION;
5374                 if (pExcepInfo) pExcepInfo->scode = V_ERROR(&varresult);
5375             }
5376
5377 func_fail:
5378             HeapFree(GetProcessHeap(), 0, buffer);
5379             break;
5380         }
5381         case FUNC_DISPATCH:  {
5382            IDispatch *disp;
5383
5384            hres = IUnknown_QueryInterface((LPUNKNOWN)pIUnk,&IID_IDispatch,(LPVOID*)&disp);
5385            if (SUCCEEDED(hres)) {
5386                FIXME("Calling Invoke in IDispatch iface. untested!\n");
5387                hres = IDispatch_Invoke(
5388                                      disp,memid,&IID_NULL,LOCALE_USER_DEFAULT,wFlags,pDispParams,
5389                                      pVarResult,pExcepInfo,pArgErr
5390                                      );
5391                if (FAILED(hres))
5392                    FIXME("IDispatch::Invoke failed with %08lx. (Could be not a real error?)\n", hres);
5393                IDispatch_Release(disp);
5394            } else
5395                FIXME("FUNC_DISPATCH used on object without IDispatch iface?\n");
5396            break;
5397         }
5398         default:
5399             FIXME("Unknown function invocation type %d\n", func_desc->funckind);
5400             hres = E_FAIL;
5401             break;
5402         }
5403
5404         TRACE("-- 0x%08lx\n", hres);
5405         return hres;
5406
5407     } else if(SUCCEEDED(hres = ITypeInfo2_GetVarIndexOfMemId(iface, memid, &var_index))) {
5408         VARDESC *var_desc;
5409
5410         hres = ITypeInfo2_GetVarDesc(iface, var_index, &var_desc);
5411         if(FAILED(hres)) return hres;
5412         
5413         FIXME("varseek: Found memid, but variable-based invoking not supported\n");
5414         dump_VARDESC(var_desc);
5415         ITypeInfo2_ReleaseVarDesc(iface, var_desc);
5416         return E_NOTIMPL;
5417     }
5418
5419     /* not found, look for it in inherited interfaces */
5420     ITypeInfo2_GetTypeKind(iface, &type_kind);
5421     if(type_kind == TKIND_INTERFACE || type_kind == TKIND_DISPATCH) {
5422         HREFTYPE ref_type;
5423         if(SUCCEEDED(ITypeInfo2_GetRefTypeOfImplType(iface, 0, &ref_type))) {
5424             /* recursive search */
5425             ITypeInfo *pTInfo;
5426             hres = ITypeInfo_GetRefTypeInfo(iface, ref_type, &pTInfo);
5427             if(SUCCEEDED(hres)){
5428                 hres = ITypeInfo_Invoke(pTInfo,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr);
5429                 ITypeInfo_Release(pTInfo);
5430                 return hres;
5431             }
5432             WARN("Could not search inherited interface!\n");
5433         }
5434     }
5435     ERR("did not find member id %ld, flags 0x%x!\n", memid, wFlags);
5436     return DISP_E_MEMBERNOTFOUND;
5437 }
5438
5439 /* ITypeInfo::GetDocumentation
5440  *
5441  * Retrieves the documentation string, the complete Help file name and path,
5442  * and the context ID for the Help topic for a specified type description.
5443  *
5444  * (Can be tested by the Visual Basic Editor in Word for instance.)
5445  */
5446 static HRESULT WINAPI ITypeInfo_fnGetDocumentation( ITypeInfo2 *iface,
5447         MEMBERID memid, BSTR  *pBstrName, BSTR  *pBstrDocString,
5448         DWORD  *pdwHelpContext, BSTR  *pBstrHelpFile)
5449 {
5450     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5451     const TLBFuncDesc *pFDesc;
5452     const TLBVarDesc *pVDesc;
5453     TRACE("(%p) memid %ld Name(%p) DocString(%p)"
5454           " HelpContext(%p) HelpFile(%p)\n",
5455         This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
5456     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
5457         if(pBstrName)
5458             *pBstrName=SysAllocString(This->Name);
5459         if(pBstrDocString)
5460             *pBstrDocString=SysAllocString(This->DocString);
5461         if(pdwHelpContext)
5462             *pdwHelpContext=This->dwHelpContext;
5463         if(pBstrHelpFile)
5464             *pBstrHelpFile=SysAllocString(This->DocString);/* FIXME */
5465         return S_OK;
5466     }else {/* for a member */
5467     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
5468         if(pFDesc->funcdesc.memid==memid){
5469           if(pBstrName)
5470             *pBstrName = SysAllocString(pFDesc->Name);
5471           if(pBstrDocString)
5472             *pBstrDocString=SysAllocString(pFDesc->HelpString);
5473           if(pdwHelpContext)
5474             *pdwHelpContext=pFDesc->helpcontext;
5475           return S_OK;
5476         }
5477     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
5478         if(pVDesc->vardesc.memid==memid){
5479             if(pBstrName)
5480               *pBstrName = SysAllocString(pVDesc->Name);
5481             if(pBstrDocString)
5482               *pBstrDocString=SysAllocString(pVDesc->HelpString);
5483             if(pdwHelpContext)
5484               *pdwHelpContext=pVDesc->HelpContext;
5485             return S_OK;
5486         }
5487     }
5488     WARN("member %ld not found\n", memid);
5489     return TYPE_E_ELEMENTNOTFOUND;
5490 }
5491
5492 /*  ITypeInfo::GetDllEntry
5493  *
5494  * Retrieves a description or specification of an entry point for a function
5495  * in a DLL.
5496  */
5497 static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid,
5498         INVOKEKIND invKind, BSTR  *pBstrDllName, BSTR  *pBstrName,
5499         WORD  *pwOrdinal)
5500 {
5501     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5502     const TLBFuncDesc *pFDesc;
5503
5504     TRACE("(%p)->(memid %lx, %d, %p, %p, %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
5505
5506     if (pBstrDllName) *pBstrDllName = NULL;
5507     if (pBstrName) *pBstrName = NULL;
5508     if (pwOrdinal) *pwOrdinal = 0;
5509
5510     if (This->TypeAttr.typekind != TKIND_MODULE)
5511         return TYPE_E_BADMODULEKIND;
5512
5513     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
5514         if(pFDesc->funcdesc.memid==memid){
5515             dump_TypeInfo(This);
5516             if (TRACE_ON(ole))
5517                 dump_TLBFuncDescOne(pFDesc);
5518
5519             if (pBstrDllName)
5520                 *pBstrDllName = SysAllocString(This->DllName);
5521
5522             if (HIWORD(pFDesc->Entry) && (pFDesc->Entry != (void*)-1)) {
5523                 if (pBstrName)
5524                     *pBstrName = SysAllocString(pFDesc->Entry);
5525                 if (pwOrdinal)
5526                     *pwOrdinal = -1;
5527                 return S_OK;
5528             }
5529             if (pBstrName)
5530                 *pBstrName = NULL;
5531             if (pwOrdinal)
5532                 *pwOrdinal = (DWORD)pFDesc->Entry;
5533             return S_OK;
5534         }
5535     return TYPE_E_ELEMENTNOTFOUND;
5536 }
5537
5538 /* ITypeInfo::GetRefTypeInfo
5539  *
5540  * If a type description references other type descriptions, it retrieves
5541  * the referenced type descriptions.
5542  */
5543 static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo(
5544         ITypeInfo2 *iface,
5545         HREFTYPE hRefType,
5546         ITypeInfo  **ppTInfo)
5547 {
5548     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5549     HRESULT result = E_FAIL;
5550
5551     if ((This->hreftype != -1) && (This->hreftype == hRefType))
5552     {
5553         *ppTInfo = (ITypeInfo *)&This->lpVtbl;
5554         ITypeInfo_AddRef(*ppTInfo);
5555         result = S_OK;
5556     }
5557     else if (hRefType == -1 &&
5558         (((ITypeInfoImpl*) This)->TypeAttr.typekind   == TKIND_DISPATCH) &&
5559         (((ITypeInfoImpl*) This)->TypeAttr.wTypeFlags &  TYPEFLAG_FDUAL))
5560     {
5561           /* when we meet a DUAL dispinterface, we must create the interface
5562           * version of it.
5563           */
5564           ITypeInfoImpl* pTypeInfoImpl = (ITypeInfoImpl*) ITypeInfo_Constructor();
5565
5566
5567           /* the interface version contains the same information as the dispinterface
5568            * copy the contents of the structs.
5569            */
5570           *pTypeInfoImpl = *This;
5571           pTypeInfoImpl->ref = 1;
5572
5573           /* change the type to interface */
5574           pTypeInfoImpl->TypeAttr.typekind = TKIND_INTERFACE;
5575
5576           *ppTInfo = (ITypeInfo*) pTypeInfoImpl;
5577
5578           ITypeInfo_AddRef((ITypeInfo*) pTypeInfoImpl);
5579
5580           result = S_OK;
5581
5582     } else {
5583         TLBRefType *pRefType;
5584         for(pRefType = This->reflist; pRefType; pRefType = pRefType->next) {
5585             if(pRefType->reference == hRefType)
5586                 break;
5587         }
5588         if(!pRefType)
5589           FIXME("Can't find pRefType for ref %lx\n", hRefType);
5590         if(pRefType && hRefType != -1) {
5591             ITypeLib *pTLib = NULL;
5592
5593             if(pRefType->pImpTLInfo == TLB_REF_INTERNAL) {
5594                 UINT Index;
5595                 result = ITypeInfo_GetContainingTypeLib(iface, &pTLib, &Index);
5596             } else {
5597                 if(pRefType->pImpTLInfo->pImpTypeLib) {
5598                     TRACE("typeinfo in imported typelib that is already loaded\n");
5599                     pTLib = (ITypeLib*)pRefType->pImpTLInfo->pImpTypeLib;
5600                     ITypeLib2_AddRef((ITypeLib*) pTLib);
5601                     result = S_OK;
5602                 } else {
5603                     TRACE("typeinfo in imported typelib that isn't already loaded\n");
5604                     result = LoadRegTypeLib( &pRefType->pImpTLInfo->guid,
5605                                              pRefType->pImpTLInfo->wVersionMajor,
5606                                              pRefType->pImpTLInfo->wVersionMinor,
5607                                              pRefType->pImpTLInfo->lcid,
5608                                              &pTLib);
5609
5610                     if(!SUCCEEDED(result)) {
5611                         BSTR libnam=SysAllocString(pRefType->pImpTLInfo->name);
5612                         result=LoadTypeLib(libnam, &pTLib);
5613                         SysFreeString(libnam);
5614                     }
5615                     if(SUCCEEDED(result)) {
5616                         pRefType->pImpTLInfo->pImpTypeLib = (ITypeLibImpl*)pTLib;
5617                         ITypeLib2_AddRef(pTLib);
5618                     }
5619                 }
5620             }
5621             if(SUCCEEDED(result)) {
5622                 if(pRefType->index == TLB_REF_USE_GUID)
5623                     result = ITypeLib2_GetTypeInfoOfGuid(pTLib,
5624                                                          &pRefType->guid,
5625                                                          ppTInfo);
5626                 else
5627                     result = ITypeLib2_GetTypeInfo(pTLib, pRefType->index,
5628                                                    ppTInfo);
5629             }
5630             if (pTLib != NULL)
5631                 ITypeLib2_Release(pTLib);
5632         }
5633     }
5634
5635     TRACE("(%p) hreftype 0x%04lx loaded %s (%p)\n", This, hRefType,
5636           SUCCEEDED(result)? "SUCCESS":"FAILURE", *ppTInfo);
5637     return result;
5638 }
5639
5640 /* ITypeInfo::AddressOfMember
5641  *
5642  * Retrieves the addresses of static functions or variables, such as those
5643  * defined in a DLL.
5644  */
5645 static HRESULT WINAPI ITypeInfo_fnAddressOfMember( ITypeInfo2 *iface,
5646         MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
5647 {
5648     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5649     HRESULT hr;
5650     BSTR dll, entry;
5651     WORD ordinal;
5652     HMODULE module;
5653
5654     TRACE("(%p)->(0x%lx, 0x%x, %p)\n", This, memid, invKind, ppv);
5655
5656     hr = ITypeInfo_GetDllEntry(iface, memid, invKind, &dll, &entry, &ordinal);
5657     if (FAILED(hr))
5658         return hr;
5659
5660     module = LoadLibraryW(dll);
5661     if (!module)
5662     {
5663         ERR("couldn't load %s\n", debugstr_w(dll));
5664         SysFreeString(dll);
5665         if (entry) SysFreeString(entry);
5666         return STG_E_FILENOTFOUND;
5667     }
5668     /* FIXME: store library somewhere where we can free it */
5669
5670     if (entry)
5671     {
5672         LPSTR entryA;
5673         INT len = WideCharToMultiByte(CP_ACP, 0, entry, -1, NULL, 0, NULL, NULL);
5674         entryA = HeapAlloc(GetProcessHeap(), 0, len);
5675         WideCharToMultiByte(CP_ACP, 0, entry, -1, entryA, len, NULL, NULL);
5676
5677         *ppv = GetProcAddress(module, entryA);
5678         if (!*ppv)
5679             ERR("function not found %s\n", debugstr_a(entryA));
5680
5681         HeapFree(GetProcessHeap(), 0, entryA);
5682     }
5683     else
5684     {
5685         *ppv = GetProcAddress(module, MAKEINTRESOURCEA(ordinal));
5686         if (!*ppv)
5687             ERR("function not found %d\n", ordinal);
5688     }
5689
5690     SysFreeString(dll);
5691     if (entry) SysFreeString(entry);
5692
5693     if (!*ppv)
5694         return TYPE_E_DLLFUNCTIONNOTFOUND;
5695
5696     return S_OK;
5697 }
5698
5699 /* ITypeInfo::CreateInstance
5700  *
5701  * Creates a new instance of a type that describes a component object class
5702  * (coclass).
5703  */
5704 static HRESULT WINAPI ITypeInfo_fnCreateInstance( ITypeInfo2 *iface,
5705         IUnknown *pUnk, REFIID riid, VOID  **ppvObj)
5706 {
5707     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5708     FIXME("(%p) stub!\n", This);
5709     return S_OK;
5710 }
5711
5712 /* ITypeInfo::GetMops
5713  *
5714  * Retrieves marshalling information.
5715  */
5716 static HRESULT WINAPI ITypeInfo_fnGetMops( ITypeInfo2 *iface, MEMBERID memid,
5717                                 BSTR  *pBstrMops)
5718 {
5719     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5720     FIXME("(%p) stub!\n", This);
5721     return S_OK;
5722 }
5723
5724 /* ITypeInfo::GetContainingTypeLib
5725  *
5726  * Retrieves the containing type library and the index of the type description
5727  * within that type library.
5728  */
5729 static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( ITypeInfo2 *iface,
5730         ITypeLib  * *ppTLib, UINT  *pIndex)
5731 {
5732     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5733     
5734     /* If a pointer is null, we simply ignore it, the ATL in particular passes pIndex as 0 */
5735     if (pIndex) {
5736       *pIndex=This->index;
5737       TRACE("returning pIndex=%d\n", *pIndex);
5738     }
5739     
5740     if (ppTLib) {
5741       *ppTLib=(LPTYPELIB )(This->pTypeLib);
5742       ITypeLib2_AddRef(*ppTLib);
5743       TRACE("returning ppTLib=%p\n", *ppTLib);
5744     }
5745     
5746     return S_OK;
5747 }
5748
5749 /* ITypeInfo::ReleaseTypeAttr
5750  *
5751  * Releases a TYPEATTR previously returned by GetTypeAttr.
5752  *
5753  */
5754 static void WINAPI ITypeInfo_fnReleaseTypeAttr( ITypeInfo2 *iface,
5755         TYPEATTR* pTypeAttr)
5756 {
5757     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5758     TRACE("(%p)->(%p)\n", This, pTypeAttr);
5759     HeapFree(GetProcessHeap(), 0, pTypeAttr);
5760 }
5761
5762 /* ITypeInfo::ReleaseFuncDesc
5763  *
5764  * Releases a FUNCDESC previously returned by GetFuncDesc. *
5765  */
5766 static void WINAPI ITypeInfo_fnReleaseFuncDesc(
5767         ITypeInfo2 *iface,
5768         FUNCDESC *pFuncDesc)
5769 {
5770     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5771     SHORT i;
5772
5773     TRACE("(%p)->(%p)\n", This, pFuncDesc);
5774
5775     for (i = 0; i < pFuncDesc->cParams; i++)
5776         TLB_FreeElemDesc(&pFuncDesc->lprgelemdescParam[i]);
5777     TLB_FreeElemDesc(&pFuncDesc->elemdescFunc);
5778
5779     SysFreeString((BSTR)pFuncDesc);
5780 }
5781
5782 /* ITypeInfo::ReleaseVarDesc
5783  *
5784  * Releases a VARDESC previously returned by GetVarDesc.
5785  */
5786 static void WINAPI ITypeInfo_fnReleaseVarDesc( ITypeInfo2 *iface,
5787         VARDESC *pVarDesc)
5788 {
5789     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5790     TRACE("(%p)->(%p)\n", This, pVarDesc);
5791
5792     TLB_FreeElemDesc(&pVarDesc->elemdescVar);
5793     if (pVarDesc->varkind == VAR_CONST)
5794         VariantClear(pVarDesc->u.lpvarValue);
5795     SysFreeString((BSTR)pVarDesc);
5796 }
5797
5798 /* ITypeInfo2::GetTypeKind
5799  *
5800  * Returns the TYPEKIND enumeration quickly, without doing any allocations.
5801  *
5802  */
5803 static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo2 * iface,
5804     TYPEKIND *pTypeKind)
5805 {
5806     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5807     *pTypeKind=This->TypeAttr.typekind;
5808     TRACE("(%p) type 0x%0x\n", This,*pTypeKind);
5809     return S_OK;
5810 }
5811
5812 /* ITypeInfo2::GetTypeFlags
5813  *
5814  * Returns the type flags without any allocations. This returns a DWORD type
5815  * flag, which expands the type flags without growing the TYPEATTR (type
5816  * attribute).
5817  *
5818  */
5819 static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo2 *iface, ULONG *pTypeFlags)
5820 {
5821     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5822     *pTypeFlags=This->TypeAttr.wTypeFlags;
5823     TRACE("(%p) flags 0x%lx\n", This,*pTypeFlags);
5824     return S_OK;
5825 }
5826
5827 /* ITypeInfo2::GetFuncIndexOfMemId
5828  * Binds to a specific member based on a known DISPID, where the member name
5829  * is not known (for example, when binding to a default member).
5830  *
5831  */
5832 static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo2 * iface,
5833     MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex)
5834 {
5835     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5836     const TLBFuncDesc *pFuncInfo;
5837     int i;
5838     HRESULT result;
5839
5840     for(i = 0, pFuncInfo = This->funclist; pFuncInfo; i++, pFuncInfo=pFuncInfo->next)
5841         if(memid == pFuncInfo->funcdesc.memid && (invKind & pFuncInfo->funcdesc.invkind))
5842             break;
5843     if(pFuncInfo) {
5844         *pFuncIndex = i;
5845         result = S_OK;
5846     } else
5847         result = TYPE_E_ELEMENTNOTFOUND;
5848
5849     TRACE("(%p) memid 0x%08lx invKind 0x%04x -> %s\n", This,
5850           memid, invKind, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
5851     return result;
5852 }
5853
5854 /* TypeInfo2::GetVarIndexOfMemId
5855  *
5856  * Binds to a specific member based on a known DISPID, where the member name
5857  * is not known (for example, when binding to a default member).
5858  *
5859  */
5860 static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( ITypeInfo2 * iface,
5861     MEMBERID memid, UINT *pVarIndex)
5862 {
5863     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5864     TLBVarDesc *pVarInfo;
5865     int i;
5866     HRESULT result;
5867     for(i=0, pVarInfo=This->varlist; pVarInfo &&
5868             memid != pVarInfo->vardesc.memid; i++, pVarInfo=pVarInfo->next)
5869         ;
5870     if(pVarInfo) {
5871         *pVarIndex = i;
5872         result = S_OK;
5873     } else
5874         result = TYPE_E_ELEMENTNOTFOUND;
5875
5876     TRACE("(%p) memid 0x%08lx -> %s\n", This,
5877           memid, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
5878     return result;
5879 }
5880
5881 /* ITypeInfo2::GetCustData
5882  *
5883  * Gets the custom data
5884  */
5885 static HRESULT WINAPI ITypeInfo2_fnGetCustData(
5886         ITypeInfo2 * iface,
5887         REFGUID guid,
5888         VARIANT *pVarVal)
5889 {
5890     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5891     TLBCustData *pCData;
5892
5893     for(pCData=This->pCustData; pCData; pCData = pCData->next)
5894         if( IsEqualIID(guid, &pCData->guid)) break;
5895
5896     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
5897
5898     if(pCData)
5899     {
5900         VariantInit( pVarVal);
5901         VariantCopy( pVarVal, &pCData->data);
5902         return S_OK;
5903     }
5904     return E_INVALIDARG;  /* FIXME: correct? */
5905 }
5906
5907 /* ITypeInfo2::GetFuncCustData
5908  *
5909  * Gets the custom data
5910  */
5911 static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData(
5912         ITypeInfo2 * iface,
5913         UINT index,
5914         REFGUID guid,
5915         VARIANT *pVarVal)
5916 {
5917     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5918     TLBCustData *pCData=NULL;
5919     TLBFuncDesc * pFDesc;
5920     int i;
5921     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
5922             pFDesc=pFDesc->next);
5923
5924     if(pFDesc)
5925         for(pCData=pFDesc->pCustData; pCData; pCData = pCData->next)
5926             if( IsEqualIID(guid, &pCData->guid)) break;
5927
5928     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
5929
5930     if(pCData){
5931         VariantInit( pVarVal);
5932         VariantCopy( pVarVal, &pCData->data);
5933         return S_OK;
5934     }
5935     return E_INVALIDARG;  /* FIXME: correct? */
5936 }
5937
5938 /* ITypeInfo2::GetParamCustData
5939  *
5940  * Gets the custom data
5941  */
5942 static HRESULT WINAPI ITypeInfo2_fnGetParamCustData(
5943         ITypeInfo2 * iface,
5944         UINT indexFunc,
5945         UINT indexParam,
5946         REFGUID guid,
5947         VARIANT *pVarVal)
5948 {
5949     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5950     TLBCustData *pCData=NULL;
5951     TLBFuncDesc * pFDesc;
5952     int i;
5953
5954     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,pFDesc=pFDesc->next);
5955
5956     if(pFDesc && indexParam >=0 && indexParam<pFDesc->funcdesc.cParams)
5957         for(pCData=pFDesc->pParamDesc[indexParam].pCustData; pCData;
5958                 pCData = pCData->next)
5959             if( IsEqualIID(guid, &pCData->guid)) break;
5960
5961     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
5962
5963     if(pCData)
5964     {
5965         VariantInit( pVarVal);
5966         VariantCopy( pVarVal, &pCData->data);
5967         return S_OK;
5968     }
5969     return E_INVALIDARG;  /* FIXME: correct? */
5970 }
5971
5972 /* ITypeInfo2::GetVarCustData
5973  *
5974  * Gets the custom data
5975  */
5976 static HRESULT WINAPI ITypeInfo2_fnGetVarCustData(
5977         ITypeInfo2 * iface,
5978         UINT index,
5979         REFGUID guid,
5980         VARIANT *pVarVal)
5981 {
5982     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5983     TLBCustData *pCData=NULL;
5984     TLBVarDesc * pVDesc;
5985     int i;
5986
5987     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next);
5988
5989     if(pVDesc)
5990     {
5991       for(pCData=pVDesc->pCustData; pCData; pCData = pCData->next)
5992       {
5993         if( IsEqualIID(guid, &pCData->guid)) break;
5994       }
5995     }
5996
5997     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
5998
5999     if(pCData)
6000     {
6001         VariantInit( pVarVal);
6002         VariantCopy( pVarVal, &pCData->data);
6003         return S_OK;
6004     }
6005     return E_INVALIDARG;  /* FIXME: correct? */
6006 }
6007
6008 /* ITypeInfo2::GetImplCustData
6009  *
6010  * Gets the custom data
6011  */
6012 static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData(
6013         ITypeInfo2 * iface,
6014         UINT index,
6015         REFGUID guid,
6016         VARIANT *pVarVal)
6017 {
6018     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6019     TLBCustData *pCData=NULL;
6020     TLBImplType * pRDesc;
6021     int i;
6022
6023     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++, pRDesc=pRDesc->next);
6024
6025     if(pRDesc)
6026     {
6027       for(pCData=pRDesc->pCustData; pCData; pCData = pCData->next)
6028       {
6029         if( IsEqualIID(guid, &pCData->guid)) break;
6030       }
6031     }
6032
6033     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
6034
6035     if(pCData)
6036     {
6037         VariantInit( pVarVal);
6038         VariantCopy( pVarVal, &pCData->data);
6039         return S_OK;
6040     }
6041     return E_INVALIDARG;  /* FIXME: correct? */
6042 }
6043
6044 /* ITypeInfo2::GetDocumentation2
6045  *
6046  * Retrieves the documentation string, the complete Help file name and path,
6047  * the localization context to use, and the context ID for the library Help
6048  * topic in the Help file.
6049  *
6050  */
6051 static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2(
6052         ITypeInfo2 * iface,
6053         MEMBERID memid,
6054         LCID lcid,
6055         BSTR *pbstrHelpString,
6056         DWORD *pdwHelpStringContext,
6057         BSTR *pbstrHelpStringDll)
6058 {
6059     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6060     const TLBFuncDesc *pFDesc;
6061     const TLBVarDesc *pVDesc;
6062     TRACE("(%p) memid %ld lcid(0x%lx)  HelpString(%p) "
6063           "HelpStringContext(%p) HelpStringDll(%p)\n",
6064           This, memid, lcid, pbstrHelpString, pdwHelpStringContext,
6065           pbstrHelpStringDll );
6066     /* the help string should be obtained from the helpstringdll,
6067      * using the _DLLGetDocumentation function, based on the supplied
6068      * lcid. Nice to do sometime...
6069      */
6070     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
6071         if(pbstrHelpString)
6072             *pbstrHelpString=SysAllocString(This->Name);
6073         if(pdwHelpStringContext)
6074             *pdwHelpStringContext=This->dwHelpStringContext;
6075         if(pbstrHelpStringDll)
6076             *pbstrHelpStringDll=
6077                 SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
6078         return S_OK;
6079     }else {/* for a member */
6080     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
6081         if(pFDesc->funcdesc.memid==memid){
6082              if(pbstrHelpString)
6083                 *pbstrHelpString=SysAllocString(pFDesc->HelpString);
6084             if(pdwHelpStringContext)
6085                 *pdwHelpStringContext=pFDesc->HelpStringContext;
6086             if(pbstrHelpStringDll)
6087                 *pbstrHelpStringDll=
6088                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
6089         return S_OK;
6090     }
6091     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
6092         if(pVDesc->vardesc.memid==memid){
6093              if(pbstrHelpString)
6094                 *pbstrHelpString=SysAllocString(pVDesc->HelpString);
6095             if(pdwHelpStringContext)
6096                 *pdwHelpStringContext=pVDesc->HelpStringContext;
6097             if(pbstrHelpStringDll)
6098                 *pbstrHelpStringDll=
6099                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
6100             return S_OK;
6101         }
6102     }
6103     return TYPE_E_ELEMENTNOTFOUND;
6104 }
6105
6106 /* ITypeInfo2::GetAllCustData
6107  *
6108  * Gets all custom data items for the Type info.
6109  *
6110  */
6111 static HRESULT WINAPI ITypeInfo2_fnGetAllCustData(
6112         ITypeInfo2 * iface,
6113         CUSTDATA *pCustData)
6114 {
6115     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6116     TLBCustData *pCData;
6117     int i;
6118
6119     TRACE("(%p) returning %d items\n", This, This->ctCustData);
6120
6121     pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
6122     if(pCustData->prgCustData ){
6123         pCustData->cCustData=This->ctCustData;
6124         for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
6125             pCustData->prgCustData[i].guid=pCData->guid;
6126             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
6127         }
6128     }else{
6129         ERR(" OUT OF MEMORY!\n");
6130         return E_OUTOFMEMORY;
6131     }
6132     return S_OK;
6133 }
6134
6135 /* ITypeInfo2::GetAllFuncCustData
6136  *
6137  * Gets all custom data items for the specified Function
6138  *
6139  */
6140 static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData(
6141         ITypeInfo2 * iface,
6142         UINT index,
6143         CUSTDATA *pCustData)
6144 {
6145     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6146     TLBCustData *pCData;
6147     TLBFuncDesc * pFDesc;
6148     int i;
6149     TRACE("(%p) index %d\n", This, index);
6150     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
6151             pFDesc=pFDesc->next)
6152         ;
6153     if(pFDesc){
6154         pCustData->prgCustData =
6155             TLB_Alloc(pFDesc->ctCustData * sizeof(CUSTDATAITEM));
6156         if(pCustData->prgCustData ){
6157             pCustData->cCustData=pFDesc->ctCustData;
6158             for(i=0, pCData=pFDesc->pCustData; pCData; i++,
6159                     pCData = pCData->next){
6160                 pCustData->prgCustData[i].guid=pCData->guid;
6161                 VariantCopy(& pCustData->prgCustData[i].varValue,
6162                         & pCData->data);
6163             }
6164         }else{
6165             ERR(" OUT OF MEMORY!\n");
6166             return E_OUTOFMEMORY;
6167         }
6168         return S_OK;
6169     }
6170     return TYPE_E_ELEMENTNOTFOUND;
6171 }
6172
6173 /* ITypeInfo2::GetAllParamCustData
6174  *
6175  * Gets all custom data items for the Functions
6176  *
6177  */
6178 static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo2 * iface,
6179     UINT indexFunc, UINT indexParam, CUSTDATA *pCustData)
6180 {
6181     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6182     TLBCustData *pCData=NULL;
6183     TLBFuncDesc * pFDesc;
6184     int i;
6185     TRACE("(%p) index %d\n", This, indexFunc);
6186     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,
6187             pFDesc=pFDesc->next)
6188         ;
6189     if(pFDesc && indexParam >=0 && indexParam<pFDesc->funcdesc.cParams){
6190         pCustData->prgCustData =
6191             TLB_Alloc(pFDesc->pParamDesc[indexParam].ctCustData *
6192                     sizeof(CUSTDATAITEM));
6193         if(pCustData->prgCustData ){
6194             pCustData->cCustData=pFDesc->pParamDesc[indexParam].ctCustData;
6195             for(i=0, pCData=pFDesc->pParamDesc[indexParam].pCustData;
6196                     pCData; i++, pCData = pCData->next){
6197                 pCustData->prgCustData[i].guid=pCData->guid;
6198                 VariantCopy(& pCustData->prgCustData[i].varValue,
6199                         & pCData->data);
6200             }
6201         }else{
6202             ERR(" OUT OF MEMORY!\n");
6203             return E_OUTOFMEMORY;
6204         }
6205         return S_OK;
6206     }
6207     return TYPE_E_ELEMENTNOTFOUND;
6208 }
6209
6210 /* ITypeInfo2::GetAllVarCustData
6211  *
6212  * Gets all custom data items for the specified Variable
6213  *
6214  */
6215 static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo2 * iface,
6216     UINT index, CUSTDATA *pCustData)
6217 {
6218     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6219     TLBCustData *pCData;
6220     TLBVarDesc * pVDesc;
6221     int i;
6222     TRACE("(%p) index %d\n", This, index);
6223     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++,
6224             pVDesc=pVDesc->next)
6225         ;
6226     if(pVDesc){
6227         pCustData->prgCustData =
6228             TLB_Alloc(pVDesc->ctCustData * sizeof(CUSTDATAITEM));
6229         if(pCustData->prgCustData ){
6230             pCustData->cCustData=pVDesc->ctCustData;
6231             for(i=0, pCData=pVDesc->pCustData; pCData; i++,
6232                     pCData = pCData->next){
6233                 pCustData->prgCustData[i].guid=pCData->guid;
6234                 VariantCopy(& pCustData->prgCustData[i].varValue,
6235                         & pCData->data);
6236             }
6237         }else{
6238             ERR(" OUT OF MEMORY!\n");
6239             return E_OUTOFMEMORY;
6240         }
6241         return S_OK;
6242     }
6243     return TYPE_E_ELEMENTNOTFOUND;
6244 }
6245
6246 /* ITypeInfo2::GetAllImplCustData
6247  *
6248  * Gets all custom data items for the specified implementation type
6249  *
6250  */
6251 static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData(
6252         ITypeInfo2 * iface,
6253         UINT index,
6254         CUSTDATA *pCustData)
6255 {
6256     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6257     TLBCustData *pCData;
6258     TLBImplType * pRDesc;
6259     int i;
6260     TRACE("(%p) index %d\n", This, index);
6261     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++,
6262             pRDesc=pRDesc->next)
6263         ;
6264     if(pRDesc){
6265         pCustData->prgCustData =
6266             TLB_Alloc(pRDesc->ctCustData * sizeof(CUSTDATAITEM));
6267         if(pCustData->prgCustData ){
6268             pCustData->cCustData=pRDesc->ctCustData;
6269             for(i=0, pCData=pRDesc->pCustData; pCData; i++,
6270                     pCData = pCData->next){
6271                 pCustData->prgCustData[i].guid=pCData->guid;
6272                 VariantCopy(& pCustData->prgCustData[i].varValue,
6273                         & pCData->data);
6274             }
6275         }else{
6276             ERR(" OUT OF MEMORY!\n");
6277             return E_OUTOFMEMORY;
6278         }
6279         return S_OK;
6280     }
6281     return TYPE_E_ELEMENTNOTFOUND;
6282 }
6283
6284 static const ITypeInfo2Vtbl tinfvt =
6285 {
6286
6287     ITypeInfo_fnQueryInterface,
6288     ITypeInfo_fnAddRef,
6289     ITypeInfo_fnRelease,
6290
6291     ITypeInfo_fnGetTypeAttr,
6292     ITypeInfo_fnGetTypeComp,
6293     ITypeInfo_fnGetFuncDesc,
6294     ITypeInfo_fnGetVarDesc,
6295     ITypeInfo_fnGetNames,
6296     ITypeInfo_fnGetRefTypeOfImplType,
6297     ITypeInfo_fnGetImplTypeFlags,
6298     ITypeInfo_fnGetIDsOfNames,
6299     ITypeInfo_fnInvoke,
6300     ITypeInfo_fnGetDocumentation,
6301     ITypeInfo_fnGetDllEntry,
6302     ITypeInfo_fnGetRefTypeInfo,
6303     ITypeInfo_fnAddressOfMember,
6304     ITypeInfo_fnCreateInstance,
6305     ITypeInfo_fnGetMops,
6306     ITypeInfo_fnGetContainingTypeLib,
6307     ITypeInfo_fnReleaseTypeAttr,
6308     ITypeInfo_fnReleaseFuncDesc,
6309     ITypeInfo_fnReleaseVarDesc,
6310
6311     ITypeInfo2_fnGetTypeKind,
6312     ITypeInfo2_fnGetTypeFlags,
6313     ITypeInfo2_fnGetFuncIndexOfMemId,
6314     ITypeInfo2_fnGetVarIndexOfMemId,
6315     ITypeInfo2_fnGetCustData,
6316     ITypeInfo2_fnGetFuncCustData,
6317     ITypeInfo2_fnGetParamCustData,
6318     ITypeInfo2_fnGetVarCustData,
6319     ITypeInfo2_fnGetImplTypeCustData,
6320     ITypeInfo2_fnGetDocumentation2,
6321     ITypeInfo2_fnGetAllCustData,
6322     ITypeInfo2_fnGetAllFuncCustData,
6323     ITypeInfo2_fnGetAllParamCustData,
6324     ITypeInfo2_fnGetAllVarCustData,
6325     ITypeInfo2_fnGetAllImplTypeCustData,
6326 };
6327
6328 /******************************************************************************
6329  * CreateDispTypeInfo [OLEAUT32.31]
6330  *
6331  * Build type information for an object so it can be called through an
6332  * IDispatch interface.
6333  *
6334  * RETURNS
6335  *  Success: S_OK. pptinfo contains the created ITypeInfo object.
6336  *  Failure: E_INVALIDARG, if one or more arguments is invalid.
6337  *
6338  * NOTES
6339  *  This call allows an objects methods to be accessed through IDispatch, by
6340  *  building an ITypeInfo object that IDispatch can use to call through.
6341  */
6342 HRESULT WINAPI CreateDispTypeInfo(
6343         INTERFACEDATA *pidata, /* [I] Description of the interface to build type info for */
6344         LCID lcid, /* [I] Locale Id */
6345         ITypeInfo **pptinfo) /* [O] Destination for created ITypeInfo object */
6346 {
6347     ITypeInfoImpl *pTIImpl;
6348     int param, func;
6349     TLBFuncDesc **ppFuncDesc;
6350
6351     pTIImpl = (ITypeInfoImpl*)ITypeInfo_Constructor();
6352     pTIImpl->pTypeLib = NULL;
6353     pTIImpl->index = 0;
6354     pTIImpl->Name = NULL;
6355     pTIImpl->dwHelpContext = -1;
6356     memset(&pTIImpl->TypeAttr.guid, 0, sizeof(GUID));
6357     pTIImpl->TypeAttr.lcid = lcid;
6358     pTIImpl->TypeAttr.typekind = TKIND_COCLASS;
6359     pTIImpl->TypeAttr.wMajorVerNum = 0;
6360     pTIImpl->TypeAttr.wMinorVerNum = 0;
6361     pTIImpl->TypeAttr.cbAlignment = 2;
6362     pTIImpl->TypeAttr.cbSizeInstance = -1;
6363     pTIImpl->TypeAttr.cbSizeVft = -1;
6364     pTIImpl->TypeAttr.cFuncs = 0;
6365     pTIImpl->TypeAttr.cImplTypes = 1;
6366     pTIImpl->TypeAttr.cVars = 0;
6367     pTIImpl->TypeAttr.wTypeFlags = 0;
6368
6369     ppFuncDesc = &pTIImpl->funclist;
6370     for(func = 0; func < pidata->cMembers; func++) {
6371         METHODDATA *md = pidata->pmethdata + func;
6372         *ppFuncDesc = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppFuncDesc));
6373         (*ppFuncDesc)->Name = SysAllocString(md->szName);
6374         (*ppFuncDesc)->funcdesc.memid = md->dispid;
6375         (*ppFuncDesc)->funcdesc.invkind = md->wFlags;
6376         (*ppFuncDesc)->funcdesc.callconv = md->cc;
6377         (*ppFuncDesc)->funcdesc.cParams = md->cArgs;
6378         (*ppFuncDesc)->funcdesc.cParamsOpt = 0;
6379         (*ppFuncDesc)->funcdesc.oVft = md->iMeth;
6380         (*ppFuncDesc)->funcdesc.wFuncFlags = 0; /*??*/
6381         (*ppFuncDesc)->funcdesc.elemdescFunc.tdesc.vt = md->vtReturn;
6382         (*ppFuncDesc)->funcdesc.lprgelemdescParam = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6383                                                               md->cArgs * sizeof(ELEMDESC));
6384         (*ppFuncDesc)->pParamDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6385                                               md->cArgs * sizeof(TLBParDesc));
6386         for(param = 0; param < md->cArgs; param++) {
6387             (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].tdesc.vt = md->ppdata[param].vt;
6388             (*ppFuncDesc)->pParamDesc[param].Name = SysAllocString(md->ppdata[param].szName);
6389         }
6390         (*ppFuncDesc)->helpcontext = 0;
6391         (*ppFuncDesc)->HelpStringContext = 0;
6392         (*ppFuncDesc)->HelpString = NULL;
6393         (*ppFuncDesc)->Entry = NULL;
6394         (*ppFuncDesc)->ctCustData = 0;
6395         (*ppFuncDesc)->pCustData = NULL;
6396         ppFuncDesc = &(*ppFuncDesc)->next;
6397     }        
6398     *pptinfo = (ITypeInfo*)pTIImpl;
6399     return S_OK;
6400
6401 }
6402
6403 static HRESULT WINAPI ITypeComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
6404 {
6405     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
6406
6407     return ITypeInfo_QueryInterface((ITypeInfo *)This, riid, ppv);
6408 }
6409
6410 static ULONG WINAPI ITypeComp_fnAddRef(ITypeComp * iface)
6411 {
6412     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
6413
6414     return ITypeInfo_AddRef((ITypeInfo *)This);
6415 }
6416
6417 static ULONG WINAPI ITypeComp_fnRelease(ITypeComp * iface)
6418 {
6419     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
6420
6421     return ITypeInfo_Release((ITypeInfo *)This);
6422 }
6423
6424 static HRESULT WINAPI ITypeComp_fnBind(
6425     ITypeComp * iface,
6426     OLECHAR * szName,
6427     ULONG lHash,
6428     WORD wFlags,
6429     ITypeInfo ** ppTInfo,
6430     DESCKIND * pDescKind,
6431     BINDPTR * pBindPtr)
6432 {
6433     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
6434     const TLBFuncDesc *pFDesc;
6435     const TLBVarDesc *pVDesc;
6436
6437     TRACE("(%s, %lx, 0x%x, %p, %p, %p)\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
6438
6439     *pDescKind = DESCKIND_NONE;
6440     pBindPtr->lpfuncdesc = NULL;
6441     *ppTInfo = NULL;
6442
6443     for(pFDesc = This->funclist; pFDesc; pFDesc = pFDesc->next)
6444         if (!wFlags || (pFDesc->funcdesc.invkind & wFlags))
6445             if (!strcmpW(pFDesc->Name, szName)) {
6446                 break;
6447             }
6448
6449     if (pFDesc)
6450     {
6451         HRESULT hr = TLB_AllocAndInitFuncDesc(
6452             &pFDesc->funcdesc,
6453             &pBindPtr->lpfuncdesc,
6454             This->TypeAttr.typekind == TKIND_DISPATCH);
6455         if (FAILED(hr))
6456             return hr;
6457         *pDescKind = DESCKIND_FUNCDESC;
6458         *ppTInfo = (ITypeInfo *)&This->lpVtbl;
6459         ITypeInfo_AddRef(*ppTInfo);
6460         return S_OK;
6461     } else {
6462         for(pVDesc = This->varlist; pVDesc; pVDesc = pVDesc->next) {
6463             if (!strcmpW(pVDesc->Name, szName)) {
6464                 HRESULT hr = TLB_AllocAndInitVarDesc(&pVDesc->vardesc, &pBindPtr->lpvardesc);
6465                 if (FAILED(hr))
6466                     return hr;
6467                 *pDescKind = DESCKIND_VARDESC;
6468                 *ppTInfo = (ITypeInfo *)&This->lpVtbl;
6469                 ITypeInfo_AddRef(*ppTInfo);
6470                 return S_OK;
6471             }
6472         }
6473     }
6474     /* FIXME: search each inherited interface, not just the first */
6475     if (This->TypeAttr.cImplTypes) {
6476         /* recursive search */
6477         ITypeInfo *pTInfo;
6478         ITypeComp *pTComp;
6479         HRESULT hr;
6480         hr=ITypeInfo_GetRefTypeInfo((ITypeInfo *)&This->lpVtbl, This->impltypelist->hRef, &pTInfo);
6481         if (SUCCEEDED(hr))
6482         {
6483             hr = ITypeInfo_GetTypeComp(pTInfo,&pTComp);
6484             ITypeInfo_Release(pTInfo);
6485         }
6486         if (SUCCEEDED(hr))
6487         {
6488             hr = ITypeComp_Bind(pTComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
6489             ITypeComp_Release(pTComp);
6490             return hr;
6491         }
6492         WARN("Could not search inherited interface!\n");
6493     }
6494     WARN("did not find member with name %s, flags 0x%x!\n", debugstr_w(szName), wFlags);
6495     return DISP_E_MEMBERNOTFOUND;
6496 }
6497
6498 static HRESULT WINAPI ITypeComp_fnBindType(
6499     ITypeComp * iface,
6500     OLECHAR * szName,
6501     ULONG lHash,
6502     ITypeInfo ** ppTInfo,
6503     ITypeComp ** ppTComp)
6504 {
6505     TRACE("(%s, %lx, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
6506
6507     /* strange behaviour (does nothing) but like the
6508      * original */
6509
6510     if (!ppTInfo || !ppTComp)
6511         return E_POINTER;
6512
6513     *ppTInfo = NULL;
6514     *ppTComp = NULL;
6515
6516     return S_OK;
6517 }
6518
6519 static const ITypeCompVtbl tcompvt =
6520 {
6521
6522     ITypeComp_fnQueryInterface,
6523     ITypeComp_fnAddRef,
6524     ITypeComp_fnRelease,
6525
6526     ITypeComp_fnBind,
6527     ITypeComp_fnBindType
6528 };