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