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