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