oleaut32: Uncomment a line to implement conversion from VT_DISPATCH to VT_BSTR.
[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 if ((rgvt[i] & VT_BYREF) && (rgvt[i] == V_VT(src_arg)))
5268                     {
5269                         V_BYREF(&rgvarg[i]) = V_BYREF(src_arg);
5270                         V_VT(&rgvarg[i]) = rgvt[i];
5271                     }
5272                     else
5273                     {
5274                         /* FIXME: this doesn't work for VT_BYREF arguments if
5275                          * they are not the same type as in the paramdesc */
5276                         V_VT(&rgvarg[i]) = V_VT(src_arg);
5277                         hres = VariantChangeType(&rgvarg[i], src_arg, 0, rgvt[i]);
5278                         V_VT(&rgvarg[i]) = rgvt[i];
5279                     }
5280
5281                     if (FAILED(hres))
5282                     {
5283                         ERR("failed to convert param %d to %s%s from %s%s\n", i,
5284                             debugstr_vt(rgvt[i]), debugstr_vf(rgvt[i]),
5285                             debugstr_VT(src_arg), debugstr_VF(src_arg));
5286                         break;
5287                     }
5288                     prgpvarg[i] = &rgvarg[i];
5289                 }
5290                 else if (wParamFlags & PARAMFLAG_FOPT)
5291                 {
5292                     VARIANTARG *arg;
5293                     arg = prgpvarg[i] = &rgvarg[i];
5294                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
5295                     {
5296                         hres = VariantCopy(arg, &func_desc->lprgelemdescParam[i].u.paramdesc.pparamdescex->varDefaultValue);
5297                         if (FAILED(hres))
5298                             break;
5299                     }
5300                     else
5301                     {
5302                         VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
5303                         V_VT(arg) = VT_VARIANT | VT_BYREF;
5304                         V_VARIANTREF(arg) = &missing_arg[i];
5305                         V_VT(V_VARIANTREF(arg)) = VT_ERROR;
5306                         V_ERROR(V_VARIANTREF(arg)) = DISP_E_PARAMNOTFOUND;
5307                     }
5308                 }
5309                 else
5310                 {
5311                     hres = DISP_E_BADPARAMCOUNT;
5312                     break;
5313                 }
5314             }
5315             if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
5316             if (func_desc->cParamsOpt < 0)
5317             {
5318                 FIXME("Does not support safearray optional parameters\n");
5319                 hres = DISP_E_BADPARAMCOUNT;
5320                 goto func_fail; /* FIXME: we don't free changed types here */
5321             }
5322
5323             V_VT(&varresult) = 0;
5324             hres = typedescvt_to_variantvt((ITypeInfo *)iface, &func_desc->elemdescFunc.tdesc, &V_VT(&varresult));
5325             if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
5326
5327             hres = DispCallFunc(pIUnk, func_desc->oVft, func_desc->callconv,
5328                                 V_VT(&varresult), func_desc->cParams, rgvt,
5329                                 prgpvarg, &varresult);
5330
5331             for (i = 0; i < func_desc->cParams; i++)
5332             {
5333                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
5334                 if (wParamFlags & PARAMFLAG_FRETVAL)
5335                 {
5336                     if (TRACE_ON(ole))
5337                     {
5338                         TRACE("[retval] value: ");
5339                         dump_Variant(prgpvarg[i]);
5340                     }
5341
5342                     if (pVarResult)
5343                         /* deref return value */
5344                         hres = VariantCopyInd(pVarResult, prgpvarg[i]);
5345
5346                     /* free data stored in varresult. Note that
5347                      * VariantClear doesn't do what we want because we are
5348                      * working with byref types. */
5349                     /* FIXME: clear safearrays, bstrs, records and
5350                      * variants here too */
5351                     if ((V_VT(prgpvarg[i]) == (VT_UNKNOWN | VT_BYREF)) ||
5352                          (V_VT(prgpvarg[i]) == (VT_DISPATCH | VT_BYREF)))
5353                     {
5354                         if(*V_UNKNOWNREF(prgpvarg[i]))
5355                             IUnknown_Release(*V_UNKNOWNREF(prgpvarg[i]));
5356                     }
5357                     break;
5358                 }
5359                 else if (i < pDispParams->cArgs)
5360                 {
5361                     if (wParamFlags & PARAMFLAG_FOUT)
5362                     {
5363                         VARIANTARG *arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - i];
5364
5365                         if ((rgvt[i] == VT_BYREF) && (V_VT(arg) != VT_BYREF))
5366                             hres = VariantChangeType(arg, &rgvarg[i], 0, V_VT(arg));
5367
5368                         if (FAILED(hres))
5369                         {
5370                             ERR("failed to convert param %d to vt %d\n", i,
5371                                 V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1 - i]));
5372                             break;
5373                         }
5374                     }
5375                     VariantClear(&rgvarg[i]);
5376                 }
5377                 else if (wParamFlags & PARAMFLAG_FOPT)
5378                 {
5379                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
5380                         VariantClear(&rgvarg[i]);
5381                 }
5382             }
5383
5384             if ((V_VT(&varresult) == VT_ERROR) && FAILED(V_ERROR(&varresult)))
5385             {
5386                 WARN("invoked function failed with error 0x%08lx\n", V_ERROR(&varresult));
5387                 hres = DISP_E_EXCEPTION;
5388                 if (pExcepInfo) pExcepInfo->scode = V_ERROR(&varresult);
5389             }
5390
5391 func_fail:
5392             HeapFree(GetProcessHeap(), 0, buffer);
5393             break;
5394         }
5395         case FUNC_DISPATCH:  {
5396            IDispatch *disp;
5397
5398            hres = IUnknown_QueryInterface((LPUNKNOWN)pIUnk,&IID_IDispatch,(LPVOID*)&disp);
5399            if (SUCCEEDED(hres)) {
5400                FIXME("Calling Invoke in IDispatch iface. untested!\n");
5401                hres = IDispatch_Invoke(
5402                                      disp,memid,&IID_NULL,LOCALE_USER_DEFAULT,wFlags,pDispParams,
5403                                      pVarResult,pExcepInfo,pArgErr
5404                                      );
5405                if (FAILED(hres))
5406                    FIXME("IDispatch::Invoke failed with %08lx. (Could be not a real error?)\n", hres);
5407                IDispatch_Release(disp);
5408            } else
5409                FIXME("FUNC_DISPATCH used on object without IDispatch iface?\n");
5410            break;
5411         }
5412         default:
5413             FIXME("Unknown function invocation type %d\n", func_desc->funckind);
5414             hres = E_FAIL;
5415             break;
5416         }
5417
5418         TRACE("-- 0x%08lx\n", hres);
5419         return hres;
5420
5421     } else if(SUCCEEDED(hres = ITypeInfo2_GetVarIndexOfMemId(iface, memid, &var_index))) {
5422         VARDESC *var_desc;
5423
5424         hres = ITypeInfo2_GetVarDesc(iface, var_index, &var_desc);
5425         if(FAILED(hres)) return hres;
5426         
5427         FIXME("varseek: Found memid, but variable-based invoking not supported\n");
5428         dump_VARDESC(var_desc);
5429         ITypeInfo2_ReleaseVarDesc(iface, var_desc);
5430         return E_NOTIMPL;
5431     }
5432
5433     /* not found, look for it in inherited interfaces */
5434     ITypeInfo2_GetTypeKind(iface, &type_kind);
5435     if(type_kind == TKIND_INTERFACE || type_kind == TKIND_DISPATCH) {
5436         HREFTYPE ref_type;
5437         if(SUCCEEDED(ITypeInfo2_GetRefTypeOfImplType(iface, 0, &ref_type))) {
5438             /* recursive search */
5439             ITypeInfo *pTInfo;
5440             hres = ITypeInfo_GetRefTypeInfo(iface, ref_type, &pTInfo);
5441             if(SUCCEEDED(hres)){
5442                 hres = ITypeInfo_Invoke(pTInfo,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr);
5443                 ITypeInfo_Release(pTInfo);
5444                 return hres;
5445             }
5446             WARN("Could not search inherited interface!\n");
5447         }
5448     }
5449     ERR("did not find member id %ld, flags 0x%x!\n", memid, wFlags);
5450     return DISP_E_MEMBERNOTFOUND;
5451 }
5452
5453 /* ITypeInfo::GetDocumentation
5454  *
5455  * Retrieves the documentation string, the complete Help file name and path,
5456  * and the context ID for the Help topic for a specified type description.
5457  *
5458  * (Can be tested by the Visual Basic Editor in Word for instance.)
5459  */
5460 static HRESULT WINAPI ITypeInfo_fnGetDocumentation( ITypeInfo2 *iface,
5461         MEMBERID memid, BSTR  *pBstrName, BSTR  *pBstrDocString,
5462         DWORD  *pdwHelpContext, BSTR  *pBstrHelpFile)
5463 {
5464     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5465     const TLBFuncDesc *pFDesc;
5466     const TLBVarDesc *pVDesc;
5467     TRACE("(%p) memid %ld Name(%p) DocString(%p)"
5468           " HelpContext(%p) HelpFile(%p)\n",
5469         This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
5470     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
5471         if(pBstrName)
5472             *pBstrName=SysAllocString(This->Name);
5473         if(pBstrDocString)
5474             *pBstrDocString=SysAllocString(This->DocString);
5475         if(pdwHelpContext)
5476             *pdwHelpContext=This->dwHelpContext;
5477         if(pBstrHelpFile)
5478             *pBstrHelpFile=SysAllocString(This->DocString);/* FIXME */
5479         return S_OK;
5480     }else {/* for a member */
5481     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
5482         if(pFDesc->funcdesc.memid==memid){
5483           if(pBstrName)
5484             *pBstrName = SysAllocString(pFDesc->Name);
5485           if(pBstrDocString)
5486             *pBstrDocString=SysAllocString(pFDesc->HelpString);
5487           if(pdwHelpContext)
5488             *pdwHelpContext=pFDesc->helpcontext;
5489           return S_OK;
5490         }
5491     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
5492         if(pVDesc->vardesc.memid==memid){
5493             if(pBstrName)
5494               *pBstrName = SysAllocString(pVDesc->Name);
5495             if(pBstrDocString)
5496               *pBstrDocString=SysAllocString(pVDesc->HelpString);
5497             if(pdwHelpContext)
5498               *pdwHelpContext=pVDesc->HelpContext;
5499             return S_OK;
5500         }
5501     }
5502     WARN("member %ld not found\n", memid);
5503     return TYPE_E_ELEMENTNOTFOUND;
5504 }
5505
5506 /*  ITypeInfo::GetDllEntry
5507  *
5508  * Retrieves a description or specification of an entry point for a function
5509  * in a DLL.
5510  */
5511 static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid,
5512         INVOKEKIND invKind, BSTR  *pBstrDllName, BSTR  *pBstrName,
5513         WORD  *pwOrdinal)
5514 {
5515     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5516     const TLBFuncDesc *pFDesc;
5517
5518     TRACE("(%p)->(memid %lx, %d, %p, %p, %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
5519
5520     if (pBstrDllName) *pBstrDllName = NULL;
5521     if (pBstrName) *pBstrName = NULL;
5522     if (pwOrdinal) *pwOrdinal = 0;
5523
5524     if (This->TypeAttr.typekind != TKIND_MODULE)
5525         return TYPE_E_BADMODULEKIND;
5526
5527     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
5528         if(pFDesc->funcdesc.memid==memid){
5529             dump_TypeInfo(This);
5530             if (TRACE_ON(ole))
5531                 dump_TLBFuncDescOne(pFDesc);
5532
5533             if (pBstrDllName)
5534                 *pBstrDllName = SysAllocString(This->DllName);
5535
5536             if (HIWORD(pFDesc->Entry) && (pFDesc->Entry != (void*)-1)) {
5537                 if (pBstrName)
5538                     *pBstrName = SysAllocString(pFDesc->Entry);
5539                 if (pwOrdinal)
5540                     *pwOrdinal = -1;
5541                 return S_OK;
5542             }
5543             if (pBstrName)
5544                 *pBstrName = NULL;
5545             if (pwOrdinal)
5546                 *pwOrdinal = (DWORD)pFDesc->Entry;
5547             return S_OK;
5548         }
5549     return TYPE_E_ELEMENTNOTFOUND;
5550 }
5551
5552 /* ITypeInfo::GetRefTypeInfo
5553  *
5554  * If a type description references other type descriptions, it retrieves
5555  * the referenced type descriptions.
5556  */
5557 static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo(
5558         ITypeInfo2 *iface,
5559         HREFTYPE hRefType,
5560         ITypeInfo  **ppTInfo)
5561 {
5562     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5563     HRESULT result = E_FAIL;
5564
5565     if ((This->hreftype != -1) && (This->hreftype == hRefType))
5566     {
5567         *ppTInfo = (ITypeInfo *)&This->lpVtbl;
5568         ITypeInfo_AddRef(*ppTInfo);
5569         result = S_OK;
5570     }
5571     else if (hRefType == -1 &&
5572         (((ITypeInfoImpl*) This)->TypeAttr.typekind   == TKIND_DISPATCH) &&
5573         (((ITypeInfoImpl*) This)->TypeAttr.wTypeFlags &  TYPEFLAG_FDUAL))
5574     {
5575           /* when we meet a DUAL dispinterface, we must create the interface
5576           * version of it.
5577           */
5578           ITypeInfoImpl* pTypeInfoImpl = (ITypeInfoImpl*) ITypeInfo_Constructor();
5579
5580
5581           /* the interface version contains the same information as the dispinterface
5582            * copy the contents of the structs.
5583            */
5584           *pTypeInfoImpl = *This;
5585           pTypeInfoImpl->ref = 1;
5586
5587           /* change the type to interface */
5588           pTypeInfoImpl->TypeAttr.typekind = TKIND_INTERFACE;
5589
5590           *ppTInfo = (ITypeInfo*) pTypeInfoImpl;
5591
5592           ITypeInfo_AddRef((ITypeInfo*) pTypeInfoImpl);
5593
5594           result = S_OK;
5595
5596     } else {
5597         TLBRefType *pRefType;
5598         for(pRefType = This->reflist; pRefType; pRefType = pRefType->next) {
5599             if(pRefType->reference == hRefType)
5600                 break;
5601         }
5602         if(!pRefType)
5603           FIXME("Can't find pRefType for ref %lx\n", hRefType);
5604         if(pRefType && hRefType != -1) {
5605             ITypeLib *pTLib = NULL;
5606
5607             if(pRefType->pImpTLInfo == TLB_REF_INTERNAL) {
5608                 UINT Index;
5609                 result = ITypeInfo_GetContainingTypeLib(iface, &pTLib, &Index);
5610             } else {
5611                 if(pRefType->pImpTLInfo->pImpTypeLib) {
5612                     TRACE("typeinfo in imported typelib that is already loaded\n");
5613                     pTLib = (ITypeLib*)pRefType->pImpTLInfo->pImpTypeLib;
5614                     ITypeLib2_AddRef((ITypeLib*) pTLib);
5615                     result = S_OK;
5616                 } else {
5617                     TRACE("typeinfo in imported typelib that isn't already loaded\n");
5618                     result = LoadRegTypeLib( &pRefType->pImpTLInfo->guid,
5619                                              pRefType->pImpTLInfo->wVersionMajor,
5620                                              pRefType->pImpTLInfo->wVersionMinor,
5621                                              pRefType->pImpTLInfo->lcid,
5622                                              &pTLib);
5623
5624                     if(!SUCCEEDED(result)) {
5625                         BSTR libnam=SysAllocString(pRefType->pImpTLInfo->name);
5626                         result=LoadTypeLib(libnam, &pTLib);
5627                         SysFreeString(libnam);
5628                     }
5629                     if(SUCCEEDED(result)) {
5630                         pRefType->pImpTLInfo->pImpTypeLib = (ITypeLibImpl*)pTLib;
5631                         ITypeLib2_AddRef(pTLib);
5632                     }
5633                 }
5634             }
5635             if(SUCCEEDED(result)) {
5636                 if(pRefType->index == TLB_REF_USE_GUID)
5637                     result = ITypeLib2_GetTypeInfoOfGuid(pTLib,
5638                                                          &pRefType->guid,
5639                                                          ppTInfo);
5640                 else
5641                     result = ITypeLib2_GetTypeInfo(pTLib, pRefType->index,
5642                                                    ppTInfo);
5643             }
5644             if (pTLib != NULL)
5645                 ITypeLib2_Release(pTLib);
5646         }
5647     }
5648
5649     TRACE("(%p) hreftype 0x%04lx loaded %s (%p)\n", This, hRefType,
5650           SUCCEEDED(result)? "SUCCESS":"FAILURE", *ppTInfo);
5651     return result;
5652 }
5653
5654 /* ITypeInfo::AddressOfMember
5655  *
5656  * Retrieves the addresses of static functions or variables, such as those
5657  * defined in a DLL.
5658  */
5659 static HRESULT WINAPI ITypeInfo_fnAddressOfMember( ITypeInfo2 *iface,
5660         MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
5661 {
5662     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5663     HRESULT hr;
5664     BSTR dll, entry;
5665     WORD ordinal;
5666     HMODULE module;
5667
5668     TRACE("(%p)->(0x%lx, 0x%x, %p)\n", This, memid, invKind, ppv);
5669
5670     hr = ITypeInfo_GetDllEntry(iface, memid, invKind, &dll, &entry, &ordinal);
5671     if (FAILED(hr))
5672         return hr;
5673
5674     module = LoadLibraryW(dll);
5675     if (!module)
5676     {
5677         ERR("couldn't load %s\n", debugstr_w(dll));
5678         SysFreeString(dll);
5679         if (entry) SysFreeString(entry);
5680         return STG_E_FILENOTFOUND;
5681     }
5682     /* FIXME: store library somewhere where we can free it */
5683
5684     if (entry)
5685     {
5686         LPSTR entryA;
5687         INT len = WideCharToMultiByte(CP_ACP, 0, entry, -1, NULL, 0, NULL, NULL);
5688         entryA = HeapAlloc(GetProcessHeap(), 0, len);
5689         WideCharToMultiByte(CP_ACP, 0, entry, -1, entryA, len, NULL, NULL);
5690
5691         *ppv = GetProcAddress(module, entryA);
5692         if (!*ppv)
5693             ERR("function not found %s\n", debugstr_a(entryA));
5694
5695         HeapFree(GetProcessHeap(), 0, entryA);
5696     }
5697     else
5698     {
5699         *ppv = GetProcAddress(module, MAKEINTRESOURCEA(ordinal));
5700         if (!*ppv)
5701             ERR("function not found %d\n", ordinal);
5702     }
5703
5704     SysFreeString(dll);
5705     if (entry) SysFreeString(entry);
5706
5707     if (!*ppv)
5708         return TYPE_E_DLLFUNCTIONNOTFOUND;
5709
5710     return S_OK;
5711 }
5712
5713 /* ITypeInfo::CreateInstance
5714  *
5715  * Creates a new instance of a type that describes a component object class
5716  * (coclass).
5717  */
5718 static HRESULT WINAPI ITypeInfo_fnCreateInstance( ITypeInfo2 *iface,
5719         IUnknown *pUnk, REFIID riid, VOID  **ppvObj)
5720 {
5721     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5722     FIXME("(%p) stub!\n", This);
5723     return S_OK;
5724 }
5725
5726 /* ITypeInfo::GetMops
5727  *
5728  * Retrieves marshalling information.
5729  */
5730 static HRESULT WINAPI ITypeInfo_fnGetMops( ITypeInfo2 *iface, MEMBERID memid,
5731                                 BSTR  *pBstrMops)
5732 {
5733     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5734     FIXME("(%p) stub!\n", This);
5735     return S_OK;
5736 }
5737
5738 /* ITypeInfo::GetContainingTypeLib
5739  *
5740  * Retrieves the containing type library and the index of the type description
5741  * within that type library.
5742  */
5743 static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( ITypeInfo2 *iface,
5744         ITypeLib  * *ppTLib, UINT  *pIndex)
5745 {
5746     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5747     
5748     /* If a pointer is null, we simply ignore it, the ATL in particular passes pIndex as 0 */
5749     if (pIndex) {
5750       *pIndex=This->index;
5751       TRACE("returning pIndex=%d\n", *pIndex);
5752     }
5753     
5754     if (ppTLib) {
5755       *ppTLib=(LPTYPELIB )(This->pTypeLib);
5756       ITypeLib2_AddRef(*ppTLib);
5757       TRACE("returning ppTLib=%p\n", *ppTLib);
5758     }
5759     
5760     return S_OK;
5761 }
5762
5763 /* ITypeInfo::ReleaseTypeAttr
5764  *
5765  * Releases a TYPEATTR previously returned by GetTypeAttr.
5766  *
5767  */
5768 static void WINAPI ITypeInfo_fnReleaseTypeAttr( ITypeInfo2 *iface,
5769         TYPEATTR* pTypeAttr)
5770 {
5771     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5772     TRACE("(%p)->(%p)\n", This, pTypeAttr);
5773     HeapFree(GetProcessHeap(), 0, pTypeAttr);
5774 }
5775
5776 /* ITypeInfo::ReleaseFuncDesc
5777  *
5778  * Releases a FUNCDESC previously returned by GetFuncDesc. *
5779  */
5780 static void WINAPI ITypeInfo_fnReleaseFuncDesc(
5781         ITypeInfo2 *iface,
5782         FUNCDESC *pFuncDesc)
5783 {
5784     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5785     SHORT i;
5786
5787     TRACE("(%p)->(%p)\n", This, pFuncDesc);
5788
5789     for (i = 0; i < pFuncDesc->cParams; i++)
5790         TLB_FreeElemDesc(&pFuncDesc->lprgelemdescParam[i]);
5791     TLB_FreeElemDesc(&pFuncDesc->elemdescFunc);
5792
5793     SysFreeString((BSTR)pFuncDesc);
5794 }
5795
5796 /* ITypeInfo::ReleaseVarDesc
5797  *
5798  * Releases a VARDESC previously returned by GetVarDesc.
5799  */
5800 static void WINAPI ITypeInfo_fnReleaseVarDesc( ITypeInfo2 *iface,
5801         VARDESC *pVarDesc)
5802 {
5803     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5804     TRACE("(%p)->(%p)\n", This, pVarDesc);
5805
5806     TLB_FreeElemDesc(&pVarDesc->elemdescVar);
5807     if (pVarDesc->varkind == VAR_CONST)
5808         VariantClear(pVarDesc->u.lpvarValue);
5809     SysFreeString((BSTR)pVarDesc);
5810 }
5811
5812 /* ITypeInfo2::GetTypeKind
5813  *
5814  * Returns the TYPEKIND enumeration quickly, without doing any allocations.
5815  *
5816  */
5817 static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo2 * iface,
5818     TYPEKIND *pTypeKind)
5819 {
5820     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5821     *pTypeKind=This->TypeAttr.typekind;
5822     TRACE("(%p) type 0x%0x\n", This,*pTypeKind);
5823     return S_OK;
5824 }
5825
5826 /* ITypeInfo2::GetTypeFlags
5827  *
5828  * Returns the type flags without any allocations. This returns a DWORD type
5829  * flag, which expands the type flags without growing the TYPEATTR (type
5830  * attribute).
5831  *
5832  */
5833 static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo2 *iface, ULONG *pTypeFlags)
5834 {
5835     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5836     *pTypeFlags=This->TypeAttr.wTypeFlags;
5837     TRACE("(%p) flags 0x%lx\n", This,*pTypeFlags);
5838     return S_OK;
5839 }
5840
5841 /* ITypeInfo2::GetFuncIndexOfMemId
5842  * Binds to a specific member based on a known DISPID, where the member name
5843  * is not known (for example, when binding to a default member).
5844  *
5845  */
5846 static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo2 * iface,
5847     MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex)
5848 {
5849     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5850     const TLBFuncDesc *pFuncInfo;
5851     int i;
5852     HRESULT result;
5853
5854     for(i = 0, pFuncInfo = This->funclist; pFuncInfo; i++, pFuncInfo=pFuncInfo->next)
5855         if(memid == pFuncInfo->funcdesc.memid && (invKind & pFuncInfo->funcdesc.invkind))
5856             break;
5857     if(pFuncInfo) {
5858         *pFuncIndex = i;
5859         result = S_OK;
5860     } else
5861         result = TYPE_E_ELEMENTNOTFOUND;
5862
5863     TRACE("(%p) memid 0x%08lx invKind 0x%04x -> %s\n", This,
5864           memid, invKind, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
5865     return result;
5866 }
5867
5868 /* TypeInfo2::GetVarIndexOfMemId
5869  *
5870  * Binds to a specific member based on a known DISPID, where the member name
5871  * is not known (for example, when binding to a default member).
5872  *
5873  */
5874 static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( ITypeInfo2 * iface,
5875     MEMBERID memid, UINT *pVarIndex)
5876 {
5877     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5878     TLBVarDesc *pVarInfo;
5879     int i;
5880     HRESULT result;
5881     for(i=0, pVarInfo=This->varlist; pVarInfo &&
5882             memid != pVarInfo->vardesc.memid; i++, pVarInfo=pVarInfo->next)
5883         ;
5884     if(pVarInfo) {
5885         *pVarIndex = i;
5886         result = S_OK;
5887     } else
5888         result = TYPE_E_ELEMENTNOTFOUND;
5889
5890     TRACE("(%p) memid 0x%08lx -> %s\n", This,
5891           memid, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
5892     return result;
5893 }
5894
5895 /* ITypeInfo2::GetCustData
5896  *
5897  * Gets the custom data
5898  */
5899 static HRESULT WINAPI ITypeInfo2_fnGetCustData(
5900         ITypeInfo2 * iface,
5901         REFGUID guid,
5902         VARIANT *pVarVal)
5903 {
5904     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5905     TLBCustData *pCData;
5906
5907     for(pCData=This->pCustData; pCData; pCData = pCData->next)
5908         if( IsEqualIID(guid, &pCData->guid)) break;
5909
5910     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
5911
5912     if(pCData)
5913     {
5914         VariantInit( pVarVal);
5915         VariantCopy( pVarVal, &pCData->data);
5916         return S_OK;
5917     }
5918     return E_INVALIDARG;  /* FIXME: correct? */
5919 }
5920
5921 /* ITypeInfo2::GetFuncCustData
5922  *
5923  * Gets the custom data
5924  */
5925 static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData(
5926         ITypeInfo2 * iface,
5927         UINT index,
5928         REFGUID guid,
5929         VARIANT *pVarVal)
5930 {
5931     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5932     TLBCustData *pCData=NULL;
5933     TLBFuncDesc * pFDesc;
5934     int i;
5935     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
5936             pFDesc=pFDesc->next);
5937
5938     if(pFDesc)
5939         for(pCData=pFDesc->pCustData; pCData; pCData = pCData->next)
5940             if( IsEqualIID(guid, &pCData->guid)) break;
5941
5942     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
5943
5944     if(pCData){
5945         VariantInit( pVarVal);
5946         VariantCopy( pVarVal, &pCData->data);
5947         return S_OK;
5948     }
5949     return E_INVALIDARG;  /* FIXME: correct? */
5950 }
5951
5952 /* ITypeInfo2::GetParamCustData
5953  *
5954  * Gets the custom data
5955  */
5956 static HRESULT WINAPI ITypeInfo2_fnGetParamCustData(
5957         ITypeInfo2 * iface,
5958         UINT indexFunc,
5959         UINT indexParam,
5960         REFGUID guid,
5961         VARIANT *pVarVal)
5962 {
5963     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5964     TLBCustData *pCData=NULL;
5965     TLBFuncDesc * pFDesc;
5966     int i;
5967
5968     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,pFDesc=pFDesc->next);
5969
5970     if(pFDesc && indexParam >=0 && indexParam<pFDesc->funcdesc.cParams)
5971         for(pCData=pFDesc->pParamDesc[indexParam].pCustData; pCData;
5972                 pCData = pCData->next)
5973             if( IsEqualIID(guid, &pCData->guid)) break;
5974
5975     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
5976
5977     if(pCData)
5978     {
5979         VariantInit( pVarVal);
5980         VariantCopy( pVarVal, &pCData->data);
5981         return S_OK;
5982     }
5983     return E_INVALIDARG;  /* FIXME: correct? */
5984 }
5985
5986 /* ITypeInfo2::GetVarCustData
5987  *
5988  * Gets the custom data
5989  */
5990 static HRESULT WINAPI ITypeInfo2_fnGetVarCustData(
5991         ITypeInfo2 * iface,
5992         UINT index,
5993         REFGUID guid,
5994         VARIANT *pVarVal)
5995 {
5996     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5997     TLBCustData *pCData=NULL;
5998     TLBVarDesc * pVDesc;
5999     int i;
6000
6001     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next);
6002
6003     if(pVDesc)
6004     {
6005       for(pCData=pVDesc->pCustData; pCData; pCData = pCData->next)
6006       {
6007         if( IsEqualIID(guid, &pCData->guid)) break;
6008       }
6009     }
6010
6011     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
6012
6013     if(pCData)
6014     {
6015         VariantInit( pVarVal);
6016         VariantCopy( pVarVal, &pCData->data);
6017         return S_OK;
6018     }
6019     return E_INVALIDARG;  /* FIXME: correct? */
6020 }
6021
6022 /* ITypeInfo2::GetImplCustData
6023  *
6024  * Gets the custom data
6025  */
6026 static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData(
6027         ITypeInfo2 * iface,
6028         UINT index,
6029         REFGUID guid,
6030         VARIANT *pVarVal)
6031 {
6032     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6033     TLBCustData *pCData=NULL;
6034     TLBImplType * pRDesc;
6035     int i;
6036
6037     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++, pRDesc=pRDesc->next);
6038
6039     if(pRDesc)
6040     {
6041       for(pCData=pRDesc->pCustData; pCData; pCData = pCData->next)
6042       {
6043         if( IsEqualIID(guid, &pCData->guid)) break;
6044       }
6045     }
6046
6047     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
6048
6049     if(pCData)
6050     {
6051         VariantInit( pVarVal);
6052         VariantCopy( pVarVal, &pCData->data);
6053         return S_OK;
6054     }
6055     return E_INVALIDARG;  /* FIXME: correct? */
6056 }
6057
6058 /* ITypeInfo2::GetDocumentation2
6059  *
6060  * Retrieves the documentation string, the complete Help file name and path,
6061  * the localization context to use, and the context ID for the library Help
6062  * topic in the Help file.
6063  *
6064  */
6065 static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2(
6066         ITypeInfo2 * iface,
6067         MEMBERID memid,
6068         LCID lcid,
6069         BSTR *pbstrHelpString,
6070         DWORD *pdwHelpStringContext,
6071         BSTR *pbstrHelpStringDll)
6072 {
6073     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6074     const TLBFuncDesc *pFDesc;
6075     const TLBVarDesc *pVDesc;
6076     TRACE("(%p) memid %ld lcid(0x%lx)  HelpString(%p) "
6077           "HelpStringContext(%p) HelpStringDll(%p)\n",
6078           This, memid, lcid, pbstrHelpString, pdwHelpStringContext,
6079           pbstrHelpStringDll );
6080     /* the help string should be obtained from the helpstringdll,
6081      * using the _DLLGetDocumentation function, based on the supplied
6082      * lcid. Nice to do sometime...
6083      */
6084     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
6085         if(pbstrHelpString)
6086             *pbstrHelpString=SysAllocString(This->Name);
6087         if(pdwHelpStringContext)
6088             *pdwHelpStringContext=This->dwHelpStringContext;
6089         if(pbstrHelpStringDll)
6090             *pbstrHelpStringDll=
6091                 SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
6092         return S_OK;
6093     }else {/* for a member */
6094     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
6095         if(pFDesc->funcdesc.memid==memid){
6096              if(pbstrHelpString)
6097                 *pbstrHelpString=SysAllocString(pFDesc->HelpString);
6098             if(pdwHelpStringContext)
6099                 *pdwHelpStringContext=pFDesc->HelpStringContext;
6100             if(pbstrHelpStringDll)
6101                 *pbstrHelpStringDll=
6102                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
6103         return S_OK;
6104     }
6105     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
6106         if(pVDesc->vardesc.memid==memid){
6107              if(pbstrHelpString)
6108                 *pbstrHelpString=SysAllocString(pVDesc->HelpString);
6109             if(pdwHelpStringContext)
6110                 *pdwHelpStringContext=pVDesc->HelpStringContext;
6111             if(pbstrHelpStringDll)
6112                 *pbstrHelpStringDll=
6113                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
6114             return S_OK;
6115         }
6116     }
6117     return TYPE_E_ELEMENTNOTFOUND;
6118 }
6119
6120 /* ITypeInfo2::GetAllCustData
6121  *
6122  * Gets all custom data items for the Type info.
6123  *
6124  */
6125 static HRESULT WINAPI ITypeInfo2_fnGetAllCustData(
6126         ITypeInfo2 * iface,
6127         CUSTDATA *pCustData)
6128 {
6129     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6130     TLBCustData *pCData;
6131     int i;
6132
6133     TRACE("(%p) returning %d items\n", This, This->ctCustData);
6134
6135     pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
6136     if(pCustData->prgCustData ){
6137         pCustData->cCustData=This->ctCustData;
6138         for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
6139             pCustData->prgCustData[i].guid=pCData->guid;
6140             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
6141         }
6142     }else{
6143         ERR(" OUT OF MEMORY!\n");
6144         return E_OUTOFMEMORY;
6145     }
6146     return S_OK;
6147 }
6148
6149 /* ITypeInfo2::GetAllFuncCustData
6150  *
6151  * Gets all custom data items for the specified Function
6152  *
6153  */
6154 static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData(
6155         ITypeInfo2 * iface,
6156         UINT index,
6157         CUSTDATA *pCustData)
6158 {
6159     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6160     TLBCustData *pCData;
6161     TLBFuncDesc * pFDesc;
6162     int i;
6163     TRACE("(%p) index %d\n", This, index);
6164     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
6165             pFDesc=pFDesc->next)
6166         ;
6167     if(pFDesc){
6168         pCustData->prgCustData =
6169             TLB_Alloc(pFDesc->ctCustData * sizeof(CUSTDATAITEM));
6170         if(pCustData->prgCustData ){
6171             pCustData->cCustData=pFDesc->ctCustData;
6172             for(i=0, pCData=pFDesc->pCustData; pCData; i++,
6173                     pCData = pCData->next){
6174                 pCustData->prgCustData[i].guid=pCData->guid;
6175                 VariantCopy(& pCustData->prgCustData[i].varValue,
6176                         & pCData->data);
6177             }
6178         }else{
6179             ERR(" OUT OF MEMORY!\n");
6180             return E_OUTOFMEMORY;
6181         }
6182         return S_OK;
6183     }
6184     return TYPE_E_ELEMENTNOTFOUND;
6185 }
6186
6187 /* ITypeInfo2::GetAllParamCustData
6188  *
6189  * Gets all custom data items for the Functions
6190  *
6191  */
6192 static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo2 * iface,
6193     UINT indexFunc, UINT indexParam, CUSTDATA *pCustData)
6194 {
6195     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6196     TLBCustData *pCData=NULL;
6197     TLBFuncDesc * pFDesc;
6198     int i;
6199     TRACE("(%p) index %d\n", This, indexFunc);
6200     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,
6201             pFDesc=pFDesc->next)
6202         ;
6203     if(pFDesc && indexParam >=0 && indexParam<pFDesc->funcdesc.cParams){
6204         pCustData->prgCustData =
6205             TLB_Alloc(pFDesc->pParamDesc[indexParam].ctCustData *
6206                     sizeof(CUSTDATAITEM));
6207         if(pCustData->prgCustData ){
6208             pCustData->cCustData=pFDesc->pParamDesc[indexParam].ctCustData;
6209             for(i=0, pCData=pFDesc->pParamDesc[indexParam].pCustData;
6210                     pCData; i++, pCData = pCData->next){
6211                 pCustData->prgCustData[i].guid=pCData->guid;
6212                 VariantCopy(& pCustData->prgCustData[i].varValue,
6213                         & pCData->data);
6214             }
6215         }else{
6216             ERR(" OUT OF MEMORY!\n");
6217             return E_OUTOFMEMORY;
6218         }
6219         return S_OK;
6220     }
6221     return TYPE_E_ELEMENTNOTFOUND;
6222 }
6223
6224 /* ITypeInfo2::GetAllVarCustData
6225  *
6226  * Gets all custom data items for the specified Variable
6227  *
6228  */
6229 static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo2 * iface,
6230     UINT index, CUSTDATA *pCustData)
6231 {
6232     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6233     TLBCustData *pCData;
6234     TLBVarDesc * pVDesc;
6235     int i;
6236     TRACE("(%p) index %d\n", This, index);
6237     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++,
6238             pVDesc=pVDesc->next)
6239         ;
6240     if(pVDesc){
6241         pCustData->prgCustData =
6242             TLB_Alloc(pVDesc->ctCustData * sizeof(CUSTDATAITEM));
6243         if(pCustData->prgCustData ){
6244             pCustData->cCustData=pVDesc->ctCustData;
6245             for(i=0, pCData=pVDesc->pCustData; pCData; i++,
6246                     pCData = pCData->next){
6247                 pCustData->prgCustData[i].guid=pCData->guid;
6248                 VariantCopy(& pCustData->prgCustData[i].varValue,
6249                         & pCData->data);
6250             }
6251         }else{
6252             ERR(" OUT OF MEMORY!\n");
6253             return E_OUTOFMEMORY;
6254         }
6255         return S_OK;
6256     }
6257     return TYPE_E_ELEMENTNOTFOUND;
6258 }
6259
6260 /* ITypeInfo2::GetAllImplCustData
6261  *
6262  * Gets all custom data items for the specified implementation type
6263  *
6264  */
6265 static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData(
6266         ITypeInfo2 * iface,
6267         UINT index,
6268         CUSTDATA *pCustData)
6269 {
6270     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6271     TLBCustData *pCData;
6272     TLBImplType * pRDesc;
6273     int i;
6274     TRACE("(%p) index %d\n", This, index);
6275     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++,
6276             pRDesc=pRDesc->next)
6277         ;
6278     if(pRDesc){
6279         pCustData->prgCustData =
6280             TLB_Alloc(pRDesc->ctCustData * sizeof(CUSTDATAITEM));
6281         if(pCustData->prgCustData ){
6282             pCustData->cCustData=pRDesc->ctCustData;
6283             for(i=0, pCData=pRDesc->pCustData; pCData; i++,
6284                     pCData = pCData->next){
6285                 pCustData->prgCustData[i].guid=pCData->guid;
6286                 VariantCopy(& pCustData->prgCustData[i].varValue,
6287                         & pCData->data);
6288             }
6289         }else{
6290             ERR(" OUT OF MEMORY!\n");
6291             return E_OUTOFMEMORY;
6292         }
6293         return S_OK;
6294     }
6295     return TYPE_E_ELEMENTNOTFOUND;
6296 }
6297
6298 static const ITypeInfo2Vtbl tinfvt =
6299 {
6300
6301     ITypeInfo_fnQueryInterface,
6302     ITypeInfo_fnAddRef,
6303     ITypeInfo_fnRelease,
6304
6305     ITypeInfo_fnGetTypeAttr,
6306     ITypeInfo_fnGetTypeComp,
6307     ITypeInfo_fnGetFuncDesc,
6308     ITypeInfo_fnGetVarDesc,
6309     ITypeInfo_fnGetNames,
6310     ITypeInfo_fnGetRefTypeOfImplType,
6311     ITypeInfo_fnGetImplTypeFlags,
6312     ITypeInfo_fnGetIDsOfNames,
6313     ITypeInfo_fnInvoke,
6314     ITypeInfo_fnGetDocumentation,
6315     ITypeInfo_fnGetDllEntry,
6316     ITypeInfo_fnGetRefTypeInfo,
6317     ITypeInfo_fnAddressOfMember,
6318     ITypeInfo_fnCreateInstance,
6319     ITypeInfo_fnGetMops,
6320     ITypeInfo_fnGetContainingTypeLib,
6321     ITypeInfo_fnReleaseTypeAttr,
6322     ITypeInfo_fnReleaseFuncDesc,
6323     ITypeInfo_fnReleaseVarDesc,
6324
6325     ITypeInfo2_fnGetTypeKind,
6326     ITypeInfo2_fnGetTypeFlags,
6327     ITypeInfo2_fnGetFuncIndexOfMemId,
6328     ITypeInfo2_fnGetVarIndexOfMemId,
6329     ITypeInfo2_fnGetCustData,
6330     ITypeInfo2_fnGetFuncCustData,
6331     ITypeInfo2_fnGetParamCustData,
6332     ITypeInfo2_fnGetVarCustData,
6333     ITypeInfo2_fnGetImplTypeCustData,
6334     ITypeInfo2_fnGetDocumentation2,
6335     ITypeInfo2_fnGetAllCustData,
6336     ITypeInfo2_fnGetAllFuncCustData,
6337     ITypeInfo2_fnGetAllParamCustData,
6338     ITypeInfo2_fnGetAllVarCustData,
6339     ITypeInfo2_fnGetAllImplTypeCustData,
6340 };
6341
6342 /******************************************************************************
6343  * CreateDispTypeInfo [OLEAUT32.31]
6344  *
6345  * Build type information for an object so it can be called through an
6346  * IDispatch interface.
6347  *
6348  * RETURNS
6349  *  Success: S_OK. pptinfo contains the created ITypeInfo object.
6350  *  Failure: E_INVALIDARG, if one or more arguments is invalid.
6351  *
6352  * NOTES
6353  *  This call allows an objects methods to be accessed through IDispatch, by
6354  *  building an ITypeInfo object that IDispatch can use to call through.
6355  */
6356 HRESULT WINAPI CreateDispTypeInfo(
6357         INTERFACEDATA *pidata, /* [I] Description of the interface to build type info for */
6358         LCID lcid, /* [I] Locale Id */
6359         ITypeInfo **pptinfo) /* [O] Destination for created ITypeInfo object */
6360 {
6361     ITypeInfoImpl *pTIClass, *pTIIface;
6362     ITypeLibImpl *pTypeLibImpl;
6363     int param, func;
6364     TLBFuncDesc **ppFuncDesc;
6365
6366     TRACE("\n");
6367     pTypeLibImpl = TypeLibImpl_Constructor();
6368     if (!pTypeLibImpl) return E_FAIL;
6369
6370     pTIIface = (ITypeInfoImpl*)ITypeInfo_Constructor();
6371     pTIIface->pTypeLib = pTypeLibImpl;
6372     pTIIface->index = 0;
6373     pTIIface->Name = NULL;
6374     pTIIface->dwHelpContext = -1;
6375     memset(&pTIIface->TypeAttr.guid, 0, sizeof(GUID));
6376     pTIIface->TypeAttr.lcid = lcid;
6377     pTIIface->TypeAttr.typekind = TKIND_INTERFACE;
6378     pTIIface->TypeAttr.wMajorVerNum = 0;
6379     pTIIface->TypeAttr.wMinorVerNum = 0;
6380     pTIIface->TypeAttr.cbAlignment = 2;
6381     pTIIface->TypeAttr.cbSizeInstance = -1;
6382     pTIIface->TypeAttr.cbSizeVft = -1;
6383     pTIIface->TypeAttr.cFuncs = 0;
6384     pTIIface->TypeAttr.cImplTypes = 0;
6385     pTIIface->TypeAttr.cVars = 0;
6386     pTIIface->TypeAttr.wTypeFlags = 0;
6387
6388     ppFuncDesc = &pTIIface->funclist;
6389     for(func = 0; func < pidata->cMembers; func++) {
6390         METHODDATA *md = pidata->pmethdata + func;
6391         *ppFuncDesc = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppFuncDesc));
6392         (*ppFuncDesc)->Name = SysAllocString(md->szName);
6393         (*ppFuncDesc)->funcdesc.memid = md->dispid;
6394         (*ppFuncDesc)->funcdesc.funckind = FUNC_VIRTUAL;
6395         (*ppFuncDesc)->funcdesc.invkind = md->wFlags;
6396         (*ppFuncDesc)->funcdesc.callconv = md->cc;
6397         (*ppFuncDesc)->funcdesc.cParams = md->cArgs;
6398         (*ppFuncDesc)->funcdesc.cParamsOpt = 0;
6399         (*ppFuncDesc)->funcdesc.oVft = md->iMeth << 2;
6400         (*ppFuncDesc)->funcdesc.wFuncFlags = 0;
6401         (*ppFuncDesc)->funcdesc.elemdescFunc.tdesc.vt = md->vtReturn;
6402         (*ppFuncDesc)->funcdesc.elemdescFunc.u.paramdesc.wParamFlags = PARAMFLAG_NONE;
6403         (*ppFuncDesc)->funcdesc.elemdescFunc.u.paramdesc.pparamdescex = NULL;
6404         (*ppFuncDesc)->funcdesc.lprgelemdescParam = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6405                                                               md->cArgs * sizeof(ELEMDESC));
6406         (*ppFuncDesc)->pParamDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6407                                               md->cArgs * sizeof(TLBParDesc));
6408         for(param = 0; param < md->cArgs; param++) {
6409             (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].tdesc.vt = md->ppdata[param].vt;
6410             (*ppFuncDesc)->pParamDesc[param].Name = SysAllocString(md->ppdata[param].szName);
6411         }
6412         (*ppFuncDesc)->helpcontext = 0;
6413         (*ppFuncDesc)->HelpStringContext = 0;
6414         (*ppFuncDesc)->HelpString = NULL;
6415         (*ppFuncDesc)->Entry = NULL;
6416         (*ppFuncDesc)->ctCustData = 0;
6417         (*ppFuncDesc)->pCustData = NULL;
6418         (*ppFuncDesc)->next = NULL;
6419         ppFuncDesc = &(*ppFuncDesc)->next;
6420     }
6421
6422     dump_TypeInfo(pTIIface);
6423
6424     pTypeLibImpl->pTypeInfo = pTIIface;
6425     pTypeLibImpl->TypeInfoCount++;
6426
6427     pTIClass = (ITypeInfoImpl*)ITypeInfo_Constructor();
6428     pTIClass->pTypeLib = pTypeLibImpl;
6429     pTIClass->index = 1;
6430     pTIClass->Name = NULL;
6431     pTIClass->dwHelpContext = -1;
6432     memset(&pTIClass->TypeAttr.guid, 0, sizeof(GUID));
6433     pTIClass->TypeAttr.lcid = lcid;
6434     pTIClass->TypeAttr.typekind = TKIND_COCLASS;
6435     pTIClass->TypeAttr.wMajorVerNum = 0;
6436     pTIClass->TypeAttr.wMinorVerNum = 0;
6437     pTIClass->TypeAttr.cbAlignment = 2;
6438     pTIClass->TypeAttr.cbSizeInstance = -1;
6439     pTIClass->TypeAttr.cbSizeVft = -1;
6440     pTIClass->TypeAttr.cFuncs = 0;
6441     pTIClass->TypeAttr.cImplTypes = 1;
6442     pTIClass->TypeAttr.cVars = 0;
6443     pTIClass->TypeAttr.wTypeFlags = 0;
6444
6445     pTIClass->impltypelist = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pTIClass->impltypelist));
6446     pTIClass->impltypelist->hRef = 1;
6447
6448     pTIClass->reflist = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pTIClass->reflist));
6449     pTIClass->reflist->index = 0;
6450     pTIClass->reflist->reference = 1;
6451     pTIClass->reflist->pImpTLInfo = TLB_REF_INTERNAL;
6452
6453     dump_TypeInfo(pTIClass);
6454
6455     pTIIface->next = pTIClass;
6456     pTypeLibImpl->TypeInfoCount++;
6457
6458     *pptinfo = (ITypeInfo*)pTIClass;
6459     return S_OK;
6460
6461 }
6462
6463 static HRESULT WINAPI ITypeComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
6464 {
6465     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
6466
6467     return ITypeInfo_QueryInterface((ITypeInfo *)This, riid, ppv);
6468 }
6469
6470 static ULONG WINAPI ITypeComp_fnAddRef(ITypeComp * iface)
6471 {
6472     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
6473
6474     return ITypeInfo_AddRef((ITypeInfo *)This);
6475 }
6476
6477 static ULONG WINAPI ITypeComp_fnRelease(ITypeComp * iface)
6478 {
6479     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
6480
6481     return ITypeInfo_Release((ITypeInfo *)This);
6482 }
6483
6484 static HRESULT WINAPI ITypeComp_fnBind(
6485     ITypeComp * iface,
6486     OLECHAR * szName,
6487     ULONG lHash,
6488     WORD wFlags,
6489     ITypeInfo ** ppTInfo,
6490     DESCKIND * pDescKind,
6491     BINDPTR * pBindPtr)
6492 {
6493     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
6494     const TLBFuncDesc *pFDesc;
6495     const TLBVarDesc *pVDesc;
6496
6497     TRACE("(%s, %lx, 0x%x, %p, %p, %p)\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
6498
6499     *pDescKind = DESCKIND_NONE;
6500     pBindPtr->lpfuncdesc = NULL;
6501     *ppTInfo = NULL;
6502
6503     for(pFDesc = This->funclist; pFDesc; pFDesc = pFDesc->next)
6504         if (!wFlags || (pFDesc->funcdesc.invkind & wFlags))
6505             if (!strcmpW(pFDesc->Name, szName)) {
6506                 break;
6507             }
6508
6509     if (pFDesc)
6510     {
6511         HRESULT hr = TLB_AllocAndInitFuncDesc(
6512             &pFDesc->funcdesc,
6513             &pBindPtr->lpfuncdesc,
6514             This->TypeAttr.typekind == TKIND_DISPATCH);
6515         if (FAILED(hr))
6516             return hr;
6517         *pDescKind = DESCKIND_FUNCDESC;
6518         *ppTInfo = (ITypeInfo *)&This->lpVtbl;
6519         ITypeInfo_AddRef(*ppTInfo);
6520         return S_OK;
6521     } else {
6522         for(pVDesc = This->varlist; pVDesc; pVDesc = pVDesc->next) {
6523             if (!strcmpW(pVDesc->Name, szName)) {
6524                 HRESULT hr = TLB_AllocAndInitVarDesc(&pVDesc->vardesc, &pBindPtr->lpvardesc);
6525                 if (FAILED(hr))
6526                     return hr;
6527                 *pDescKind = DESCKIND_VARDESC;
6528                 *ppTInfo = (ITypeInfo *)&This->lpVtbl;
6529                 ITypeInfo_AddRef(*ppTInfo);
6530                 return S_OK;
6531             }
6532         }
6533     }
6534     /* FIXME: search each inherited interface, not just the first */
6535     if (This->TypeAttr.cImplTypes) {
6536         /* recursive search */
6537         ITypeInfo *pTInfo;
6538         ITypeComp *pTComp;
6539         HRESULT hr;
6540         hr=ITypeInfo_GetRefTypeInfo((ITypeInfo *)&This->lpVtbl, This->impltypelist->hRef, &pTInfo);
6541         if (SUCCEEDED(hr))
6542         {
6543             hr = ITypeInfo_GetTypeComp(pTInfo,&pTComp);
6544             ITypeInfo_Release(pTInfo);
6545         }
6546         if (SUCCEEDED(hr))
6547         {
6548             hr = ITypeComp_Bind(pTComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
6549             ITypeComp_Release(pTComp);
6550             return hr;
6551         }
6552         WARN("Could not search inherited interface!\n");
6553     }
6554     WARN("did not find member with name %s, flags 0x%x!\n", debugstr_w(szName), wFlags);
6555     return DISP_E_MEMBERNOTFOUND;
6556 }
6557
6558 static HRESULT WINAPI ITypeComp_fnBindType(
6559     ITypeComp * iface,
6560     OLECHAR * szName,
6561     ULONG lHash,
6562     ITypeInfo ** ppTInfo,
6563     ITypeComp ** ppTComp)
6564 {
6565     TRACE("(%s, %lx, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
6566
6567     /* strange behaviour (does nothing) but like the
6568      * original */
6569
6570     if (!ppTInfo || !ppTComp)
6571         return E_POINTER;
6572
6573     *ppTInfo = NULL;
6574     *ppTComp = NULL;
6575
6576     return S_OK;
6577 }
6578
6579 static const ITypeCompVtbl tcompvt =
6580 {
6581
6582     ITypeComp_fnQueryInterface,
6583     ITypeComp_fnAddRef,
6584     ITypeComp_fnRelease,
6585
6586     ITypeComp_fnBind,
6587     ITypeComp_fnBindType
6588 };