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