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