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