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