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