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