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