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