oleaut32: Fix ITypeInfo::GetFuncDesc to return the correct information for dual dispi...
[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 /* internal function to make the inherited interfaces' methods appear
4551  * part of the interface */
4552 static HRESULT ITypeInfoImpl_GetInternalDispatchFuncDesc( ITypeInfo *iface,
4553     UINT index, const FUNCDESC **ppFuncDesc, UINT *funcs)
4554 {
4555     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4556     HRESULT hr;
4557     UINT i;
4558     UINT implemented_funcs = 0;
4559
4560     if (funcs)
4561         *funcs = 0;
4562
4563     for (i = 0; i < This->TypeAttr.cImplTypes; i++)
4564     {
4565         HREFTYPE href;
4566         ITypeInfo *pSubTypeInfo;
4567         UINT sub_funcs;
4568
4569         hr = ITypeInfo_GetRefTypeOfImplType(iface, i, &href);
4570         if (FAILED(hr))
4571             return hr;
4572         hr = ITypeInfo_GetRefTypeInfo(iface, href, &pSubTypeInfo);
4573         if (FAILED(hr))
4574             return hr;
4575
4576         hr = ITypeInfoImpl_GetInternalDispatchFuncDesc(pSubTypeInfo,
4577                                                        index,
4578                                                        ppFuncDesc,
4579                                                        &sub_funcs);
4580         implemented_funcs += sub_funcs;
4581         ITypeInfo_Release(pSubTypeInfo);
4582         if (SUCCEEDED(hr))
4583             return hr;
4584     }
4585
4586     if (funcs)
4587         *funcs = implemented_funcs + This->TypeAttr.cFuncs;
4588     
4589     if (index < implemented_funcs)
4590         return E_INVALIDARG;
4591     return ITypeInfoImpl_GetInternalFuncDesc(iface, index - implemented_funcs,
4592                                              ppFuncDesc);
4593 }
4594
4595 /* ITypeInfo::GetFuncDesc
4596  *
4597  * Retrieves the FUNCDESC structure that contains information about a
4598  * specified function.
4599  *
4600  */
4601 static HRESULT WINAPI ITypeInfo_fnGetFuncDesc( ITypeInfo2 *iface, UINT index,
4602         LPFUNCDESC  *ppFuncDesc)
4603 {
4604     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4605     const FUNCDESC *internal_funcdesc;
4606     HRESULT hr;
4607
4608     TRACE("(%p) index %d\n", This, index);
4609
4610     if ((This->TypeAttr.typekind == TKIND_DISPATCH) &&
4611         (This->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL))
4612         hr = ITypeInfoImpl_GetInternalDispatchFuncDesc((ITypeInfo *)iface, index,
4613                                                        &internal_funcdesc, NULL);
4614     else
4615         hr = ITypeInfoImpl_GetInternalFuncDesc((ITypeInfo *)iface, index,
4616                                                &internal_funcdesc);
4617     if (FAILED(hr))
4618     {
4619         WARN("description for function %d not found\n", index);
4620         return hr;
4621     }
4622
4623     return TLB_AllocAndInitFuncDesc(
4624         internal_funcdesc,
4625         ppFuncDesc,
4626         This->TypeAttr.typekind == TKIND_DISPATCH);
4627 }
4628
4629 static HRESULT TLB_AllocAndInitVarDesc( const VARDESC *src, VARDESC **dest_ptr )
4630 {
4631     VARDESC *dest;
4632     char *buffer;
4633     SIZE_T size = sizeof(*src);
4634     HRESULT hr;
4635
4636     if (src->lpstrSchema) size += (strlenW(src->lpstrSchema) + 1) * sizeof(WCHAR);
4637     if (src->varkind == VAR_CONST)
4638         size += sizeof(VARIANT);
4639     size += TLB_SizeElemDesc(&src->elemdescVar);
4640
4641     dest = (VARDESC *)SysAllocStringByteLen(NULL, size);
4642     if (!dest) return E_OUTOFMEMORY;
4643
4644     *dest = *src;
4645     buffer = (char *)(dest + 1);
4646     if (src->lpstrSchema)
4647     {
4648         int len;
4649         dest->lpstrSchema = (LPOLESTR)buffer;
4650         len = strlenW(src->lpstrSchema);
4651         memcpy(dest->lpstrSchema, src->lpstrSchema, (len + 1) * sizeof(WCHAR));
4652         buffer += (len + 1) * sizeof(WCHAR);
4653     }
4654
4655     if (src->varkind == VAR_CONST)
4656     {
4657         HRESULT hr;
4658
4659         dest->u.lpvarValue = (VARIANT *)buffer;
4660         *dest->u.lpvarValue = *src->u.lpvarValue;
4661         buffer += sizeof(VARIANT);
4662         VariantInit(dest->u.lpvarValue);
4663         hr = VariantCopy(dest->u.lpvarValue, src->u.lpvarValue);
4664         if (FAILED(hr))
4665         {
4666             SysFreeString((BSTR)dest_ptr);
4667             return hr;
4668         }
4669     }
4670     hr = TLB_CopyElemDesc(&src->elemdescVar, &dest->elemdescVar, &buffer);
4671     if (FAILED(hr))
4672     {
4673         if (src->varkind == VAR_CONST)
4674             VariantClear(dest->u.lpvarValue);
4675         SysFreeString((BSTR)dest);
4676         return hr;
4677     }
4678     *dest_ptr = dest;
4679     return S_OK;
4680 }
4681
4682 /* ITypeInfo::GetVarDesc
4683  *
4684  * Retrieves a VARDESC structure that describes the specified variable.
4685  *
4686  */
4687 static HRESULT WINAPI ITypeInfo_fnGetVarDesc( ITypeInfo2 *iface, UINT index,
4688         LPVARDESC  *ppVarDesc)
4689 {
4690     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4691     int i;
4692     const TLBVarDesc *pVDesc;
4693
4694     TRACE("(%p) index %d\n", This, index);
4695
4696     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next)
4697         ;
4698
4699     if (pVDesc)
4700         return TLB_AllocAndInitVarDesc(&pVDesc->vardesc, ppVarDesc);
4701
4702     return E_INVALIDARG;
4703 }
4704
4705 /* ITypeInfo_GetNames
4706  *
4707  * Retrieves the variable with the specified member ID (or the name of the
4708  * property or method and its parameters) that correspond to the specified
4709  * function ID.
4710  */
4711 static HRESULT WINAPI ITypeInfo_fnGetNames( ITypeInfo2 *iface, MEMBERID memid,
4712         BSTR  *rgBstrNames, UINT cMaxNames, UINT  *pcNames)
4713 {
4714     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4715     const TLBFuncDesc *pFDesc;
4716     const TLBVarDesc *pVDesc;
4717     int i;
4718     TRACE("(%p) memid=0x%08lx Maxname=%d\n", This, memid, cMaxNames);
4719     for(pFDesc=This->funclist; pFDesc && pFDesc->funcdesc.memid != memid; pFDesc=pFDesc->next);
4720     if(pFDesc)
4721     {
4722       /* function found, now return function and parameter names */
4723       for(i=0; i<cMaxNames && i <= pFDesc->funcdesc.cParams; i++)
4724       {
4725         if(!i)
4726           *rgBstrNames=SysAllocString(pFDesc->Name);
4727         else
4728           rgBstrNames[i]=SysAllocString(pFDesc->pParamDesc[i-1].Name);
4729       }
4730       *pcNames=i;
4731     }
4732     else
4733     {
4734       for(pVDesc=This->varlist; pVDesc && pVDesc->vardesc.memid != memid; pVDesc=pVDesc->next);
4735       if(pVDesc)
4736       {
4737         *rgBstrNames=SysAllocString(pVDesc->Name);
4738         *pcNames=1;
4739       }
4740       else
4741       {
4742         if(This->TypeAttr.cImplTypes &&
4743            (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
4744           /* recursive search */
4745           ITypeInfo *pTInfo;
4746           HRESULT result;
4747           result=ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef,
4748                                           &pTInfo);
4749           if(SUCCEEDED(result))
4750           {
4751             result=ITypeInfo_GetNames(pTInfo, memid, rgBstrNames, cMaxNames, pcNames);
4752             ITypeInfo_Release(pTInfo);
4753             return result;
4754           }
4755           WARN("Could not search inherited interface!\n");
4756         }
4757         else
4758         {
4759           WARN("no names found\n");
4760         }
4761         *pcNames=0;
4762         return TYPE_E_ELEMENTNOTFOUND;
4763       }
4764     }
4765     return S_OK;
4766 }
4767
4768
4769 /* ITypeInfo::GetRefTypeOfImplType
4770  *
4771  * If a type description describes a COM class, it retrieves the type
4772  * description of the implemented interface types. For an interface,
4773  * GetRefTypeOfImplType returns the type information for inherited interfaces,
4774  * if any exist.
4775  *
4776  */
4777 static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType(
4778         ITypeInfo2 *iface,
4779         UINT index,
4780         HREFTYPE  *pRefType)
4781 {
4782     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4783     int i;
4784     HRESULT hr = S_OK;
4785     const TLBImplType *pImpl = This->impltypelist;
4786
4787     TRACE("(%p) index %d\n", This, index);
4788     if (TRACE_ON(ole)) dump_TypeInfo(This);
4789
4790     if(index==(UINT)-1)
4791     {
4792       /* only valid on dual interfaces;
4793          retrieve the associated TKIND_INTERFACE handle for the current TKIND_DISPATCH
4794       */
4795       if( This->TypeAttr.typekind != TKIND_DISPATCH) return E_INVALIDARG;
4796
4797       if (This->TypeAttr.wTypeFlags & TYPEFLAG_FDISPATCHABLE &&
4798           This->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL )
4799       {
4800         *pRefType = -1;
4801       }
4802       else
4803       {
4804         hr = TYPE_E_ELEMENTNOTFOUND;
4805       }
4806     }
4807     else
4808     {
4809       /* get element n from linked list */
4810       for(i=0; pImpl && i<index; i++)
4811       {
4812         pImpl = pImpl->next;
4813       }
4814
4815       if (pImpl)
4816         *pRefType = pImpl->hRef;
4817       else
4818         hr = TYPE_E_ELEMENTNOTFOUND;
4819     }
4820
4821     if(TRACE_ON(ole))
4822     {
4823         if(SUCCEEDED(hr))
4824             TRACE("SUCCESS -- hRef = 0x%08lx\n", *pRefType );
4825         else
4826             TRACE("FAILURE -- hresult = 0x%08lx\n", hr);
4827     }
4828
4829     return hr;
4830 }
4831
4832 /* ITypeInfo::GetImplTypeFlags
4833  *
4834  * Retrieves the IMPLTYPEFLAGS enumeration for one implemented interface
4835  * or base interface in a type description.
4836  */
4837 static HRESULT WINAPI ITypeInfo_fnGetImplTypeFlags( ITypeInfo2 *iface,
4838         UINT index, INT  *pImplTypeFlags)
4839 {
4840     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4841     int i;
4842     TLBImplType *pImpl;
4843
4844     TRACE("(%p) index %d\n", This, index);
4845     for(i=0, pImpl=This->impltypelist; i<index && pImpl;
4846         i++, pImpl=pImpl->next)
4847         ;
4848     if(i==index && pImpl){
4849         *pImplTypeFlags=pImpl->implflags;
4850         return S_OK;
4851     }
4852     *pImplTypeFlags=0;
4853     return TYPE_E_ELEMENTNOTFOUND;
4854 }
4855
4856 /* GetIDsOfNames
4857  * Maps between member names and member IDs, and parameter names and
4858  * parameter IDs.
4859  */
4860 static HRESULT WINAPI ITypeInfo_fnGetIDsOfNames( ITypeInfo2 *iface,
4861         LPOLESTR  *rgszNames, UINT cNames, MEMBERID  *pMemId)
4862 {
4863     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4864     const TLBFuncDesc *pFDesc;
4865     const TLBVarDesc *pVDesc;
4866     HRESULT ret=S_OK;
4867     int i;
4868
4869     TRACE("(%p) Name %s cNames %d\n", This, debugstr_w(*rgszNames),
4870             cNames);
4871
4872     /* init out parameters in case of failure */
4873     for (i = 0; i < cNames; i++)
4874         pMemId[i] = MEMBERID_NIL;
4875
4876     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next) {
4877         int j;
4878         if(!lstrcmpiW(*rgszNames, pFDesc->Name)) {
4879             if(cNames) *pMemId=pFDesc->funcdesc.memid;
4880             for(i=1; i < cNames; i++){
4881                 for(j=0; j<pFDesc->funcdesc.cParams; j++)
4882                     if(!lstrcmpiW(rgszNames[i],pFDesc->pParamDesc[j].Name))
4883                             break;
4884                 if( j<pFDesc->funcdesc.cParams)
4885                     pMemId[i]=j;
4886                 else
4887                    ret=DISP_E_UNKNOWNNAME;
4888             };
4889             TRACE("-- 0x%08lx\n", ret);
4890             return ret;
4891         }
4892     }
4893     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) {
4894         if(!lstrcmpiW(*rgszNames, pVDesc->Name)) {
4895             if(cNames) *pMemId=pVDesc->vardesc.memid;
4896             return ret;
4897         }
4898     }
4899     /* not found, see if it can be found in an inherited interface */
4900     if(This->TypeAttr.cImplTypes) {
4901         /* recursive search */
4902         ITypeInfo *pTInfo;
4903         ret=ITypeInfo_GetRefTypeInfo(iface,
4904                 This->impltypelist->hRef, &pTInfo);
4905         if(SUCCEEDED(ret)){
4906             ret=ITypeInfo_GetIDsOfNames(pTInfo, rgszNames, cNames, pMemId );
4907             ITypeInfo_Release(pTInfo);
4908             return ret;
4909         }
4910         WARN("Could not search inherited interface!\n");
4911     } else
4912         WARN("no names found\n");
4913     return DISP_E_UNKNOWNNAME;
4914 }
4915
4916 /* ITypeInfo::Invoke
4917  *
4918  * Invokes a method, or accesses a property of an object, that implements the
4919  * interface described by the type description.
4920  */
4921 DWORD
4922 _invoke(FARPROC func,CALLCONV callconv, int nrargs, DWORD *args) {
4923     DWORD res;
4924
4925     if (TRACE_ON(ole)) {
4926         int i;
4927         TRACE("Calling %p(",func);
4928         for (i=0;i<nrargs;i++) TRACE("%08lx,",args[i]);
4929         TRACE(")\n");
4930     }
4931
4932     switch (callconv) {
4933     case CC_STDCALL:
4934
4935         switch (nrargs) {
4936         case 0:
4937                 res = func();
4938                 break;
4939         case 1:
4940                 res = func(args[0]);
4941                 break;
4942         case 2:
4943                 res = func(args[0],args[1]);
4944                 break;
4945         case 3:
4946                 res = func(args[0],args[1],args[2]);
4947                 break;
4948         case 4:
4949                 res = func(args[0],args[1],args[2],args[3]);
4950                 break;
4951         case 5:
4952                 res = func(args[0],args[1],args[2],args[3],args[4]);
4953                 break;
4954         case 6:
4955                 res = func(args[0],args[1],args[2],args[3],args[4],args[5]);
4956                 break;
4957         case 7:
4958                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
4959                 break;
4960         case 8:
4961                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]);
4962                 break;
4963         case 9:
4964                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]);
4965                 break;
4966         case 10:
4967                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9]);
4968                 break;
4969         case 11:
4970                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10]);
4971                 break;
4972         case 12:
4973                 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]);
4974                 break;
4975         case 13:
4976                 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]);
4977                 break;
4978         case 14:
4979                 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]);
4980                 break;
4981         case 15:
4982                 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]);
4983                 break;
4984         case 16:
4985                 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]);
4986                 break;
4987         case 17:
4988                 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]);
4989                 break;
4990         case 18:
4991                 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]);
4992                 break;
4993         case 19:
4994                 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]);
4995                 break;
4996         case 20:
4997                 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]);
4998                 break;
4999         case 21:
5000                 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]);
5001                 break;
5002         case 22:
5003                 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]);
5004                 break;
5005         case 23:
5006                 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]);
5007                 break;
5008         default:
5009                 FIXME("unsupported number of arguments %d in stdcall\n",nrargs);
5010                 res = -1;
5011                 break;
5012         }
5013         break;
5014     default:
5015         FIXME("unsupported calling convention %d\n",callconv);
5016         res = -1;
5017         break;
5018     }
5019     TRACE("returns %08lx\n",res);
5020     return res;
5021 }
5022
5023 extern int _argsize(DWORD vt);
5024
5025 static HRESULT userdefined_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
5026 {
5027     HRESULT hr = S_OK;
5028     ITypeInfo *tinfo2 = NULL;
5029     TYPEATTR *tattr = NULL;
5030
5031     hr = ITypeInfo_GetRefTypeInfo(tinfo, tdesc->u.hreftype, &tinfo2);
5032     if (hr)
5033     {
5034         ERR("Could not get typeinfo of hreftype %lx for VT_USERDEFINED, "
5035             "hr = 0x%08lx\n",
5036               tdesc->u.hreftype, hr);
5037         return hr;
5038     }
5039     hr = ITypeInfo_GetTypeAttr(tinfo2, &tattr);
5040     if (hr)
5041     {
5042         ERR("ITypeInfo_GetTypeAttr failed, hr = 0x%08lx\n", hr);
5043         ITypeInfo_Release(tinfo2);
5044         return hr;
5045     }
5046
5047     switch (tattr->typekind)
5048     {
5049     case TKIND_ENUM:
5050         *vt |= VT_I4;
5051         break;
5052
5053     case TKIND_ALIAS:
5054         tdesc = &tattr->tdescAlias;
5055         hr = typedescvt_to_variantvt(tinfo2, &tattr->tdescAlias, vt);
5056         break;
5057
5058     case TKIND_INTERFACE:
5059         if (IsEqualIID(&IID_IDispatch, &tattr->guid))
5060            *vt |= VT_DISPATCH;
5061         else
5062            *vt |= VT_UNKNOWN;
5063         break;
5064
5065     case TKIND_DISPATCH:
5066         *vt |= VT_DISPATCH;
5067         break;
5068
5069     case TKIND_COCLASS:
5070         *vt |= VT_UNKNOWN;
5071         break;
5072
5073     case TKIND_RECORD:
5074         FIXME("TKIND_RECORD unhandled.\n");
5075         hr = E_NOTIMPL;
5076         break;
5077
5078     case TKIND_UNION:
5079         FIXME("TKIND_UNION unhandled.\n");
5080         hr = E_NOTIMPL;
5081         break;
5082
5083     default:
5084         FIXME("TKIND %d unhandled.\n",tattr->typekind);
5085         hr = E_NOTIMPL;
5086         break;
5087     }
5088     ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
5089     ITypeInfo_Release(tinfo2);
5090     return hr;
5091 }
5092
5093 static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
5094 {
5095     HRESULT hr = S_OK;
5096
5097     /* enforce only one level of pointer indirection */
5098     if (!(*vt & VT_BYREF) && !(*vt & VT_ARRAY) && (tdesc->vt == VT_PTR))
5099     {
5100         tdesc = tdesc->u.lptdesc;
5101
5102         /* munch VT_PTR -> VT_USERDEFINED(interface) into VT_UNKNOWN or
5103          * VT_DISPATCH and VT_PTR -> VT_PTR -> VT_USERDEFINED(interface) into 
5104          * VT_BYREF|VT_DISPATCH or VT_BYREF|VT_UNKNOWN */
5105         if ((tdesc->vt == VT_USERDEFINED) ||
5106             ((tdesc->vt == VT_PTR) && (tdesc->u.lptdesc->vt == VT_USERDEFINED)))
5107         {
5108             VARTYPE vt_userdefined = 0;
5109             const TYPEDESC *tdesc_userdefined = tdesc;
5110             if (tdesc->vt == VT_PTR)
5111             {
5112                 vt_userdefined = VT_BYREF;
5113                 tdesc_userdefined = tdesc->u.lptdesc;
5114             }
5115             hr = userdefined_to_variantvt(tinfo, tdesc_userdefined, &vt_userdefined);
5116             if ((hr == S_OK) && 
5117                 (((vt_userdefined & VT_TYPEMASK) == VT_UNKNOWN) ||
5118                  ((vt_userdefined & VT_TYPEMASK) == VT_DISPATCH)))
5119             {
5120                 *vt |= vt_userdefined;
5121                 return S_OK;
5122             }
5123         }
5124         *vt = VT_BYREF;
5125     }
5126
5127     switch (tdesc->vt)
5128     {
5129     case VT_HRESULT:
5130         *vt |= VT_ERROR;
5131         break;
5132     case VT_USERDEFINED:
5133         hr = userdefined_to_variantvt(tinfo, tdesc, vt);
5134         break;
5135     case VT_VOID:
5136     case VT_CARRAY:
5137     case VT_PTR:
5138     case VT_LPSTR:
5139     case VT_LPWSTR:
5140         ERR("cannot convert type %d into variant VT\n", tdesc->vt);
5141         hr = DISP_E_BADVARTYPE;
5142         break;
5143     case VT_SAFEARRAY:
5144         *vt |= VT_ARRAY;
5145         hr = typedescvt_to_variantvt(tinfo, tdesc->u.lptdesc, vt);
5146         break;
5147     default:
5148         *vt |= tdesc->vt;
5149         break;
5150     }
5151     return hr;
5152 }
5153
5154 /***********************************************************************
5155  *              DispCallFunc (OLEAUT32.@)
5156  *
5157  * Invokes a function of the specifed calling convention, passing the
5158  * specified arguments and returns the result.
5159  *
5160  * PARAMS
5161  *  pvInstance  [I] Optional pointer to the instance whose function to invoke.
5162  *  oVft        [I] The offset in the vtable. See notes.
5163  *  cc          [I] Calling convention of the function to call.
5164  *  vtReturn    [I] The return type of the function.
5165  *  cActuals    [I] Number of parameters.
5166  *  prgvt       [I] The types of the parameters to pass. This is used for sizing only.
5167  *  prgpvarg    [I] The arguments to pass.
5168  *  pvargResult [O] The return value of the function. Can be NULL.
5169  *
5170  * RETURNS
5171  *  Success: S_OK.
5172  *  Failure: HRESULT code.
5173  *
5174  * NOTES
5175  *  The HRESULT return value of this function is not affected by the return
5176  *  value of the user supplied function, which is returned in pvargResult.
5177  *
5178  *  If pvInstance is NULL then a non-object function is to be called and oVft
5179  *  is the address of the function to call.
5180  *
5181  * The cc parameter can be one of the following values:
5182  *|CC_FASTCALL
5183  *|CC_CDECL
5184  *|CC_PASCAL
5185  *|CC_STDCALL
5186  *|CC_FPFASTCALL
5187  *|CC_SYSCALL
5188  *|CC_MPWCDECL
5189  *|CC_MPWPASCAL
5190  *
5191  */
5192 HRESULT WINAPI
5193 DispCallFunc(
5194     void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals,
5195     VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult)
5196 {
5197     int i, argsize, argspos;
5198     DWORD *args;
5199     HRESULT hres;
5200
5201     TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
5202         pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
5203         pvargResult, V_VT(pvargResult));
5204
5205     argsize = 0;
5206     if (pvInstance)
5207         argsize++; /* for This pointer */
5208
5209     for (i=0;i<cActuals;i++)
5210     {
5211         TRACE("arg %d: type %d, size %d\n",i,prgvt[i],_argsize(prgvt[i]));
5212         dump_Variant(prgpvarg[i]);
5213         argsize += _argsize(prgvt[i]);
5214     }
5215     args = HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*argsize);
5216
5217     argspos = 0;
5218     if (pvInstance)
5219     {
5220         args[0] = (DWORD)pvInstance; /* the This pointer is always the first parameter */
5221         argspos++;
5222     }
5223
5224     for (i=0;i<cActuals;i++)
5225     {
5226         VARIANT *arg = prgpvarg[i];
5227         TRACE("Storing arg %d (%d as %d)\n",i,V_VT(arg),prgvt[i]);
5228         if (prgvt[i] == VT_VARIANT)
5229             memcpy(&args[argspos], arg, _argsize(prgvt[i]) * sizeof(DWORD));
5230         else
5231             memcpy(&args[argspos], &V_NONE(arg), _argsize(prgvt[i]) * sizeof(DWORD));
5232         argspos += _argsize(prgvt[i]);
5233     }
5234
5235     if (pvInstance)
5236     {
5237         FARPROC *vtable = *(FARPROC**)pvInstance;
5238         hres = _invoke(vtable[oVft/sizeof(void *)], cc, argsize, args);
5239     }
5240     else
5241         /* if we aren't invoking an object then the function pointer is stored
5242          * in oVft */
5243         hres = _invoke((FARPROC)oVft, cc, argsize, args);
5244
5245     if (pvargResult && (vtReturn != VT_EMPTY))
5246     {
5247         TRACE("Method returned 0x%08lx\n",hres);
5248         V_VT(pvargResult) = vtReturn;
5249         V_UI4(pvargResult) = hres;
5250     }
5251
5252     HeapFree(GetProcessHeap(),0,args);
5253     return S_OK;
5254 }
5255
5256 #define INVBUF_ELEMENT_SIZE \
5257     (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *) + sizeof(VARTYPE))
5258 #define INVBUF_GET_ARG_ARRAY(buffer, params) \
5259     ((VARIANTARG *)(buffer))
5260 #define INVBUF_GET_MISSING_ARG_ARRAY(buffer, params) \
5261     ((VARIANTARG *)((char *)(buffer) + sizeof(VARIANTARG) * (params)))
5262 #define INVBUF_GET_ARG_PTR_ARRAY(buffer, params) \
5263     ((VARIANTARG **)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG)) * (params)))
5264 #define INVBUF_GET_ARG_TYPE_ARRAY(buffer, params) \
5265     ((VARTYPE *)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *)) * (params)))
5266
5267 static HRESULT WINAPI ITypeInfo_fnInvoke(
5268     ITypeInfo2 *iface,
5269     VOID  *pIUnk,
5270     MEMBERID memid,
5271     UINT16 wFlags,
5272     DISPPARAMS  *pDispParams,
5273     VARIANT  *pVarResult,
5274     EXCEPINFO  *pExcepInfo,
5275     UINT  *pArgErr)
5276 {
5277     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5278     int i;
5279     unsigned int var_index;
5280     TYPEKIND type_kind;
5281     HRESULT hres;
5282     const TLBFuncDesc *pFuncInfo;
5283
5284     TRACE("(%p)(%p,id=%ld,flags=0x%08x,%p,%p,%p,%p)\n",
5285       This,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr
5286     );
5287
5288     if (!pDispParams)
5289     {
5290         ERR("NULL pDispParams not allowed\n");
5291         return E_INVALIDARG;
5292     }
5293
5294     dump_DispParms(pDispParams);
5295
5296     if (pDispParams->cNamedArgs > pDispParams->cArgs)
5297     {
5298         ERR("named argument array cannot be bigger than argument array (%d/%d)\n",
5299             pDispParams->cNamedArgs, pDispParams->cArgs);
5300         return E_INVALIDARG;
5301     }
5302
5303     /* we do this instead of using GetFuncDesc since it will return a fake
5304      * FUNCDESC for dispinterfaces and we want the real function description */
5305     for (pFuncInfo = This->funclist; pFuncInfo; pFuncInfo=pFuncInfo->next)
5306         if ((memid == pFuncInfo->funcdesc.memid) &&
5307             (wFlags & pFuncInfo->funcdesc.invkind))
5308             break;
5309
5310     if (pFuncInfo) {
5311         const FUNCDESC *func_desc = &pFuncInfo->funcdesc;
5312
5313         if (TRACE_ON(ole))
5314         {
5315             TRACE("invoking:\n");
5316             dump_TLBFuncDescOne(pFuncInfo);
5317         }
5318         
5319         switch (func_desc->funckind) {
5320         case FUNC_PUREVIRTUAL:
5321         case FUNC_VIRTUAL: {
5322             void *buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INVBUF_ELEMENT_SIZE * func_desc->cParams);
5323             VARIANT varresult;
5324             VARIANT retval; /* pointer for storing byref retvals in */
5325             VARIANTARG **prgpvarg = INVBUF_GET_ARG_PTR_ARRAY(buffer, func_desc->cParams);
5326             VARIANTARG *rgvarg = INVBUF_GET_ARG_ARRAY(buffer, func_desc->cParams);
5327             VARTYPE *rgvt = INVBUF_GET_ARG_TYPE_ARRAY(buffer, func_desc->cParams);
5328
5329             hres = S_OK;
5330             for (i = 0; i < func_desc->cParams; i++)
5331             {
5332                 TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc;
5333                 hres = typedescvt_to_variantvt((ITypeInfo *)iface, tdesc, &rgvt[i]);
5334                 if (FAILED(hres))
5335                     goto func_fail;
5336             }
5337
5338             TRACE("changing args\n");
5339             for (i = 0; i < func_desc->cParams; i++)
5340             {
5341                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
5342
5343                 if (wParamFlags & PARAMFLAG_FRETVAL)
5344                 {
5345                     /* note: this check is placed so that if the caller passes
5346                      * in a VARIANTARG for the retval we just ignore it, like
5347                      * native does */
5348                     if (i == func_desc->cParams - 1)
5349                     {
5350                         VARIANTARG *arg;
5351                         arg = prgpvarg[i] = &rgvarg[i];
5352                         memset(arg, 0, sizeof(*arg));
5353                         V_VT(arg) = rgvt[i];
5354                         memset(&retval, 0, sizeof(retval));
5355                         V_BYREF(arg) = &retval;
5356                     }
5357                     else
5358                     {
5359                         ERR("[retval] parameter must be the last parameter of the method (%d/%d)\n", i, func_desc->cParams);
5360                         hres = E_UNEXPECTED;
5361                         break;
5362                     }
5363                 }
5364                 else if (i < pDispParams->cArgs)
5365                 {
5366                     VARIANTARG *src_arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - i];
5367                     dump_Variant(src_arg);
5368
5369                     if (rgvt[i] == VT_VARIANT)
5370                         hres = VariantCopy(&rgvarg[i], src_arg);
5371                     else if (rgvt[i] == (VT_VARIANT | VT_BYREF))
5372                     {
5373                         if (rgvt[i] == V_VT(src_arg))
5374                             V_VARIANTREF(&rgvarg[i]) = V_VARIANTREF(src_arg);
5375                         else
5376                         {
5377                             VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
5378                             hres = VariantCopy(&missing_arg[i], src_arg);
5379                             V_VARIANTREF(&rgvarg[i]) = &missing_arg[i];
5380                         }
5381                         V_VT(&rgvarg[i]) = rgvt[i];
5382                     }
5383                     else if ((rgvt[i] & VT_BYREF) && !V_ISBYREF(src_arg))
5384                     {
5385                         VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
5386                         V_VT(&missing_arg[i]) = V_VT(src_arg);
5387                         hres = VariantChangeType(&missing_arg[i], src_arg, 0, rgvt[i] & ~VT_BYREF);
5388                         V_BYREF(&rgvarg[i]) = &V_NONE(&missing_arg[i]);
5389                         V_VT(&rgvarg[i]) = rgvt[i];
5390                     }
5391                     else if ((rgvt[i] & VT_BYREF) && (rgvt[i] == V_VT(src_arg)))
5392                     {
5393                         V_BYREF(&rgvarg[i]) = V_BYREF(src_arg);
5394                         V_VT(&rgvarg[i]) = rgvt[i];
5395                     }
5396                     else
5397                     {
5398                         /* FIXME: this doesn't work for VT_BYREF arguments if
5399                          * they are not the same type as in the paramdesc */
5400                         V_VT(&rgvarg[i]) = V_VT(src_arg);
5401                         hres = VariantChangeType(&rgvarg[i], src_arg, 0, rgvt[i]);
5402                         V_VT(&rgvarg[i]) = rgvt[i];
5403                     }
5404
5405                     if (FAILED(hres))
5406                     {
5407                         ERR("failed to convert param %d to %s%s from %s%s\n", i,
5408                             debugstr_vt(rgvt[i]), debugstr_vf(rgvt[i]),
5409                             debugstr_VT(src_arg), debugstr_VF(src_arg));
5410                         break;
5411                     }
5412                     prgpvarg[i] = &rgvarg[i];
5413                 }
5414                 else if (wParamFlags & PARAMFLAG_FOPT)
5415                 {
5416                     VARIANTARG *arg;
5417                     arg = prgpvarg[i] = &rgvarg[i];
5418                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
5419                     {
5420                         hres = VariantCopy(arg, &func_desc->lprgelemdescParam[i].u.paramdesc.pparamdescex->varDefaultValue);
5421                         if (FAILED(hres))
5422                             break;
5423                     }
5424                     else
5425                     {
5426                         VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
5427                         V_VT(arg) = VT_VARIANT | VT_BYREF;
5428                         V_VARIANTREF(arg) = &missing_arg[i];
5429                         V_VT(V_VARIANTREF(arg)) = VT_ERROR;
5430                         V_ERROR(V_VARIANTREF(arg)) = DISP_E_PARAMNOTFOUND;
5431                     }
5432                 }
5433                 else
5434                 {
5435                     hres = DISP_E_BADPARAMCOUNT;
5436                     break;
5437                 }
5438             }
5439             if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
5440             if (func_desc->cParamsOpt < 0)
5441             {
5442                 FIXME("Does not support safearray optional parameters\n");
5443                 hres = DISP_E_BADPARAMCOUNT;
5444                 goto func_fail; /* FIXME: we don't free changed types here */
5445             }
5446
5447             /* VT_VOID is a special case for return types, so it is not
5448              * handled in the general function */
5449             if (func_desc->elemdescFunc.tdesc.vt == VT_VOID)
5450                 V_VT(&varresult) = VT_EMPTY;
5451             else
5452             {
5453                 V_VT(&varresult) = 0;
5454                 hres = typedescvt_to_variantvt((ITypeInfo *)iface, &func_desc->elemdescFunc.tdesc, &V_VT(&varresult));
5455                 if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
5456             }
5457
5458             hres = DispCallFunc(pIUnk, func_desc->oVft, func_desc->callconv,
5459                                 V_VT(&varresult), func_desc->cParams, rgvt,
5460                                 prgpvarg, &varresult);
5461
5462             for (i = 0; i < func_desc->cParams; i++)
5463             {
5464                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
5465                 if (wParamFlags & PARAMFLAG_FRETVAL)
5466                 {
5467                     if (TRACE_ON(ole))
5468                     {
5469                         TRACE("[retval] value: ");
5470                         dump_Variant(prgpvarg[i]);
5471                     }
5472
5473                     if (pVarResult)
5474                     {
5475                         VariantInit(pVarResult);
5476                         /* deref return value */
5477                         hres = VariantCopyInd(pVarResult, prgpvarg[i]);
5478                     }
5479
5480                     /* free data stored in varresult. Note that
5481                      * VariantClear doesn't do what we want because we are
5482                      * working with byref types. */
5483                     /* FIXME: clear safearrays, bstrs, records and
5484                      * variants here too */
5485                     if ((V_VT(prgpvarg[i]) == (VT_UNKNOWN | VT_BYREF)) ||
5486                          (V_VT(prgpvarg[i]) == (VT_DISPATCH | VT_BYREF)))
5487                     {
5488                         if(*V_UNKNOWNREF(prgpvarg[i]))
5489                             IUnknown_Release(*V_UNKNOWNREF(prgpvarg[i]));
5490                     }
5491                     break;
5492                 }
5493                 else if (i < pDispParams->cArgs)
5494                 {
5495                     if (wParamFlags & PARAMFLAG_FOUT)
5496                     {
5497                         VARIANTARG *arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - i];
5498
5499                         if ((rgvt[i] == VT_BYREF) && (V_VT(arg) != VT_BYREF))
5500                             hres = VariantChangeType(arg, &rgvarg[i], 0, V_VT(arg));
5501
5502                         if (FAILED(hres))
5503                         {
5504                             ERR("failed to convert param %d to vt %d\n", i,
5505                                 V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1 - i]));
5506                             break;
5507                         }
5508                     }
5509                     VariantClear(&rgvarg[i]);
5510                 }
5511                 else if (wParamFlags & PARAMFLAG_FOPT)
5512                 {
5513                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
5514                         VariantClear(&rgvarg[i]);
5515                 }
5516             }
5517
5518             if ((V_VT(&varresult) == VT_ERROR) && FAILED(V_ERROR(&varresult)))
5519             {
5520                 WARN("invoked function failed with error 0x%08lx\n", V_ERROR(&varresult));
5521                 hres = DISP_E_EXCEPTION;
5522                 if (pExcepInfo) pExcepInfo->scode = V_ERROR(&varresult);
5523             }
5524
5525 func_fail:
5526             HeapFree(GetProcessHeap(), 0, buffer);
5527             break;
5528         }
5529         case FUNC_DISPATCH:  {
5530            IDispatch *disp;
5531
5532            hres = IUnknown_QueryInterface((LPUNKNOWN)pIUnk,&IID_IDispatch,(LPVOID*)&disp);
5533            if (SUCCEEDED(hres)) {
5534                FIXME("Calling Invoke in IDispatch iface. untested!\n");
5535                hres = IDispatch_Invoke(
5536                                      disp,memid,&IID_NULL,LOCALE_USER_DEFAULT,wFlags,pDispParams,
5537                                      pVarResult,pExcepInfo,pArgErr
5538                                      );
5539                if (FAILED(hres))
5540                    FIXME("IDispatch::Invoke failed with %08lx. (Could be not a real error?)\n", hres);
5541                IDispatch_Release(disp);
5542            } else
5543                FIXME("FUNC_DISPATCH used on object without IDispatch iface?\n");
5544            break;
5545         }
5546         default:
5547             FIXME("Unknown function invocation type %d\n", func_desc->funckind);
5548             hres = E_FAIL;
5549             break;
5550         }
5551
5552         TRACE("-- 0x%08lx\n", hres);
5553         return hres;
5554
5555     } else if(SUCCEEDED(hres = ITypeInfo2_GetVarIndexOfMemId(iface, memid, &var_index))) {
5556         VARDESC *var_desc;
5557
5558         hres = ITypeInfo2_GetVarDesc(iface, var_index, &var_desc);
5559         if(FAILED(hres)) return hres;
5560         
5561         FIXME("varseek: Found memid, but variable-based invoking not supported\n");
5562         dump_VARDESC(var_desc);
5563         ITypeInfo2_ReleaseVarDesc(iface, var_desc);
5564         return E_NOTIMPL;
5565     }
5566
5567     /* not found, look for it in inherited interfaces */
5568     ITypeInfo2_GetTypeKind(iface, &type_kind);
5569     if(type_kind == TKIND_INTERFACE || type_kind == TKIND_DISPATCH) {
5570         HREFTYPE ref_type;
5571         if(SUCCEEDED(ITypeInfo2_GetRefTypeOfImplType(iface, 0, &ref_type))) {
5572             /* recursive search */
5573             ITypeInfo *pTInfo;
5574             hres = ITypeInfo_GetRefTypeInfo(iface, ref_type, &pTInfo);
5575             if(SUCCEEDED(hres)){
5576                 hres = ITypeInfo_Invoke(pTInfo,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr);
5577                 ITypeInfo_Release(pTInfo);
5578                 return hres;
5579             }
5580             WARN("Could not search inherited interface!\n");
5581         }
5582     }
5583     ERR("did not find member id %ld, flags 0x%x!\n", memid, wFlags);
5584     return DISP_E_MEMBERNOTFOUND;
5585 }
5586
5587 /* ITypeInfo::GetDocumentation
5588  *
5589  * Retrieves the documentation string, the complete Help file name and path,
5590  * and the context ID for the Help topic for a specified type description.
5591  *
5592  * (Can be tested by the Visual Basic Editor in Word for instance.)
5593  */
5594 static HRESULT WINAPI ITypeInfo_fnGetDocumentation( ITypeInfo2 *iface,
5595         MEMBERID memid, BSTR  *pBstrName, BSTR  *pBstrDocString,
5596         DWORD  *pdwHelpContext, BSTR  *pBstrHelpFile)
5597 {
5598     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5599     const TLBFuncDesc *pFDesc;
5600     const TLBVarDesc *pVDesc;
5601     TRACE("(%p) memid %ld Name(%p) DocString(%p)"
5602           " HelpContext(%p) HelpFile(%p)\n",
5603         This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
5604     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
5605         if(pBstrName)
5606             *pBstrName=SysAllocString(This->Name);
5607         if(pBstrDocString)
5608             *pBstrDocString=SysAllocString(This->DocString);
5609         if(pdwHelpContext)
5610             *pdwHelpContext=This->dwHelpContext;
5611         if(pBstrHelpFile)
5612             *pBstrHelpFile=SysAllocString(This->DocString);/* FIXME */
5613         return S_OK;
5614     }else {/* for a member */
5615     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
5616         if(pFDesc->funcdesc.memid==memid){
5617           if(pBstrName)
5618             *pBstrName = SysAllocString(pFDesc->Name);
5619           if(pBstrDocString)
5620             *pBstrDocString=SysAllocString(pFDesc->HelpString);
5621           if(pdwHelpContext)
5622             *pdwHelpContext=pFDesc->helpcontext;
5623           return S_OK;
5624         }
5625     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
5626         if(pVDesc->vardesc.memid==memid){
5627             if(pBstrName)
5628               *pBstrName = SysAllocString(pVDesc->Name);
5629             if(pBstrDocString)
5630               *pBstrDocString=SysAllocString(pVDesc->HelpString);
5631             if(pdwHelpContext)
5632               *pdwHelpContext=pVDesc->HelpContext;
5633             return S_OK;
5634         }
5635     }
5636
5637     if(This->TypeAttr.cImplTypes &&
5638        (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
5639         /* recursive search */
5640         ITypeInfo *pTInfo;
5641         HRESULT result;
5642         result = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef,
5643                                         &pTInfo);
5644         if(SUCCEEDED(result)) {
5645             result = ITypeInfo_GetDocumentation(pTInfo, memid, pBstrName,
5646                 pBstrDocString, pdwHelpContext, pBstrHelpFile);
5647             ITypeInfo_Release(pTInfo);
5648             return result;
5649         }
5650         WARN("Could not search inherited interface!\n");
5651     }
5652
5653     WARN("member %ld not found\n", memid);
5654     return TYPE_E_ELEMENTNOTFOUND;
5655 }
5656
5657 /*  ITypeInfo::GetDllEntry
5658  *
5659  * Retrieves a description or specification of an entry point for a function
5660  * in a DLL.
5661  */
5662 static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid,
5663         INVOKEKIND invKind, BSTR  *pBstrDllName, BSTR  *pBstrName,
5664         WORD  *pwOrdinal)
5665 {
5666     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5667     const TLBFuncDesc *pFDesc;
5668
5669     TRACE("(%p)->(memid %lx, %d, %p, %p, %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
5670
5671     if (pBstrDllName) *pBstrDllName = NULL;
5672     if (pBstrName) *pBstrName = NULL;
5673     if (pwOrdinal) *pwOrdinal = 0;
5674
5675     if (This->TypeAttr.typekind != TKIND_MODULE)
5676         return TYPE_E_BADMODULEKIND;
5677
5678     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
5679         if(pFDesc->funcdesc.memid==memid){
5680             dump_TypeInfo(This);
5681             if (TRACE_ON(ole))
5682                 dump_TLBFuncDescOne(pFDesc);
5683
5684             if (pBstrDllName)
5685                 *pBstrDllName = SysAllocString(This->DllName);
5686
5687             if (HIWORD(pFDesc->Entry) && (pFDesc->Entry != (void*)-1)) {
5688                 if (pBstrName)
5689                     *pBstrName = SysAllocString(pFDesc->Entry);
5690                 if (pwOrdinal)
5691                     *pwOrdinal = -1;
5692                 return S_OK;
5693             }
5694             if (pBstrName)
5695                 *pBstrName = NULL;
5696             if (pwOrdinal)
5697                 *pwOrdinal = (DWORD)pFDesc->Entry;
5698             return S_OK;
5699         }
5700     return TYPE_E_ELEMENTNOTFOUND;
5701 }
5702
5703 /* ITypeInfo::GetRefTypeInfo
5704  *
5705  * If a type description references other type descriptions, it retrieves
5706  * the referenced type descriptions.
5707  */
5708 static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo(
5709         ITypeInfo2 *iface,
5710         HREFTYPE hRefType,
5711         ITypeInfo  **ppTInfo)
5712 {
5713     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5714     HRESULT result = E_FAIL;
5715
5716     if ((This->hreftype != -1) && (This->hreftype == hRefType))
5717     {
5718         *ppTInfo = (ITypeInfo *)&This->lpVtbl;
5719         ITypeInfo_AddRef(*ppTInfo);
5720         result = S_OK;
5721     }
5722     else if (hRefType == -1 &&
5723         (((ITypeInfoImpl*) This)->TypeAttr.typekind   == TKIND_DISPATCH) &&
5724         (((ITypeInfoImpl*) This)->TypeAttr.wTypeFlags &  TYPEFLAG_FDUAL))
5725     {
5726           /* when we meet a DUAL dispinterface, we must create the interface
5727           * version of it.
5728           */
5729           ITypeInfoImpl* pTypeInfoImpl = (ITypeInfoImpl*) ITypeInfo_Constructor();
5730
5731
5732           /* the interface version contains the same information as the dispinterface
5733            * copy the contents of the structs.
5734            */
5735           *pTypeInfoImpl = *This;
5736           pTypeInfoImpl->ref = 1;
5737
5738           /* change the type to interface */
5739           pTypeInfoImpl->TypeAttr.typekind = TKIND_INTERFACE;
5740
5741           *ppTInfo = (ITypeInfo*) pTypeInfoImpl;
5742
5743           ITypeInfo_AddRef((ITypeInfo*) pTypeInfoImpl);
5744
5745           result = S_OK;
5746
5747     } else {
5748         TLBRefType *pRefType;
5749         for(pRefType = This->reflist; pRefType; pRefType = pRefType->next) {
5750             if(pRefType->reference == hRefType)
5751                 break;
5752         }
5753         if(!pRefType)
5754           FIXME("Can't find pRefType for ref %lx\n", hRefType);
5755         if(pRefType && hRefType != -1) {
5756             ITypeLib *pTLib = NULL;
5757
5758             if(pRefType->pImpTLInfo == TLB_REF_INTERNAL) {
5759                 UINT Index;
5760                 result = ITypeInfo_GetContainingTypeLib(iface, &pTLib, &Index);
5761             } else {
5762                 if(pRefType->pImpTLInfo->pImpTypeLib) {
5763                     TRACE("typeinfo in imported typelib that is already loaded\n");
5764                     pTLib = (ITypeLib*)pRefType->pImpTLInfo->pImpTypeLib;
5765                     ITypeLib2_AddRef((ITypeLib*) pTLib);
5766                     result = S_OK;
5767                 } else {
5768                     TRACE("typeinfo in imported typelib that isn't already loaded\n");
5769                     result = LoadRegTypeLib( &pRefType->pImpTLInfo->guid,
5770                                              pRefType->pImpTLInfo->wVersionMajor,
5771                                              pRefType->pImpTLInfo->wVersionMinor,
5772                                              pRefType->pImpTLInfo->lcid,
5773                                              &pTLib);
5774
5775                     if(!SUCCEEDED(result)) {
5776                         BSTR libnam=SysAllocString(pRefType->pImpTLInfo->name);
5777                         result=LoadTypeLib(libnam, &pTLib);
5778                         SysFreeString(libnam);
5779                     }
5780                     if(SUCCEEDED(result)) {
5781                         pRefType->pImpTLInfo->pImpTypeLib = (ITypeLibImpl*)pTLib;
5782                         ITypeLib2_AddRef(pTLib);
5783                     }
5784                 }
5785             }
5786             if(SUCCEEDED(result)) {
5787                 if(pRefType->index == TLB_REF_USE_GUID)
5788                     result = ITypeLib2_GetTypeInfoOfGuid(pTLib,
5789                                                          &pRefType->guid,
5790                                                          ppTInfo);
5791                 else
5792                     result = ITypeLib2_GetTypeInfo(pTLib, pRefType->index,
5793                                                    ppTInfo);
5794             }
5795             if (pTLib != NULL)
5796                 ITypeLib2_Release(pTLib);
5797         }
5798     }
5799
5800     TRACE("(%p) hreftype 0x%04lx loaded %s (%p)\n", This, hRefType,
5801           SUCCEEDED(result)? "SUCCESS":"FAILURE", *ppTInfo);
5802     return result;
5803 }
5804
5805 /* ITypeInfo::AddressOfMember
5806  *
5807  * Retrieves the addresses of static functions or variables, such as those
5808  * defined in a DLL.
5809  */
5810 static HRESULT WINAPI ITypeInfo_fnAddressOfMember( ITypeInfo2 *iface,
5811         MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
5812 {
5813     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5814     HRESULT hr;
5815     BSTR dll, entry;
5816     WORD ordinal;
5817     HMODULE module;
5818
5819     TRACE("(%p)->(0x%lx, 0x%x, %p)\n", This, memid, invKind, ppv);
5820
5821     hr = ITypeInfo_GetDllEntry(iface, memid, invKind, &dll, &entry, &ordinal);
5822     if (FAILED(hr))
5823         return hr;
5824
5825     module = LoadLibraryW(dll);
5826     if (!module)
5827     {
5828         ERR("couldn't load %s\n", debugstr_w(dll));
5829         SysFreeString(dll);
5830         if (entry) SysFreeString(entry);
5831         return STG_E_FILENOTFOUND;
5832     }
5833     /* FIXME: store library somewhere where we can free it */
5834
5835     if (entry)
5836     {
5837         LPSTR entryA;
5838         INT len = WideCharToMultiByte(CP_ACP, 0, entry, -1, NULL, 0, NULL, NULL);
5839         entryA = HeapAlloc(GetProcessHeap(), 0, len);
5840         WideCharToMultiByte(CP_ACP, 0, entry, -1, entryA, len, NULL, NULL);
5841
5842         *ppv = GetProcAddress(module, entryA);
5843         if (!*ppv)
5844             ERR("function not found %s\n", debugstr_a(entryA));
5845
5846         HeapFree(GetProcessHeap(), 0, entryA);
5847     }
5848     else
5849     {
5850         *ppv = GetProcAddress(module, MAKEINTRESOURCEA(ordinal));
5851         if (!*ppv)
5852             ERR("function not found %d\n", ordinal);
5853     }
5854
5855     SysFreeString(dll);
5856     if (entry) SysFreeString(entry);
5857
5858     if (!*ppv)
5859         return TYPE_E_DLLFUNCTIONNOTFOUND;
5860
5861     return S_OK;
5862 }
5863
5864 /* ITypeInfo::CreateInstance
5865  *
5866  * Creates a new instance of a type that describes a component object class
5867  * (coclass).
5868  */
5869 static HRESULT WINAPI ITypeInfo_fnCreateInstance( ITypeInfo2 *iface,
5870         IUnknown *pUnk, REFIID riid, VOID  **ppvObj)
5871 {
5872     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5873     FIXME("(%p) stub!\n", This);
5874     return S_OK;
5875 }
5876
5877 /* ITypeInfo::GetMops
5878  *
5879  * Retrieves marshalling information.
5880  */
5881 static HRESULT WINAPI ITypeInfo_fnGetMops( ITypeInfo2 *iface, MEMBERID memid,
5882                                 BSTR  *pBstrMops)
5883 {
5884     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5885     FIXME("(%p) stub!\n", This);
5886     return S_OK;
5887 }
5888
5889 /* ITypeInfo::GetContainingTypeLib
5890  *
5891  * Retrieves the containing type library and the index of the type description
5892  * within that type library.
5893  */
5894 static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( ITypeInfo2 *iface,
5895         ITypeLib  * *ppTLib, UINT  *pIndex)
5896 {
5897     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5898     
5899     /* If a pointer is null, we simply ignore it, the ATL in particular passes pIndex as 0 */
5900     if (pIndex) {
5901       *pIndex=This->index;
5902       TRACE("returning pIndex=%d\n", *pIndex);
5903     }
5904     
5905     if (ppTLib) {
5906       *ppTLib=(LPTYPELIB )(This->pTypeLib);
5907       ITypeLib2_AddRef(*ppTLib);
5908       TRACE("returning ppTLib=%p\n", *ppTLib);
5909     }
5910     
5911     return S_OK;
5912 }
5913
5914 /* ITypeInfo::ReleaseTypeAttr
5915  *
5916  * Releases a TYPEATTR previously returned by GetTypeAttr.
5917  *
5918  */
5919 static void WINAPI ITypeInfo_fnReleaseTypeAttr( ITypeInfo2 *iface,
5920         TYPEATTR* pTypeAttr)
5921 {
5922     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5923     TRACE("(%p)->(%p)\n", This, pTypeAttr);
5924     HeapFree(GetProcessHeap(), 0, pTypeAttr);
5925 }
5926
5927 /* ITypeInfo::ReleaseFuncDesc
5928  *
5929  * Releases a FUNCDESC previously returned by GetFuncDesc. *
5930  */
5931 static void WINAPI ITypeInfo_fnReleaseFuncDesc(
5932         ITypeInfo2 *iface,
5933         FUNCDESC *pFuncDesc)
5934 {
5935     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5936     SHORT i;
5937
5938     TRACE("(%p)->(%p)\n", This, pFuncDesc);
5939
5940     for (i = 0; i < pFuncDesc->cParams; i++)
5941         TLB_FreeElemDesc(&pFuncDesc->lprgelemdescParam[i]);
5942     TLB_FreeElemDesc(&pFuncDesc->elemdescFunc);
5943
5944     SysFreeString((BSTR)pFuncDesc);
5945 }
5946
5947 /* ITypeInfo::ReleaseVarDesc
5948  *
5949  * Releases a VARDESC previously returned by GetVarDesc.
5950  */
5951 static void WINAPI ITypeInfo_fnReleaseVarDesc( ITypeInfo2 *iface,
5952         VARDESC *pVarDesc)
5953 {
5954     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5955     TRACE("(%p)->(%p)\n", This, pVarDesc);
5956
5957     TLB_FreeElemDesc(&pVarDesc->elemdescVar);
5958     if (pVarDesc->varkind == VAR_CONST)
5959         VariantClear(pVarDesc->u.lpvarValue);
5960     SysFreeString((BSTR)pVarDesc);
5961 }
5962
5963 /* ITypeInfo2::GetTypeKind
5964  *
5965  * Returns the TYPEKIND enumeration quickly, without doing any allocations.
5966  *
5967  */
5968 static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo2 * iface,
5969     TYPEKIND *pTypeKind)
5970 {
5971     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5972     *pTypeKind=This->TypeAttr.typekind;
5973     TRACE("(%p) type 0x%0x\n", This,*pTypeKind);
5974     return S_OK;
5975 }
5976
5977 /* ITypeInfo2::GetTypeFlags
5978  *
5979  * Returns the type flags without any allocations. This returns a DWORD type
5980  * flag, which expands the type flags without growing the TYPEATTR (type
5981  * attribute).
5982  *
5983  */
5984 static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo2 *iface, ULONG *pTypeFlags)
5985 {
5986     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5987     *pTypeFlags=This->TypeAttr.wTypeFlags;
5988     TRACE("(%p) flags 0x%lx\n", This,*pTypeFlags);
5989     return S_OK;
5990 }
5991
5992 /* ITypeInfo2::GetFuncIndexOfMemId
5993  * Binds to a specific member based on a known DISPID, where the member name
5994  * is not known (for example, when binding to a default member).
5995  *
5996  */
5997 static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo2 * iface,
5998     MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex)
5999 {
6000     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6001     const TLBFuncDesc *pFuncInfo;
6002     int i;
6003     HRESULT result;
6004
6005     for(i = 0, pFuncInfo = This->funclist; pFuncInfo; i++, pFuncInfo=pFuncInfo->next)
6006         if(memid == pFuncInfo->funcdesc.memid && (invKind & pFuncInfo->funcdesc.invkind))
6007             break;
6008     if(pFuncInfo) {
6009         *pFuncIndex = i;
6010         result = S_OK;
6011     } else
6012         result = TYPE_E_ELEMENTNOTFOUND;
6013
6014     TRACE("(%p) memid 0x%08lx invKind 0x%04x -> %s\n", This,
6015           memid, invKind, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
6016     return result;
6017 }
6018
6019 /* TypeInfo2::GetVarIndexOfMemId
6020  *
6021  * Binds to a specific member based on a known DISPID, where the member name
6022  * is not known (for example, when binding to a default member).
6023  *
6024  */
6025 static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( ITypeInfo2 * iface,
6026     MEMBERID memid, UINT *pVarIndex)
6027 {
6028     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6029     TLBVarDesc *pVarInfo;
6030     int i;
6031     HRESULT result;
6032     for(i=0, pVarInfo=This->varlist; pVarInfo &&
6033             memid != pVarInfo->vardesc.memid; i++, pVarInfo=pVarInfo->next)
6034         ;
6035     if(pVarInfo) {
6036         *pVarIndex = i;
6037         result = S_OK;
6038     } else
6039         result = TYPE_E_ELEMENTNOTFOUND;
6040
6041     TRACE("(%p) memid 0x%08lx -> %s\n", This,
6042           memid, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
6043     return result;
6044 }
6045
6046 /* ITypeInfo2::GetCustData
6047  *
6048  * Gets the custom data
6049  */
6050 static HRESULT WINAPI ITypeInfo2_fnGetCustData(
6051         ITypeInfo2 * iface,
6052         REFGUID guid,
6053         VARIANT *pVarVal)
6054 {
6055     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6056     TLBCustData *pCData;
6057
6058     for(pCData=This->pCustData; pCData; pCData = pCData->next)
6059         if( IsEqualIID(guid, &pCData->guid)) break;
6060
6061     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
6062
6063     if(pCData)
6064     {
6065         VariantInit( pVarVal);
6066         VariantCopy( pVarVal, &pCData->data);
6067         return S_OK;
6068     }
6069     return E_INVALIDARG;  /* FIXME: correct? */
6070 }
6071
6072 /* ITypeInfo2::GetFuncCustData
6073  *
6074  * Gets the custom data
6075  */
6076 static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData(
6077         ITypeInfo2 * iface,
6078         UINT index,
6079         REFGUID guid,
6080         VARIANT *pVarVal)
6081 {
6082     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6083     TLBCustData *pCData=NULL;
6084     TLBFuncDesc * pFDesc;
6085     int i;
6086     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
6087             pFDesc=pFDesc->next);
6088
6089     if(pFDesc)
6090         for(pCData=pFDesc->pCustData; pCData; pCData = pCData->next)
6091             if( IsEqualIID(guid, &pCData->guid)) break;
6092
6093     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
6094
6095     if(pCData){
6096         VariantInit( pVarVal);
6097         VariantCopy( pVarVal, &pCData->data);
6098         return S_OK;
6099     }
6100     return E_INVALIDARG;  /* FIXME: correct? */
6101 }
6102
6103 /* ITypeInfo2::GetParamCustData
6104  *
6105  * Gets the custom data
6106  */
6107 static HRESULT WINAPI ITypeInfo2_fnGetParamCustData(
6108         ITypeInfo2 * iface,
6109         UINT indexFunc,
6110         UINT indexParam,
6111         REFGUID guid,
6112         VARIANT *pVarVal)
6113 {
6114     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6115     TLBCustData *pCData=NULL;
6116     TLBFuncDesc * pFDesc;
6117     int i;
6118
6119     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,pFDesc=pFDesc->next);
6120
6121     if(pFDesc && indexParam >=0 && indexParam<pFDesc->funcdesc.cParams)
6122         for(pCData=pFDesc->pParamDesc[indexParam].pCustData; pCData;
6123                 pCData = pCData->next)
6124             if( IsEqualIID(guid, &pCData->guid)) break;
6125
6126     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
6127
6128     if(pCData)
6129     {
6130         VariantInit( pVarVal);
6131         VariantCopy( pVarVal, &pCData->data);
6132         return S_OK;
6133     }
6134     return E_INVALIDARG;  /* FIXME: correct? */
6135 }
6136
6137 /* ITypeInfo2::GetVarCustData
6138  *
6139  * Gets the custom data
6140  */
6141 static HRESULT WINAPI ITypeInfo2_fnGetVarCustData(
6142         ITypeInfo2 * iface,
6143         UINT index,
6144         REFGUID guid,
6145         VARIANT *pVarVal)
6146 {
6147     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6148     TLBCustData *pCData=NULL;
6149     TLBVarDesc * pVDesc;
6150     int i;
6151
6152     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next);
6153
6154     if(pVDesc)
6155     {
6156       for(pCData=pVDesc->pCustData; pCData; pCData = pCData->next)
6157       {
6158         if( IsEqualIID(guid, &pCData->guid)) break;
6159       }
6160     }
6161
6162     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
6163
6164     if(pCData)
6165     {
6166         VariantInit( pVarVal);
6167         VariantCopy( pVarVal, &pCData->data);
6168         return S_OK;
6169     }
6170     return E_INVALIDARG;  /* FIXME: correct? */
6171 }
6172
6173 /* ITypeInfo2::GetImplCustData
6174  *
6175  * Gets the custom data
6176  */
6177 static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData(
6178         ITypeInfo2 * iface,
6179         UINT index,
6180         REFGUID guid,
6181         VARIANT *pVarVal)
6182 {
6183     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6184     TLBCustData *pCData=NULL;
6185     TLBImplType * pRDesc;
6186     int i;
6187
6188     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++, pRDesc=pRDesc->next);
6189
6190     if(pRDesc)
6191     {
6192       for(pCData=pRDesc->pCustData; pCData; pCData = pCData->next)
6193       {
6194         if( IsEqualIID(guid, &pCData->guid)) break;
6195       }
6196     }
6197
6198     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
6199
6200     if(pCData)
6201     {
6202         VariantInit( pVarVal);
6203         VariantCopy( pVarVal, &pCData->data);
6204         return S_OK;
6205     }
6206     return E_INVALIDARG;  /* FIXME: correct? */
6207 }
6208
6209 /* ITypeInfo2::GetDocumentation2
6210  *
6211  * Retrieves the documentation string, the complete Help file name and path,
6212  * the localization context to use, and the context ID for the library Help
6213  * topic in the Help file.
6214  *
6215  */
6216 static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2(
6217         ITypeInfo2 * iface,
6218         MEMBERID memid,
6219         LCID lcid,
6220         BSTR *pbstrHelpString,
6221         DWORD *pdwHelpStringContext,
6222         BSTR *pbstrHelpStringDll)
6223 {
6224     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6225     const TLBFuncDesc *pFDesc;
6226     const TLBVarDesc *pVDesc;
6227     TRACE("(%p) memid %ld lcid(0x%lx)  HelpString(%p) "
6228           "HelpStringContext(%p) HelpStringDll(%p)\n",
6229           This, memid, lcid, pbstrHelpString, pdwHelpStringContext,
6230           pbstrHelpStringDll );
6231     /* the help string should be obtained from the helpstringdll,
6232      * using the _DLLGetDocumentation function, based on the supplied
6233      * lcid. Nice to do sometime...
6234      */
6235     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
6236         if(pbstrHelpString)
6237             *pbstrHelpString=SysAllocString(This->Name);
6238         if(pdwHelpStringContext)
6239             *pdwHelpStringContext=This->dwHelpStringContext;
6240         if(pbstrHelpStringDll)
6241             *pbstrHelpStringDll=
6242                 SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
6243         return S_OK;
6244     }else {/* for a member */
6245     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
6246         if(pFDesc->funcdesc.memid==memid){
6247              if(pbstrHelpString)
6248                 *pbstrHelpString=SysAllocString(pFDesc->HelpString);
6249             if(pdwHelpStringContext)
6250                 *pdwHelpStringContext=pFDesc->HelpStringContext;
6251             if(pbstrHelpStringDll)
6252                 *pbstrHelpStringDll=
6253                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
6254         return S_OK;
6255     }
6256     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
6257         if(pVDesc->vardesc.memid==memid){
6258              if(pbstrHelpString)
6259                 *pbstrHelpString=SysAllocString(pVDesc->HelpString);
6260             if(pdwHelpStringContext)
6261                 *pdwHelpStringContext=pVDesc->HelpStringContext;
6262             if(pbstrHelpStringDll)
6263                 *pbstrHelpStringDll=
6264                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
6265             return S_OK;
6266         }
6267     }
6268     return TYPE_E_ELEMENTNOTFOUND;
6269 }
6270
6271 /* ITypeInfo2::GetAllCustData
6272  *
6273  * Gets all custom data items for the Type info.
6274  *
6275  */
6276 static HRESULT WINAPI ITypeInfo2_fnGetAllCustData(
6277         ITypeInfo2 * iface,
6278         CUSTDATA *pCustData)
6279 {
6280     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6281     TLBCustData *pCData;
6282     int i;
6283
6284     TRACE("(%p) returning %d items\n", This, This->ctCustData);
6285
6286     pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
6287     if(pCustData->prgCustData ){
6288         pCustData->cCustData=This->ctCustData;
6289         for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
6290             pCustData->prgCustData[i].guid=pCData->guid;
6291             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
6292         }
6293     }else{
6294         ERR(" OUT OF MEMORY!\n");
6295         return E_OUTOFMEMORY;
6296     }
6297     return S_OK;
6298 }
6299
6300 /* ITypeInfo2::GetAllFuncCustData
6301  *
6302  * Gets all custom data items for the specified Function
6303  *
6304  */
6305 static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData(
6306         ITypeInfo2 * iface,
6307         UINT index,
6308         CUSTDATA *pCustData)
6309 {
6310     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6311     TLBCustData *pCData;
6312     TLBFuncDesc * pFDesc;
6313     int i;
6314     TRACE("(%p) index %d\n", This, index);
6315     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
6316             pFDesc=pFDesc->next)
6317         ;
6318     if(pFDesc){
6319         pCustData->prgCustData =
6320             TLB_Alloc(pFDesc->ctCustData * sizeof(CUSTDATAITEM));
6321         if(pCustData->prgCustData ){
6322             pCustData->cCustData=pFDesc->ctCustData;
6323             for(i=0, pCData=pFDesc->pCustData; pCData; i++,
6324                     pCData = pCData->next){
6325                 pCustData->prgCustData[i].guid=pCData->guid;
6326                 VariantCopy(& pCustData->prgCustData[i].varValue,
6327                         & pCData->data);
6328             }
6329         }else{
6330             ERR(" OUT OF MEMORY!\n");
6331             return E_OUTOFMEMORY;
6332         }
6333         return S_OK;
6334     }
6335     return TYPE_E_ELEMENTNOTFOUND;
6336 }
6337
6338 /* ITypeInfo2::GetAllParamCustData
6339  *
6340  * Gets all custom data items for the Functions
6341  *
6342  */
6343 static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo2 * iface,
6344     UINT indexFunc, UINT indexParam, CUSTDATA *pCustData)
6345 {
6346     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6347     TLBCustData *pCData=NULL;
6348     TLBFuncDesc * pFDesc;
6349     int i;
6350     TRACE("(%p) index %d\n", This, indexFunc);
6351     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,
6352             pFDesc=pFDesc->next)
6353         ;
6354     if(pFDesc && indexParam >=0 && indexParam<pFDesc->funcdesc.cParams){
6355         pCustData->prgCustData =
6356             TLB_Alloc(pFDesc->pParamDesc[indexParam].ctCustData *
6357                     sizeof(CUSTDATAITEM));
6358         if(pCustData->prgCustData ){
6359             pCustData->cCustData=pFDesc->pParamDesc[indexParam].ctCustData;
6360             for(i=0, pCData=pFDesc->pParamDesc[indexParam].pCustData;
6361                     pCData; i++, pCData = pCData->next){
6362                 pCustData->prgCustData[i].guid=pCData->guid;
6363                 VariantCopy(& pCustData->prgCustData[i].varValue,
6364                         & pCData->data);
6365             }
6366         }else{
6367             ERR(" OUT OF MEMORY!\n");
6368             return E_OUTOFMEMORY;
6369         }
6370         return S_OK;
6371     }
6372     return TYPE_E_ELEMENTNOTFOUND;
6373 }
6374
6375 /* ITypeInfo2::GetAllVarCustData
6376  *
6377  * Gets all custom data items for the specified Variable
6378  *
6379  */
6380 static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo2 * iface,
6381     UINT index, CUSTDATA *pCustData)
6382 {
6383     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6384     TLBCustData *pCData;
6385     TLBVarDesc * pVDesc;
6386     int i;
6387     TRACE("(%p) index %d\n", This, index);
6388     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++,
6389             pVDesc=pVDesc->next)
6390         ;
6391     if(pVDesc){
6392         pCustData->prgCustData =
6393             TLB_Alloc(pVDesc->ctCustData * sizeof(CUSTDATAITEM));
6394         if(pCustData->prgCustData ){
6395             pCustData->cCustData=pVDesc->ctCustData;
6396             for(i=0, pCData=pVDesc->pCustData; pCData; i++,
6397                     pCData = pCData->next){
6398                 pCustData->prgCustData[i].guid=pCData->guid;
6399                 VariantCopy(& pCustData->prgCustData[i].varValue,
6400                         & pCData->data);
6401             }
6402         }else{
6403             ERR(" OUT OF MEMORY!\n");
6404             return E_OUTOFMEMORY;
6405         }
6406         return S_OK;
6407     }
6408     return TYPE_E_ELEMENTNOTFOUND;
6409 }
6410
6411 /* ITypeInfo2::GetAllImplCustData
6412  *
6413  * Gets all custom data items for the specified implementation type
6414  *
6415  */
6416 static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData(
6417         ITypeInfo2 * iface,
6418         UINT index,
6419         CUSTDATA *pCustData)
6420 {
6421     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6422     TLBCustData *pCData;
6423     TLBImplType * pRDesc;
6424     int i;
6425     TRACE("(%p) index %d\n", This, index);
6426     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++,
6427             pRDesc=pRDesc->next)
6428         ;
6429     if(pRDesc){
6430         pCustData->prgCustData =
6431             TLB_Alloc(pRDesc->ctCustData * sizeof(CUSTDATAITEM));
6432         if(pCustData->prgCustData ){
6433             pCustData->cCustData=pRDesc->ctCustData;
6434             for(i=0, pCData=pRDesc->pCustData; pCData; i++,
6435                     pCData = pCData->next){
6436                 pCustData->prgCustData[i].guid=pCData->guid;
6437                 VariantCopy(& pCustData->prgCustData[i].varValue,
6438                         & pCData->data);
6439             }
6440         }else{
6441             ERR(" OUT OF MEMORY!\n");
6442             return E_OUTOFMEMORY;
6443         }
6444         return S_OK;
6445     }
6446     return TYPE_E_ELEMENTNOTFOUND;
6447 }
6448
6449 static const ITypeInfo2Vtbl tinfvt =
6450 {
6451
6452     ITypeInfo_fnQueryInterface,
6453     ITypeInfo_fnAddRef,
6454     ITypeInfo_fnRelease,
6455
6456     ITypeInfo_fnGetTypeAttr,
6457     ITypeInfo_fnGetTypeComp,
6458     ITypeInfo_fnGetFuncDesc,
6459     ITypeInfo_fnGetVarDesc,
6460     ITypeInfo_fnGetNames,
6461     ITypeInfo_fnGetRefTypeOfImplType,
6462     ITypeInfo_fnGetImplTypeFlags,
6463     ITypeInfo_fnGetIDsOfNames,
6464     ITypeInfo_fnInvoke,
6465     ITypeInfo_fnGetDocumentation,
6466     ITypeInfo_fnGetDllEntry,
6467     ITypeInfo_fnGetRefTypeInfo,
6468     ITypeInfo_fnAddressOfMember,
6469     ITypeInfo_fnCreateInstance,
6470     ITypeInfo_fnGetMops,
6471     ITypeInfo_fnGetContainingTypeLib,
6472     ITypeInfo_fnReleaseTypeAttr,
6473     ITypeInfo_fnReleaseFuncDesc,
6474     ITypeInfo_fnReleaseVarDesc,
6475
6476     ITypeInfo2_fnGetTypeKind,
6477     ITypeInfo2_fnGetTypeFlags,
6478     ITypeInfo2_fnGetFuncIndexOfMemId,
6479     ITypeInfo2_fnGetVarIndexOfMemId,
6480     ITypeInfo2_fnGetCustData,
6481     ITypeInfo2_fnGetFuncCustData,
6482     ITypeInfo2_fnGetParamCustData,
6483     ITypeInfo2_fnGetVarCustData,
6484     ITypeInfo2_fnGetImplTypeCustData,
6485     ITypeInfo2_fnGetDocumentation2,
6486     ITypeInfo2_fnGetAllCustData,
6487     ITypeInfo2_fnGetAllFuncCustData,
6488     ITypeInfo2_fnGetAllParamCustData,
6489     ITypeInfo2_fnGetAllVarCustData,
6490     ITypeInfo2_fnGetAllImplTypeCustData,
6491 };
6492
6493 /******************************************************************************
6494  * CreateDispTypeInfo [OLEAUT32.31]
6495  *
6496  * Build type information for an object so it can be called through an
6497  * IDispatch interface.
6498  *
6499  * RETURNS
6500  *  Success: S_OK. pptinfo contains the created ITypeInfo object.
6501  *  Failure: E_INVALIDARG, if one or more arguments is invalid.
6502  *
6503  * NOTES
6504  *  This call allows an objects methods to be accessed through IDispatch, by
6505  *  building an ITypeInfo object that IDispatch can use to call through.
6506  */
6507 HRESULT WINAPI CreateDispTypeInfo(
6508         INTERFACEDATA *pidata, /* [I] Description of the interface to build type info for */
6509         LCID lcid, /* [I] Locale Id */
6510         ITypeInfo **pptinfo) /* [O] Destination for created ITypeInfo object */
6511 {
6512     ITypeInfoImpl *pTIClass, *pTIIface;
6513     ITypeLibImpl *pTypeLibImpl;
6514     int param, func;
6515     TLBFuncDesc **ppFuncDesc;
6516
6517     TRACE("\n");
6518     pTypeLibImpl = TypeLibImpl_Constructor();
6519     if (!pTypeLibImpl) return E_FAIL;
6520
6521     pTIIface = (ITypeInfoImpl*)ITypeInfo_Constructor();
6522     pTIIface->pTypeLib = pTypeLibImpl;
6523     pTIIface->index = 0;
6524     pTIIface->Name = NULL;
6525     pTIIface->dwHelpContext = -1;
6526     memset(&pTIIface->TypeAttr.guid, 0, sizeof(GUID));
6527     pTIIface->TypeAttr.lcid = lcid;
6528     pTIIface->TypeAttr.typekind = TKIND_INTERFACE;
6529     pTIIface->TypeAttr.wMajorVerNum = 0;
6530     pTIIface->TypeAttr.wMinorVerNum = 0;
6531     pTIIface->TypeAttr.cbAlignment = 2;
6532     pTIIface->TypeAttr.cbSizeInstance = -1;
6533     pTIIface->TypeAttr.cbSizeVft = -1;
6534     pTIIface->TypeAttr.cFuncs = 0;
6535     pTIIface->TypeAttr.cImplTypes = 0;
6536     pTIIface->TypeAttr.cVars = 0;
6537     pTIIface->TypeAttr.wTypeFlags = 0;
6538
6539     ppFuncDesc = &pTIIface->funclist;
6540     for(func = 0; func < pidata->cMembers; func++) {
6541         METHODDATA *md = pidata->pmethdata + func;
6542         *ppFuncDesc = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppFuncDesc));
6543         (*ppFuncDesc)->Name = SysAllocString(md->szName);
6544         (*ppFuncDesc)->funcdesc.memid = md->dispid;
6545         (*ppFuncDesc)->funcdesc.funckind = FUNC_VIRTUAL;
6546         (*ppFuncDesc)->funcdesc.invkind = md->wFlags;
6547         (*ppFuncDesc)->funcdesc.callconv = md->cc;
6548         (*ppFuncDesc)->funcdesc.cParams = md->cArgs;
6549         (*ppFuncDesc)->funcdesc.cParamsOpt = 0;
6550         (*ppFuncDesc)->funcdesc.oVft = md->iMeth << 2;
6551         (*ppFuncDesc)->funcdesc.wFuncFlags = 0;
6552         (*ppFuncDesc)->funcdesc.elemdescFunc.tdesc.vt = md->vtReturn;
6553         (*ppFuncDesc)->funcdesc.elemdescFunc.u.paramdesc.wParamFlags = PARAMFLAG_NONE;
6554         (*ppFuncDesc)->funcdesc.elemdescFunc.u.paramdesc.pparamdescex = NULL;
6555         (*ppFuncDesc)->funcdesc.lprgelemdescParam = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6556                                                               md->cArgs * sizeof(ELEMDESC));
6557         (*ppFuncDesc)->pParamDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6558                                               md->cArgs * sizeof(TLBParDesc));
6559         for(param = 0; param < md->cArgs; param++) {
6560             (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].tdesc.vt = md->ppdata[param].vt;
6561             (*ppFuncDesc)->pParamDesc[param].Name = SysAllocString(md->ppdata[param].szName);
6562         }
6563         (*ppFuncDesc)->helpcontext = 0;
6564         (*ppFuncDesc)->HelpStringContext = 0;
6565         (*ppFuncDesc)->HelpString = NULL;
6566         (*ppFuncDesc)->Entry = NULL;
6567         (*ppFuncDesc)->ctCustData = 0;
6568         (*ppFuncDesc)->pCustData = NULL;
6569         (*ppFuncDesc)->next = NULL;
6570         ppFuncDesc = &(*ppFuncDesc)->next;
6571     }
6572
6573     dump_TypeInfo(pTIIface);
6574
6575     pTypeLibImpl->pTypeInfo = pTIIface;
6576     pTypeLibImpl->TypeInfoCount++;
6577
6578     pTIClass = (ITypeInfoImpl*)ITypeInfo_Constructor();
6579     pTIClass->pTypeLib = pTypeLibImpl;
6580     pTIClass->index = 1;
6581     pTIClass->Name = NULL;
6582     pTIClass->dwHelpContext = -1;
6583     memset(&pTIClass->TypeAttr.guid, 0, sizeof(GUID));
6584     pTIClass->TypeAttr.lcid = lcid;
6585     pTIClass->TypeAttr.typekind = TKIND_COCLASS;
6586     pTIClass->TypeAttr.wMajorVerNum = 0;
6587     pTIClass->TypeAttr.wMinorVerNum = 0;
6588     pTIClass->TypeAttr.cbAlignment = 2;
6589     pTIClass->TypeAttr.cbSizeInstance = -1;
6590     pTIClass->TypeAttr.cbSizeVft = -1;
6591     pTIClass->TypeAttr.cFuncs = 0;
6592     pTIClass->TypeAttr.cImplTypes = 1;
6593     pTIClass->TypeAttr.cVars = 0;
6594     pTIClass->TypeAttr.wTypeFlags = 0;
6595
6596     pTIClass->impltypelist = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pTIClass->impltypelist));
6597     pTIClass->impltypelist->hRef = 1;
6598
6599     pTIClass->reflist = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pTIClass->reflist));
6600     pTIClass->reflist->index = 0;
6601     pTIClass->reflist->reference = 1;
6602     pTIClass->reflist->pImpTLInfo = TLB_REF_INTERNAL;
6603
6604     dump_TypeInfo(pTIClass);
6605
6606     pTIIface->next = pTIClass;
6607     pTypeLibImpl->TypeInfoCount++;
6608
6609     *pptinfo = (ITypeInfo*)pTIClass;
6610     return S_OK;
6611
6612 }
6613
6614 static HRESULT WINAPI ITypeComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
6615 {
6616     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
6617
6618     return ITypeInfo_QueryInterface((ITypeInfo *)This, riid, ppv);
6619 }
6620
6621 static ULONG WINAPI ITypeComp_fnAddRef(ITypeComp * iface)
6622 {
6623     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
6624
6625     return ITypeInfo_AddRef((ITypeInfo *)This);
6626 }
6627
6628 static ULONG WINAPI ITypeComp_fnRelease(ITypeComp * iface)
6629 {
6630     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
6631
6632     return ITypeInfo_Release((ITypeInfo *)This);
6633 }
6634
6635 static HRESULT WINAPI ITypeComp_fnBind(
6636     ITypeComp * iface,
6637     OLECHAR * szName,
6638     ULONG lHash,
6639     WORD wFlags,
6640     ITypeInfo ** ppTInfo,
6641     DESCKIND * pDescKind,
6642     BINDPTR * pBindPtr)
6643 {
6644     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
6645     const TLBFuncDesc *pFDesc;
6646     const TLBVarDesc *pVDesc;
6647     HRESULT hr = DISP_E_MEMBERNOTFOUND;
6648
6649     TRACE("(%s, %lx, 0x%x, %p, %p, %p)\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
6650
6651     *pDescKind = DESCKIND_NONE;
6652     pBindPtr->lpfuncdesc = NULL;
6653     *ppTInfo = NULL;
6654
6655     for(pFDesc = This->funclist; pFDesc; pFDesc = pFDesc->next)
6656         if (!strcmpiW(pFDesc->Name, szName)) {
6657             if (!wFlags || (pFDesc->funcdesc.invkind & wFlags))
6658                 break;
6659             else
6660                 /* name found, but wrong flags */
6661                 hr = TYPE_E_TYPEMISMATCH;
6662         }
6663
6664     if (pFDesc)
6665     {
6666         HRESULT hr = TLB_AllocAndInitFuncDesc(
6667             &pFDesc->funcdesc,
6668             &pBindPtr->lpfuncdesc,
6669             This->TypeAttr.typekind == TKIND_DISPATCH);
6670         if (FAILED(hr))
6671             return hr;
6672         *pDescKind = DESCKIND_FUNCDESC;
6673         *ppTInfo = (ITypeInfo *)&This->lpVtbl;
6674         ITypeInfo_AddRef(*ppTInfo);
6675         return S_OK;
6676     } else {
6677         for(pVDesc = This->varlist; pVDesc; pVDesc = pVDesc->next) {
6678             if (!strcmpiW(pVDesc->Name, szName)) {
6679                 HRESULT hr = TLB_AllocAndInitVarDesc(&pVDesc->vardesc, &pBindPtr->lpvardesc);
6680                 if (FAILED(hr))
6681                     return hr;
6682                 *pDescKind = DESCKIND_VARDESC;
6683                 *ppTInfo = (ITypeInfo *)&This->lpVtbl;
6684                 ITypeInfo_AddRef(*ppTInfo);
6685                 return S_OK;
6686             }
6687         }
6688     }
6689     /* FIXME: search each inherited interface, not just the first */
6690     if (hr == DISP_E_MEMBERNOTFOUND && This->TypeAttr.cImplTypes) {
6691         /* recursive search */
6692         ITypeInfo *pTInfo;
6693         ITypeComp *pTComp;
6694         HRESULT hr;
6695         hr=ITypeInfo_GetRefTypeInfo((ITypeInfo *)&This->lpVtbl, This->impltypelist->hRef, &pTInfo);
6696         if (SUCCEEDED(hr))
6697         {
6698             hr = ITypeInfo_GetTypeComp(pTInfo,&pTComp);
6699             ITypeInfo_Release(pTInfo);
6700         }
6701         if (SUCCEEDED(hr))
6702         {
6703             hr = ITypeComp_Bind(pTComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
6704             ITypeComp_Release(pTComp);
6705             return hr;
6706         }
6707         WARN("Could not search inherited interface!\n");
6708     }
6709     WARN("did not find member with name %s, flags 0x%x!\n", debugstr_w(szName), wFlags);
6710     return hr;
6711 }
6712
6713 static HRESULT WINAPI ITypeComp_fnBindType(
6714     ITypeComp * iface,
6715     OLECHAR * szName,
6716     ULONG lHash,
6717     ITypeInfo ** ppTInfo,
6718     ITypeComp ** ppTComp)
6719 {
6720     TRACE("(%s, %lx, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
6721
6722     /* strange behaviour (does nothing) but like the
6723      * original */
6724
6725     if (!ppTInfo || !ppTComp)
6726         return E_POINTER;
6727
6728     *ppTInfo = NULL;
6729     *ppTComp = NULL;
6730
6731     return S_OK;
6732 }
6733
6734 static const ITypeCompVtbl tcompvt =
6735 {
6736
6737     ITypeComp_fnQueryInterface,
6738     ITypeComp_fnAddRef,
6739     ITypeComp_fnRelease,
6740
6741     ITypeComp_fnBind,
6742     ITypeComp_fnBindType
6743 };