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