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