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