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