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