msi: Write-strings warnings fix.
[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                                                (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                                                (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             return S_OK;
2214         }
2215     }
2216     LeaveCriticalSection(&cache_section);
2217
2218     /* now actually load and parse the typelib */
2219     if (hinstDLL)
2220     {
2221         static const WCHAR TYPELIBW[] = {'T','Y','P','E','L','I','B',0};
2222         HRSRC hrsrc = FindResourceW(hinstDLL, MAKEINTRESOURCEW(index), TYPELIBW);
2223         if (hrsrc)
2224         {
2225             HGLOBAL hGlobal = LoadResource(hinstDLL, hrsrc);
2226             if (hGlobal)
2227             {
2228                 LPVOID pBase = LockResource(hGlobal);
2229                 DWORD  dwTLBLength = SizeofResource(hinstDLL, hrsrc);
2230
2231                 if (pBase)
2232                 {
2233                     /* try to load as incore resource */
2234                     DWORD dwSignature = FromLEDWord(*((DWORD*) pBase));
2235                     if (dwSignature == MSFT_SIGNATURE)
2236                         *ppTypeLib = ITypeLib2_Constructor_MSFT(pBase, dwTLBLength);
2237                     else if (dwSignature == SLTG_SIGNATURE)
2238                         *ppTypeLib = ITypeLib2_Constructor_SLTG(pBase, dwTLBLength);
2239                     else
2240                         FIXME("Header type magic 0x%08lx not supported.\n",dwSignature);
2241                 }
2242                 FreeResource( hGlobal );
2243             }
2244         }
2245         FreeLibrary(hinstDLL);
2246     }
2247     else
2248     {
2249         HANDLE hFile = CreateFileW(pszPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
2250         if (INVALID_HANDLE_VALUE != hFile)
2251         {
2252             HANDLE hMapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL );
2253             if (hMapping)
2254             {
2255                 LPVOID pBase = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
2256                 if(pBase)
2257                 {
2258                     /* retrieve file size */
2259                     DWORD dwTLBLength = GetFileSize(hFile, NULL);
2260                     DWORD dwSignature = FromLEDWord(*((DWORD*) pBase));
2261
2262                     if (dwSignature == MSFT_SIGNATURE)
2263                         *ppTypeLib = ITypeLib2_Constructor_MSFT(pBase, dwTLBLength);
2264                     else if (dwSignature == SLTG_SIGNATURE)
2265                         *ppTypeLib = ITypeLib2_Constructor_SLTG(pBase, dwTLBLength);
2266
2267                     UnmapViewOfFile(pBase);
2268                 }
2269                 CloseHandle(hMapping);
2270             }
2271             CloseHandle(hFile);
2272         }
2273     }
2274
2275     if(*ppTypeLib) {
2276         ITypeLibImpl *impl = (ITypeLibImpl*)*ppTypeLib;
2277
2278         TRACE("adding to cache\n");
2279         impl->path = HeapAlloc(GetProcessHeap(), 0, (strlenW(pszPath)+1) * sizeof(WCHAR));
2280         lstrcpyW(impl->path, pszPath);
2281         /* We should really canonicalise the path here. */
2282         impl->index = index;
2283
2284         /* FIXME: check if it has added already in the meantime */
2285         EnterCriticalSection(&cache_section);
2286         if ((impl->next = tlb_cache_first) != NULL) impl->next->prev = impl;
2287         impl->prev = NULL;
2288         tlb_cache_first = impl;
2289         LeaveCriticalSection(&cache_section);
2290         ret = S_OK;
2291     } else
2292         ERR("Loading of typelib %s failed with error %ld\n", debugstr_w(pszFileName), GetLastError());
2293
2294     return ret;
2295 }
2296
2297 /*================== ITypeLib(2) Methods ===================================*/
2298
2299 static ITypeLibImpl* TypeLibImpl_Constructor(void)
2300 {
2301     ITypeLibImpl* pTypeLibImpl;
2302
2303     pTypeLibImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeLibImpl));
2304     if (!pTypeLibImpl) return NULL;
2305
2306     pTypeLibImpl->lpVtbl = &tlbvt;
2307     pTypeLibImpl->lpVtblTypeComp = &tlbtcvt;
2308     pTypeLibImpl->ref = 1;
2309
2310     return pTypeLibImpl;
2311 }
2312
2313 /****************************************************************************
2314  *      ITypeLib2_Constructor_MSFT
2315  *
2316  * loading an MSFT typelib from an in-memory image
2317  */
2318 static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength)
2319 {
2320     TLBContext cx;
2321     long lPSegDir;
2322     MSFT_Header tlbHeader;
2323     MSFT_SegDir tlbSegDir;
2324     ITypeLibImpl * pTypeLibImpl;
2325
2326     TRACE("%p, TLB length = %ld\n", pLib, dwTLBLength);
2327
2328     pTypeLibImpl = TypeLibImpl_Constructor();
2329     if (!pTypeLibImpl) return NULL;
2330
2331     /* get pointer to beginning of typelib data */
2332     cx.pos = 0;
2333     cx.oStart=0;
2334     cx.mapping = pLib;
2335     cx.pLibInfo = pTypeLibImpl;
2336     cx.length = dwTLBLength;
2337
2338     /* read header */
2339     MSFT_ReadLEDWords((void*)&tlbHeader, sizeof(tlbHeader), &cx, 0);
2340     TRACE_(typelib)("header:\n");
2341     TRACE_(typelib)("\tmagic1=0x%08x ,magic2=0x%08x\n",tlbHeader.magic1,tlbHeader.magic2 );
2342     if (tlbHeader.magic1 != MSFT_SIGNATURE) {
2343         FIXME("Header type magic 0x%08x not supported.\n",tlbHeader.magic1);
2344         return NULL;
2345     }
2346     TRACE_(typelib)("\tdispatchpos = 0x%x\n", tlbHeader.dispatchpos);
2347
2348     /* there is a small amount of information here until the next important
2349      * part:
2350      * the segment directory . Try to calculate the amount of data */
2351     lPSegDir = sizeof(tlbHeader) + (tlbHeader.nrtypeinfos)*4 + ((tlbHeader.varflags & HELPDLLFLAG)? 4 :0);
2352
2353     /* now read the segment directory */
2354     TRACE("read segment directory (at %ld)\n",lPSegDir);
2355     MSFT_ReadLEDWords(&tlbSegDir, sizeof(tlbSegDir), &cx, lPSegDir);
2356     cx.pTblDir = &tlbSegDir;
2357
2358     /* just check two entries */
2359     if ( tlbSegDir.pTypeInfoTab.res0c != 0x0F || tlbSegDir.pImpInfo.res0c != 0x0F)
2360     {
2361         ERR("cannot find the table directory, ptr=0x%lx\n",lPSegDir);
2362         HeapFree(GetProcessHeap(),0,pTypeLibImpl);
2363         return NULL;
2364     }
2365
2366     /* now fill our internal data */
2367     /* TLIBATTR fields */
2368     MSFT_ReadGuid(&pTypeLibImpl->LibAttr.guid, tlbHeader.posguid, &cx);
2369
2370     /*    pTypeLibImpl->LibAttr.lcid = tlbHeader.lcid;*/
2371     /* Windows seems to have zero here, is this correct? */
2372     if(SUBLANGID(tlbHeader.lcid) == SUBLANG_NEUTRAL)
2373       pTypeLibImpl->LibAttr.lcid = MAKELCID(MAKELANGID(PRIMARYLANGID(tlbHeader.lcid),0),0);
2374     else
2375       pTypeLibImpl->LibAttr.lcid = 0;
2376
2377     pTypeLibImpl->LibAttr.syskind = tlbHeader.varflags & 0x0f; /* check the mask */
2378     pTypeLibImpl->LibAttr.wMajorVerNum = LOWORD(tlbHeader.version);
2379     pTypeLibImpl->LibAttr.wMinorVerNum = HIWORD(tlbHeader.version);
2380     pTypeLibImpl->LibAttr.wLibFlags = (WORD) tlbHeader.flags & 0xffff;/* check mask */
2381
2382     /* name, eventually add to a hash table */
2383     pTypeLibImpl->Name = MSFT_ReadName(&cx, tlbHeader.NameOffset);
2384
2385     /* help info */
2386     pTypeLibImpl->DocString = MSFT_ReadString(&cx, tlbHeader.helpstring);
2387     pTypeLibImpl->HelpFile = MSFT_ReadString(&cx, tlbHeader.helpfile);
2388
2389     if( tlbHeader.varflags & HELPDLLFLAG)
2390     {
2391             int offset;
2392             MSFT_ReadLEDWords(&offset, sizeof(offset), &cx, sizeof(tlbHeader));
2393             pTypeLibImpl->HelpStringDll = MSFT_ReadString(&cx, offset);
2394     }
2395
2396     pTypeLibImpl->dwHelpContext = tlbHeader.helpstringcontext;
2397
2398     /* custom data */
2399     if(tlbHeader.CustomDataOffset >= 0)
2400     {
2401         pTypeLibImpl->ctCustData = MSFT_CustData(&cx, tlbHeader.CustomDataOffset, &pTypeLibImpl->pCustData);
2402     }
2403
2404     /* fill in typedescriptions */
2405     if(tlbSegDir.pTypdescTab.length > 0)
2406     {
2407         int i, j, cTD = tlbSegDir.pTypdescTab.length / (2*sizeof(INT));
2408         INT16 td[4];
2409         pTypeLibImpl->pTypeDesc = TLB_Alloc( cTD * sizeof(TYPEDESC));
2410         MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pTypdescTab.offset);
2411         for(i=0; i<cTD; )
2412         {
2413             /* FIXME: add several sanity checks here */
2414             pTypeLibImpl->pTypeDesc[i].vt = td[0] & VT_TYPEMASK;
2415             if(td[0] == VT_PTR || td[0] == VT_SAFEARRAY)
2416             {
2417                 /* FIXME: check safearray */
2418                 if(td[3] < 0)
2419                     pTypeLibImpl->pTypeDesc[i].u.lptdesc= & stndTypeDesc[td[2]];
2420                 else
2421                     pTypeLibImpl->pTypeDesc[i].u.lptdesc= & pTypeLibImpl->pTypeDesc[td[2]/8];
2422             }
2423             else if(td[0] == VT_CARRAY)
2424             {
2425                 /* array descr table here */
2426                 pTypeLibImpl->pTypeDesc[i].u.lpadesc = (void *)((int) td[2]);  /* temp store offset in*/
2427             }
2428             else if(td[0] == VT_USERDEFINED)
2429             {
2430                 pTypeLibImpl->pTypeDesc[i].u.hreftype = MAKELONG(td[2],td[3]);
2431             }
2432             if(++i<cTD) MSFT_ReadLEWords(td, sizeof(td), &cx, DO_NOT_SEEK);
2433         }
2434
2435         /* second time around to fill the array subscript info */
2436         for(i=0;i<cTD;i++)
2437         {
2438             if(pTypeLibImpl->pTypeDesc[i].vt != VT_CARRAY) continue;
2439             if(tlbSegDir.pArrayDescriptions.offset>0)
2440             {
2441                 MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pArrayDescriptions.offset + (int) pTypeLibImpl->pTypeDesc[i].u.lpadesc);
2442                 pTypeLibImpl->pTypeDesc[i].u.lpadesc = TLB_Alloc(sizeof(ARRAYDESC)+sizeof(SAFEARRAYBOUND)*(td[3]-1));
2443
2444                 if(td[1]<0)
2445                     pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem.vt = td[0] & VT_TYPEMASK;
2446                 else
2447                     pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem = stndTypeDesc[td[0]/8];
2448
2449                 pTypeLibImpl->pTypeDesc[i].u.lpadesc->cDims = td[2];
2450
2451                 for(j = 0; j<td[2]; j++)
2452                 {
2453                     MSFT_ReadLEDWords(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].cElements,
2454                                       sizeof(INT), &cx, DO_NOT_SEEK);
2455                     MSFT_ReadLEDWords(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].lLbound,
2456                                       sizeof(INT), &cx, DO_NOT_SEEK);
2457                 }
2458             }
2459             else
2460             {
2461                 pTypeLibImpl->pTypeDesc[i].u.lpadesc = NULL;
2462                 ERR("didn't find array description data\n");
2463             }
2464         }
2465     }
2466
2467     /* imported type libs */
2468     if(tlbSegDir.pImpFiles.offset>0)
2469     {
2470         TLBImpLib **ppImpLib = &(pTypeLibImpl->pImpLibs);
2471         int oGuid, offset = tlbSegDir.pImpFiles.offset;
2472         UINT16 size;
2473
2474         while(offset < tlbSegDir.pImpFiles.offset +tlbSegDir.pImpFiles.length)
2475         {
2476             char *name;
2477             DWORD len;
2478
2479             *ppImpLib = TLB_Alloc(sizeof(TLBImpLib));
2480             (*ppImpLib)->offset = offset - tlbSegDir.pImpFiles.offset;
2481             MSFT_ReadLEDWords(&oGuid, sizeof(INT), &cx, offset);
2482
2483             MSFT_ReadLEDWords(&(*ppImpLib)->lcid,         sizeof(LCID),   &cx, DO_NOT_SEEK);
2484             MSFT_ReadLEWords(&(*ppImpLib)->wVersionMajor, sizeof(WORD),   &cx, DO_NOT_SEEK);
2485             MSFT_ReadLEWords(&(*ppImpLib)->wVersionMinor, sizeof(WORD),   &cx, DO_NOT_SEEK);
2486             MSFT_ReadLEWords(& size,                      sizeof(UINT16), &cx, DO_NOT_SEEK);
2487
2488             size >>= 2;
2489             name = TLB_Alloc(size+1);
2490             MSFT_Read(name, size, &cx, DO_NOT_SEEK);
2491             len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0 );
2492             (*ppImpLib)->name = TLB_Alloc(len * sizeof(WCHAR));
2493             MultiByteToWideChar(CP_ACP, 0, name, -1, (*ppImpLib)->name, len );
2494             TLB_Free(name);
2495
2496             MSFT_ReadGuid(&(*ppImpLib)->guid, oGuid, &cx);
2497             offset = (offset + sizeof(INT) + sizeof(DWORD) + sizeof(LCID) + sizeof(UINT16) + size + 3) & ~3;
2498
2499             ppImpLib = &(*ppImpLib)->next;
2500         }
2501     }
2502
2503     /* type info's */
2504     if(tlbHeader.nrtypeinfos >= 0 )
2505     {
2506         /*pTypeLibImpl->TypeInfoCount=tlbHeader.nrtypeinfos; */
2507         ITypeInfoImpl **ppTI = &(pTypeLibImpl->pTypeInfo);
2508         int i;
2509
2510         for(i = 0; i<(int)tlbHeader.nrtypeinfos; i++)
2511         {
2512             *ppTI = MSFT_DoTypeInfo(&cx, i, tlbHeader.dispatchpos, pTypeLibImpl);
2513
2514             ppTI = &((*ppTI)->next);
2515             (pTypeLibImpl->TypeInfoCount)++;
2516         }
2517     }
2518
2519     TRACE("(%p)\n", pTypeLibImpl);
2520     return (ITypeLib2*) pTypeLibImpl;
2521 }
2522
2523
2524 static BSTR TLB_MultiByteToBSTR(char *ptr)
2525 {
2526     DWORD len;
2527     WCHAR *nameW;
2528     BSTR ret;
2529
2530     len = MultiByteToWideChar(CP_ACP, 0, ptr, -1, NULL, 0);
2531     nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2532     MultiByteToWideChar(CP_ACP, 0, ptr, -1, nameW, len);
2533     ret = SysAllocString(nameW);
2534     HeapFree(GetProcessHeap(), 0, nameW);
2535     return ret;
2536 }
2537
2538 static BOOL TLB_GUIDFromString(char *str, GUID *guid)
2539 {
2540   char b[3];
2541   int i;
2542   short s;
2543
2544   if(sscanf(str, "%lx-%hx-%hx-%hx", &guid->Data1, &guid->Data2, &guid->Data3, &s) != 4) {
2545     FIXME("Can't parse guid %s\n", debugstr_guid(guid));
2546     return FALSE;
2547   }
2548
2549   guid->Data4[0] = s >> 8;
2550   guid->Data4[1] = s & 0xff;
2551
2552   b[2] = '\0';
2553   for(i = 0; i < 6; i++) {
2554     memcpy(b, str + 24 + 2 * i, 2);
2555     guid->Data4[i + 2] = strtol(b, NULL, 16);
2556   }
2557   return TRUE;
2558 }
2559
2560 static WORD SLTG_ReadString(char *ptr, BSTR *pBstr)
2561 {
2562     WORD bytelen;
2563     DWORD len;
2564     WCHAR *nameW;
2565
2566     *pBstr = NULL;
2567     bytelen = *(WORD*)ptr;
2568     if(bytelen == 0xffff) return 2;
2569     len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, NULL, 0);
2570     nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2571     len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, nameW, len);
2572     *pBstr = SysAllocStringLen(nameW, len);
2573     HeapFree(GetProcessHeap(), 0, nameW);
2574     return bytelen + 2;
2575 }
2576
2577 static WORD SLTG_ReadStringA(char *ptr, char **str)
2578 {
2579     WORD bytelen;
2580
2581     *str = NULL;
2582     bytelen = *(WORD*)ptr;
2583     if(bytelen == 0xffff) return 2;
2584     *str = HeapAlloc(GetProcessHeap(), 0, bytelen + 1);
2585     memcpy(*str, ptr + 2, bytelen);
2586     (*str)[bytelen] = '\0';
2587     return bytelen + 2;
2588 }
2589
2590 static DWORD SLTG_ReadLibBlk(LPVOID pLibBlk, ITypeLibImpl *pTypeLibImpl)
2591 {
2592     char *ptr = pLibBlk;
2593     WORD w;
2594
2595     if((w = *(WORD*)ptr) != SLTG_LIBBLK_MAGIC) {
2596         FIXME("libblk magic = %04x\n", w);
2597         return 0;
2598     }
2599
2600     ptr += 6;
2601     if((w = *(WORD*)ptr) != 0xffff) {
2602         FIXME("LibBlk.res06 = %04x. Assumung string and skipping\n", w);
2603         ptr += w;
2604     }
2605     ptr += 2;
2606
2607     ptr += SLTG_ReadString(ptr, &pTypeLibImpl->DocString);
2608
2609     ptr += SLTG_ReadString(ptr, &pTypeLibImpl->HelpFile);
2610
2611     pTypeLibImpl->dwHelpContext = *(DWORD*)ptr;
2612     ptr += 4;
2613
2614     pTypeLibImpl->LibAttr.syskind = *(WORD*)ptr;
2615     ptr += 2;
2616
2617     if(SUBLANGID(*(WORD*)ptr) == SUBLANG_NEUTRAL)
2618         pTypeLibImpl->LibAttr.lcid = MAKELCID(MAKELANGID(PRIMARYLANGID(*(WORD*)ptr),0),0);
2619     else
2620         pTypeLibImpl->LibAttr.lcid = 0;
2621     ptr += 2;
2622
2623     ptr += 4; /* skip res12 */
2624
2625     pTypeLibImpl->LibAttr.wLibFlags = *(WORD*)ptr;
2626     ptr += 2;
2627
2628     pTypeLibImpl->LibAttr.wMajorVerNum = *(WORD*)ptr;
2629     ptr += 2;
2630
2631     pTypeLibImpl->LibAttr.wMinorVerNum = *(WORD*)ptr;
2632     ptr += 2;
2633
2634     memcpy(&pTypeLibImpl->LibAttr.guid, ptr, sizeof(GUID));
2635     ptr += sizeof(GUID);
2636
2637     return ptr - (char*)pLibBlk;
2638 }
2639
2640 static WORD *SLTG_DoType(WORD *pType, char *pBlk, TYPEDESC *pTD)
2641 {
2642     BOOL done = FALSE;
2643
2644     while(!done) {
2645         if((*pType & 0xe00) == 0xe00) {
2646             pTD->vt = VT_PTR;
2647             pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2648                                        sizeof(TYPEDESC));
2649             pTD = pTD->u.lptdesc;
2650         }
2651         switch(*pType & 0x3f) {
2652         case VT_PTR:
2653             pTD->vt = VT_PTR;
2654             pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2655                                        sizeof(TYPEDESC));
2656             pTD = pTD->u.lptdesc;
2657             break;
2658
2659         case VT_USERDEFINED:
2660             pTD->vt = VT_USERDEFINED;
2661             pTD->u.hreftype = *(++pType) / 4;
2662             done = TRUE;
2663             break;
2664
2665         case VT_CARRAY:
2666           {
2667             /* *(pType+1) is offset to a SAFEARRAY, *(pType+2) is type of
2668                array */
2669
2670             SAFEARRAY *pSA = (SAFEARRAY *)(pBlk + *(++pType));
2671
2672             pTD->vt = VT_CARRAY;
2673             pTD->u.lpadesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2674                                 sizeof(ARRAYDESC) +
2675                                 (pSA->cDims - 1) * sizeof(SAFEARRAYBOUND));
2676             pTD->u.lpadesc->cDims = pSA->cDims;
2677             memcpy(pTD->u.lpadesc->rgbounds, pSA->rgsabound,
2678                    pSA->cDims * sizeof(SAFEARRAYBOUND));
2679
2680             pTD = &pTD->u.lpadesc->tdescElem;
2681             break;
2682           }
2683
2684         case VT_SAFEARRAY:
2685           {
2686             /* FIXME: *(pType+1) gives an offset to SAFEARRAY, is this
2687                useful? */
2688
2689             pType++;
2690             pTD->vt = VT_SAFEARRAY;
2691             pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2692                                        sizeof(TYPEDESC));
2693             pTD = pTD->u.lptdesc;
2694             break;
2695           }
2696         default:
2697             pTD->vt = *pType & 0x3f;
2698             done = TRUE;
2699             break;
2700         }
2701         pType++;
2702     }
2703     return pType;
2704 }
2705
2706 static WORD *SLTG_DoElem(WORD *pType, char *pBlk, ELEMDESC *pElem)
2707 {
2708     /* Handle [in/out] first */
2709     if((*pType & 0xc000) == 0xc000)
2710         pElem->u.paramdesc.wParamFlags = PARAMFLAG_NONE;
2711     else if(*pType & 0x8000)
2712         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN | PARAMFLAG_FOUT;
2713     else if(*pType & 0x4000)
2714         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FOUT;
2715     else
2716         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN;
2717
2718     if(*pType & 0x2000)
2719         pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FLCID;
2720
2721     if(*pType & 0x80)
2722         pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FRETVAL;
2723
2724     return SLTG_DoType(pType, pBlk, &pElem->tdesc);
2725 }
2726
2727
2728 static void SLTG_DoRefs(SLTG_RefInfo *pRef, ITypeInfoImpl *pTI,
2729                         char *pNameTable)
2730 {
2731     int ref;
2732     char *name;
2733     TLBRefType **ppRefType;
2734
2735     if(pRef->magic != SLTG_REF_MAGIC) {
2736         FIXME("Ref magic = %x\n", pRef->magic);
2737         return;
2738     }
2739     name = ( (char*)(&pRef->names) + pRef->number);
2740
2741     ppRefType = &pTI->reflist;
2742     for(ref = 0; ref < pRef->number >> 3; ref++) {
2743         char *refname;
2744         unsigned int lib_offs, type_num;
2745
2746         *ppRefType = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2747                                sizeof(**ppRefType));
2748
2749         name += SLTG_ReadStringA(name, &refname);
2750         if(sscanf(refname, "*\\R%x*#%x", &lib_offs, &type_num) != 2)
2751             FIXME("Can't sscanf ref\n");
2752         if(lib_offs != 0xffff) {
2753             TLBImpLib **import = &pTI->pTypeLib->pImpLibs;
2754
2755             while(*import) {
2756                 if((*import)->offset == lib_offs)
2757                     break;
2758                 import = &(*import)->next;
2759             }
2760             if(!*import) {
2761                 char fname[MAX_PATH+1];
2762                 int len;
2763
2764                 *import = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2765                                     sizeof(**import));
2766                 (*import)->offset = lib_offs;
2767                 TLB_GUIDFromString( pNameTable + lib_offs + 4,
2768                                     &(*import)->guid);
2769                 if(sscanf(pNameTable + lib_offs + 40, "}#%hd.%hd#%lx#%s",
2770                           &(*import)->wVersionMajor,
2771                           &(*import)->wVersionMinor,
2772                           &(*import)->lcid, fname) != 4) {
2773                   FIXME("can't sscanf ref %s\n",
2774                         pNameTable + lib_offs + 40);
2775                 }
2776                 len = strlen(fname);
2777                 if(fname[len-1] != '#')
2778                     FIXME("fname = %s\n", fname);
2779                 fname[len-1] = '\0';
2780                 (*import)->name = TLB_MultiByteToBSTR(fname);
2781             }
2782             (*ppRefType)->pImpTLInfo = *import;
2783         } else { /* internal ref */
2784           (*ppRefType)->pImpTLInfo = TLB_REF_INTERNAL;
2785         }
2786         (*ppRefType)->reference = ref;
2787         (*ppRefType)->index = type_num;
2788
2789         HeapFree(GetProcessHeap(), 0, refname);
2790         ppRefType = &(*ppRefType)->next;
2791     }
2792     if((BYTE)*name != SLTG_REF_MAGIC)
2793       FIXME("End of ref block magic = %x\n", *name);
2794     dump_TLBRefType(pTI->reflist);
2795 }
2796
2797 static char *SLTG_DoImpls(char *pBlk, ITypeInfoImpl *pTI,
2798                           BOOL OneOnly)
2799 {
2800     SLTG_ImplInfo *info;
2801     TLBImplType **ppImplType = &pTI->impltypelist;
2802     /* I don't really get this structure, usually it's 0x16 bytes
2803        long, but iuser.tlb contains some that are 0x18 bytes long.
2804        That's ok because we can use the next ptr to jump to the next
2805        one. But how do we know the length of the last one?  The WORD
2806        at offs 0x8 might be the clue.  For now I'm just assuming that
2807        the last one is the regular 0x16 bytes. */
2808
2809     info = (SLTG_ImplInfo*)pBlk;
2810     while(1) {
2811         *ppImplType = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2812                                 sizeof(**ppImplType));
2813         (*ppImplType)->hRef = info->ref;
2814         (*ppImplType)->implflags = info->impltypeflags;
2815         pTI->TypeAttr.cImplTypes++;
2816         ppImplType = &(*ppImplType)->next;
2817
2818         if(info->next == 0xffff)
2819             break;
2820         if(OneOnly)
2821             FIXME("Interface inheriting more than one interface\n");
2822         info = (SLTG_ImplInfo*)(pBlk + info->next);
2823     }
2824     info++; /* see comment at top of function */
2825     return (char*)info;
2826 }
2827
2828 static void SLTG_DoVars(char *pBlk, char *pFirstItem, ITypeInfoImpl *pTI, unsigned short cVars, char *pNameTable)
2829 {
2830   TLBVarDesc **ppVarDesc = &pTI->varlist;
2831   BSTR bstrPrevName = NULL;
2832   SLTG_Variable *pItem;
2833   unsigned short i;
2834   WORD *pType;
2835   char buf[300];
2836
2837   for(pItem = (SLTG_Variable *)pFirstItem, i = 0; i < cVars;
2838       pItem = (SLTG_Variable *)(pBlk + pItem->next), i++) {
2839
2840       *ppVarDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2841                              sizeof(**ppVarDesc));
2842       (*ppVarDesc)->vardesc.memid = pItem->memid;
2843
2844       if (pItem->magic != SLTG_VAR_MAGIC &&
2845           pItem->magic != SLTG_VAR_WITH_FLAGS_MAGIC) {
2846           FIXME_(typelib)("var magic = %02x\n", pItem->magic);
2847           return;
2848       }
2849
2850       if (pItem->name == 0xfffe)
2851         (*ppVarDesc)->Name = SysAllocString(bstrPrevName);
2852       else
2853         (*ppVarDesc)->Name = TLB_MultiByteToBSTR(pItem->name + pNameTable);
2854
2855       TRACE_(typelib)("byte_offs = 0x%x\n", pItem->byte_offs);
2856       TRACE_(typelib)("memid = 0x%lx\n", pItem->memid);
2857
2858       if (pItem->flags & 0x40) {
2859         TRACE_(typelib)("VAR_DISPATCH\n");
2860         (*ppVarDesc)->vardesc.varkind = VAR_DISPATCH;
2861       }
2862       else if (pItem->flags & 0x10) {
2863         TRACE_(typelib)("VAR_CONST\n");
2864         (*ppVarDesc)->vardesc.varkind = VAR_CONST;
2865         (*ppVarDesc)->vardesc.u.lpvarValue = HeapAlloc(GetProcessHeap(), 0,
2866                                                        sizeof(VARIANT));
2867         V_VT((*ppVarDesc)->vardesc.u.lpvarValue) = VT_INT;
2868         V_UNION((*ppVarDesc)->vardesc.u.lpvarValue, intVal) =
2869           *(INT*)(pBlk + pItem->byte_offs);
2870       }
2871       else {
2872         TRACE_(typelib)("VAR_PERINSTANCE\n");
2873         (*ppVarDesc)->vardesc.u.oInst = pItem->byte_offs;
2874         (*ppVarDesc)->vardesc.varkind = VAR_PERINSTANCE;
2875       }
2876
2877       if (pItem->magic == SLTG_VAR_WITH_FLAGS_MAGIC)
2878         (*ppVarDesc)->vardesc.wVarFlags = pItem->varflags;
2879
2880       if (pItem->flags & 0x80)
2881         (*ppVarDesc)->vardesc.wVarFlags |= VARFLAG_FREADONLY;
2882
2883       if(pItem->flags & 0x02)
2884           pType = &pItem->type;
2885       else
2886           pType = (WORD*)(pBlk + pItem->type);
2887
2888       if (pItem->flags & ~0xd2)
2889         FIXME_(typelib)("unhandled flags = %02x\n", pItem->flags & ~0xd2);
2890
2891       SLTG_DoElem(pType, pBlk,
2892                   &(*ppVarDesc)->vardesc.elemdescVar);
2893
2894       dump_TypeDesc(&(*ppVarDesc)->vardesc.elemdescVar.tdesc, buf);
2895
2896       bstrPrevName = (*ppVarDesc)->Name;
2897       ppVarDesc = &((*ppVarDesc)->next);
2898   }
2899   pTI->TypeAttr.cVars = cVars;
2900 }
2901
2902 static void SLTG_DoFuncs(char *pBlk, char *pFirstItem, ITypeInfoImpl *pTI, unsigned short cFuncs, char *pNameTable)
2903 {
2904     SLTG_Function *pFunc;
2905     unsigned short i;
2906     TLBFuncDesc **ppFuncDesc = &pTI->funclist;
2907
2908     for(pFunc = (SLTG_Function*)pFirstItem, i = 0; i < cFuncs;
2909         pFunc = (SLTG_Function*)(pBlk + pFunc->next), i++) {
2910
2911         int param;
2912         WORD *pType, *pArg;
2913
2914         *ppFuncDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2915                                 sizeof(**ppFuncDesc));
2916
2917         switch (pFunc->magic & ~SLTG_FUNCTION_FLAGS_PRESENT) {
2918         case SLTG_FUNCTION_MAGIC:
2919             (*ppFuncDesc)->funcdesc.funckind = FUNC_PUREVIRTUAL;
2920             break;
2921         case SLTG_DISPATCH_FUNCTION_MAGIC:
2922             (*ppFuncDesc)->funcdesc.funckind = FUNC_DISPATCH;
2923             break;
2924         case SLTG_STATIC_FUNCTION_MAGIC:
2925             (*ppFuncDesc)->funcdesc.funckind = FUNC_STATIC;
2926             break;
2927         default:
2928             FIXME("unimplemented func magic = %02x\n", pFunc->magic & ~SLTG_FUNCTION_FLAGS_PRESENT);
2929             HeapFree(GetProcessHeap(), 0, *ppFuncDesc);
2930             *ppFuncDesc = NULL;
2931             return;
2932         }
2933         (*ppFuncDesc)->Name = TLB_MultiByteToBSTR(pFunc->name + pNameTable);
2934
2935         (*ppFuncDesc)->funcdesc.memid = pFunc->dispid;
2936         (*ppFuncDesc)->funcdesc.invkind = pFunc->inv >> 4;
2937         (*ppFuncDesc)->funcdesc.callconv = pFunc->nacc & 0x7;
2938         (*ppFuncDesc)->funcdesc.cParams = pFunc->nacc >> 3;
2939         (*ppFuncDesc)->funcdesc.cParamsOpt = (pFunc->retnextopt & 0x7e) >> 1;
2940         (*ppFuncDesc)->funcdesc.oVft = pFunc->vtblpos;
2941
2942         if(pFunc->magic & SLTG_FUNCTION_FLAGS_PRESENT)
2943             (*ppFuncDesc)->funcdesc.wFuncFlags = pFunc->funcflags;
2944
2945         if(pFunc->retnextopt & 0x80)
2946             pType = &pFunc->rettype;
2947         else
2948             pType = (WORD*)(pBlk + pFunc->rettype);
2949
2950         SLTG_DoElem(pType, pBlk, &(*ppFuncDesc)->funcdesc.elemdescFunc);
2951
2952         (*ppFuncDesc)->funcdesc.lprgelemdescParam =
2953           HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2954                     (*ppFuncDesc)->funcdesc.cParams * sizeof(ELEMDESC));
2955         (*ppFuncDesc)->pParamDesc =
2956           HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2957                     (*ppFuncDesc)->funcdesc.cParams * sizeof(TLBParDesc));
2958
2959         pArg = (WORD*)(pBlk + pFunc->arg_off);
2960
2961         for(param = 0; param < (*ppFuncDesc)->funcdesc.cParams; param++) {
2962             char *paramName = pNameTable + *pArg;
2963             BOOL HaveOffs;
2964             /* If arg type follows then paramName points to the 2nd
2965                letter of the name, else the next WORD is an offset to
2966                the arg type and paramName points to the first letter.
2967                So let's take one char off paramName and see if we're
2968                pointing at an alpha-numeric char.  However if *pArg is
2969                0xffff or 0xfffe then the param has no name, the former
2970                meaning that the next WORD is the type, the latter
2971                meaning the the next WORD is an offset to the type. */
2972
2973             HaveOffs = FALSE;
2974             if(*pArg == 0xffff)
2975                 paramName = NULL;
2976             else if(*pArg == 0xfffe) {
2977                 paramName = NULL;
2978                 HaveOffs = TRUE;
2979             }
2980             else if(paramName[-1] && !isalnum(paramName[-1]))
2981                 HaveOffs = TRUE;
2982
2983             pArg++;
2984
2985             if(HaveOffs) { /* the next word is an offset to type */
2986                 pType = (WORD*)(pBlk + *pArg);
2987                 SLTG_DoElem(pType, pBlk,
2988                             &(*ppFuncDesc)->funcdesc.lprgelemdescParam[param]);
2989                 pArg++;
2990             } else {
2991                 if(paramName)
2992                   paramName--;
2993                 pArg = SLTG_DoElem(pArg, pBlk,
2994                            &(*ppFuncDesc)->funcdesc.lprgelemdescParam[param]);
2995             }
2996
2997             /* Are we an optional param ? */
2998             if((*ppFuncDesc)->funcdesc.cParams - param <=
2999                (*ppFuncDesc)->funcdesc.cParamsOpt)
3000               (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].u.paramdesc.wParamFlags |= PARAMFLAG_FOPT;
3001
3002             if(paramName) {
3003                 (*ppFuncDesc)->pParamDesc[param].Name =
3004                   TLB_MultiByteToBSTR(paramName);
3005             }
3006         }
3007
3008         ppFuncDesc = &((*ppFuncDesc)->next);
3009         if(pFunc->next == 0xffff) break;
3010     }
3011     pTI->TypeAttr.cFuncs = cFuncs;
3012 }
3013
3014 static void SLTG_ProcessCoClass(char *pBlk, ITypeInfoImpl *pTI,
3015                                 char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3016                                 SLTG_TypeInfoTail *pTITail)
3017 {
3018     char *pFirstItem, *pNextItem;
3019
3020     if(pTIHeader->href_table != 0xffffffff) {
3021         SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI,
3022                     pNameTable);
3023     }
3024
3025     pFirstItem = pNextItem = pBlk;
3026
3027     if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
3028         pNextItem = SLTG_DoImpls(pFirstItem, pTI, FALSE);
3029     }
3030 }
3031
3032
3033 static void SLTG_ProcessInterface(char *pBlk, ITypeInfoImpl *pTI,
3034                                   char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3035                                   SLTG_TypeInfoTail *pTITail)
3036 {
3037     char *pFirstItem, *pNextItem;
3038
3039     if(pTIHeader->href_table != 0xffffffff) {
3040         SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI,
3041                     pNameTable);
3042     }
3043
3044     pFirstItem = pNextItem = pBlk;
3045
3046     if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
3047         pNextItem = SLTG_DoImpls(pFirstItem, pTI, TRUE);
3048     }
3049
3050     if (pTITail->funcs_off != 0xffff)
3051         SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable);
3052
3053     if (TRACE_ON(typelib))
3054         dump_TLBFuncDesc(pTI->funclist);
3055 }
3056
3057 static void SLTG_ProcessRecord(char *pBlk, ITypeInfoImpl *pTI,
3058                                char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3059                                SLTG_TypeInfoTail *pTITail)
3060 {
3061   SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable);
3062 }
3063
3064 static void SLTG_ProcessAlias(char *pBlk, ITypeInfoImpl *pTI,
3065                               char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3066                               SLTG_TypeInfoTail *pTITail)
3067 {
3068   WORD *pType;
3069
3070   if (pTITail->simple_alias) {
3071     /* if simple alias, no more processing required */
3072     pTI->TypeAttr.tdescAlias.vt = pTITail->tdescalias_vt;
3073     return;
3074   }
3075
3076   if(pTIHeader->href_table != 0xffffffff) {
3077       SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI,
3078                   pNameTable);
3079   }
3080
3081   /* otherwise it is an offset to a type */
3082   pType = (WORD *)(pBlk + pTITail->tdescalias_vt);
3083
3084   SLTG_DoType(pType, pBlk, &pTI->TypeAttr.tdescAlias);
3085 }
3086
3087 static void SLTG_ProcessDispatch(char *pBlk, ITypeInfoImpl *pTI,
3088                                  char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3089                                  SLTG_TypeInfoTail *pTITail)
3090 {
3091   if (pTIHeader->href_table != 0xffffffff)
3092       SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI,
3093                                   pNameTable);
3094
3095   if (pTITail->vars_off != 0xffff)
3096     SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable);
3097
3098   if (pTITail->funcs_off != 0xffff)
3099     SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable);
3100
3101   /* this is necessary to cope with MSFT typelibs that set cFuncs to the number
3102    * of dispinterface functons including the IDispatch ones, so
3103    * ITypeInfo::GetFuncDesc takes the real value for cFuncs from cbSizeVft */
3104   pTI->TypeAttr.cbSizeVft = pTI->TypeAttr.cFuncs * sizeof(void *);
3105
3106   if (TRACE_ON(typelib))
3107       dump_TLBFuncDesc(pTI->funclist);
3108 }
3109
3110 static void SLTG_ProcessEnum(char *pBlk, ITypeInfoImpl *pTI,
3111                              char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3112                              SLTG_TypeInfoTail *pTITail)
3113 {
3114   SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable);
3115 }
3116
3117 static void SLTG_ProcessModule(char *pBlk, ITypeInfoImpl *pTI,
3118                                char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3119                                SLTG_TypeInfoTail *pTITail)
3120 {
3121   if (pTIHeader->href_table != 0xffffffff)
3122       SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI,
3123                                   pNameTable);
3124
3125   if (pTITail->vars_off != 0xffff)
3126     SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable);
3127
3128   if (pTITail->funcs_off != 0xffff)
3129     SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable);
3130 }
3131
3132 /* Because SLTG_OtherTypeInfo is such a painful struct, we make a more
3133    managable copy of it into this */
3134 typedef struct {
3135   WORD small_no;
3136   char *index_name;
3137   char *other_name;
3138   WORD res1a;
3139   WORD name_offs;
3140   WORD more_bytes;
3141   char *extra;
3142   WORD res20;
3143   DWORD helpcontext;
3144   WORD res26;
3145   GUID uuid;
3146 } SLTG_InternalOtherTypeInfo;
3147
3148 /****************************************************************************
3149  *      ITypeLib2_Constructor_SLTG
3150  *
3151  * loading a SLTG typelib from an in-memory image
3152  */
3153 static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength)
3154 {
3155     ITypeLibImpl *pTypeLibImpl;
3156     SLTG_Header *pHeader;
3157     SLTG_BlkEntry *pBlkEntry;
3158     SLTG_Magic *pMagic;
3159     SLTG_Index *pIndex;
3160     SLTG_Pad9 *pPad9;
3161     LPVOID pBlk, pFirstBlk;
3162     SLTG_LibBlk *pLibBlk;
3163     SLTG_InternalOtherTypeInfo *pOtherTypeInfoBlks;
3164     char *pAfterOTIBlks = NULL;
3165     char *pNameTable, *ptr;
3166     int i;
3167     DWORD len, order;
3168     ITypeInfoImpl **ppTypeInfoImpl;
3169
3170     TRACE_(typelib)("%p, TLB length = %ld\n", pLib, dwTLBLength);
3171
3172
3173     pTypeLibImpl = TypeLibImpl_Constructor();
3174     if (!pTypeLibImpl) return NULL;
3175
3176     pHeader = pLib;
3177
3178     TRACE_(typelib)("header:\n");
3179     TRACE_(typelib)("\tmagic=0x%08lx, file blocks = %d\n", pHeader->SLTG_magic,
3180           pHeader->nrOfFileBlks );
3181     if (pHeader->SLTG_magic != SLTG_SIGNATURE) {
3182         FIXME("Header type magic 0x%08lx not supported.\n",
3183               pHeader->SLTG_magic);
3184         return NULL;
3185     }
3186
3187     /* There are pHeader->nrOfFileBlks - 2 TypeInfo records in this typelib */
3188     pTypeLibImpl->TypeInfoCount = pHeader->nrOfFileBlks - 2;
3189
3190     /* This points to pHeader->nrOfFileBlks - 1 of SLTG_BlkEntry */
3191     pBlkEntry = (SLTG_BlkEntry*)(pHeader + 1);
3192
3193     /* Next we have a magic block */
3194     pMagic = (SLTG_Magic*)(pBlkEntry + pHeader->nrOfFileBlks - 1);
3195
3196     /* Let's see if we're still in sync */
3197     if(memcmp(pMagic->CompObj_magic, SLTG_COMPOBJ_MAGIC,
3198               sizeof(SLTG_COMPOBJ_MAGIC))) {
3199         FIXME("CompObj magic = %s\n", pMagic->CompObj_magic);
3200         return NULL;
3201     }
3202     if(memcmp(pMagic->dir_magic, SLTG_DIR_MAGIC,
3203               sizeof(SLTG_DIR_MAGIC))) {
3204         FIXME("dir magic = %s\n", pMagic->dir_magic);
3205         return NULL;
3206     }
3207
3208     pIndex = (SLTG_Index*)(pMagic+1);
3209
3210     pPad9 = (SLTG_Pad9*)(pIndex + pTypeLibImpl->TypeInfoCount);
3211
3212     pFirstBlk = (LPVOID)(pPad9 + 1);
3213
3214     /* We'll set up a ptr to the main library block, which is the last one. */
3215
3216     for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0;
3217           pBlkEntry[order].next != 0;
3218           order = pBlkEntry[order].next - 1, i++) {
3219        pBlk = (char*)pBlk + pBlkEntry[order].len;
3220     }
3221     pLibBlk = pBlk;
3222
3223     len = SLTG_ReadLibBlk(pLibBlk, pTypeLibImpl);
3224
3225     /* Now there's 0x40 bytes of 0xffff with the numbers 0 to TypeInfoCount
3226        interspersed */
3227
3228     len += 0x40;
3229
3230     /* And now TypeInfoCount of SLTG_OtherTypeInfo */
3231
3232     pOtherTypeInfoBlks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3233                                    sizeof(*pOtherTypeInfoBlks) *
3234                                    pTypeLibImpl->TypeInfoCount);
3235
3236
3237     ptr = (char*)pLibBlk + len;
3238
3239     for(i = 0; i < pTypeLibImpl->TypeInfoCount; i++) {
3240         WORD w, extra;
3241         len = 0;
3242
3243         pOtherTypeInfoBlks[i].small_no = *(WORD*)ptr;
3244
3245         w = *(WORD*)(ptr + 2);
3246         if(w != 0xffff) {
3247             len += w;
3248             pOtherTypeInfoBlks[i].index_name = HeapAlloc(GetProcessHeap(),0,
3249                                                          w+1);
3250             memcpy(pOtherTypeInfoBlks[i].index_name, ptr + 4, w);
3251             pOtherTypeInfoBlks[i].index_name[w] = '\0';
3252         }
3253         w = *(WORD*)(ptr + 4 + len);
3254         if(w != 0xffff) {
3255             TRACE_(typelib)("\twith %s\n", debugstr_an(ptr + 6 + len, w));
3256             len += w;
3257             pOtherTypeInfoBlks[i].other_name = HeapAlloc(GetProcessHeap(),0,
3258                                                          w+1);
3259             memcpy(pOtherTypeInfoBlks[i].other_name, ptr + 6 + len, w);
3260             pOtherTypeInfoBlks[i].other_name[w] = '\0';
3261         }
3262         pOtherTypeInfoBlks[i].res1a = *(WORD*)(ptr + len + 6);
3263         pOtherTypeInfoBlks[i].name_offs = *(WORD*)(ptr + len + 8);
3264         extra = pOtherTypeInfoBlks[i].more_bytes = *(WORD*)(ptr + 10 + len);
3265         if(extra) {
3266             pOtherTypeInfoBlks[i].extra = HeapAlloc(GetProcessHeap(),0,
3267                                                     extra);
3268             memcpy(pOtherTypeInfoBlks[i].extra, ptr + 12, extra);
3269             len += extra;
3270         }
3271         pOtherTypeInfoBlks[i].res20 = *(WORD*)(ptr + 12 + len);
3272         pOtherTypeInfoBlks[i].helpcontext = *(DWORD*)(ptr + 14 + len);
3273         pOtherTypeInfoBlks[i].res26 = *(WORD*)(ptr + 18 + len);
3274         memcpy(&pOtherTypeInfoBlks[i].uuid, ptr + 20 + len, sizeof(GUID));
3275         len += sizeof(SLTG_OtherTypeInfo);
3276         ptr += len;
3277     }
3278
3279     pAfterOTIBlks = ptr;
3280
3281     /* Skip this WORD and get the next DWORD */
3282     len = *(DWORD*)(pAfterOTIBlks + 2);
3283
3284     /* Now add this to pLibBLk look at what we're pointing at and
3285        possibly add 0x20, then add 0x216, sprinkle a bit a magic
3286        dust and we should be pointing at the beginning of the name
3287        table */
3288
3289     pNameTable = (char*)pLibBlk + len;
3290
3291    switch(*(WORD*)pNameTable) {
3292    case 0xffff:
3293        break;
3294    case 0x0200:
3295        pNameTable += 0x20;
3296        break;
3297    default:
3298        FIXME("pNameTable jump = %x\n", *(WORD*)pNameTable);
3299        break;
3300    }
3301
3302     pNameTable += 0x216;
3303
3304     pNameTable += 2;
3305
3306     TRACE("Library name is %s\n", pNameTable + pLibBlk->name);
3307
3308     pTypeLibImpl->Name = TLB_MultiByteToBSTR(pNameTable + pLibBlk->name);
3309
3310
3311     /* Hopefully we now have enough ptrs set up to actually read in
3312        some TypeInfos.  It's not clear which order to do them in, so
3313        I'll just follow the links along the BlkEntry chain and read
3314        them in in the order in which they're in the file */
3315
3316     ppTypeInfoImpl = &(pTypeLibImpl->pTypeInfo);
3317
3318     for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0;
3319         pBlkEntry[order].next != 0;
3320         order = pBlkEntry[order].next - 1, i++) {
3321
3322       SLTG_TypeInfoHeader *pTIHeader;
3323       SLTG_TypeInfoTail *pTITail;
3324       SLTG_MemberHeader *pMemHeader;
3325
3326       if(strcmp(pBlkEntry[order].index_string + (char*)pMagic,
3327                 pOtherTypeInfoBlks[i].index_name)) {
3328         FIXME("Index strings don't match\n");
3329         return NULL;
3330       }
3331
3332       pTIHeader = pBlk;
3333       if(pTIHeader->magic != SLTG_TIHEADER_MAGIC) {
3334         FIXME("TypeInfoHeader magic = %04x\n", pTIHeader->magic);
3335         return NULL;
3336       }
3337       TRACE("pTIHeader->res06 = %lx, pTIHeader->res0e = %lx, pTIHeader->res16 = %lx, pTIHeader->res1e = %lx\n",
3338         pTIHeader->res06, pTIHeader->res0e, pTIHeader->res16, pTIHeader->res1e);
3339
3340       *ppTypeInfoImpl = (ITypeInfoImpl*)ITypeInfo_Constructor();
3341       (*ppTypeInfoImpl)->pTypeLib = pTypeLibImpl;
3342       (*ppTypeInfoImpl)->index = i;
3343       (*ppTypeInfoImpl)->Name = TLB_MultiByteToBSTR(
3344                                              pOtherTypeInfoBlks[i].name_offs +
3345                                              pNameTable);
3346       (*ppTypeInfoImpl)->dwHelpContext = pOtherTypeInfoBlks[i].helpcontext;
3347       memcpy(&((*ppTypeInfoImpl)->TypeAttr.guid), &pOtherTypeInfoBlks[i].uuid,
3348              sizeof(GUID));
3349       (*ppTypeInfoImpl)->TypeAttr.typekind = pTIHeader->typekind;
3350       (*ppTypeInfoImpl)->TypeAttr.wMajorVerNum = pTIHeader->major_version;
3351       (*ppTypeInfoImpl)->TypeAttr.wMinorVerNum = pTIHeader->minor_version;
3352       (*ppTypeInfoImpl)->TypeAttr.wTypeFlags =
3353         (pTIHeader->typeflags1 >> 3) | (pTIHeader->typeflags2 << 5);
3354
3355       if((pTIHeader->typeflags1 & 7) != 2)
3356         FIXME("typeflags1 = %02x\n", pTIHeader->typeflags1);
3357       if(pTIHeader->typeflags3 != 2)
3358         FIXME("typeflags3 = %02x\n", pTIHeader->typeflags3);
3359
3360       TRACE("TypeInfo %s of kind %s guid %s typeflags %04x\n",
3361             debugstr_w((*ppTypeInfoImpl)->Name),
3362             typekind_desc[pTIHeader->typekind],
3363             debugstr_guid(&(*ppTypeInfoImpl)->TypeAttr.guid),
3364             (*ppTypeInfoImpl)->TypeAttr.wTypeFlags);
3365
3366       pMemHeader = (SLTG_MemberHeader*)((char *)pBlk + pTIHeader->elem_table);
3367
3368       pTITail = (SLTG_TypeInfoTail*)((char *)(pMemHeader + 1) + pMemHeader->cbExtra);
3369
3370       (*ppTypeInfoImpl)->TypeAttr.cbAlignment = pTITail->cbAlignment;
3371       (*ppTypeInfoImpl)->TypeAttr.cbSizeInstance = pTITail->cbSizeInstance;
3372       (*ppTypeInfoImpl)->TypeAttr.cbSizeVft = pTITail->cbSizeVft;
3373
3374       switch(pTIHeader->typekind) {
3375       case TKIND_ENUM:
3376         SLTG_ProcessEnum((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
3377                          pTIHeader, pTITail);
3378         break;
3379
3380       case TKIND_RECORD:
3381         SLTG_ProcessRecord((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
3382                            pTIHeader, pTITail);
3383         break;
3384
3385       case TKIND_INTERFACE:
3386         SLTG_ProcessInterface((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
3387                               pTIHeader, pTITail);
3388         break;
3389
3390       case TKIND_COCLASS:
3391         SLTG_ProcessCoClass((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
3392                             pTIHeader, pTITail);
3393         break;
3394
3395       case TKIND_ALIAS:
3396         SLTG_ProcessAlias((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
3397                           pTIHeader, pTITail);
3398         break;
3399
3400       case TKIND_DISPATCH:
3401         SLTG_ProcessDispatch((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
3402                              pTIHeader, pTITail);
3403         break;
3404
3405       case TKIND_MODULE:
3406         SLTG_ProcessModule((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
3407                            pTIHeader, pTITail);
3408         break;
3409
3410       default:
3411         FIXME("Not processing typekind %d\n", pTIHeader->typekind);
3412         break;
3413
3414       }
3415
3416       if(pTITail) { /* could get cFuncs, cVars and cImplTypes from here
3417                        but we've already set those */
3418 #define X(x) TRACE_(typelib)("tt "#x": %x\n",pTITail->res##x);
3419           X(06);
3420           X(16);
3421           X(18);
3422           X(1a);
3423           X(1e);
3424           X(24);
3425           X(26);
3426           X(2a);
3427           X(2c);
3428           X(2e);
3429           X(30);
3430           X(32);
3431           X(34);
3432       }
3433       ppTypeInfoImpl = &((*ppTypeInfoImpl)->next);
3434       pBlk = (char*)pBlk + pBlkEntry[order].len;
3435     }
3436
3437     if(i != pTypeLibImpl->TypeInfoCount) {
3438       FIXME("Somehow processed %d TypeInfos\n", i);
3439       return NULL;
3440     }
3441
3442     HeapFree(GetProcessHeap(), 0, pOtherTypeInfoBlks);
3443     return (ITypeLib2*)pTypeLibImpl;
3444 }
3445
3446 /* ITypeLib::QueryInterface
3447  */
3448 static HRESULT WINAPI ITypeLib2_fnQueryInterface(
3449         ITypeLib2 * iface,
3450         REFIID riid,
3451         VOID **ppvObject)
3452 {
3453     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3454
3455     TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
3456
3457     *ppvObject=NULL;
3458     if(IsEqualIID(riid, &IID_IUnknown) ||
3459        IsEqualIID(riid,&IID_ITypeLib)||
3460        IsEqualIID(riid,&IID_ITypeLib2))
3461     {
3462         *ppvObject = This;
3463     }
3464
3465     if(*ppvObject)
3466     {
3467         ITypeLib2_AddRef(iface);
3468         TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
3469         return S_OK;
3470     }
3471     TRACE("-- Interface: E_NOINTERFACE\n");
3472     return E_NOINTERFACE;
3473 }
3474
3475 /* ITypeLib::AddRef
3476  */
3477 static ULONG WINAPI ITypeLib2_fnAddRef( ITypeLib2 *iface)
3478 {
3479     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3480     ULONG ref = InterlockedIncrement(&This->ref);
3481
3482     TRACE("(%p)->ref was %lu\n",This, ref - 1);
3483
3484     return ref;
3485 }
3486
3487 /* ITypeLib::Release
3488  */
3489 static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface)
3490 {
3491     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3492     ULONG ref = InterlockedDecrement(&This->ref);
3493
3494     TRACE("(%p)->(%lu)\n",This, ref);
3495
3496     if (!ref)
3497     {
3498       /* remove cache entry */
3499       if(This->path)
3500       {
3501           TRACE("removing from cache list\n");
3502           EnterCriticalSection(&cache_section);
3503           if (This->next) This->next->prev = This->prev;
3504           if (This->prev) This->prev->next = This->next;
3505           else tlb_cache_first = This->next;
3506           LeaveCriticalSection(&cache_section);
3507           HeapFree(GetProcessHeap(), 0, This->path);
3508       }
3509       /* FIXME destroy child objects */
3510       TRACE(" destroying ITypeLib(%p)\n",This);
3511
3512       if (This->Name)
3513       {
3514           SysFreeString(This->Name);
3515           This->Name = NULL;
3516       }
3517
3518       if (This->DocString)
3519       {
3520           SysFreeString(This->DocString);
3521           This->DocString = NULL;
3522       }
3523
3524       if (This->HelpFile)
3525       {
3526           SysFreeString(This->HelpFile);
3527           This->HelpFile = NULL;
3528       }
3529
3530       if (This->HelpStringDll)
3531       {
3532           SysFreeString(This->HelpStringDll);
3533           This->HelpStringDll = NULL;
3534       }
3535
3536       if (This->pTypeInfo) /* can be NULL */
3537           ITypeInfo_Release((ITypeInfo*) This->pTypeInfo);
3538       HeapFree(GetProcessHeap(),0,This);
3539       return 0;
3540     }
3541
3542     return ref;
3543 }
3544
3545 /* ITypeLib::GetTypeInfoCount
3546  *
3547  * Returns the number of type descriptions in the type library
3548  */
3549 static UINT WINAPI ITypeLib2_fnGetTypeInfoCount( ITypeLib2 *iface)
3550 {
3551     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3552     TRACE("(%p)->count is %d\n",This, This->TypeInfoCount);
3553     return This->TypeInfoCount;
3554 }
3555
3556 /* ITypeLib::GetTypeInfo
3557  *
3558  * retrieves the specified type description in the library.
3559  */
3560 static HRESULT WINAPI ITypeLib2_fnGetTypeInfo(
3561     ITypeLib2 *iface,
3562     UINT index,
3563     ITypeInfo **ppTInfo)
3564 {
3565     int i;
3566
3567     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3568     ITypeInfoImpl *pTypeInfo = This->pTypeInfo;
3569
3570     TRACE("(%p)->(index=%d)\n", This, index);
3571
3572     if (!ppTInfo) return E_INVALIDARG;
3573
3574     /* search element n in list */
3575     for(i=0; i < index; i++)
3576     {
3577       pTypeInfo = pTypeInfo->next;
3578       if (!pTypeInfo)
3579       {
3580         TRACE("-- element not found\n");
3581         return TYPE_E_ELEMENTNOTFOUND;
3582       }
3583     }
3584
3585     *ppTInfo = (ITypeInfo *) pTypeInfo;
3586
3587     ITypeInfo_AddRef(*ppTInfo);
3588     TRACE("-- found (%p)\n",*ppTInfo);
3589     return S_OK;
3590 }
3591
3592
3593 /* ITypeLibs::GetTypeInfoType
3594  *
3595  * Retrieves the type of a type description.
3596  */
3597 static HRESULT WINAPI ITypeLib2_fnGetTypeInfoType(
3598     ITypeLib2 *iface,
3599     UINT index,
3600     TYPEKIND *pTKind)
3601 {
3602     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3603     int i;
3604     ITypeInfoImpl *pTInfo = This->pTypeInfo;
3605     
3606     if ((ITypeLib2_fnGetTypeInfoCount(iface) < index + 1) || (index < 0))
3607          return TYPE_E_ELEMENTNOTFOUND;
3608
3609     TRACE("(%p) index %d\n", This, index);
3610
3611     if(!pTKind) return E_INVALIDARG;
3612
3613     /* search element n in list */
3614     for(i=0; i < index; i++)
3615     {
3616       if(!pTInfo)
3617       {
3618         TRACE("-- element not found\n");
3619         return TYPE_E_ELEMENTNOTFOUND;
3620       }
3621       pTInfo = pTInfo->next;
3622     }
3623
3624     *pTKind = pTInfo->TypeAttr.typekind;
3625     TRACE("-- found Type (%d)\n", *pTKind);
3626     return S_OK;
3627 }
3628
3629 /* ITypeLib::GetTypeInfoOfGuid
3630  *
3631  * Retrieves the type description that corresponds to the specified GUID.
3632  *
3633  */
3634 static HRESULT WINAPI ITypeLib2_fnGetTypeInfoOfGuid(
3635     ITypeLib2 *iface,
3636     REFGUID guid,
3637     ITypeInfo **ppTInfo)
3638 {
3639     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3640     ITypeInfoImpl *pTypeInfo = This->pTypeInfo; /* head of list */
3641
3642     TRACE("(%p)\n\tguid:\t%s)\n",This,debugstr_guid(guid));
3643
3644     if (!pTypeInfo)
3645     {
3646         WARN("-- element not found\n");
3647         return TYPE_E_ELEMENTNOTFOUND;
3648     }
3649
3650     /* search linked list for guid */
3651     while( !IsEqualIID(guid,&pTypeInfo->TypeAttr.guid) )
3652     {
3653       pTypeInfo = pTypeInfo->next;
3654
3655       if (!pTypeInfo)
3656       {
3657         /* end of list reached */
3658         WARN("-- element not found\n");
3659         return TYPE_E_ELEMENTNOTFOUND;
3660       }
3661     }
3662
3663     TRACE("-- found (%p, %s)\n",
3664           pTypeInfo,
3665           debugstr_w(pTypeInfo->Name));
3666
3667     *ppTInfo = (ITypeInfo*)pTypeInfo;
3668     ITypeInfo_AddRef(*ppTInfo);
3669     return S_OK;
3670 }
3671
3672 /* ITypeLib::GetLibAttr
3673  *
3674  * Retrieves the structure that contains the library's attributes.
3675  *
3676  */
3677 static HRESULT WINAPI ITypeLib2_fnGetLibAttr(
3678         ITypeLib2 *iface,
3679         LPTLIBATTR *ppTLibAttr)
3680 {
3681     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3682     TRACE("(%p)\n",This);
3683     *ppTLibAttr = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppTLibAttr));
3684     memcpy(*ppTLibAttr, &This->LibAttr, sizeof(**ppTLibAttr));
3685     return S_OK;
3686 }
3687
3688 /* ITypeLib::GetTypeComp
3689  *
3690  * Enables a client compiler to bind to a library's types, variables,
3691  * constants, and global functions.
3692  *
3693  */
3694 static HRESULT WINAPI ITypeLib2_fnGetTypeComp(
3695         ITypeLib2 *iface,
3696         ITypeComp **ppTComp)
3697 {
3698     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3699
3700     TRACE("(%p)->(%p)\n",This,ppTComp);
3701     *ppTComp = (ITypeComp *)&This->lpVtblTypeComp;
3702     ITypeComp_AddRef(*ppTComp);
3703
3704     return S_OK;
3705 }
3706
3707 /* ITypeLib::GetDocumentation
3708  *
3709  * Retrieves the library's documentation string, the complete Help file name
3710  * and path, and the context identifier for the library Help topic in the Help
3711  * file.
3712  *
3713  * On a successful return all non-null BSTR pointers will have been set,
3714  * possibly to NULL.
3715  */
3716 static HRESULT WINAPI ITypeLib2_fnGetDocumentation(
3717     ITypeLib2 *iface,
3718     INT index,
3719     BSTR *pBstrName,
3720     BSTR *pBstrDocString,
3721     DWORD *pdwHelpContext,
3722     BSTR *pBstrHelpFile)
3723 {
3724     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3725
3726     HRESULT result = E_INVALIDARG;
3727
3728     ITypeInfo *pTInfo;
3729
3730
3731     TRACE("(%p) index %d Name(%p) DocString(%p) HelpContext(%p) HelpFile(%p)\n",
3732         This, index,
3733         pBstrName, pBstrDocString,
3734         pdwHelpContext, pBstrHelpFile);
3735
3736     if(index<0)
3737     {
3738         /* documentation for the typelib */
3739         if(pBstrName)
3740         {
3741             if (This->Name)
3742             {
3743                 if(!(*pBstrName = SysAllocString(This->Name)))
3744                     goto memerr1;
3745             }
3746             else
3747                 *pBstrName = NULL;
3748         }
3749         if(pBstrDocString)
3750         {
3751             if (This->DocString)
3752             {
3753                 if(!(*pBstrDocString = SysAllocString(This->DocString)))
3754                     goto memerr2;
3755             }
3756             else if (This->Name)
3757             {
3758                 if(!(*pBstrDocString = SysAllocString(This->Name)))
3759                     goto memerr2;
3760             }
3761             else
3762                 *pBstrDocString = NULL;
3763         }
3764         if(pdwHelpContext)
3765         {
3766             *pdwHelpContext = This->dwHelpContext;
3767         }
3768         if(pBstrHelpFile)
3769         {
3770             if (This->HelpFile)
3771             {
3772                 if(!(*pBstrHelpFile = SysAllocString(This->HelpFile)))
3773                     goto memerr3;
3774             }
3775             else
3776                 *pBstrHelpFile = NULL;
3777         }
3778
3779         result = S_OK;
3780     }
3781     else
3782     {
3783         /* for a typeinfo */
3784         result = ITypeLib2_fnGetTypeInfo(iface, index, &pTInfo);
3785
3786         if(SUCCEEDED(result))
3787         {
3788             result = ITypeInfo_GetDocumentation(pTInfo,
3789                                           MEMBERID_NIL,
3790                                           pBstrName,
3791                                           pBstrDocString,
3792                                           pdwHelpContext, pBstrHelpFile);
3793
3794             ITypeInfo_Release(pTInfo);
3795         }
3796     }
3797     return result;
3798 memerr3:
3799     if (pBstrDocString) SysFreeString (*pBstrDocString);
3800 memerr2:
3801     if (pBstrName) SysFreeString (*pBstrName);
3802 memerr1:
3803     return STG_E_INSUFFICIENTMEMORY;
3804 }
3805
3806 /* ITypeLib::IsName
3807  *
3808  * Indicates whether a passed-in string contains the name of a type or member
3809  * described in the library.
3810  *
3811  */
3812 static HRESULT WINAPI ITypeLib2_fnIsName(
3813         ITypeLib2 *iface,
3814         LPOLESTR szNameBuf,
3815         ULONG lHashVal,
3816         BOOL *pfName)
3817 {
3818     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3819     ITypeInfoImpl *pTInfo;
3820     TLBFuncDesc *pFInfo;
3821     TLBVarDesc *pVInfo;
3822     int i;
3823     UINT nNameBufLen = (lstrlenW(szNameBuf)+1)*sizeof(WCHAR);
3824
3825     TRACE("(%p)->(%s,%08lx,%p)\n", This, debugstr_w(szNameBuf), lHashVal,
3826           pfName);
3827
3828     *pfName=TRUE;
3829     for(pTInfo=This->pTypeInfo;pTInfo;pTInfo=pTInfo->next){
3830         if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
3831         for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
3832             if(!memcmp(szNameBuf,pFInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
3833             for(i=0;i<pFInfo->funcdesc.cParams;i++)
3834                 if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name, nNameBufLen))
3835                     goto ITypeLib2_fnIsName_exit;
3836         }
3837         for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next)
3838             if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
3839
3840     }
3841     *pfName=FALSE;
3842
3843 ITypeLib2_fnIsName_exit:
3844     TRACE("(%p)slow! search for %s: %s found!\n", This,
3845           debugstr_w(szNameBuf), *pfName?"NOT":"");
3846
3847     return S_OK;
3848 }
3849
3850 /* ITypeLib::FindName
3851  *
3852  * Finds occurrences of a type description in a type library. This may be used
3853  * to quickly verify that a name exists in a type library.
3854  *
3855  */
3856 static HRESULT WINAPI ITypeLib2_fnFindName(
3857         ITypeLib2 *iface,
3858         LPOLESTR szNameBuf,
3859         ULONG lHashVal,
3860         ITypeInfo **ppTInfo,
3861         MEMBERID *rgMemId,
3862         UINT16 *pcFound)
3863 {
3864     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3865     ITypeInfoImpl *pTInfo;
3866     TLBFuncDesc *pFInfo;
3867     TLBVarDesc *pVInfo;
3868     int i,j = 0;
3869     UINT nNameBufLen = (lstrlenW(szNameBuf)+1)*sizeof(WCHAR);
3870
3871     for(pTInfo=This->pTypeInfo;pTInfo && j<*pcFound; pTInfo=pTInfo->next){
3872         if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit;
3873         for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
3874             if(!memcmp(szNameBuf,pFInfo->Name,nNameBufLen)) goto ITypeLib2_fnFindName_exit;
3875             for(i=0;i<pFInfo->funcdesc.cParams;i++) {
3876                 if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name,nNameBufLen))
3877                     goto ITypeLib2_fnFindName_exit;
3878             }
3879         }
3880         for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next)
3881             if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit;
3882         continue;
3883 ITypeLib2_fnFindName_exit:
3884         ITypeInfo_AddRef((ITypeInfo*)pTInfo);
3885         ppTInfo[j]=(LPTYPEINFO)pTInfo;
3886         j++;
3887     }
3888     TRACE("(%p)slow! search for %d with %s: found %d TypeInfo's!\n",
3889           This, *pcFound, debugstr_w(szNameBuf), j);
3890
3891     *pcFound=j;
3892
3893     return S_OK;
3894 }
3895
3896 /* ITypeLib::ReleaseTLibAttr
3897  *
3898  * Releases the TLIBATTR originally obtained from ITypeLib::GetLibAttr.
3899  *
3900  */
3901 static VOID WINAPI ITypeLib2_fnReleaseTLibAttr(
3902         ITypeLib2 *iface,
3903         TLIBATTR *pTLibAttr)
3904 {
3905     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3906     TRACE("freeing (%p)\n",This);
3907     HeapFree(GetProcessHeap(),0,pTLibAttr);
3908
3909 }
3910
3911 /* ITypeLib2::GetCustData
3912  *
3913  * gets the custom data
3914  */
3915 static HRESULT WINAPI ITypeLib2_fnGetCustData(
3916         ITypeLib2 * iface,
3917         REFGUID guid,
3918         VARIANT *pVarVal)
3919 {
3920     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3921     TLBCustData *pCData;
3922
3923     for(pCData=This->pCustData; pCData; pCData = pCData->next)
3924     {
3925       if( IsEqualIID(guid, &pCData->guid)) break;
3926     }
3927
3928     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
3929
3930     if(pCData)
3931     {
3932         VariantInit( pVarVal);
3933         VariantCopy( pVarVal, &pCData->data);
3934         return S_OK;
3935     }
3936     return E_INVALIDARG;  /* FIXME: correct? */
3937 }
3938
3939 /* ITypeLib2::GetLibStatistics
3940  *
3941  * Returns statistics about a type library that are required for efficient
3942  * sizing of hash tables.
3943  *
3944  */
3945 static HRESULT WINAPI ITypeLib2_fnGetLibStatistics(
3946         ITypeLib2 * iface,
3947         ULONG *pcUniqueNames,
3948         ULONG *pcchUniqueNames)
3949 {
3950     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3951
3952     FIXME("(%p): stub!\n", This);
3953
3954     if(pcUniqueNames) *pcUniqueNames=1;
3955     if(pcchUniqueNames) *pcchUniqueNames=1;
3956     return S_OK;
3957 }
3958
3959 /* ITypeLib2::GetDocumentation2
3960  *
3961  * Retrieves the library's documentation string, the complete Help file name
3962  * and path, the localization context to use, and the context ID for the
3963  * library Help topic in the Help file.
3964  *
3965  */
3966 static HRESULT WINAPI ITypeLib2_fnGetDocumentation2(
3967         ITypeLib2 * iface,
3968         INT index,
3969         LCID lcid,
3970         BSTR *pbstrHelpString,
3971         DWORD *pdwHelpStringContext,
3972         BSTR *pbstrHelpStringDll)
3973 {
3974     ITypeLibImpl *This = (ITypeLibImpl *)iface;
3975     HRESULT result;
3976     ITypeInfo *pTInfo;
3977
3978     FIXME("(%p) index %d lcid %ld half implemented stub!\n", This, index, lcid);
3979
3980     /* the help string should be obtained from the helpstringdll,
3981      * using the _DLLGetDocumentation function, based on the supplied
3982      * lcid. Nice to do sometime...
3983      */
3984     if(index<0)
3985     {
3986       /* documentation for the typelib */
3987       if(pbstrHelpString)
3988         *pbstrHelpString=SysAllocString(This->DocString);
3989       if(pdwHelpStringContext)
3990         *pdwHelpStringContext=This->dwHelpContext;
3991       if(pbstrHelpStringDll)
3992         *pbstrHelpStringDll=SysAllocString(This->HelpStringDll);
3993
3994       result = S_OK;
3995     }
3996     else
3997     {
3998       /* for a typeinfo */
3999       result=ITypeLib2_GetTypeInfo(iface, index, &pTInfo);
4000
4001       if(SUCCEEDED(result))
4002       {
4003         ITypeInfo2 * pTInfo2;
4004         result = ITypeInfo_QueryInterface(pTInfo,
4005                                           &IID_ITypeInfo2,
4006                                           (LPVOID*) &pTInfo2);
4007
4008         if(SUCCEEDED(result))
4009         {
4010           result = ITypeInfo2_GetDocumentation2(pTInfo2,
4011                                            MEMBERID_NIL,
4012                                            lcid,
4013                                            pbstrHelpString,
4014                                            pdwHelpStringContext,
4015                                            pbstrHelpStringDll);
4016
4017           ITypeInfo2_Release(pTInfo2);
4018         }
4019
4020         ITypeInfo_Release(pTInfo);
4021       }
4022     }
4023     return result;
4024 }
4025
4026 /* ITypeLib2::GetAllCustData
4027  *
4028  * Gets all custom data items for the library.
4029  *
4030  */
4031 static HRESULT WINAPI ITypeLib2_fnGetAllCustData(
4032         ITypeLib2 * iface,
4033         CUSTDATA *pCustData)
4034 {
4035     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4036     TLBCustData *pCData;
4037     int i;
4038     TRACE("(%p) returning %d items\n", This, This->ctCustData);
4039     pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
4040     if(pCustData->prgCustData ){
4041         pCustData->cCustData=This->ctCustData;
4042         for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
4043             pCustData->prgCustData[i].guid=pCData->guid;
4044             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
4045         }
4046     }else{
4047         ERR(" OUT OF MEMORY!\n");
4048         return E_OUTOFMEMORY;
4049     }
4050     return S_OK;
4051 }
4052
4053 static const ITypeLib2Vtbl tlbvt = {
4054     ITypeLib2_fnQueryInterface,
4055     ITypeLib2_fnAddRef,
4056     ITypeLib2_fnRelease,
4057     ITypeLib2_fnGetTypeInfoCount,
4058     ITypeLib2_fnGetTypeInfo,
4059     ITypeLib2_fnGetTypeInfoType,
4060     ITypeLib2_fnGetTypeInfoOfGuid,
4061     ITypeLib2_fnGetLibAttr,
4062     ITypeLib2_fnGetTypeComp,
4063     ITypeLib2_fnGetDocumentation,
4064     ITypeLib2_fnIsName,
4065     ITypeLib2_fnFindName,
4066     ITypeLib2_fnReleaseTLibAttr,
4067
4068     ITypeLib2_fnGetCustData,
4069     ITypeLib2_fnGetLibStatistics,
4070     ITypeLib2_fnGetDocumentation2,
4071     ITypeLib2_fnGetAllCustData
4072  };
4073
4074
4075 static HRESULT WINAPI ITypeLibComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
4076 {
4077     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4078
4079     return ITypeLib2_QueryInterface((ITypeLib *)This, riid, ppv);
4080 }
4081
4082 static ULONG WINAPI ITypeLibComp_fnAddRef(ITypeComp * iface)
4083 {
4084     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4085
4086     return ITypeLib2_AddRef((ITypeLib2 *)This);
4087 }
4088
4089 static ULONG WINAPI ITypeLibComp_fnRelease(ITypeComp * iface)
4090 {
4091     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4092
4093     return ITypeLib2_Release((ITypeLib2 *)This);
4094 }
4095
4096 static HRESULT WINAPI ITypeLibComp_fnBind(
4097     ITypeComp * iface,
4098     OLECHAR * szName,
4099     ULONG lHash,
4100     WORD wFlags,
4101     ITypeInfo ** ppTInfo,
4102     DESCKIND * pDescKind,
4103     BINDPTR * pBindPtr)
4104 {
4105     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4106     ITypeInfoImpl *pTypeInfo;
4107
4108     TRACE("(%s, 0x%lx, 0x%x, %p, %p, %p)\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
4109
4110     *pDescKind = DESCKIND_NONE;
4111     pBindPtr->lptcomp = NULL;
4112     *ppTInfo = NULL;
4113
4114     for (pTypeInfo = This->pTypeInfo; pTypeInfo; pTypeInfo = pTypeInfo->next)
4115     {
4116         TRACE("testing %s\n", debugstr_w(pTypeInfo->Name));
4117
4118         /* FIXME: check wFlags here? */
4119         /* FIXME: we should use a hash table to look this info up using lHash
4120          * instead of an O(n) search */
4121         if ((pTypeInfo->TypeAttr.typekind == TKIND_ENUM) ||
4122             (pTypeInfo->TypeAttr.typekind == TKIND_MODULE))
4123         {
4124             if (pTypeInfo->Name && !strcmpW(pTypeInfo->Name, szName))
4125             {
4126                 *pDescKind = DESCKIND_TYPECOMP;
4127                 pBindPtr->lptcomp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4128                 ITypeComp_AddRef(pBindPtr->lptcomp);
4129                 TRACE("module or enum: %s\n", debugstr_w(szName));
4130                 return S_OK;
4131             }
4132         }
4133
4134         if ((pTypeInfo->TypeAttr.typekind == TKIND_MODULE) ||
4135             (pTypeInfo->TypeAttr.typekind == TKIND_ENUM))
4136         {
4137             ITypeComp *pSubTypeComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4138             HRESULT hr;
4139
4140             hr = ITypeComp_Bind(pSubTypeComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
4141             if (SUCCEEDED(hr) && (*pDescKind != DESCKIND_NONE))
4142             {
4143                 TRACE("found in module or in enum: %s\n", debugstr_w(szName));
4144                 return S_OK;
4145             }
4146         }
4147
4148         if ((pTypeInfo->TypeAttr.typekind == TKIND_COCLASS) &&
4149             (pTypeInfo->TypeAttr.wTypeFlags & TYPEFLAG_FAPPOBJECT))
4150         {
4151             ITypeComp *pSubTypeComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4152             HRESULT hr;
4153             ITypeInfo *subtypeinfo;
4154             BINDPTR subbindptr;
4155             DESCKIND subdesckind;
4156
4157             hr = ITypeComp_Bind(pSubTypeComp, szName, lHash, wFlags,
4158                 &subtypeinfo, &subdesckind, &subbindptr);
4159             if (SUCCEEDED(hr) && (subdesckind != DESCKIND_NONE))
4160             {
4161                 TYPEDESC tdesc_appobject =
4162                 {
4163                     {
4164                         (TYPEDESC *)pTypeInfo->hreftype
4165                     },
4166                     VT_USERDEFINED
4167                 };
4168                 const VARDESC vardesc_appobject =
4169                 {
4170                     -2,         /* memid */
4171                     NULL,       /* lpstrSchema */
4172                     {
4173                         0       /* oInst */
4174                     },
4175                     {
4176                                 /* ELEMDESC */
4177                         {
4178                                 /* TYPEDESC */
4179                                 {
4180                                     &tdesc_appobject
4181                                 },
4182                                 VT_PTR
4183                         },
4184                     },
4185                     0,          /* wVarFlags */
4186                     VAR_STATIC  /* varkind */
4187                 };
4188
4189                 TRACE("found in implicit app object: %s\n", debugstr_w(szName));
4190
4191                 /* cleanup things filled in by Bind call so we can put our
4192                  * application object data in there instead */
4193                 switch (subdesckind)
4194                 {
4195                 case DESCKIND_FUNCDESC:
4196                     ITypeInfo_ReleaseFuncDesc(subtypeinfo, subbindptr.lpfuncdesc);
4197                     break;
4198                 case DESCKIND_VARDESC:
4199                     ITypeInfo_ReleaseVarDesc(subtypeinfo, subbindptr.lpvardesc);
4200                     break;
4201                 default:
4202                     break;
4203                 }
4204                 if (subtypeinfo) ITypeInfo_Release(subtypeinfo);
4205
4206                 if (pTypeInfo->hreftype == -1)
4207                     FIXME("no hreftype for interface %p\n", pTypeInfo);
4208
4209                 hr = TLB_AllocAndInitVarDesc(&vardesc_appobject, &pBindPtr->lpvardesc);
4210                 if (FAILED(hr))
4211                     return hr;
4212
4213                 *pDescKind = DESCKIND_IMPLICITAPPOBJ;
4214                 *ppTInfo = (ITypeInfo *)pTypeInfo;
4215                 ITypeInfo_AddRef(*ppTInfo);
4216                 return S_OK;
4217             }
4218         }
4219     }
4220
4221     TRACE("name not found %s\n", debugstr_w(szName));
4222     return S_OK;
4223 }
4224
4225 static HRESULT WINAPI ITypeLibComp_fnBindType(
4226     ITypeComp * iface,
4227     OLECHAR * szName,
4228     ULONG lHash,
4229     ITypeInfo ** ppTInfo,
4230     ITypeComp ** ppTComp)
4231 {
4232     FIXME("(%s, %lx, %p, %p): stub\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
4233     return E_NOTIMPL;
4234 }
4235
4236 static const ITypeCompVtbl tlbtcvt =
4237 {
4238
4239     ITypeLibComp_fnQueryInterface,
4240     ITypeLibComp_fnAddRef,
4241     ITypeLibComp_fnRelease,
4242
4243     ITypeLibComp_fnBind,
4244     ITypeLibComp_fnBindType
4245 };
4246
4247 /*================== ITypeInfo(2) Methods ===================================*/
4248 static ITypeInfo2 * WINAPI ITypeInfo_Constructor(void)
4249 {
4250     ITypeInfoImpl * pTypeInfoImpl;
4251
4252     pTypeInfoImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeInfoImpl));
4253     if (pTypeInfoImpl)
4254     {
4255       pTypeInfoImpl->lpVtbl = &tinfvt;
4256       pTypeInfoImpl->lpVtblTypeComp = &tcompvt;
4257       pTypeInfoImpl->ref=1;
4258       pTypeInfoImpl->hreftype = -1;
4259       pTypeInfoImpl->TypeAttr.memidConstructor = MEMBERID_NIL;
4260       pTypeInfoImpl->TypeAttr.memidDestructor = MEMBERID_NIL;
4261     }
4262     TRACE("(%p)\n", pTypeInfoImpl);
4263     return (ITypeInfo2*) pTypeInfoImpl;
4264 }
4265
4266 /* ITypeInfo::QueryInterface
4267  */
4268 static HRESULT WINAPI ITypeInfo_fnQueryInterface(
4269         ITypeInfo2 *iface,
4270         REFIID riid,
4271         VOID **ppvObject)
4272 {
4273     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4274
4275     TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
4276
4277     *ppvObject=NULL;
4278     if(IsEqualIID(riid, &IID_IUnknown) ||
4279             IsEqualIID(riid,&IID_ITypeInfo)||
4280             IsEqualIID(riid,&IID_ITypeInfo2))
4281         *ppvObject = This;
4282
4283     if(*ppvObject){
4284         ITypeInfo_AddRef(iface);
4285         TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
4286         return S_OK;
4287     }
4288     TRACE("-- Interface: E_NOINTERFACE\n");
4289     return E_NOINTERFACE;
4290 }
4291
4292 /* ITypeInfo::AddRef
4293  */
4294 static ULONG WINAPI ITypeInfo_fnAddRef( ITypeInfo2 *iface)
4295 {
4296     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4297     ULONG ref = InterlockedIncrement(&This->ref);
4298
4299     ITypeLib2_AddRef((ITypeLib2*)This->pTypeLib);
4300
4301     TRACE("(%p)->ref is %lu\n",This, ref);
4302     return ref;
4303 }
4304
4305 /* ITypeInfo::Release
4306  */
4307 static ULONG WINAPI ITypeInfo_fnRelease(ITypeInfo2 *iface)
4308 {
4309     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4310     ULONG ref = InterlockedDecrement(&This->ref);
4311
4312     TRACE("(%p)->(%lu)\n",This, ref);
4313
4314     if (ref)   {
4315       /* We don't release ITypeLib when ref=0 because
4316          it means that function is called by ITypeLib2_Release */
4317       ITypeLib2_Release((ITypeLib2*)This->pTypeLib);
4318     } else   {
4319       static int once = 0;
4320       if (!once)
4321       {
4322           once = 1;
4323           FIXME("destroy child objects\n");
4324       }
4325
4326       TRACE("destroying ITypeInfo(%p)\n",This);
4327       if (This->Name)
4328       {
4329           SysFreeString(This->Name);
4330           This->Name = 0;
4331       }
4332
4333       if (This->DocString)
4334       {
4335           SysFreeString(This->DocString);
4336           This->DocString = 0;
4337       }
4338
4339       if (This->DllName)
4340       {
4341           SysFreeString(This->DllName);
4342           This->DllName = 0;
4343       }
4344
4345       if (This->next)
4346       {
4347         ITypeInfo_Release((ITypeInfo*)This->next);
4348       }
4349
4350       HeapFree(GetProcessHeap(),0,This);
4351       return 0;
4352     }
4353     return ref;
4354 }
4355
4356 /* ITypeInfo::GetTypeAttr
4357  *
4358  * Retrieves a TYPEATTR structure that contains the attributes of the type
4359  * description.
4360  *
4361  */
4362 static HRESULT WINAPI ITypeInfo_fnGetTypeAttr( ITypeInfo2 *iface,
4363         LPTYPEATTR  *ppTypeAttr)
4364 {
4365     const ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4366     SIZE_T size;
4367
4368     TRACE("(%p)\n",This);
4369
4370     size = sizeof(**ppTypeAttr);
4371     if (This->TypeAttr.typekind == TKIND_ALIAS)
4372         size += TLB_SizeTypeDesc(&This->TypeAttr.tdescAlias, FALSE);
4373
4374     *ppTypeAttr = HeapAlloc(GetProcessHeap(), 0, size);
4375     if (!*ppTypeAttr)
4376         return E_OUTOFMEMORY;
4377
4378     memcpy(*ppTypeAttr, &This->TypeAttr, sizeof(**ppTypeAttr));
4379
4380     if (This->TypeAttr.typekind == TKIND_ALIAS)
4381         TLB_CopyTypeDesc(&(*ppTypeAttr)->tdescAlias,
4382             &This->TypeAttr.tdescAlias, (void *)(*ppTypeAttr + 1));
4383
4384     if((*ppTypeAttr)->typekind == TKIND_DISPATCH) {
4385         (*ppTypeAttr)->cFuncs = (*ppTypeAttr)->cbSizeVft / 4; /* This should include all the inherited
4386                                                                  funcs */
4387         (*ppTypeAttr)->cbSizeVft = 28; /* This is always the size of IDispatch's vtbl */
4388         (*ppTypeAttr)->wTypeFlags &= ~TYPEFLAG_FOLEAUTOMATION;
4389     }
4390     return S_OK;
4391 }
4392
4393 /* ITypeInfo::GetTypeComp
4394  *
4395  * Retrieves the ITypeComp interface for the type description, which enables a
4396  * client compiler to bind to the type description's members.
4397  *
4398  */
4399 static HRESULT WINAPI ITypeInfo_fnGetTypeComp( ITypeInfo2 *iface,
4400         ITypeComp  * *ppTComp)
4401 {
4402     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4403
4404     TRACE("(%p)->(%p) stub!\n", This, ppTComp);
4405
4406     *ppTComp = (ITypeComp *)&This->lpVtblTypeComp;
4407     ITypeComp_AddRef(*ppTComp);
4408     return S_OK;
4409 }
4410
4411 static SIZE_T TLB_SizeElemDesc( const ELEMDESC *elemdesc )
4412 {
4413     SIZE_T size = TLB_SizeTypeDesc(&elemdesc->tdesc, FALSE);
4414     if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
4415         size += sizeof(*elemdesc->u.paramdesc.pparamdescex);
4416     return size;
4417 }
4418
4419 static HRESULT TLB_CopyElemDesc( const ELEMDESC *src, ELEMDESC *dest, char **buffer )
4420 {
4421     memcpy(dest, src, sizeof(ELEMDESC));
4422     *buffer = TLB_CopyTypeDesc(&dest->tdesc, &src->tdesc, *buffer);
4423     if (src->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
4424     {
4425         const PARAMDESCEX *pparamdescex_src = src->u.paramdesc.pparamdescex;
4426         PARAMDESCEX *pparamdescex_dest = dest->u.paramdesc.pparamdescex = (PARAMDESCEX *)*buffer;
4427         *buffer += sizeof(PARAMDESCEX);
4428         memcpy(pparamdescex_dest, pparamdescex_src, sizeof(PARAMDESCEX));
4429         VariantInit(&pparamdescex_dest->varDefaultValue);
4430         return VariantCopy(&pparamdescex_dest->varDefaultValue, 
4431                            (VARIANTARG *)&pparamdescex_src->varDefaultValue);
4432     }
4433     else
4434         dest->u.paramdesc.pparamdescex = NULL;
4435     return S_OK;
4436 }
4437
4438 static void TLB_FreeElemDesc( ELEMDESC *elemdesc )
4439 {
4440     if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
4441         VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue);
4442 }
4443
4444 static HRESULT TLB_AllocAndInitFuncDesc( const FUNCDESC *src, FUNCDESC **dest_ptr, BOOL dispinterface )
4445 {
4446     FUNCDESC *dest;
4447     char *buffer;
4448     SIZE_T size = sizeof(*src);
4449     SHORT i;
4450     HRESULT hr;
4451
4452     size += sizeof(*src->lprgscode) * src->cScodes;
4453     size += TLB_SizeElemDesc(&src->elemdescFunc);
4454     for (i = 0; i < src->cParams; i++)
4455     {
4456         size += sizeof(ELEMDESC);
4457         size += TLB_SizeElemDesc(&src->lprgelemdescParam[i]);
4458     }
4459
4460     dest = (FUNCDESC *)SysAllocStringByteLen(NULL, size);
4461     if (!dest) return E_OUTOFMEMORY;
4462
4463     memcpy(dest, src, sizeof(FUNCDESC));
4464     buffer = (char *)(dest + 1);
4465
4466     dest->lprgscode = (SCODE *)buffer;
4467     memcpy(dest->lprgscode, src->lprgscode, sizeof(*src->lprgscode) * src->cScodes);
4468     buffer += sizeof(*src->lprgscode) * src->cScodes;
4469
4470     hr = TLB_CopyElemDesc(&src->elemdescFunc, &dest->elemdescFunc, &buffer);
4471     if (FAILED(hr))
4472     {
4473         SysFreeString((BSTR)dest);
4474         return hr;
4475     }
4476
4477     dest->lprgelemdescParam = (ELEMDESC *)buffer;
4478     buffer += sizeof(ELEMDESC) * src->cParams;
4479     for (i = 0; i < src->cParams; i++)
4480     {
4481         hr = TLB_CopyElemDesc(&src->lprgelemdescParam[i], &dest->lprgelemdescParam[i], &buffer);
4482         if (FAILED(hr))
4483             break;
4484     }
4485     if (FAILED(hr))
4486     {
4487         /* undo the above actions */
4488         for (i = i - 1; i >= 0; i--)
4489             TLB_FreeElemDesc(&dest->lprgelemdescParam[i]);
4490         TLB_FreeElemDesc(&dest->elemdescFunc);
4491         SysFreeString((BSTR)dest);
4492         return hr;
4493     }
4494
4495     /* special treatment for dispinterfaces: this makes functions appear
4496      * to return their [retval] value when it is really returning an
4497      * HRESULT */
4498     if (dispinterface && dest->elemdescFunc.tdesc.vt == VT_HRESULT)
4499     {
4500         if (dest->cParams &&
4501             (dest->lprgelemdescParam[dest->cParams - 1].u.paramdesc.wParamFlags & PARAMFLAG_FRETVAL))
4502         {
4503             ELEMDESC *elemdesc = &dest->lprgelemdescParam[dest->cParams - 1];
4504             if (elemdesc->tdesc.vt != VT_PTR)
4505             {
4506                 ERR("elemdesc should have started with VT_PTR instead of:\n");
4507                 if (ERR_ON(ole))
4508                     dump_ELEMDESC(elemdesc);
4509                 return E_UNEXPECTED;
4510             }
4511
4512             /* copy last parameter to the return value. we are using a flat
4513              * buffer so there is no danger of leaking memory in
4514              * elemdescFunc */
4515             dest->elemdescFunc.tdesc = *elemdesc->tdesc.u.lptdesc;
4516
4517             /* remove the last parameter */
4518             dest->cParams--;
4519         }
4520         else
4521             /* otherwise this function is made to appear to have no return
4522              * value */
4523             dest->elemdescFunc.tdesc.vt = VT_VOID;
4524
4525     }
4526
4527     *dest_ptr = dest;
4528     return S_OK;
4529 }
4530
4531 HRESULT ITypeInfoImpl_GetInternalFuncDesc( ITypeInfo *iface, UINT index, const FUNCDESC **ppFuncDesc )
4532 {
4533     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4534     const TLBFuncDesc *pFDesc;
4535     int i;
4536
4537     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++, pFDesc=pFDesc->next)
4538         ;
4539
4540     if (pFDesc)
4541     {
4542         *ppFuncDesc = &pFDesc->funcdesc;
4543         return S_OK;
4544     }
4545
4546     return E_INVALIDARG;
4547 }
4548
4549 /* ITypeInfo::GetFuncDesc
4550  *
4551  * Retrieves the FUNCDESC structure that contains information about a
4552  * specified function.
4553  *
4554  */
4555 static HRESULT WINAPI ITypeInfo_fnGetFuncDesc( ITypeInfo2 *iface, UINT index,
4556         LPFUNCDESC  *ppFuncDesc)
4557 {
4558     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4559     const FUNCDESC *internal_funcdesc;
4560     HRESULT hr;
4561
4562     TRACE("(%p) index %d\n", This, index);
4563
4564     hr = ITypeInfoImpl_GetInternalFuncDesc((ITypeInfo *)iface, index, &internal_funcdesc);
4565     if (FAILED(hr))
4566         return hr;
4567
4568     return TLB_AllocAndInitFuncDesc(
4569         internal_funcdesc,
4570         ppFuncDesc,
4571         This->TypeAttr.typekind == TKIND_DISPATCH);
4572 }
4573
4574 static HRESULT TLB_AllocAndInitVarDesc( const VARDESC *src, VARDESC **dest_ptr )
4575 {
4576     VARDESC *dest;
4577     char *buffer;
4578     SIZE_T size = sizeof(*src);
4579     HRESULT hr;
4580
4581     if (src->lpstrSchema) size += (strlenW(src->lpstrSchema) + 1) * sizeof(WCHAR);
4582     if (src->varkind == VAR_CONST)
4583         size += sizeof(VARIANT);
4584     size += TLB_SizeElemDesc(&src->elemdescVar);
4585
4586     dest = (VARDESC *)SysAllocStringByteLen(NULL, size);
4587     if (!dest) return E_OUTOFMEMORY;
4588
4589     *dest = *src;
4590     buffer = (char *)(dest + 1);
4591     if (src->lpstrSchema)
4592     {
4593         int len;
4594         dest->lpstrSchema = (LPOLESTR)buffer;
4595         len = strlenW(src->lpstrSchema);
4596         memcpy(dest->lpstrSchema, src->lpstrSchema, (len + 1) * sizeof(WCHAR));
4597         buffer += (len + 1) * sizeof(WCHAR);
4598     }
4599
4600     if (src->varkind == VAR_CONST)
4601     {
4602         HRESULT hr;
4603
4604         dest->u.lpvarValue = (VARIANT *)buffer;
4605         *dest->u.lpvarValue = *src->u.lpvarValue;
4606         buffer += sizeof(VARIANT);
4607         VariantInit(dest->u.lpvarValue);
4608         hr = VariantCopy(dest->u.lpvarValue, src->u.lpvarValue);
4609         if (FAILED(hr))
4610         {
4611             SysFreeString((BSTR)dest_ptr);
4612             return hr;
4613         }
4614     }
4615     hr = TLB_CopyElemDesc(&src->elemdescVar, &dest->elemdescVar, &buffer);
4616     if (FAILED(hr))
4617     {
4618         if (src->varkind == VAR_CONST)
4619             VariantClear(dest->u.lpvarValue);
4620         SysFreeString((BSTR)dest);
4621         return hr;
4622     }
4623     *dest_ptr = dest;
4624     return S_OK;
4625 }
4626
4627 /* ITypeInfo::GetVarDesc
4628  *
4629  * Retrieves a VARDESC structure that describes the specified variable.
4630  *
4631  */
4632 static HRESULT WINAPI ITypeInfo_fnGetVarDesc( ITypeInfo2 *iface, UINT index,
4633         LPVARDESC  *ppVarDesc)
4634 {
4635     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4636     int i;
4637     const TLBVarDesc *pVDesc;
4638
4639     TRACE("(%p) index %d\n", This, index);
4640
4641     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next)
4642         ;
4643
4644     if (pVDesc)
4645         return TLB_AllocAndInitVarDesc(&pVDesc->vardesc, ppVarDesc);
4646
4647     return E_INVALIDARG;
4648 }
4649
4650 /* ITypeInfo_GetNames
4651  *
4652  * Retrieves the variable with the specified member ID (or the name of the
4653  * property or method and its parameters) that correspond to the specified
4654  * function ID.
4655  */
4656 static HRESULT WINAPI ITypeInfo_fnGetNames( ITypeInfo2 *iface, MEMBERID memid,
4657         BSTR  *rgBstrNames, UINT cMaxNames, UINT  *pcNames)
4658 {
4659     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4660     const TLBFuncDesc *pFDesc;
4661     const TLBVarDesc *pVDesc;
4662     int i;
4663     TRACE("(%p) memid=0x%08lx Maxname=%d\n", This, memid, cMaxNames);
4664     for(pFDesc=This->funclist; pFDesc && pFDesc->funcdesc.memid != memid; pFDesc=pFDesc->next);
4665     if(pFDesc)
4666     {
4667       /* function found, now return function and parameter names */
4668       for(i=0; i<cMaxNames && i <= pFDesc->funcdesc.cParams; i++)
4669       {
4670         if(!i)
4671           *rgBstrNames=SysAllocString(pFDesc->Name);
4672         else
4673           rgBstrNames[i]=SysAllocString(pFDesc->pParamDesc[i-1].Name);
4674       }
4675       *pcNames=i;
4676     }
4677     else
4678     {
4679       for(pVDesc=This->varlist; pVDesc && pVDesc->vardesc.memid != memid; pVDesc=pVDesc->next);
4680       if(pVDesc)
4681       {
4682         *rgBstrNames=SysAllocString(pVDesc->Name);
4683         *pcNames=1;
4684       }
4685       else
4686       {
4687         if(This->TypeAttr.cImplTypes &&
4688            (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
4689           /* recursive search */
4690           ITypeInfo *pTInfo;
4691           HRESULT result;
4692           result=ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef,
4693                                           &pTInfo);
4694           if(SUCCEEDED(result))
4695           {
4696             result=ITypeInfo_GetNames(pTInfo, memid, rgBstrNames, cMaxNames, pcNames);
4697             ITypeInfo_Release(pTInfo);
4698             return result;
4699           }
4700           WARN("Could not search inherited interface!\n");
4701         }
4702         else
4703         {
4704           WARN("no names found\n");
4705         }
4706         *pcNames=0;
4707         return TYPE_E_ELEMENTNOTFOUND;
4708       }
4709     }
4710     return S_OK;
4711 }
4712
4713
4714 /* ITypeInfo::GetRefTypeOfImplType
4715  *
4716  * If a type description describes a COM class, it retrieves the type
4717  * description of the implemented interface types. For an interface,
4718  * GetRefTypeOfImplType returns the type information for inherited interfaces,
4719  * if any exist.
4720  *
4721  */
4722 static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType(
4723         ITypeInfo2 *iface,
4724         UINT index,
4725         HREFTYPE  *pRefType)
4726 {
4727     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4728     int i;
4729     HRESULT hr = S_OK;
4730     const TLBImplType *pImpl = This->impltypelist;
4731
4732     TRACE("(%p) index %d\n", This, index);
4733     if (TRACE_ON(ole)) dump_TypeInfo(This);
4734
4735     if(index==(UINT)-1)
4736     {
4737       /* only valid on dual interfaces;
4738          retrieve the associated TKIND_INTERFACE handle for the current TKIND_DISPATCH
4739       */
4740       if( This->TypeAttr.typekind != TKIND_DISPATCH) return E_INVALIDARG;
4741
4742       if (This->TypeAttr.wTypeFlags & TYPEFLAG_FDISPATCHABLE &&
4743           This->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL )
4744       {
4745         *pRefType = -1;
4746       }
4747       else
4748       {
4749         hr = TYPE_E_ELEMENTNOTFOUND;
4750       }
4751     }
4752     else
4753     {
4754       /* get element n from linked list */
4755       for(i=0; pImpl && i<index; i++)
4756       {
4757         pImpl = pImpl->next;
4758       }
4759
4760       if (pImpl)
4761         *pRefType = pImpl->hRef;
4762       else
4763         hr = TYPE_E_ELEMENTNOTFOUND;
4764     }
4765
4766     if(TRACE_ON(ole))
4767     {
4768         if(SUCCEEDED(hr))
4769             TRACE("SUCCESS -- hRef = 0x%08lx\n", *pRefType );
4770         else
4771             TRACE("FAILURE -- hresult = 0x%08lx\n", hr);
4772     }
4773
4774     return hr;
4775 }
4776
4777 /* ITypeInfo::GetImplTypeFlags
4778  *
4779  * Retrieves the IMPLTYPEFLAGS enumeration for one implemented interface
4780  * or base interface in a type description.
4781  */
4782 static HRESULT WINAPI ITypeInfo_fnGetImplTypeFlags( ITypeInfo2 *iface,
4783         UINT index, INT  *pImplTypeFlags)
4784 {
4785     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4786     int i;
4787     TLBImplType *pImpl;
4788
4789     TRACE("(%p) index %d\n", This, index);
4790     for(i=0, pImpl=This->impltypelist; i<index && pImpl;
4791         i++, pImpl=pImpl->next)
4792         ;
4793     if(i==index && pImpl){
4794         *pImplTypeFlags=pImpl->implflags;
4795         return S_OK;
4796     }
4797     *pImplTypeFlags=0;
4798     return TYPE_E_ELEMENTNOTFOUND;
4799 }
4800
4801 /* GetIDsOfNames
4802  * Maps between member names and member IDs, and parameter names and
4803  * parameter IDs.
4804  */
4805 static HRESULT WINAPI ITypeInfo_fnGetIDsOfNames( ITypeInfo2 *iface,
4806         LPOLESTR  *rgszNames, UINT cNames, MEMBERID  *pMemId)
4807 {
4808     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4809     const TLBFuncDesc *pFDesc;
4810     const TLBVarDesc *pVDesc;
4811     HRESULT ret=S_OK;
4812     int i;
4813
4814     TRACE("(%p) Name %s cNames %d\n", This, debugstr_w(*rgszNames),
4815             cNames);
4816
4817     /* init out parameters in case of failure */
4818     for (i = 0; i < cNames; i++)
4819         pMemId[i] = MEMBERID_NIL;
4820
4821     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next) {
4822         int j;
4823         if(!lstrcmpiW(*rgszNames, pFDesc->Name)) {
4824             if(cNames) *pMemId=pFDesc->funcdesc.memid;
4825             for(i=1; i < cNames; i++){
4826                 for(j=0; j<pFDesc->funcdesc.cParams; j++)
4827                     if(!lstrcmpiW(rgszNames[i],pFDesc->pParamDesc[j].Name))
4828                             break;
4829                 if( j<pFDesc->funcdesc.cParams)
4830                     pMemId[i]=j;
4831                 else
4832                    ret=DISP_E_UNKNOWNNAME;
4833             };
4834             TRACE("-- 0x%08lx\n", ret);
4835             return ret;
4836         }
4837     }
4838     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) {
4839         if(!lstrcmpiW(*rgszNames, pVDesc->Name)) {
4840             if(cNames) *pMemId=pVDesc->vardesc.memid;
4841             return ret;
4842         }
4843     }
4844     /* not found, see if it can be found in an inherited interface */
4845     if(This->TypeAttr.cImplTypes) {
4846         /* recursive search */
4847         ITypeInfo *pTInfo;
4848         ret=ITypeInfo_GetRefTypeInfo(iface,
4849                 This->impltypelist->hRef, &pTInfo);
4850         if(SUCCEEDED(ret)){
4851             ret=ITypeInfo_GetIDsOfNames(pTInfo, rgszNames, cNames, pMemId );
4852             ITypeInfo_Release(pTInfo);
4853             return ret;
4854         }
4855         WARN("Could not search inherited interface!\n");
4856     } else
4857         WARN("no names found\n");
4858     return DISP_E_UNKNOWNNAME;
4859 }
4860
4861 /* ITypeInfo::Invoke
4862  *
4863  * Invokes a method, or accesses a property of an object, that implements the
4864  * interface described by the type description.
4865  */
4866 DWORD
4867 _invoke(FARPROC func,CALLCONV callconv, int nrargs, DWORD *args) {
4868     DWORD res;
4869
4870     if (TRACE_ON(ole)) {
4871         int i;
4872         TRACE("Calling %p(",func);
4873         for (i=0;i<nrargs;i++) TRACE("%08lx,",args[i]);
4874         TRACE(")\n");
4875     }
4876
4877     switch (callconv) {
4878     case CC_STDCALL:
4879
4880         switch (nrargs) {
4881         case 0:
4882                 res = func();
4883                 break;
4884         case 1:
4885                 res = func(args[0]);
4886                 break;
4887         case 2:
4888                 res = func(args[0],args[1]);
4889                 break;
4890         case 3:
4891                 res = func(args[0],args[1],args[2]);
4892                 break;
4893         case 4:
4894                 res = func(args[0],args[1],args[2],args[3]);
4895                 break;
4896         case 5:
4897                 res = func(args[0],args[1],args[2],args[3],args[4]);
4898                 break;
4899         case 6:
4900                 res = func(args[0],args[1],args[2],args[3],args[4],args[5]);
4901                 break;
4902         case 7:
4903                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
4904                 break;
4905         case 8:
4906                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]);
4907                 break;
4908         case 9:
4909                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]);
4910                 break;
4911         case 10:
4912                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9]);
4913                 break;
4914         case 11:
4915                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10]);
4916                 break;
4917         case 12:
4918                 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]);
4919                 break;
4920         case 13:
4921                 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]);
4922                 break;
4923         case 14:
4924                 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]);
4925                 break;
4926         case 15:
4927                 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]);
4928                 break;
4929         case 16:
4930                 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]);
4931                 break;
4932         case 17:
4933                 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]);
4934                 break;
4935         case 18:
4936                 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]);
4937                 break;
4938         case 19:
4939                 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]);
4940                 break;
4941         case 20:
4942                 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]);
4943                 break;
4944         case 21:
4945                 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]);
4946                 break;
4947         case 22:
4948                 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]);
4949                 break;
4950         case 23:
4951                 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]);
4952                 break;
4953         default:
4954                 FIXME("unsupported number of arguments %d in stdcall\n",nrargs);
4955                 res = -1;
4956                 break;
4957         }
4958         break;
4959     default:
4960         FIXME("unsupported calling convention %d\n",callconv);
4961         res = -1;
4962         break;
4963     }
4964     TRACE("returns %08lx\n",res);
4965     return res;
4966 }
4967
4968 extern int _argsize(DWORD vt);
4969
4970 static HRESULT userdefined_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
4971 {
4972     HRESULT hr = S_OK;
4973     ITypeInfo *tinfo2 = NULL;
4974     TYPEATTR *tattr = NULL;
4975
4976     hr = ITypeInfo_GetRefTypeInfo(tinfo, tdesc->u.hreftype, &tinfo2);
4977     if (hr)
4978     {
4979         ERR("Could not get typeinfo of hreftype %lx for VT_USERDEFINED, "
4980             "hr = 0x%08lx\n",
4981               tdesc->u.hreftype, hr);
4982         return hr;
4983     }
4984     hr = ITypeInfo_GetTypeAttr(tinfo2, &tattr);
4985     if (hr)
4986     {
4987         ERR("ITypeInfo_GetTypeAttr failed, hr = 0x%08lx\n", hr);
4988         ITypeInfo_Release(tinfo2);
4989         return hr;
4990     }
4991
4992     switch (tattr->typekind)
4993     {
4994     case TKIND_ENUM:
4995         *vt |= VT_I4;
4996         break;
4997
4998     case TKIND_ALIAS:
4999         tdesc = &tattr->tdescAlias;
5000         hr = typedescvt_to_variantvt(tinfo2, &tattr->tdescAlias, vt);
5001         break;
5002
5003     case TKIND_INTERFACE:
5004         if (IsEqualIID(&IID_IDispatch, &tattr->guid))
5005            *vt |= VT_DISPATCH;
5006         else
5007            *vt |= VT_UNKNOWN;
5008         break;
5009
5010     case TKIND_DISPATCH:
5011         *vt |= VT_DISPATCH;
5012         break;
5013
5014     case TKIND_RECORD:
5015         FIXME("TKIND_RECORD unhandled.\n");
5016         hr = E_NOTIMPL;
5017         break;
5018
5019     case TKIND_UNION:
5020         FIXME("TKIND_UNION unhandled.\n");
5021         hr = E_NOTIMPL;
5022         break;
5023
5024     default:
5025         FIXME("TKIND %d unhandled.\n",tattr->typekind);
5026         hr = E_NOTIMPL;
5027         break;
5028     }
5029     ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
5030     ITypeInfo_Release(tinfo2);
5031     return hr;
5032 }
5033
5034 static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
5035 {
5036     HRESULT hr = S_OK;
5037
5038     /* enforce only one level of pointer indirection */
5039     if (!(*vt & VT_BYREF) && !(*vt & VT_ARRAY) && (tdesc->vt == VT_PTR))
5040     {
5041         tdesc = tdesc->u.lptdesc;
5042
5043         /* munch VT_PTR -> VT_USERDEFINED(interface) into VT_UNKNOWN or
5044          * VT_DISPATCH and VT_PTR -> VT_PTR -> VT_USERDEFINED(interface) into 
5045          * VT_BYREF|VT_DISPATCH or VT_BYREF|VT_UNKNOWN */
5046         if ((tdesc->vt == VT_USERDEFINED) ||
5047             ((tdesc->vt == VT_PTR) && (tdesc->u.lptdesc->vt == VT_USERDEFINED)))
5048         {
5049             VARTYPE vt_userdefined = 0;
5050             const TYPEDESC *tdesc_userdefined = tdesc;
5051             if (tdesc->vt == VT_PTR)
5052             {
5053                 vt_userdefined = VT_BYREF;
5054                 tdesc_userdefined = tdesc->u.lptdesc;
5055             }
5056             hr = userdefined_to_variantvt(tinfo, tdesc_userdefined, &vt_userdefined);
5057             if ((hr == S_OK) && 
5058                 (((vt_userdefined & VT_TYPEMASK) == VT_UNKNOWN) ||
5059                  ((vt_userdefined & VT_TYPEMASK) == VT_DISPATCH)))
5060             {
5061                 *vt |= vt_userdefined;
5062                 return S_OK;
5063             }
5064         }
5065         *vt = VT_BYREF;
5066     }
5067
5068     switch (tdesc->vt)
5069     {
5070     case VT_HRESULT:
5071         *vt |= VT_ERROR;
5072         break;
5073     case VT_USERDEFINED:
5074         hr = userdefined_to_variantvt(tinfo, tdesc, vt);
5075         break;
5076     case VT_VOID:
5077     case VT_CARRAY:
5078     case VT_PTR:
5079     case VT_LPSTR:
5080     case VT_LPWSTR:
5081         ERR("cannot convert type %d into variant VT\n", tdesc->vt);
5082         hr = DISP_E_BADVARTYPE;
5083         break;
5084     case VT_SAFEARRAY:
5085         *vt |= VT_ARRAY;
5086         hr = typedescvt_to_variantvt(tinfo, tdesc->u.lptdesc, vt);
5087         break;
5088     default:
5089         *vt |= tdesc->vt;
5090         break;
5091     }
5092     return hr;
5093 }
5094
5095 /***********************************************************************
5096  *              DispCallFunc (OLEAUT32.@)
5097  *
5098  * Invokes a function of the specifed calling convention, passing the
5099  * specified arguments and returns the result.
5100  *
5101  * PARAMS
5102  *  pvInstance  [I] Optional pointer to the instance whose function to invoke.
5103  *  oVft        [I] The offset in the vtable. See notes.
5104  *  cc          [I] Calling convention of the function to call.
5105  *  vtReturn    [I] The return type of the function.
5106  *  cActuals    [I] Number of parameters.
5107  *  prgvt       [I] The types of the parameters to pass. This is used for sizing only.
5108  *  prgpvarg    [I] The arguments to pass.
5109  *  pvargResult [O] The return value of the function. Can be NULL.
5110  *
5111  * RETURNS
5112  *  Success: S_OK.
5113  *  Failure: HRESULT code.
5114  *
5115  * NOTES
5116  *  The HRESULT return value of this function is not affected by the return
5117  *  value of the user supplied function, which is returned in pvargResult.
5118  *
5119  *  If pvInstance is NULL then a non-object function is to be called and oVft
5120  *  is the address of the function to call.
5121  *
5122  * The cc parameter can be one of the following values:
5123  *|CC_FASTCALL
5124  *|CC_CDECL
5125  *|CC_PASCAL
5126  *|CC_STDCALL
5127  *|CC_FPFASTCALL
5128  *|CC_SYSCALL
5129  *|CC_MPWCDECL
5130  *|CC_MPWPASCAL
5131  *
5132  */
5133 HRESULT WINAPI
5134 DispCallFunc(
5135     void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals,
5136     VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult)
5137 {
5138     int i, argsize, argspos;
5139     DWORD *args;
5140     HRESULT hres;
5141
5142     TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
5143         pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
5144         pvargResult, V_VT(pvargResult));
5145
5146     argsize = 0;
5147     if (pvInstance)
5148         argsize++; /* for This pointer */
5149
5150     for (i=0;i<cActuals;i++)
5151     {
5152         TRACE("arg %d: type %d, size %d\n",i,prgvt[i],_argsize(prgvt[i]));
5153         dump_Variant(prgpvarg[i]);
5154         argsize += _argsize(prgvt[i]);
5155     }
5156     args = HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*argsize);
5157
5158     argspos = 0;
5159     if (pvInstance)
5160     {
5161         args[0] = (DWORD)pvInstance; /* the This pointer is always the first parameter */
5162         argspos++;
5163     }
5164
5165     for (i=0;i<cActuals;i++)
5166     {
5167         VARIANT *arg = prgpvarg[i];
5168         TRACE("Storing arg %d (%d as %d)\n",i,V_VT(arg),prgvt[i]);
5169         if (prgvt[i] == VT_VARIANT)
5170             memcpy(&args[argspos], arg, _argsize(prgvt[i]) * sizeof(DWORD));
5171         else
5172             memcpy(&args[argspos], &V_NONE(arg), _argsize(prgvt[i]) * sizeof(DWORD));
5173         argspos += _argsize(prgvt[i]);
5174     }
5175
5176     if (pvInstance)
5177     {
5178         FARPROC *vtable = *(FARPROC**)pvInstance;
5179         hres = _invoke(vtable[oVft/sizeof(void *)], cc, argsize, args);
5180     }
5181     else
5182         /* if we aren't invoking an object then the function pointer is stored
5183          * in oVft */
5184         hres = _invoke((FARPROC)oVft, cc, argsize, args);
5185
5186     if (pvargResult && (vtReturn != VT_EMPTY))
5187     {
5188         TRACE("Method returned 0x%08lx\n",hres);
5189         V_VT(pvargResult) = vtReturn;
5190         V_UI4(pvargResult) = hres;
5191     }
5192
5193     HeapFree(GetProcessHeap(),0,args);
5194     return S_OK;
5195 }
5196
5197 #define INVBUF_ELEMENT_SIZE \
5198     (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *) + sizeof(VARTYPE))
5199 #define INVBUF_GET_ARG_ARRAY(buffer, params) \
5200     ((VARIANTARG *)(buffer))
5201 #define INVBUF_GET_MISSING_ARG_ARRAY(buffer, params) \
5202     ((VARIANTARG *)((char *)(buffer) + sizeof(VARIANTARG) * (params)))
5203 #define INVBUF_GET_ARG_PTR_ARRAY(buffer, params) \
5204     ((VARIANTARG **)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG)) * (params)))
5205 #define INVBUF_GET_ARG_TYPE_ARRAY(buffer, params) \
5206     ((VARTYPE *)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *)) * (params)))
5207
5208 static HRESULT WINAPI ITypeInfo_fnInvoke(
5209     ITypeInfo2 *iface,
5210     VOID  *pIUnk,
5211     MEMBERID memid,
5212     UINT16 wFlags,
5213     DISPPARAMS  *pDispParams,
5214     VARIANT  *pVarResult,
5215     EXCEPINFO  *pExcepInfo,
5216     UINT  *pArgErr)
5217 {
5218     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5219     int i;
5220     unsigned int var_index;
5221     TYPEKIND type_kind;
5222     HRESULT hres;
5223     const TLBFuncDesc *pFuncInfo;
5224
5225     TRACE("(%p)(%p,id=%ld,flags=0x%08x,%p,%p,%p,%p)\n",
5226       This,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr
5227     );
5228
5229     if (!pDispParams)
5230     {
5231         ERR("NULL pDispParams not allowed\n");
5232         return E_INVALIDARG;
5233     }
5234
5235     dump_DispParms(pDispParams);
5236
5237     if (pDispParams->cNamedArgs > pDispParams->cArgs)
5238     {
5239         ERR("named argument array cannot be bigger than argument array (%d/%d)\n",
5240             pDispParams->cNamedArgs, pDispParams->cArgs);
5241         return E_INVALIDARG;
5242     }
5243
5244     /* we do this instead of using GetFuncDesc since it will return a fake
5245      * FUNCDESC for dispinterfaces and we want the real function description */
5246     for (pFuncInfo = This->funclist; pFuncInfo; pFuncInfo=pFuncInfo->next)
5247         if ((memid == pFuncInfo->funcdesc.memid) &&
5248             (wFlags & pFuncInfo->funcdesc.invkind))
5249             break;
5250
5251     if (pFuncInfo) {
5252         const FUNCDESC *func_desc = &pFuncInfo->funcdesc;
5253
5254         if (TRACE_ON(ole))
5255         {
5256             TRACE("invoking:\n");
5257             dump_TLBFuncDescOne(pFuncInfo);
5258         }
5259         
5260         switch (func_desc->funckind) {
5261         case FUNC_PUREVIRTUAL:
5262         case FUNC_VIRTUAL: {
5263             void *buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INVBUF_ELEMENT_SIZE * func_desc->cParams);
5264             VARIANT varresult;
5265             VARIANT retval; /* pointer for storing byref retvals in */
5266             VARIANTARG **prgpvarg = INVBUF_GET_ARG_PTR_ARRAY(buffer, func_desc->cParams);
5267             VARIANTARG *rgvarg = INVBUF_GET_ARG_ARRAY(buffer, func_desc->cParams);
5268             VARTYPE *rgvt = INVBUF_GET_ARG_TYPE_ARRAY(buffer, func_desc->cParams);
5269
5270             hres = S_OK;
5271             for (i = 0; i < func_desc->cParams; i++)
5272             {
5273                 TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc;
5274                 hres = typedescvt_to_variantvt((ITypeInfo *)iface, tdesc, &rgvt[i]);
5275                 if (FAILED(hres))
5276                     goto func_fail;
5277             }
5278
5279             TRACE("changing args\n");
5280             for (i = 0; i < func_desc->cParams; i++)
5281             {
5282                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
5283
5284                 if (wParamFlags & PARAMFLAG_FRETVAL)
5285                 {
5286                     /* note: this check is placed so that if the caller passes
5287                      * in a VARIANTARG for the retval we just ignore it, like
5288                      * native does */
5289                     if (i == func_desc->cParams - 1)
5290                     {
5291                         VARIANTARG *arg;
5292                         arg = prgpvarg[i] = &rgvarg[i];
5293                         memset(arg, 0, sizeof(*arg));
5294                         V_VT(arg) = rgvt[i];
5295                         memset(&retval, 0, sizeof(retval));
5296                         V_BYREF(arg) = &retval;
5297                     }
5298                     else
5299                     {
5300                         ERR("[retval] parameter must be the last parameter of the method (%d/%d)\n", i, func_desc->cParams);
5301                         hres = E_UNEXPECTED;
5302                         break;
5303                     }
5304                 }
5305                 else if (i < pDispParams->cArgs)
5306                 {
5307                     VARIANTARG *src_arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - i];
5308                     dump_Variant(src_arg);
5309
5310                     if (rgvt[i] == VT_VARIANT)
5311                         hres = VariantCopy(&rgvarg[i], src_arg);
5312                     else if (rgvt[i] == (VT_VARIANT | VT_BYREF))
5313                     {
5314                         if (rgvt[i] == V_VT(src_arg))
5315                             V_VARIANTREF(&rgvarg[i]) = V_VARIANTREF(src_arg);
5316                         else
5317                         {
5318                             VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
5319                             hres = VariantCopy(&missing_arg[i], src_arg);
5320                             V_VARIANTREF(&rgvarg[i]) = &missing_arg[i];
5321                         }
5322                         V_VT(&rgvarg[i]) = rgvt[i];
5323                     }
5324                     else if ((rgvt[i] & VT_BYREF) && !V_ISBYREF(src_arg))
5325                     {
5326                         VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
5327                         V_VT(&missing_arg[i]) = V_VT(src_arg);
5328                         hres = VariantChangeType(&missing_arg[i], src_arg, 0, rgvt[i] & ~VT_BYREF);
5329                         V_BYREF(&rgvarg[i]) = &V_NONE(&missing_arg[i]);
5330                         V_VT(&rgvarg[i]) = rgvt[i];
5331                     }
5332                     else if ((rgvt[i] & VT_BYREF) && (rgvt[i] == V_VT(src_arg)))
5333                     {
5334                         V_BYREF(&rgvarg[i]) = V_BYREF(src_arg);
5335                         V_VT(&rgvarg[i]) = rgvt[i];
5336                     }
5337                     else
5338                     {
5339                         /* FIXME: this doesn't work for VT_BYREF arguments if
5340                          * they are not the same type as in the paramdesc */
5341                         V_VT(&rgvarg[i]) = V_VT(src_arg);
5342                         hres = VariantChangeType(&rgvarg[i], src_arg, 0, rgvt[i]);
5343                         V_VT(&rgvarg[i]) = rgvt[i];
5344                     }
5345
5346                     if (FAILED(hres))
5347                     {
5348                         ERR("failed to convert param %d to %s%s from %s%s\n", i,
5349                             debugstr_vt(rgvt[i]), debugstr_vf(rgvt[i]),
5350                             debugstr_VT(src_arg), debugstr_VF(src_arg));
5351                         break;
5352                     }
5353                     prgpvarg[i] = &rgvarg[i];
5354                 }
5355                 else if (wParamFlags & PARAMFLAG_FOPT)
5356                 {
5357                     VARIANTARG *arg;
5358                     arg = prgpvarg[i] = &rgvarg[i];
5359                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
5360                     {
5361                         hres = VariantCopy(arg, &func_desc->lprgelemdescParam[i].u.paramdesc.pparamdescex->varDefaultValue);
5362                         if (FAILED(hres))
5363                             break;
5364                     }
5365                     else
5366                     {
5367                         VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
5368                         V_VT(arg) = VT_VARIANT | VT_BYREF;
5369                         V_VARIANTREF(arg) = &missing_arg[i];
5370                         V_VT(V_VARIANTREF(arg)) = VT_ERROR;
5371                         V_ERROR(V_VARIANTREF(arg)) = DISP_E_PARAMNOTFOUND;
5372                     }
5373                 }
5374                 else
5375                 {
5376                     hres = DISP_E_BADPARAMCOUNT;
5377                     break;
5378                 }
5379             }
5380             if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
5381             if (func_desc->cParamsOpt < 0)
5382             {
5383                 FIXME("Does not support safearray optional parameters\n");
5384                 hres = DISP_E_BADPARAMCOUNT;
5385                 goto func_fail; /* FIXME: we don't free changed types here */
5386             }
5387
5388             /* VT_VOID is a special case for return types, so it is not
5389              * handled in the general function */
5390             if (func_desc->elemdescFunc.tdesc.vt == VT_VOID)
5391                 V_VT(&varresult) = VT_EMPTY;
5392             else
5393             {
5394                 V_VT(&varresult) = 0;
5395                 hres = typedescvt_to_variantvt((ITypeInfo *)iface, &func_desc->elemdescFunc.tdesc, &V_VT(&varresult));
5396                 if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
5397             }
5398
5399             hres = DispCallFunc(pIUnk, func_desc->oVft, func_desc->callconv,
5400                                 V_VT(&varresult), func_desc->cParams, rgvt,
5401                                 prgpvarg, &varresult);
5402
5403             for (i = 0; i < func_desc->cParams; i++)
5404             {
5405                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
5406                 if (wParamFlags & PARAMFLAG_FRETVAL)
5407                 {
5408                     if (TRACE_ON(ole))
5409                     {
5410                         TRACE("[retval] value: ");
5411                         dump_Variant(prgpvarg[i]);
5412                     }
5413
5414                     if (pVarResult)
5415                     {
5416                         VariantInit(pVarResult);
5417                         /* deref return value */
5418                         hres = VariantCopyInd(pVarResult, prgpvarg[i]);
5419                     }
5420
5421                     /* free data stored in varresult. Note that
5422                      * VariantClear doesn't do what we want because we are
5423                      * working with byref types. */
5424                     /* FIXME: clear safearrays, bstrs, records and
5425                      * variants here too */
5426                     if ((V_VT(prgpvarg[i]) == (VT_UNKNOWN | VT_BYREF)) ||
5427                          (V_VT(prgpvarg[i]) == (VT_DISPATCH | VT_BYREF)))
5428                     {
5429                         if(*V_UNKNOWNREF(prgpvarg[i]))
5430                             IUnknown_Release(*V_UNKNOWNREF(prgpvarg[i]));
5431                     }
5432                     break;
5433                 }
5434                 else if (i < pDispParams->cArgs)
5435                 {
5436                     if (wParamFlags & PARAMFLAG_FOUT)
5437                     {
5438                         VARIANTARG *arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - i];
5439
5440                         if ((rgvt[i] == VT_BYREF) && (V_VT(arg) != VT_BYREF))
5441                             hres = VariantChangeType(arg, &rgvarg[i], 0, V_VT(arg));
5442
5443                         if (FAILED(hres))
5444                         {
5445                             ERR("failed to convert param %d to vt %d\n", i,
5446                                 V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1 - i]));
5447                             break;
5448                         }
5449                     }
5450                     VariantClear(&rgvarg[i]);
5451                 }
5452                 else if (wParamFlags & PARAMFLAG_FOPT)
5453                 {
5454                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
5455                         VariantClear(&rgvarg[i]);
5456                 }
5457             }
5458
5459             if ((V_VT(&varresult) == VT_ERROR) && FAILED(V_ERROR(&varresult)))
5460             {
5461                 WARN("invoked function failed with error 0x%08lx\n", V_ERROR(&varresult));
5462                 hres = DISP_E_EXCEPTION;
5463                 if (pExcepInfo) pExcepInfo->scode = V_ERROR(&varresult);
5464             }
5465
5466 func_fail:
5467             HeapFree(GetProcessHeap(), 0, buffer);
5468             break;
5469         }
5470         case FUNC_DISPATCH:  {
5471            IDispatch *disp;
5472
5473            hres = IUnknown_QueryInterface((LPUNKNOWN)pIUnk,&IID_IDispatch,(LPVOID*)&disp);
5474            if (SUCCEEDED(hres)) {
5475                FIXME("Calling Invoke in IDispatch iface. untested!\n");
5476                hres = IDispatch_Invoke(
5477                                      disp,memid,&IID_NULL,LOCALE_USER_DEFAULT,wFlags,pDispParams,
5478                                      pVarResult,pExcepInfo,pArgErr
5479                                      );
5480                if (FAILED(hres))
5481                    FIXME("IDispatch::Invoke failed with %08lx. (Could be not a real error?)\n", hres);
5482                IDispatch_Release(disp);
5483            } else
5484                FIXME("FUNC_DISPATCH used on object without IDispatch iface?\n");
5485            break;
5486         }
5487         default:
5488             FIXME("Unknown function invocation type %d\n", func_desc->funckind);
5489             hres = E_FAIL;
5490             break;
5491         }
5492
5493         TRACE("-- 0x%08lx\n", hres);
5494         return hres;
5495
5496     } else if(SUCCEEDED(hres = ITypeInfo2_GetVarIndexOfMemId(iface, memid, &var_index))) {
5497         VARDESC *var_desc;
5498
5499         hres = ITypeInfo2_GetVarDesc(iface, var_index, &var_desc);
5500         if(FAILED(hres)) return hres;
5501         
5502         FIXME("varseek: Found memid, but variable-based invoking not supported\n");
5503         dump_VARDESC(var_desc);
5504         ITypeInfo2_ReleaseVarDesc(iface, var_desc);
5505         return E_NOTIMPL;
5506     }
5507
5508     /* not found, look for it in inherited interfaces */
5509     ITypeInfo2_GetTypeKind(iface, &type_kind);
5510     if(type_kind == TKIND_INTERFACE || type_kind == TKIND_DISPATCH) {
5511         HREFTYPE ref_type;
5512         if(SUCCEEDED(ITypeInfo2_GetRefTypeOfImplType(iface, 0, &ref_type))) {
5513             /* recursive search */
5514             ITypeInfo *pTInfo;
5515             hres = ITypeInfo_GetRefTypeInfo(iface, ref_type, &pTInfo);
5516             if(SUCCEEDED(hres)){
5517                 hres = ITypeInfo_Invoke(pTInfo,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr);
5518                 ITypeInfo_Release(pTInfo);
5519                 return hres;
5520             }
5521             WARN("Could not search inherited interface!\n");
5522         }
5523     }
5524     ERR("did not find member id %ld, flags 0x%x!\n", memid, wFlags);
5525     return DISP_E_MEMBERNOTFOUND;
5526 }
5527
5528 /* ITypeInfo::GetDocumentation
5529  *
5530  * Retrieves the documentation string, the complete Help file name and path,
5531  * and the context ID for the Help topic for a specified type description.
5532  *
5533  * (Can be tested by the Visual Basic Editor in Word for instance.)
5534  */
5535 static HRESULT WINAPI ITypeInfo_fnGetDocumentation( ITypeInfo2 *iface,
5536         MEMBERID memid, BSTR  *pBstrName, BSTR  *pBstrDocString,
5537         DWORD  *pdwHelpContext, BSTR  *pBstrHelpFile)
5538 {
5539     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5540     const TLBFuncDesc *pFDesc;
5541     const TLBVarDesc *pVDesc;
5542     TRACE("(%p) memid %ld Name(%p) DocString(%p)"
5543           " HelpContext(%p) HelpFile(%p)\n",
5544         This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
5545     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
5546         if(pBstrName)
5547             *pBstrName=SysAllocString(This->Name);
5548         if(pBstrDocString)
5549             *pBstrDocString=SysAllocString(This->DocString);
5550         if(pdwHelpContext)
5551             *pdwHelpContext=This->dwHelpContext;
5552         if(pBstrHelpFile)
5553             *pBstrHelpFile=SysAllocString(This->DocString);/* FIXME */
5554         return S_OK;
5555     }else {/* for a member */
5556     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
5557         if(pFDesc->funcdesc.memid==memid){
5558           if(pBstrName)
5559             *pBstrName = SysAllocString(pFDesc->Name);
5560           if(pBstrDocString)
5561             *pBstrDocString=SysAllocString(pFDesc->HelpString);
5562           if(pdwHelpContext)
5563             *pdwHelpContext=pFDesc->helpcontext;
5564           return S_OK;
5565         }
5566     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
5567         if(pVDesc->vardesc.memid==memid){
5568             if(pBstrName)
5569               *pBstrName = SysAllocString(pVDesc->Name);
5570             if(pBstrDocString)
5571               *pBstrDocString=SysAllocString(pVDesc->HelpString);
5572             if(pdwHelpContext)
5573               *pdwHelpContext=pVDesc->HelpContext;
5574             return S_OK;
5575         }
5576     }
5577     WARN("member %ld not found\n", memid);
5578     return TYPE_E_ELEMENTNOTFOUND;
5579 }
5580
5581 /*  ITypeInfo::GetDllEntry
5582  *
5583  * Retrieves a description or specification of an entry point for a function
5584  * in a DLL.
5585  */
5586 static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid,
5587         INVOKEKIND invKind, BSTR  *pBstrDllName, BSTR  *pBstrName,
5588         WORD  *pwOrdinal)
5589 {
5590     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5591     const TLBFuncDesc *pFDesc;
5592
5593     TRACE("(%p)->(memid %lx, %d, %p, %p, %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
5594
5595     if (pBstrDllName) *pBstrDllName = NULL;
5596     if (pBstrName) *pBstrName = NULL;
5597     if (pwOrdinal) *pwOrdinal = 0;
5598
5599     if (This->TypeAttr.typekind != TKIND_MODULE)
5600         return TYPE_E_BADMODULEKIND;
5601
5602     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
5603         if(pFDesc->funcdesc.memid==memid){
5604             dump_TypeInfo(This);
5605             if (TRACE_ON(ole))
5606                 dump_TLBFuncDescOne(pFDesc);
5607
5608             if (pBstrDllName)
5609                 *pBstrDllName = SysAllocString(This->DllName);
5610
5611             if (HIWORD(pFDesc->Entry) && (pFDesc->Entry != (void*)-1)) {
5612                 if (pBstrName)
5613                     *pBstrName = SysAllocString(pFDesc->Entry);
5614                 if (pwOrdinal)
5615                     *pwOrdinal = -1;
5616                 return S_OK;
5617             }
5618             if (pBstrName)
5619                 *pBstrName = NULL;
5620             if (pwOrdinal)
5621                 *pwOrdinal = (DWORD)pFDesc->Entry;
5622             return S_OK;
5623         }
5624     return TYPE_E_ELEMENTNOTFOUND;
5625 }
5626
5627 /* ITypeInfo::GetRefTypeInfo
5628  *
5629  * If a type description references other type descriptions, it retrieves
5630  * the referenced type descriptions.
5631  */
5632 static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo(
5633         ITypeInfo2 *iface,
5634         HREFTYPE hRefType,
5635         ITypeInfo  **ppTInfo)
5636 {
5637     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5638     HRESULT result = E_FAIL;
5639
5640     if ((This->hreftype != -1) && (This->hreftype == hRefType))
5641     {
5642         *ppTInfo = (ITypeInfo *)&This->lpVtbl;
5643         ITypeInfo_AddRef(*ppTInfo);
5644         result = S_OK;
5645     }
5646     else if (hRefType == -1 &&
5647         (((ITypeInfoImpl*) This)->TypeAttr.typekind   == TKIND_DISPATCH) &&
5648         (((ITypeInfoImpl*) This)->TypeAttr.wTypeFlags &  TYPEFLAG_FDUAL))
5649     {
5650           /* when we meet a DUAL dispinterface, we must create the interface
5651           * version of it.
5652           */
5653           ITypeInfoImpl* pTypeInfoImpl = (ITypeInfoImpl*) ITypeInfo_Constructor();
5654
5655
5656           /* the interface version contains the same information as the dispinterface
5657            * copy the contents of the structs.
5658            */
5659           *pTypeInfoImpl = *This;
5660           pTypeInfoImpl->ref = 1;
5661
5662           /* change the type to interface */
5663           pTypeInfoImpl->TypeAttr.typekind = TKIND_INTERFACE;
5664
5665           *ppTInfo = (ITypeInfo*) pTypeInfoImpl;
5666
5667           ITypeInfo_AddRef((ITypeInfo*) pTypeInfoImpl);
5668
5669           result = S_OK;
5670
5671     } else {
5672         TLBRefType *pRefType;
5673         for(pRefType = This->reflist; pRefType; pRefType = pRefType->next) {
5674             if(pRefType->reference == hRefType)
5675                 break;
5676         }
5677         if(!pRefType)
5678           FIXME("Can't find pRefType for ref %lx\n", hRefType);
5679         if(pRefType && hRefType != -1) {
5680             ITypeLib *pTLib = NULL;
5681
5682             if(pRefType->pImpTLInfo == TLB_REF_INTERNAL) {
5683                 UINT Index;
5684                 result = ITypeInfo_GetContainingTypeLib(iface, &pTLib, &Index);
5685             } else {
5686                 if(pRefType->pImpTLInfo->pImpTypeLib) {
5687                     TRACE("typeinfo in imported typelib that is already loaded\n");
5688                     pTLib = (ITypeLib*)pRefType->pImpTLInfo->pImpTypeLib;
5689                     ITypeLib2_AddRef((ITypeLib*) pTLib);
5690                     result = S_OK;
5691                 } else {
5692                     TRACE("typeinfo in imported typelib that isn't already loaded\n");
5693                     result = LoadRegTypeLib( &pRefType->pImpTLInfo->guid,
5694                                              pRefType->pImpTLInfo->wVersionMajor,
5695                                              pRefType->pImpTLInfo->wVersionMinor,
5696                                              pRefType->pImpTLInfo->lcid,
5697                                              &pTLib);
5698
5699                     if(!SUCCEEDED(result)) {
5700                         BSTR libnam=SysAllocString(pRefType->pImpTLInfo->name);
5701                         result=LoadTypeLib(libnam, &pTLib);
5702                         SysFreeString(libnam);
5703                     }
5704                     if(SUCCEEDED(result)) {
5705                         pRefType->pImpTLInfo->pImpTypeLib = (ITypeLibImpl*)pTLib;
5706                         ITypeLib2_AddRef(pTLib);
5707                     }
5708                 }
5709             }
5710             if(SUCCEEDED(result)) {
5711                 if(pRefType->index == TLB_REF_USE_GUID)
5712                     result = ITypeLib2_GetTypeInfoOfGuid(pTLib,
5713                                                          &pRefType->guid,
5714                                                          ppTInfo);
5715                 else
5716                     result = ITypeLib2_GetTypeInfo(pTLib, pRefType->index,
5717                                                    ppTInfo);
5718             }
5719             if (pTLib != NULL)
5720                 ITypeLib2_Release(pTLib);
5721         }
5722     }
5723
5724     TRACE("(%p) hreftype 0x%04lx loaded %s (%p)\n", This, hRefType,
5725           SUCCEEDED(result)? "SUCCESS":"FAILURE", *ppTInfo);
5726     return result;
5727 }
5728
5729 /* ITypeInfo::AddressOfMember
5730  *
5731  * Retrieves the addresses of static functions or variables, such as those
5732  * defined in a DLL.
5733  */
5734 static HRESULT WINAPI ITypeInfo_fnAddressOfMember( ITypeInfo2 *iface,
5735         MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
5736 {
5737     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5738     HRESULT hr;
5739     BSTR dll, entry;
5740     WORD ordinal;
5741     HMODULE module;
5742
5743     TRACE("(%p)->(0x%lx, 0x%x, %p)\n", This, memid, invKind, ppv);
5744
5745     hr = ITypeInfo_GetDllEntry(iface, memid, invKind, &dll, &entry, &ordinal);
5746     if (FAILED(hr))
5747         return hr;
5748
5749     module = LoadLibraryW(dll);
5750     if (!module)
5751     {
5752         ERR("couldn't load %s\n", debugstr_w(dll));
5753         SysFreeString(dll);
5754         if (entry) SysFreeString(entry);
5755         return STG_E_FILENOTFOUND;
5756     }
5757     /* FIXME: store library somewhere where we can free it */
5758
5759     if (entry)
5760     {
5761         LPSTR entryA;
5762         INT len = WideCharToMultiByte(CP_ACP, 0, entry, -1, NULL, 0, NULL, NULL);
5763         entryA = HeapAlloc(GetProcessHeap(), 0, len);
5764         WideCharToMultiByte(CP_ACP, 0, entry, -1, entryA, len, NULL, NULL);
5765
5766         *ppv = GetProcAddress(module, entryA);
5767         if (!*ppv)
5768             ERR("function not found %s\n", debugstr_a(entryA));
5769
5770         HeapFree(GetProcessHeap(), 0, entryA);
5771     }
5772     else
5773     {
5774         *ppv = GetProcAddress(module, MAKEINTRESOURCEA(ordinal));
5775         if (!*ppv)
5776             ERR("function not found %d\n", ordinal);
5777     }
5778
5779     SysFreeString(dll);
5780     if (entry) SysFreeString(entry);
5781
5782     if (!*ppv)
5783         return TYPE_E_DLLFUNCTIONNOTFOUND;
5784
5785     return S_OK;
5786 }
5787
5788 /* ITypeInfo::CreateInstance
5789  *
5790  * Creates a new instance of a type that describes a component object class
5791  * (coclass).
5792  */
5793 static HRESULT WINAPI ITypeInfo_fnCreateInstance( ITypeInfo2 *iface,
5794         IUnknown *pUnk, REFIID riid, VOID  **ppvObj)
5795 {
5796     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5797     FIXME("(%p) stub!\n", This);
5798     return S_OK;
5799 }
5800
5801 /* ITypeInfo::GetMops
5802  *
5803  * Retrieves marshalling information.
5804  */
5805 static HRESULT WINAPI ITypeInfo_fnGetMops( ITypeInfo2 *iface, MEMBERID memid,
5806                                 BSTR  *pBstrMops)
5807 {
5808     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5809     FIXME("(%p) stub!\n", This);
5810     return S_OK;
5811 }
5812
5813 /* ITypeInfo::GetContainingTypeLib
5814  *
5815  * Retrieves the containing type library and the index of the type description
5816  * within that type library.
5817  */
5818 static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( ITypeInfo2 *iface,
5819         ITypeLib  * *ppTLib, UINT  *pIndex)
5820 {
5821     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5822     
5823     /* If a pointer is null, we simply ignore it, the ATL in particular passes pIndex as 0 */
5824     if (pIndex) {
5825       *pIndex=This->index;
5826       TRACE("returning pIndex=%d\n", *pIndex);
5827     }
5828     
5829     if (ppTLib) {
5830       *ppTLib=(LPTYPELIB )(This->pTypeLib);
5831       ITypeLib2_AddRef(*ppTLib);
5832       TRACE("returning ppTLib=%p\n", *ppTLib);
5833     }
5834     
5835     return S_OK;
5836 }
5837
5838 /* ITypeInfo::ReleaseTypeAttr
5839  *
5840  * Releases a TYPEATTR previously returned by GetTypeAttr.
5841  *
5842  */
5843 static void WINAPI ITypeInfo_fnReleaseTypeAttr( ITypeInfo2 *iface,
5844         TYPEATTR* pTypeAttr)
5845 {
5846     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5847     TRACE("(%p)->(%p)\n", This, pTypeAttr);
5848     HeapFree(GetProcessHeap(), 0, pTypeAttr);
5849 }
5850
5851 /* ITypeInfo::ReleaseFuncDesc
5852  *
5853  * Releases a FUNCDESC previously returned by GetFuncDesc. *
5854  */
5855 static void WINAPI ITypeInfo_fnReleaseFuncDesc(
5856         ITypeInfo2 *iface,
5857         FUNCDESC *pFuncDesc)
5858 {
5859     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5860     SHORT i;
5861
5862     TRACE("(%p)->(%p)\n", This, pFuncDesc);
5863
5864     for (i = 0; i < pFuncDesc->cParams; i++)
5865         TLB_FreeElemDesc(&pFuncDesc->lprgelemdescParam[i]);
5866     TLB_FreeElemDesc(&pFuncDesc->elemdescFunc);
5867
5868     SysFreeString((BSTR)pFuncDesc);
5869 }
5870
5871 /* ITypeInfo::ReleaseVarDesc
5872  *
5873  * Releases a VARDESC previously returned by GetVarDesc.
5874  */
5875 static void WINAPI ITypeInfo_fnReleaseVarDesc( ITypeInfo2 *iface,
5876         VARDESC *pVarDesc)
5877 {
5878     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5879     TRACE("(%p)->(%p)\n", This, pVarDesc);
5880
5881     TLB_FreeElemDesc(&pVarDesc->elemdescVar);
5882     if (pVarDesc->varkind == VAR_CONST)
5883         VariantClear(pVarDesc->u.lpvarValue);
5884     SysFreeString((BSTR)pVarDesc);
5885 }
5886
5887 /* ITypeInfo2::GetTypeKind
5888  *
5889  * Returns the TYPEKIND enumeration quickly, without doing any allocations.
5890  *
5891  */
5892 static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo2 * iface,
5893     TYPEKIND *pTypeKind)
5894 {
5895     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5896     *pTypeKind=This->TypeAttr.typekind;
5897     TRACE("(%p) type 0x%0x\n", This,*pTypeKind);
5898     return S_OK;
5899 }
5900
5901 /* ITypeInfo2::GetTypeFlags
5902  *
5903  * Returns the type flags without any allocations. This returns a DWORD type
5904  * flag, which expands the type flags without growing the TYPEATTR (type
5905  * attribute).
5906  *
5907  */
5908 static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo2 *iface, ULONG *pTypeFlags)
5909 {
5910     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5911     *pTypeFlags=This->TypeAttr.wTypeFlags;
5912     TRACE("(%p) flags 0x%lx\n", This,*pTypeFlags);
5913     return S_OK;
5914 }
5915
5916 /* ITypeInfo2::GetFuncIndexOfMemId
5917  * Binds to a specific member based on a known DISPID, where the member name
5918  * is not known (for example, when binding to a default member).
5919  *
5920  */
5921 static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo2 * iface,
5922     MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex)
5923 {
5924     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5925     const TLBFuncDesc *pFuncInfo;
5926     int i;
5927     HRESULT result;
5928
5929     for(i = 0, pFuncInfo = This->funclist; pFuncInfo; i++, pFuncInfo=pFuncInfo->next)
5930         if(memid == pFuncInfo->funcdesc.memid && (invKind & pFuncInfo->funcdesc.invkind))
5931             break;
5932     if(pFuncInfo) {
5933         *pFuncIndex = i;
5934         result = S_OK;
5935     } else
5936         result = TYPE_E_ELEMENTNOTFOUND;
5937
5938     TRACE("(%p) memid 0x%08lx invKind 0x%04x -> %s\n", This,
5939           memid, invKind, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
5940     return result;
5941 }
5942
5943 /* TypeInfo2::GetVarIndexOfMemId
5944  *
5945  * Binds to a specific member based on a known DISPID, where the member name
5946  * is not known (for example, when binding to a default member).
5947  *
5948  */
5949 static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( ITypeInfo2 * iface,
5950     MEMBERID memid, UINT *pVarIndex)
5951 {
5952     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5953     TLBVarDesc *pVarInfo;
5954     int i;
5955     HRESULT result;
5956     for(i=0, pVarInfo=This->varlist; pVarInfo &&
5957             memid != pVarInfo->vardesc.memid; i++, pVarInfo=pVarInfo->next)
5958         ;
5959     if(pVarInfo) {
5960         *pVarIndex = i;
5961         result = S_OK;
5962     } else
5963         result = TYPE_E_ELEMENTNOTFOUND;
5964
5965     TRACE("(%p) memid 0x%08lx -> %s\n", This,
5966           memid, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
5967     return result;
5968 }
5969
5970 /* ITypeInfo2::GetCustData
5971  *
5972  * Gets the custom data
5973  */
5974 static HRESULT WINAPI ITypeInfo2_fnGetCustData(
5975         ITypeInfo2 * iface,
5976         REFGUID guid,
5977         VARIANT *pVarVal)
5978 {
5979     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5980     TLBCustData *pCData;
5981
5982     for(pCData=This->pCustData; pCData; pCData = pCData->next)
5983         if( IsEqualIID(guid, &pCData->guid)) break;
5984
5985     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
5986
5987     if(pCData)
5988     {
5989         VariantInit( pVarVal);
5990         VariantCopy( pVarVal, &pCData->data);
5991         return S_OK;
5992     }
5993     return E_INVALIDARG;  /* FIXME: correct? */
5994 }
5995
5996 /* ITypeInfo2::GetFuncCustData
5997  *
5998  * Gets the custom data
5999  */
6000 static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData(
6001         ITypeInfo2 * iface,
6002         UINT index,
6003         REFGUID guid,
6004         VARIANT *pVarVal)
6005 {
6006     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6007     TLBCustData *pCData=NULL;
6008     TLBFuncDesc * pFDesc;
6009     int i;
6010     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
6011             pFDesc=pFDesc->next);
6012
6013     if(pFDesc)
6014         for(pCData=pFDesc->pCustData; pCData; pCData = pCData->next)
6015             if( IsEqualIID(guid, &pCData->guid)) break;
6016
6017     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
6018
6019     if(pCData){
6020         VariantInit( pVarVal);
6021         VariantCopy( pVarVal, &pCData->data);
6022         return S_OK;
6023     }
6024     return E_INVALIDARG;  /* FIXME: correct? */
6025 }
6026
6027 /* ITypeInfo2::GetParamCustData
6028  *
6029  * Gets the custom data
6030  */
6031 static HRESULT WINAPI ITypeInfo2_fnGetParamCustData(
6032         ITypeInfo2 * iface,
6033         UINT indexFunc,
6034         UINT indexParam,
6035         REFGUID guid,
6036         VARIANT *pVarVal)
6037 {
6038     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6039     TLBCustData *pCData=NULL;
6040     TLBFuncDesc * pFDesc;
6041     int i;
6042
6043     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,pFDesc=pFDesc->next);
6044
6045     if(pFDesc && indexParam >=0 && indexParam<pFDesc->funcdesc.cParams)
6046         for(pCData=pFDesc->pParamDesc[indexParam].pCustData; pCData;
6047                 pCData = pCData->next)
6048             if( IsEqualIID(guid, &pCData->guid)) break;
6049
6050     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
6051
6052     if(pCData)
6053     {
6054         VariantInit( pVarVal);
6055         VariantCopy( pVarVal, &pCData->data);
6056         return S_OK;
6057     }
6058     return E_INVALIDARG;  /* FIXME: correct? */
6059 }
6060
6061 /* ITypeInfo2::GetVarCustData
6062  *
6063  * Gets the custom data
6064  */
6065 static HRESULT WINAPI ITypeInfo2_fnGetVarCustData(
6066         ITypeInfo2 * iface,
6067         UINT index,
6068         REFGUID guid,
6069         VARIANT *pVarVal)
6070 {
6071     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6072     TLBCustData *pCData=NULL;
6073     TLBVarDesc * pVDesc;
6074     int i;
6075
6076     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next);
6077
6078     if(pVDesc)
6079     {
6080       for(pCData=pVDesc->pCustData; pCData; pCData = pCData->next)
6081       {
6082         if( IsEqualIID(guid, &pCData->guid)) break;
6083       }
6084     }
6085
6086     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
6087
6088     if(pCData)
6089     {
6090         VariantInit( pVarVal);
6091         VariantCopy( pVarVal, &pCData->data);
6092         return S_OK;
6093     }
6094     return E_INVALIDARG;  /* FIXME: correct? */
6095 }
6096
6097 /* ITypeInfo2::GetImplCustData
6098  *
6099  * Gets the custom data
6100  */
6101 static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData(
6102         ITypeInfo2 * iface,
6103         UINT index,
6104         REFGUID guid,
6105         VARIANT *pVarVal)
6106 {
6107     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6108     TLBCustData *pCData=NULL;
6109     TLBImplType * pRDesc;
6110     int i;
6111
6112     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++, pRDesc=pRDesc->next);
6113
6114     if(pRDesc)
6115     {
6116       for(pCData=pRDesc->pCustData; pCData; pCData = pCData->next)
6117       {
6118         if( IsEqualIID(guid, &pCData->guid)) break;
6119       }
6120     }
6121
6122     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
6123
6124     if(pCData)
6125     {
6126         VariantInit( pVarVal);
6127         VariantCopy( pVarVal, &pCData->data);
6128         return S_OK;
6129     }
6130     return E_INVALIDARG;  /* FIXME: correct? */
6131 }
6132
6133 /* ITypeInfo2::GetDocumentation2
6134  *
6135  * Retrieves the documentation string, the complete Help file name and path,
6136  * the localization context to use, and the context ID for the library Help
6137  * topic in the Help file.
6138  *
6139  */
6140 static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2(
6141         ITypeInfo2 * iface,
6142         MEMBERID memid,
6143         LCID lcid,
6144         BSTR *pbstrHelpString,
6145         DWORD *pdwHelpStringContext,
6146         BSTR *pbstrHelpStringDll)
6147 {
6148     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6149     const TLBFuncDesc *pFDesc;
6150     const TLBVarDesc *pVDesc;
6151     TRACE("(%p) memid %ld lcid(0x%lx)  HelpString(%p) "
6152           "HelpStringContext(%p) HelpStringDll(%p)\n",
6153           This, memid, lcid, pbstrHelpString, pdwHelpStringContext,
6154           pbstrHelpStringDll );
6155     /* the help string should be obtained from the helpstringdll,
6156      * using the _DLLGetDocumentation function, based on the supplied
6157      * lcid. Nice to do sometime...
6158      */
6159     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
6160         if(pbstrHelpString)
6161             *pbstrHelpString=SysAllocString(This->Name);
6162         if(pdwHelpStringContext)
6163             *pdwHelpStringContext=This->dwHelpStringContext;
6164         if(pbstrHelpStringDll)
6165             *pbstrHelpStringDll=
6166                 SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
6167         return S_OK;
6168     }else {/* for a member */
6169     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
6170         if(pFDesc->funcdesc.memid==memid){
6171              if(pbstrHelpString)
6172                 *pbstrHelpString=SysAllocString(pFDesc->HelpString);
6173             if(pdwHelpStringContext)
6174                 *pdwHelpStringContext=pFDesc->HelpStringContext;
6175             if(pbstrHelpStringDll)
6176                 *pbstrHelpStringDll=
6177                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
6178         return S_OK;
6179     }
6180     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
6181         if(pVDesc->vardesc.memid==memid){
6182              if(pbstrHelpString)
6183                 *pbstrHelpString=SysAllocString(pVDesc->HelpString);
6184             if(pdwHelpStringContext)
6185                 *pdwHelpStringContext=pVDesc->HelpStringContext;
6186             if(pbstrHelpStringDll)
6187                 *pbstrHelpStringDll=
6188                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
6189             return S_OK;
6190         }
6191     }
6192     return TYPE_E_ELEMENTNOTFOUND;
6193 }
6194
6195 /* ITypeInfo2::GetAllCustData
6196  *
6197  * Gets all custom data items for the Type info.
6198  *
6199  */
6200 static HRESULT WINAPI ITypeInfo2_fnGetAllCustData(
6201         ITypeInfo2 * iface,
6202         CUSTDATA *pCustData)
6203 {
6204     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6205     TLBCustData *pCData;
6206     int i;
6207
6208     TRACE("(%p) returning %d items\n", This, This->ctCustData);
6209
6210     pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
6211     if(pCustData->prgCustData ){
6212         pCustData->cCustData=This->ctCustData;
6213         for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
6214             pCustData->prgCustData[i].guid=pCData->guid;
6215             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
6216         }
6217     }else{
6218         ERR(" OUT OF MEMORY!\n");
6219         return E_OUTOFMEMORY;
6220     }
6221     return S_OK;
6222 }
6223
6224 /* ITypeInfo2::GetAllFuncCustData
6225  *
6226  * Gets all custom data items for the specified Function
6227  *
6228  */
6229 static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData(
6230         ITypeInfo2 * iface,
6231         UINT index,
6232         CUSTDATA *pCustData)
6233 {
6234     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6235     TLBCustData *pCData;
6236     TLBFuncDesc * pFDesc;
6237     int i;
6238     TRACE("(%p) index %d\n", This, index);
6239     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
6240             pFDesc=pFDesc->next)
6241         ;
6242     if(pFDesc){
6243         pCustData->prgCustData =
6244             TLB_Alloc(pFDesc->ctCustData * sizeof(CUSTDATAITEM));
6245         if(pCustData->prgCustData ){
6246             pCustData->cCustData=pFDesc->ctCustData;
6247             for(i=0, pCData=pFDesc->pCustData; pCData; i++,
6248                     pCData = pCData->next){
6249                 pCustData->prgCustData[i].guid=pCData->guid;
6250                 VariantCopy(& pCustData->prgCustData[i].varValue,
6251                         & pCData->data);
6252             }
6253         }else{
6254             ERR(" OUT OF MEMORY!\n");
6255             return E_OUTOFMEMORY;
6256         }
6257         return S_OK;
6258     }
6259     return TYPE_E_ELEMENTNOTFOUND;
6260 }
6261
6262 /* ITypeInfo2::GetAllParamCustData
6263  *
6264  * Gets all custom data items for the Functions
6265  *
6266  */
6267 static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo2 * iface,
6268     UINT indexFunc, UINT indexParam, CUSTDATA *pCustData)
6269 {
6270     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6271     TLBCustData *pCData=NULL;
6272     TLBFuncDesc * pFDesc;
6273     int i;
6274     TRACE("(%p) index %d\n", This, indexFunc);
6275     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,
6276             pFDesc=pFDesc->next)
6277         ;
6278     if(pFDesc && indexParam >=0 && indexParam<pFDesc->funcdesc.cParams){
6279         pCustData->prgCustData =
6280             TLB_Alloc(pFDesc->pParamDesc[indexParam].ctCustData *
6281                     sizeof(CUSTDATAITEM));
6282         if(pCustData->prgCustData ){
6283             pCustData->cCustData=pFDesc->pParamDesc[indexParam].ctCustData;
6284             for(i=0, pCData=pFDesc->pParamDesc[indexParam].pCustData;
6285                     pCData; i++, pCData = pCData->next){
6286                 pCustData->prgCustData[i].guid=pCData->guid;
6287                 VariantCopy(& pCustData->prgCustData[i].varValue,
6288                         & pCData->data);
6289             }
6290         }else{
6291             ERR(" OUT OF MEMORY!\n");
6292             return E_OUTOFMEMORY;
6293         }
6294         return S_OK;
6295     }
6296     return TYPE_E_ELEMENTNOTFOUND;
6297 }
6298
6299 /* ITypeInfo2::GetAllVarCustData
6300  *
6301  * Gets all custom data items for the specified Variable
6302  *
6303  */
6304 static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo2 * iface,
6305     UINT index, CUSTDATA *pCustData)
6306 {
6307     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6308     TLBCustData *pCData;
6309     TLBVarDesc * pVDesc;
6310     int i;
6311     TRACE("(%p) index %d\n", This, index);
6312     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++,
6313             pVDesc=pVDesc->next)
6314         ;
6315     if(pVDesc){
6316         pCustData->prgCustData =
6317             TLB_Alloc(pVDesc->ctCustData * sizeof(CUSTDATAITEM));
6318         if(pCustData->prgCustData ){
6319             pCustData->cCustData=pVDesc->ctCustData;
6320             for(i=0, pCData=pVDesc->pCustData; pCData; i++,
6321                     pCData = pCData->next){
6322                 pCustData->prgCustData[i].guid=pCData->guid;
6323                 VariantCopy(& pCustData->prgCustData[i].varValue,
6324                         & pCData->data);
6325             }
6326         }else{
6327             ERR(" OUT OF MEMORY!\n");
6328             return E_OUTOFMEMORY;
6329         }
6330         return S_OK;
6331     }
6332     return TYPE_E_ELEMENTNOTFOUND;
6333 }
6334
6335 /* ITypeInfo2::GetAllImplCustData
6336  *
6337  * Gets all custom data items for the specified implementation type
6338  *
6339  */
6340 static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData(
6341         ITypeInfo2 * iface,
6342         UINT index,
6343         CUSTDATA *pCustData)
6344 {
6345     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6346     TLBCustData *pCData;
6347     TLBImplType * pRDesc;
6348     int i;
6349     TRACE("(%p) index %d\n", This, index);
6350     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++,
6351             pRDesc=pRDesc->next)
6352         ;
6353     if(pRDesc){
6354         pCustData->prgCustData =
6355             TLB_Alloc(pRDesc->ctCustData * sizeof(CUSTDATAITEM));
6356         if(pCustData->prgCustData ){
6357             pCustData->cCustData=pRDesc->ctCustData;
6358             for(i=0, pCData=pRDesc->pCustData; pCData; i++,
6359                     pCData = pCData->next){
6360                 pCustData->prgCustData[i].guid=pCData->guid;
6361                 VariantCopy(& pCustData->prgCustData[i].varValue,
6362                         & pCData->data);
6363             }
6364         }else{
6365             ERR(" OUT OF MEMORY!\n");
6366             return E_OUTOFMEMORY;
6367         }
6368         return S_OK;
6369     }
6370     return TYPE_E_ELEMENTNOTFOUND;
6371 }
6372
6373 static const ITypeInfo2Vtbl tinfvt =
6374 {
6375
6376     ITypeInfo_fnQueryInterface,
6377     ITypeInfo_fnAddRef,
6378     ITypeInfo_fnRelease,
6379
6380     ITypeInfo_fnGetTypeAttr,
6381     ITypeInfo_fnGetTypeComp,
6382     ITypeInfo_fnGetFuncDesc,
6383     ITypeInfo_fnGetVarDesc,
6384     ITypeInfo_fnGetNames,
6385     ITypeInfo_fnGetRefTypeOfImplType,
6386     ITypeInfo_fnGetImplTypeFlags,
6387     ITypeInfo_fnGetIDsOfNames,
6388     ITypeInfo_fnInvoke,
6389     ITypeInfo_fnGetDocumentation,
6390     ITypeInfo_fnGetDllEntry,
6391     ITypeInfo_fnGetRefTypeInfo,
6392     ITypeInfo_fnAddressOfMember,
6393     ITypeInfo_fnCreateInstance,
6394     ITypeInfo_fnGetMops,
6395     ITypeInfo_fnGetContainingTypeLib,
6396     ITypeInfo_fnReleaseTypeAttr,
6397     ITypeInfo_fnReleaseFuncDesc,
6398     ITypeInfo_fnReleaseVarDesc,
6399
6400     ITypeInfo2_fnGetTypeKind,
6401     ITypeInfo2_fnGetTypeFlags,
6402     ITypeInfo2_fnGetFuncIndexOfMemId,
6403     ITypeInfo2_fnGetVarIndexOfMemId,
6404     ITypeInfo2_fnGetCustData,
6405     ITypeInfo2_fnGetFuncCustData,
6406     ITypeInfo2_fnGetParamCustData,
6407     ITypeInfo2_fnGetVarCustData,
6408     ITypeInfo2_fnGetImplTypeCustData,
6409     ITypeInfo2_fnGetDocumentation2,
6410     ITypeInfo2_fnGetAllCustData,
6411     ITypeInfo2_fnGetAllFuncCustData,
6412     ITypeInfo2_fnGetAllParamCustData,
6413     ITypeInfo2_fnGetAllVarCustData,
6414     ITypeInfo2_fnGetAllImplTypeCustData,
6415 };
6416
6417 /******************************************************************************
6418  * CreateDispTypeInfo [OLEAUT32.31]
6419  *
6420  * Build type information for an object so it can be called through an
6421  * IDispatch interface.
6422  *
6423  * RETURNS
6424  *  Success: S_OK. pptinfo contains the created ITypeInfo object.
6425  *  Failure: E_INVALIDARG, if one or more arguments is invalid.
6426  *
6427  * NOTES
6428  *  This call allows an objects methods to be accessed through IDispatch, by
6429  *  building an ITypeInfo object that IDispatch can use to call through.
6430  */
6431 HRESULT WINAPI CreateDispTypeInfo(
6432         INTERFACEDATA *pidata, /* [I] Description of the interface to build type info for */
6433         LCID lcid, /* [I] Locale Id */
6434         ITypeInfo **pptinfo) /* [O] Destination for created ITypeInfo object */
6435 {
6436     ITypeInfoImpl *pTIClass, *pTIIface;
6437     ITypeLibImpl *pTypeLibImpl;
6438     int param, func;
6439     TLBFuncDesc **ppFuncDesc;
6440
6441     TRACE("\n");
6442     pTypeLibImpl = TypeLibImpl_Constructor();
6443     if (!pTypeLibImpl) return E_FAIL;
6444
6445     pTIIface = (ITypeInfoImpl*)ITypeInfo_Constructor();
6446     pTIIface->pTypeLib = pTypeLibImpl;
6447     pTIIface->index = 0;
6448     pTIIface->Name = NULL;
6449     pTIIface->dwHelpContext = -1;
6450     memset(&pTIIface->TypeAttr.guid, 0, sizeof(GUID));
6451     pTIIface->TypeAttr.lcid = lcid;
6452     pTIIface->TypeAttr.typekind = TKIND_INTERFACE;
6453     pTIIface->TypeAttr.wMajorVerNum = 0;
6454     pTIIface->TypeAttr.wMinorVerNum = 0;
6455     pTIIface->TypeAttr.cbAlignment = 2;
6456     pTIIface->TypeAttr.cbSizeInstance = -1;
6457     pTIIface->TypeAttr.cbSizeVft = -1;
6458     pTIIface->TypeAttr.cFuncs = 0;
6459     pTIIface->TypeAttr.cImplTypes = 0;
6460     pTIIface->TypeAttr.cVars = 0;
6461     pTIIface->TypeAttr.wTypeFlags = 0;
6462
6463     ppFuncDesc = &pTIIface->funclist;
6464     for(func = 0; func < pidata->cMembers; func++) {
6465         METHODDATA *md = pidata->pmethdata + func;
6466         *ppFuncDesc = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppFuncDesc));
6467         (*ppFuncDesc)->Name = SysAllocString(md->szName);
6468         (*ppFuncDesc)->funcdesc.memid = md->dispid;
6469         (*ppFuncDesc)->funcdesc.funckind = FUNC_VIRTUAL;
6470         (*ppFuncDesc)->funcdesc.invkind = md->wFlags;
6471         (*ppFuncDesc)->funcdesc.callconv = md->cc;
6472         (*ppFuncDesc)->funcdesc.cParams = md->cArgs;
6473         (*ppFuncDesc)->funcdesc.cParamsOpt = 0;
6474         (*ppFuncDesc)->funcdesc.oVft = md->iMeth << 2;
6475         (*ppFuncDesc)->funcdesc.wFuncFlags = 0;
6476         (*ppFuncDesc)->funcdesc.elemdescFunc.tdesc.vt = md->vtReturn;
6477         (*ppFuncDesc)->funcdesc.elemdescFunc.u.paramdesc.wParamFlags = PARAMFLAG_NONE;
6478         (*ppFuncDesc)->funcdesc.elemdescFunc.u.paramdesc.pparamdescex = NULL;
6479         (*ppFuncDesc)->funcdesc.lprgelemdescParam = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6480                                                               md->cArgs * sizeof(ELEMDESC));
6481         (*ppFuncDesc)->pParamDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6482                                               md->cArgs * sizeof(TLBParDesc));
6483         for(param = 0; param < md->cArgs; param++) {
6484             (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].tdesc.vt = md->ppdata[param].vt;
6485             (*ppFuncDesc)->pParamDesc[param].Name = SysAllocString(md->ppdata[param].szName);
6486         }
6487         (*ppFuncDesc)->helpcontext = 0;
6488         (*ppFuncDesc)->HelpStringContext = 0;
6489         (*ppFuncDesc)->HelpString = NULL;
6490         (*ppFuncDesc)->Entry = NULL;
6491         (*ppFuncDesc)->ctCustData = 0;
6492         (*ppFuncDesc)->pCustData = NULL;
6493         (*ppFuncDesc)->next = NULL;
6494         ppFuncDesc = &(*ppFuncDesc)->next;
6495     }
6496
6497     dump_TypeInfo(pTIIface);
6498
6499     pTypeLibImpl->pTypeInfo = pTIIface;
6500     pTypeLibImpl->TypeInfoCount++;
6501
6502     pTIClass = (ITypeInfoImpl*)ITypeInfo_Constructor();
6503     pTIClass->pTypeLib = pTypeLibImpl;
6504     pTIClass->index = 1;
6505     pTIClass->Name = NULL;
6506     pTIClass->dwHelpContext = -1;
6507     memset(&pTIClass->TypeAttr.guid, 0, sizeof(GUID));
6508     pTIClass->TypeAttr.lcid = lcid;
6509     pTIClass->TypeAttr.typekind = TKIND_COCLASS;
6510     pTIClass->TypeAttr.wMajorVerNum = 0;
6511     pTIClass->TypeAttr.wMinorVerNum = 0;
6512     pTIClass->TypeAttr.cbAlignment = 2;
6513     pTIClass->TypeAttr.cbSizeInstance = -1;
6514     pTIClass->TypeAttr.cbSizeVft = -1;
6515     pTIClass->TypeAttr.cFuncs = 0;
6516     pTIClass->TypeAttr.cImplTypes = 1;
6517     pTIClass->TypeAttr.cVars = 0;
6518     pTIClass->TypeAttr.wTypeFlags = 0;
6519
6520     pTIClass->impltypelist = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pTIClass->impltypelist));
6521     pTIClass->impltypelist->hRef = 1;
6522
6523     pTIClass->reflist = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pTIClass->reflist));
6524     pTIClass->reflist->index = 0;
6525     pTIClass->reflist->reference = 1;
6526     pTIClass->reflist->pImpTLInfo = TLB_REF_INTERNAL;
6527
6528     dump_TypeInfo(pTIClass);
6529
6530     pTIIface->next = pTIClass;
6531     pTypeLibImpl->TypeInfoCount++;
6532
6533     *pptinfo = (ITypeInfo*)pTIClass;
6534     return S_OK;
6535
6536 }
6537
6538 static HRESULT WINAPI ITypeComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
6539 {
6540     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
6541
6542     return ITypeInfo_QueryInterface((ITypeInfo *)This, riid, ppv);
6543 }
6544
6545 static ULONG WINAPI ITypeComp_fnAddRef(ITypeComp * iface)
6546 {
6547     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
6548
6549     return ITypeInfo_AddRef((ITypeInfo *)This);
6550 }
6551
6552 static ULONG WINAPI ITypeComp_fnRelease(ITypeComp * iface)
6553 {
6554     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
6555
6556     return ITypeInfo_Release((ITypeInfo *)This);
6557 }
6558
6559 static HRESULT WINAPI ITypeComp_fnBind(
6560     ITypeComp * iface,
6561     OLECHAR * szName,
6562     ULONG lHash,
6563     WORD wFlags,
6564     ITypeInfo ** ppTInfo,
6565     DESCKIND * pDescKind,
6566     BINDPTR * pBindPtr)
6567 {
6568     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
6569     const TLBFuncDesc *pFDesc;
6570     const TLBVarDesc *pVDesc;
6571     HRESULT hr = DISP_E_MEMBERNOTFOUND;
6572
6573     TRACE("(%s, %lx, 0x%x, %p, %p, %p)\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
6574
6575     *pDescKind = DESCKIND_NONE;
6576     pBindPtr->lpfuncdesc = NULL;
6577     *ppTInfo = NULL;
6578
6579     for(pFDesc = This->funclist; pFDesc; pFDesc = pFDesc->next)
6580         if (!strcmpiW(pFDesc->Name, szName)) {
6581             if (!wFlags || (pFDesc->funcdesc.invkind & wFlags))
6582                 break;
6583             else
6584                 /* name found, but wrong flags */
6585                 hr = TYPE_E_TYPEMISMATCH;
6586         }
6587
6588     if (pFDesc)
6589     {
6590         HRESULT hr = TLB_AllocAndInitFuncDesc(
6591             &pFDesc->funcdesc,
6592             &pBindPtr->lpfuncdesc,
6593             This->TypeAttr.typekind == TKIND_DISPATCH);
6594         if (FAILED(hr))
6595             return hr;
6596         *pDescKind = DESCKIND_FUNCDESC;
6597         *ppTInfo = (ITypeInfo *)&This->lpVtbl;
6598         ITypeInfo_AddRef(*ppTInfo);
6599         return S_OK;
6600     } else {
6601         for(pVDesc = This->varlist; pVDesc; pVDesc = pVDesc->next) {
6602             if (!strcmpiW(pVDesc->Name, szName)) {
6603                 HRESULT hr = TLB_AllocAndInitVarDesc(&pVDesc->vardesc, &pBindPtr->lpvardesc);
6604                 if (FAILED(hr))
6605                     return hr;
6606                 *pDescKind = DESCKIND_VARDESC;
6607                 *ppTInfo = (ITypeInfo *)&This->lpVtbl;
6608                 ITypeInfo_AddRef(*ppTInfo);
6609                 return S_OK;
6610             }
6611         }
6612     }
6613     /* FIXME: search each inherited interface, not just the first */
6614     if (hr == DISP_E_MEMBERNOTFOUND && This->TypeAttr.cImplTypes) {
6615         /* recursive search */
6616         ITypeInfo *pTInfo;
6617         ITypeComp *pTComp;
6618         HRESULT hr;
6619         hr=ITypeInfo_GetRefTypeInfo((ITypeInfo *)&This->lpVtbl, This->impltypelist->hRef, &pTInfo);
6620         if (SUCCEEDED(hr))
6621         {
6622             hr = ITypeInfo_GetTypeComp(pTInfo,&pTComp);
6623             ITypeInfo_Release(pTInfo);
6624         }
6625         if (SUCCEEDED(hr))
6626         {
6627             hr = ITypeComp_Bind(pTComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
6628             ITypeComp_Release(pTComp);
6629             return hr;
6630         }
6631         WARN("Could not search inherited interface!\n");
6632     }
6633     WARN("did not find member with name %s, flags 0x%x!\n", debugstr_w(szName), wFlags);
6634     return hr;
6635 }
6636
6637 static HRESULT WINAPI ITypeComp_fnBindType(
6638     ITypeComp * iface,
6639     OLECHAR * szName,
6640     ULONG lHash,
6641     ITypeInfo ** ppTInfo,
6642     ITypeComp ** ppTComp)
6643 {
6644     TRACE("(%s, %lx, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
6645
6646     /* strange behaviour (does nothing) but like the
6647      * original */
6648
6649     if (!ppTInfo || !ppTComp)
6650         return E_POINTER;
6651
6652     *ppTInfo = NULL;
6653     *ppTComp = NULL;
6654
6655     return S_OK;
6656 }
6657
6658 static const ITypeCompVtbl tcompvt =
6659 {
6660
6661     ITypeComp_fnQueryInterface,
6662     ITypeComp_fnAddRef,
6663     ITypeComp_fnRelease,
6664
6665     ITypeComp_fnBind,
6666     ITypeComp_fnBindType
6667 };