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