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