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