Added location of local application data.
[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     WCHAR *pIndexStr;
266     HRESULT res;
267     INT index = 1;
268     TRACE("(%s,%d,%p)\n",debugstr_w(szFile), regkind, pptLib);
269     
270     if(!SearchPathW(NULL,szFile,NULL,sizeof(szPath)/sizeof(WCHAR),szPath,
271                     NULL)) {
272
273         /* Look for a trailing '\\' followed by an index */
274         pIndexStr = strrchrW(szFile, '\\');
275         if(pIndexStr && pIndexStr != szFile && *++pIndexStr != '\0') {
276             index = wcstol(pIndexStr, NULL, 10);
277             memcpy(szFileCopy, szFile,
278                    (pIndexStr - szFile - 1) * sizeof(WCHAR));
279             szFileCopy[pIndexStr - szFile - 1] = '\0';
280             if(!SearchPathW(NULL,szFileCopy,NULL,sizeof(szPath)/sizeof(WCHAR),
281                             szPath,NULL))
282                 return TYPE_E_CANTLOADLIBRARY;
283             if (GetFileAttributesW(szFileCopy) & FILE_ATTRIBUTE_DIRECTORY)
284                 return TYPE_E_CANTLOADLIBRARY;
285         } else
286             return TYPE_E_CANTLOADLIBRARY;
287     }
288
289     TRACE("File %s index %d\n", debugstr_w(szPath), index);
290
291     res = TLB_ReadTypeLib(szPath, 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 %ld\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
2013     /*    pTypeLibImpl->LibAttr.lcid = tlbHeader.lcid;*/
2014     /* Windows seems to have zero here, is this correct? */
2015     if(SUBLANGID(tlbHeader.lcid) == SUBLANG_NEUTRAL)
2016       pTypeLibImpl->LibAttr.lcid = PRIMARYLANGID(tlbHeader.lcid);
2017     else
2018       pTypeLibImpl->LibAttr.lcid = 0;
2019
2020     pTypeLibImpl->LibAttr.syskind = tlbHeader.varflags & 0x0f; /* check the mask */
2021     pTypeLibImpl->LibAttr.wMajorVerNum = LOWORD(tlbHeader.version);
2022     pTypeLibImpl->LibAttr.wMinorVerNum = HIWORD(tlbHeader.version);
2023     pTypeLibImpl->LibAttr.wLibFlags = (WORD) tlbHeader.flags & 0xffff;/* check mask */
2024
2025     /* name, eventually add to a hash table */
2026     pTypeLibImpl->Name = MSFT_ReadName(&cx, tlbHeader.NameOffset);
2027
2028     /* help info */
2029     pTypeLibImpl->DocString = MSFT_ReadString(&cx, tlbHeader.helpstring);
2030     pTypeLibImpl->HelpFile = MSFT_ReadString(&cx, tlbHeader.helpfile);
2031
2032     if( tlbHeader.varflags & HELPDLLFLAG)
2033     {
2034             int offset;
2035             MSFT_Read(&offset, sizeof(offset), &cx, sizeof(tlbHeader));
2036             pTypeLibImpl->HelpStringDll = MSFT_ReadString(&cx, offset);
2037     }
2038
2039     pTypeLibImpl->dwHelpContext = tlbHeader.helpstringcontext;
2040
2041     /* custom data */
2042     if(tlbHeader.CustomDataOffset >= 0)
2043     {
2044         pTypeLibImpl->ctCustData = MSFT_CustData(&cx, tlbHeader.CustomDataOffset, &pTypeLibImpl->pCustData);
2045     }
2046
2047     /* fill in typedescriptions */
2048     if(tlbSegDir.pTypdescTab.length > 0)
2049     {
2050         int i, j, cTD = tlbSegDir.pTypdescTab.length / (2*sizeof(INT));
2051         INT16 td[4];
2052         pTypeLibImpl->pTypeDesc = TLB_Alloc( cTD * sizeof(TYPEDESC));
2053         MSFT_Read(td, sizeof(td), &cx, tlbSegDir.pTypdescTab.offset);
2054         for(i=0; i<cTD; )
2055         {
2056             /* FIXME: add several sanity checks here */
2057             pTypeLibImpl->pTypeDesc[i].vt = td[0] & VT_TYPEMASK;
2058             if(td[0] == VT_PTR || td[0] == VT_SAFEARRAY)
2059             {
2060                 /* FIXME: check safearray */
2061                 if(td[3] < 0)
2062                     pTypeLibImpl->pTypeDesc[i].u.lptdesc= & stndTypeDesc[td[2]];
2063                 else
2064                     pTypeLibImpl->pTypeDesc[i].u.lptdesc= & pTypeLibImpl->pTypeDesc[td[2]/8];
2065             }
2066             else if(td[0] == VT_CARRAY)
2067             {
2068                 /* array descr table here */
2069                 pTypeLibImpl->pTypeDesc[i].u.lpadesc = (void *)((int) td[2]);  /* temp store offset in*/
2070             }
2071             else if(td[0] == VT_USERDEFINED)
2072             {
2073                 pTypeLibImpl->pTypeDesc[i].u.hreftype = MAKELONG(td[2],td[3]);
2074             }
2075             if(++i<cTD) MSFT_Read(td, sizeof(td), &cx, DO_NOT_SEEK);
2076         }
2077
2078         /* second time around to fill the array subscript info */
2079         for(i=0;i<cTD;i++)
2080         {
2081             if(pTypeLibImpl->pTypeDesc[i].vt != VT_CARRAY) continue;
2082             if(tlbSegDir.pArrayDescriptions.offset>0)
2083             {
2084                 MSFT_Read(td, sizeof(td), &cx, tlbSegDir.pArrayDescriptions.offset + (int) pTypeLibImpl->pTypeDesc[i].u.lpadesc);
2085                 pTypeLibImpl->pTypeDesc[i].u.lpadesc = TLB_Alloc(sizeof(ARRAYDESC)+sizeof(SAFEARRAYBOUND)*(td[3]-1));
2086
2087                 if(td[1]<0)
2088                     pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem.vt = td[0] & VT_TYPEMASK;
2089                 else
2090                     pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem = stndTypeDesc[td[0]/8];
2091
2092                 pTypeLibImpl->pTypeDesc[i].u.lpadesc->cDims = td[2];
2093
2094                 for(j = 0; j<td[2]; j++)
2095                 {
2096                     MSFT_Read(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].cElements, 
2097                         sizeof(INT), &cx, DO_NOT_SEEK);
2098                     MSFT_Read(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].lLbound, 
2099                         sizeof(INT), &cx, DO_NOT_SEEK);
2100                 }
2101             }
2102             else
2103             {
2104                 pTypeLibImpl->pTypeDesc[i].u.lpadesc = NULL;
2105                 ERR("didn't find array description data\n");
2106             }
2107         }
2108     }
2109
2110     /* imported type libs */
2111     if(tlbSegDir.pImpFiles.offset>0)
2112     {
2113         TLBImpLib **ppImpLib = &(pTypeLibImpl->pImpLibs);
2114         int oGuid, offset = tlbSegDir.pImpFiles.offset;
2115         UINT16 size;
2116
2117         while(offset < tlbSegDir.pImpFiles.offset +tlbSegDir.pImpFiles.length)
2118         {
2119             *ppImpLib = TLB_Alloc(sizeof(TLBImpLib));
2120             (*ppImpLib)->offset = offset - tlbSegDir.pImpFiles.offset;
2121             MSFT_Read(&oGuid, sizeof(INT), &cx, offset);
2122
2123             MSFT_Read(&(*ppImpLib)->lcid,          sizeof(LCID),   &cx, DO_NOT_SEEK);
2124             MSFT_Read(&(*ppImpLib)->wVersionMajor, sizeof(WORD),   &cx, DO_NOT_SEEK);
2125             MSFT_Read(&(*ppImpLib)->wVersionMinor, sizeof(WORD),   &cx, DO_NOT_SEEK);
2126             MSFT_Read(& size,                      sizeof(UINT16), &cx, DO_NOT_SEEK);
2127
2128             size >>= 2;
2129             (*ppImpLib)->name = TLB_Alloc(size+1);
2130             MSFT_Read((*ppImpLib)->name, size, &cx, DO_NOT_SEEK);
2131             MSFT_ReadGuid(&(*ppImpLib)->guid, oGuid, &cx);
2132             offset = (offset + sizeof(INT) + sizeof(DWORD) + sizeof(LCID) + sizeof(UINT16) + size + 3) & 0xfffffffc;
2133
2134             ppImpLib = &(*ppImpLib)->next;
2135         }
2136     }
2137
2138     /* type info's */
2139     if(tlbHeader.nrtypeinfos >= 0 )
2140     {
2141         /*pTypeLibImpl->TypeInfoCount=tlbHeader.nrtypeinfos; */
2142         ITypeInfoImpl **ppTI = &(pTypeLibImpl->pTypeInfo);
2143         int i;
2144
2145         for(i = 0; i<(int)tlbHeader.nrtypeinfos; i++)
2146         {
2147             *ppTI = MSFT_DoTypeInfo(&cx, i, pTypeLibImpl);
2148
2149             ITypeInfo_AddRef((ITypeInfo*) *ppTI);
2150             ppTI = &((*ppTI)->next);
2151             (pTypeLibImpl->TypeInfoCount)++;
2152         }
2153     }
2154
2155     TRACE("(%p)\n", pTypeLibImpl);
2156     return (ITypeLib2*) pTypeLibImpl;
2157 }
2158
2159
2160 static BSTR TLB_MultiByteToBSTR(char *ptr)
2161 {
2162     DWORD len;
2163     WCHAR *nameW;
2164     BSTR ret;
2165
2166     len = MultiByteToWideChar(CP_ACP, 0, ptr, -1, NULL, 0);
2167     nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2168     MultiByteToWideChar(CP_ACP, 0, ptr, -1, nameW, len);
2169     ret = SysAllocString(nameW);
2170     HeapFree(GetProcessHeap(), 0, nameW);
2171     return ret;
2172 }
2173
2174 static BOOL TLB_GUIDFromString(char *str, GUID *guid)
2175 {
2176   char b[3];
2177   int i;
2178   short s;
2179
2180   if(sscanf(str, "%lx-%hx-%hx-%hx", &guid->Data1, &guid->Data2, &guid->Data3, &s) != 4) {
2181     FIXME("Can't parse guid %s\n", debugstr_guid(guid));
2182     return FALSE;
2183   }
2184
2185   guid->Data4[0] = s >> 8;
2186   guid->Data4[1] = s & 0xff;
2187
2188   b[2] = '\0';
2189   for(i = 0; i < 6; i++) {
2190     memcpy(b, str + 24 + 2 * i, 2);
2191     guid->Data4[i + 2] = strtol(b, NULL, 16);
2192   }
2193   return TRUE;
2194 }
2195
2196 static WORD SLTG_ReadString(char *ptr, BSTR *pBstr)
2197 {
2198     WORD bytelen;
2199     DWORD len;
2200     WCHAR *nameW;
2201
2202     *pBstr = NULL;
2203     bytelen = *(WORD*)ptr;
2204     if(bytelen == 0xffff) return 2;
2205     len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, NULL, 0);
2206     nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2207     len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, nameW, len);
2208     *pBstr = SysAllocStringLen(nameW, len);
2209     HeapFree(GetProcessHeap(), 0, nameW);
2210     return bytelen + 2;
2211 }
2212
2213 static WORD SLTG_ReadStringA(char *ptr, char **str)
2214 {
2215     WORD bytelen;
2216
2217     *str = NULL;
2218     bytelen = *(WORD*)ptr;
2219     if(bytelen == 0xffff) return 2;
2220     *str = HeapAlloc(GetProcessHeap(), 0, bytelen + 1);
2221     memcpy(*str, ptr + 2, bytelen);
2222     (*str)[bytelen] = '\0';
2223     return bytelen + 2;
2224 }
2225
2226 static DWORD SLTG_ReadLibBlk(LPVOID pLibBlk, ITypeLibImpl *pTypeLibImpl)
2227 {
2228     char *ptr = pLibBlk;
2229     WORD w;
2230
2231     if((w = *(WORD*)ptr) != SLTG_LIBBLK_MAGIC) {
2232         FIXME("libblk magic = %04x\n", w);
2233         return 0;
2234     }
2235
2236     ptr += 6;
2237     if((w = *(WORD*)ptr) != 0xffff) {
2238         FIXME("LibBlk.res06 = %04x. Assumung string and skipping\n", w);
2239         ptr += w;
2240     }
2241     ptr += 2;
2242
2243     ptr += SLTG_ReadString(ptr, &pTypeLibImpl->DocString);
2244
2245     ptr += SLTG_ReadString(ptr, &pTypeLibImpl->HelpFile);
2246
2247     pTypeLibImpl->dwHelpContext = *(DWORD*)ptr;
2248     ptr += 4;
2249
2250     pTypeLibImpl->LibAttr.syskind = *(WORD*)ptr;
2251     ptr += 2;
2252
2253     pTypeLibImpl->LibAttr.lcid = *(WORD*)ptr;
2254     ptr += 2;
2255
2256     ptr += 4; /* skip res12 */
2257
2258     pTypeLibImpl->LibAttr.wLibFlags = *(WORD*)ptr;
2259     ptr += 2;
2260
2261     pTypeLibImpl->LibAttr.wMajorVerNum = *(WORD*)ptr;
2262     ptr += 2;
2263
2264     pTypeLibImpl->LibAttr.wMinorVerNum = *(WORD*)ptr;
2265     ptr += 2;
2266
2267     memcpy(&pTypeLibImpl->LibAttr.guid, ptr, sizeof(GUID));
2268     ptr += sizeof(GUID);
2269
2270     return ptr - (char*)pLibBlk;
2271 }
2272
2273 static WORD *SLTG_DoType(WORD *pType, char *pBlk, ELEMDESC *pElem)
2274 {
2275     BOOL done = FALSE;
2276     TYPEDESC *pTD = &pElem->tdesc;
2277
2278     /* Handle [in/out] first */
2279     if((*pType & 0xc000) == 0xc000)
2280         pElem->u.paramdesc.wParamFlags = PARAMFLAG_NONE;
2281     else if(*pType & 0x8000)
2282         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN | PARAMFLAG_FOUT;
2283     else if(*pType & 0x4000)
2284         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FOUT;
2285     else
2286         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN;
2287
2288     if(*pType & 0x2000)
2289         pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FLCID;
2290
2291     if(*pType & 0x80)
2292         pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FRETVAL;
2293
2294     while(!done) {
2295         if((*pType & 0xe00) == 0xe00) {
2296             pTD->vt = VT_PTR;
2297             pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2298                                        sizeof(TYPEDESC));
2299             pTD = pTD->u.lptdesc;
2300         }
2301         switch(*pType & 0x7f) {
2302         case VT_PTR:
2303             pTD->vt = VT_PTR;
2304             pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2305                                        sizeof(TYPEDESC));
2306             pTD = pTD->u.lptdesc;
2307             break;
2308
2309         case VT_USERDEFINED:
2310             pTD->vt = VT_USERDEFINED;
2311             pTD->u.hreftype = *(++pType) / 4;
2312             done = TRUE;
2313             break;
2314
2315         case VT_CARRAY:
2316           {
2317             /* *(pType+1) is offset to a SAFEARRAY, *(pType+2) is type of
2318                array */
2319
2320             SAFEARRAY *pSA = (SAFEARRAY *)(pBlk + *(++pType));
2321
2322             pTD->vt = VT_CARRAY;
2323             pTD->u.lpadesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2324                                 sizeof(ARRAYDESC) +
2325                                 (pSA->cDims - 1) * sizeof(SAFEARRAYBOUND));
2326             pTD->u.lpadesc->cDims = pSA->cDims;
2327             memcpy(pTD->u.lpadesc->rgbounds, pSA->rgsabound,
2328                    pSA->cDims * sizeof(SAFEARRAYBOUND));
2329
2330             pTD = &pTD->u.lpadesc->tdescElem;
2331             break;
2332           }
2333
2334         case VT_SAFEARRAY:
2335           {
2336             /* FIXME: *(pType+1) gives an offset to SAFEARRAY, is this
2337                useful? */
2338
2339             pType++;
2340             pTD->vt = VT_SAFEARRAY;
2341             pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2342                                        sizeof(TYPEDESC));
2343             pTD = pTD->u.lptdesc;
2344             break;
2345           }
2346         default:
2347             pTD->vt = *pType & 0x7f;
2348             done = TRUE;
2349             break;
2350         }
2351         pType++;
2352     }
2353     return pType;
2354 }
2355
2356
2357 static void SLTG_DoRefs(SLTG_RefInfo *pRef, ITypeInfoImpl *pTI,
2358                         char *pNameTable)
2359 {
2360     int ref;
2361     char *name;
2362     TLBRefType **ppRefType;
2363
2364     if(pRef->magic != SLTG_REF_MAGIC) {
2365         FIXME("Ref magic = %x\n", pRef->magic);
2366         return;
2367     }
2368     name = ( (char*)(&pRef->names) + pRef->number);
2369
2370     ppRefType = &pTI->reflist;
2371     for(ref = 0; ref < pRef->number >> 3; ref++) {
2372         char *refname;
2373         unsigned int lib_offs, type_num;
2374
2375         *ppRefType = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2376                                sizeof(**ppRefType));
2377
2378         name += SLTG_ReadStringA(name, &refname);
2379         if(sscanf(refname, "*\\R%x*#%x", &lib_offs, &type_num) != 2)
2380             FIXME("Can't sscanf ref\n");
2381         if(lib_offs != 0xffff) {
2382             TLBImpLib **import = &pTI->pTypeLib->pImpLibs;
2383
2384             while(*import) {
2385                 if((*import)->offset == lib_offs)
2386                     break;
2387                 import = &(*import)->next;
2388             }
2389             if(!*import) {
2390                 char fname[MAX_PATH+1];
2391                 int len;
2392
2393                 *import = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2394                                     sizeof(**import));
2395                 (*import)->offset = lib_offs;
2396                 TLB_GUIDFromString( pNameTable + lib_offs + 4,
2397                                     &(*import)->guid);
2398                 if(sscanf(pNameTable + lib_offs + 40, "}#%hd.%hd#%lx#%s",
2399                           &(*import)->wVersionMajor,
2400                           &(*import)->wVersionMinor,
2401                           &(*import)->lcid, fname) != 4) {
2402                   FIXME("can't sscanf ref %s\n",
2403                         pNameTable + lib_offs + 40);
2404                 }
2405                 len = strlen(fname);
2406                 if(fname[len-1] != '#')
2407                     FIXME("fname = %s\n", fname);
2408                 fname[len-1] = '\0';
2409                 (*import)->name = TLB_MultiByteToBSTR(fname);
2410             }
2411             (*ppRefType)->pImpTLInfo = *import;
2412         } else { /* internal ref */
2413           (*ppRefType)->pImpTLInfo = TLB_REF_INTERNAL;
2414         }
2415         (*ppRefType)->reference = ref;
2416         (*ppRefType)->index = type_num;
2417
2418         HeapFree(GetProcessHeap(), 0, refname);
2419         ppRefType = &(*ppRefType)->next;
2420     }
2421     if((BYTE)*name != SLTG_REF_MAGIC)
2422       FIXME("End of ref block magic = %x\n", *name);
2423     dump_TLBRefType(pTI->reflist);
2424 }
2425
2426 static char *SLTG_DoImpls(char *pBlk, ITypeInfoImpl *pTI,
2427                           BOOL OneOnly)
2428 {
2429     SLTG_ImplInfo *info;
2430     TLBImplType **ppImplType = &pTI->impltypelist;
2431     /* I don't really get this structure, usually it's 0x16 bytes
2432        long, but iuser.tlb contains some that are 0x18 bytes long.
2433        That's ok because we can use the next ptr to jump to the next
2434        one. But how do we know the length of the last one?  The WORD
2435        at offs 0x8 might be the clue.  For now I'm just assuming that
2436        the last one is the regular 0x16 bytes. */
2437
2438     info = (SLTG_ImplInfo*)pBlk;
2439     while(1) {
2440         *ppImplType = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2441                                 sizeof(**ppImplType));
2442         (*ppImplType)->hRef = info->ref;
2443         (*ppImplType)->implflags = info->impltypeflags;
2444         pTI->TypeAttr.cImplTypes++;
2445         ppImplType = &(*ppImplType)->next;
2446
2447         if(info->next == 0xffff)
2448             break;
2449         if(OneOnly)
2450             FIXME("Interface inheriting more than one interface\n");
2451         info = (SLTG_ImplInfo*)(pBlk + info->next);
2452     }
2453     info++; /* see comment at top of function */
2454     return (char*)info;
2455 }
2456
2457 static SLTG_TypeInfoTail *SLTG_ProcessCoClass(char *pBlk, ITypeInfoImpl *pTI,
2458                                               char *pNameTable)
2459 {
2460     SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk;
2461     SLTG_MemberHeader *pMemHeader;
2462     char *pFirstItem, *pNextItem;
2463
2464     if(pTIHeader->href_table != 0xffffffff) {
2465         SLTG_DoRefs((SLTG_RefInfo*)(pBlk + pTIHeader->href_table), pTI,
2466                     pNameTable);
2467     }
2468
2469
2470     pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table);
2471
2472     pFirstItem = pNextItem = (char*)(pMemHeader + 1);
2473
2474     if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
2475         pNextItem = SLTG_DoImpls(pFirstItem, pTI, FALSE);
2476     }
2477
2478     return (SLTG_TypeInfoTail*)(pFirstItem + pMemHeader->cbExtra);
2479 }
2480
2481
2482 static SLTG_TypeInfoTail *SLTG_ProcessInterface(char *pBlk, ITypeInfoImpl *pTI,
2483                                                 char *pNameTable)
2484 {
2485     SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk;
2486     SLTG_MemberHeader *pMemHeader;
2487     SLTG_Function *pFunc;
2488     char *pFirstItem, *pNextItem;
2489     TLBFuncDesc **ppFuncDesc = &pTI->funclist;
2490     int num = 0;
2491
2492     if(pTIHeader->href_table != 0xffffffff) {
2493         SLTG_DoRefs((SLTG_RefInfo*)(pBlk + pTIHeader->href_table), pTI,
2494                     pNameTable);
2495     }
2496
2497     pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table);
2498
2499     pFirstItem = pNextItem = (char*)(pMemHeader + 1);
2500
2501     if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
2502         pNextItem = SLTG_DoImpls(pFirstItem, pTI, TRUE);
2503     }
2504
2505     for(pFunc = (SLTG_Function*)pNextItem, num = 1; 1;
2506         pFunc = (SLTG_Function*)(pFirstItem + pFunc->next), num++) {
2507
2508         int param;
2509         WORD *pType, *pArg;
2510
2511         if(pFunc->magic != SLTG_FUNCTION_MAGIC &&
2512            pFunc->magic != SLTG_FUNCTION_WITH_FLAGS_MAGIC) {
2513             FIXME("func magic = %02x\n", pFunc->magic);
2514             return NULL;
2515         }
2516         *ppFuncDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2517                                 sizeof(**ppFuncDesc));
2518         (*ppFuncDesc)->Name = TLB_MultiByteToBSTR(pFunc->name + pNameTable);
2519
2520         (*ppFuncDesc)->funcdesc.memid = pFunc->dispid;
2521         (*ppFuncDesc)->funcdesc.invkind = pFunc->inv >> 4;
2522         (*ppFuncDesc)->funcdesc.callconv = pFunc->nacc & 0x7;
2523         (*ppFuncDesc)->funcdesc.cParams = pFunc->nacc >> 3;
2524         (*ppFuncDesc)->funcdesc.cParamsOpt = (pFunc->retnextopt & 0x7e) >> 1;
2525         (*ppFuncDesc)->funcdesc.oVft = pFunc->vtblpos;
2526
2527         if(pFunc->magic == SLTG_FUNCTION_WITH_FLAGS_MAGIC)
2528             (*ppFuncDesc)->funcdesc.wFuncFlags = pFunc->funcflags;
2529
2530         if(pFunc->retnextopt & 0x80)
2531             pType = &pFunc->rettype;
2532         else
2533             pType = (WORD*)(pFirstItem + pFunc->rettype);
2534
2535
2536         SLTG_DoType(pType, pFirstItem, &(*ppFuncDesc)->funcdesc.elemdescFunc);
2537
2538         (*ppFuncDesc)->funcdesc.lprgelemdescParam =
2539           HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2540                     (*ppFuncDesc)->funcdesc.cParams * sizeof(ELEMDESC));
2541         (*ppFuncDesc)->pParamDesc =
2542           HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2543                     (*ppFuncDesc)->funcdesc.cParams * sizeof(TLBParDesc));
2544
2545         pArg = (WORD*)(pFirstItem + pFunc->arg_off);
2546
2547         for(param = 0; param < (*ppFuncDesc)->funcdesc.cParams; param++) {
2548             char *paramName = pNameTable + *pArg;
2549             BOOL HaveOffs;
2550             /* If arg type follows then paramName points to the 2nd
2551                letter of the name, else the next WORD is an offset to
2552                the arg type and paramName points to the first letter.
2553                So let's take one char off paramName and see if we're
2554                pointing at an alpha-numeric char.  However if *pArg is
2555                0xffff or 0xfffe then the param has no name, the former
2556                meaning that the next WORD is the type, the latter
2557                meaning the the next WORD is an offset to the type. */
2558
2559             HaveOffs = FALSE;
2560             if(*pArg == 0xffff)
2561                 paramName = NULL;
2562             else if(*pArg == 0xfffe) {
2563                 paramName = NULL;
2564                 HaveOffs = TRUE;
2565             }
2566             else if(!isalnum(*(paramName-1)))
2567                 HaveOffs = TRUE;
2568
2569             pArg++;
2570
2571             if(HaveOffs) { /* the next word is an offset to type */
2572                 pType = (WORD*)(pFirstItem + *pArg);
2573                 SLTG_DoType(pType, pFirstItem,
2574                             &(*ppFuncDesc)->funcdesc.lprgelemdescParam[param]);
2575                 pArg++;
2576             } else {
2577                 if(paramName)
2578                   paramName--;
2579                 pArg = SLTG_DoType(pArg, pFirstItem,
2580                            &(*ppFuncDesc)->funcdesc.lprgelemdescParam[param]);
2581             }
2582
2583             /* Are we an optional param ? */
2584             if((*ppFuncDesc)->funcdesc.cParams - param <=
2585                (*ppFuncDesc)->funcdesc.cParamsOpt)
2586               (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].u.paramdesc.wParamFlags |= PARAMFLAG_FOPT;
2587
2588             if(paramName) {
2589                 (*ppFuncDesc)->pParamDesc[param].Name =
2590                   TLB_MultiByteToBSTR(paramName);
2591             }
2592         }
2593         
2594         ppFuncDesc = &((*ppFuncDesc)->next);
2595         if(pFunc->next == 0xffff) break;
2596     }
2597     pTI->TypeAttr.cFuncs = num;
2598     dump_TLBFuncDesc(pTI->funclist);
2599     return (SLTG_TypeInfoTail*)(pFirstItem + pMemHeader->cbExtra);
2600 }
2601
2602 static SLTG_TypeInfoTail *SLTG_ProcessRecord(char *pBlk, ITypeInfoImpl *pTI,
2603                                              char *pNameTable)
2604 {
2605   SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk;
2606   SLTG_MemberHeader *pMemHeader;
2607   SLTG_RecordItem *pItem;
2608   char *pFirstItem;
2609   TLBVarDesc **ppVarDesc = &pTI->varlist;
2610   int num = 0;
2611   WORD *pType;
2612   char buf[300];
2613
2614   pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table);
2615
2616   pFirstItem = (char*)(pMemHeader + 1);
2617   for(pItem = (SLTG_RecordItem *)pFirstItem, num = 1; 1;
2618       pItem = (SLTG_RecordItem *)(pFirstItem + pItem->next), num++) {
2619       if(pItem->magic != SLTG_RECORD_MAGIC) {
2620           FIXME("record magic = %02x\n", pItem->magic);
2621           return NULL;
2622       }
2623       *ppVarDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2624                              sizeof(**ppVarDesc));
2625       (*ppVarDesc)->Name = TLB_MultiByteToBSTR(pItem->name + pNameTable);
2626       (*ppVarDesc)->vardesc.memid = pItem->memid;
2627       (*ppVarDesc)->vardesc.u.oInst = pItem->byte_offs;
2628       (*ppVarDesc)->vardesc.varkind = VAR_PERINSTANCE;
2629
2630       if(pItem->typepos == 0x02)
2631           pType = &pItem->type;
2632       else if(pItem->typepos == 0x00)
2633           pType = (WORD*)(pFirstItem + pItem->type);
2634       else {
2635           FIXME("typepos = %02x\n", pItem->typepos);
2636           break;
2637       }
2638
2639       SLTG_DoType(pType, pFirstItem,
2640                   &(*ppVarDesc)->vardesc.elemdescVar);
2641
2642       /* FIXME("helpcontext, helpstring\n"); */
2643
2644       dump_TypeDesc(&(*ppVarDesc)->vardesc.elemdescVar.tdesc, buf);
2645
2646       ppVarDesc = &((*ppVarDesc)->next);
2647       if(pItem->next == 0xffff) break;
2648   }
2649   pTI->TypeAttr.cVars = num;
2650   return (SLTG_TypeInfoTail*)(pFirstItem + pMemHeader->cbExtra);
2651 }
2652
2653 static SLTG_TypeInfoTail *SLTG_ProcessEnum(char *pBlk, ITypeInfoImpl *pTI,
2654                                            char *pNameTable)
2655 {
2656   SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk;
2657   SLTG_MemberHeader *pMemHeader;
2658   SLTG_EnumItem *pItem;
2659   char *pFirstItem;
2660   TLBVarDesc **ppVarDesc = &pTI->varlist;
2661   int num = 0;
2662
2663   pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table);
2664
2665   pFirstItem = (char*)(pMemHeader + 1);
2666   for(pItem = (SLTG_EnumItem *)pFirstItem, num = 1; 1;
2667       pItem = (SLTG_EnumItem *)(pFirstItem + pItem->next), num++) {
2668       if(pItem->magic != SLTG_ENUMITEM_MAGIC) {
2669           FIXME("enumitem magic = %04x\n", pItem->magic);
2670           return NULL;
2671       }
2672       *ppVarDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2673                              sizeof(**ppVarDesc));
2674       (*ppVarDesc)->Name = TLB_MultiByteToBSTR(pItem->name + pNameTable);
2675       (*ppVarDesc)->vardesc.memid = pItem->memid;
2676       (*ppVarDesc)->vardesc.u.lpvarValue = HeapAlloc(GetProcessHeap(), 0,
2677                                                      sizeof(VARIANT));
2678       V_VT((*ppVarDesc)->vardesc.u.lpvarValue) = VT_INT;
2679       V_UNION((*ppVarDesc)->vardesc.u.lpvarValue, intVal) =
2680         *(INT*)(pItem->value + pFirstItem);
2681       (*ppVarDesc)->vardesc.elemdescVar.tdesc.vt = VT_I4;
2682       (*ppVarDesc)->vardesc.varkind = VAR_CONST;
2683       /* FIXME("helpcontext, helpstring\n"); */
2684
2685       ppVarDesc = &((*ppVarDesc)->next);
2686       if(pItem->next == 0xffff) break;
2687   }
2688   pTI->TypeAttr.cVars = num;
2689   return (SLTG_TypeInfoTail*)(pFirstItem + pMemHeader->cbExtra);
2690 }
2691
2692 /* Because SLTG_OtherTypeInfo is such a painfull struct, we make a more
2693    managable copy of it into this */
2694 typedef struct {
2695   WORD small_no;
2696   char *index_name;
2697   char *other_name;
2698   WORD res1a;
2699   WORD name_offs;
2700   WORD more_bytes;
2701   char *extra;
2702   WORD res20;
2703   DWORD helpcontext;
2704   WORD res26;
2705   GUID uuid;
2706 } SLTG_InternalOtherTypeInfo;
2707
2708 /****************************************************************************
2709  *      ITypeLib2_Constructor_SLTG
2710  *
2711  * loading a SLTG typelib from an in-memory image
2712  */
2713 static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength)
2714 {
2715     ITypeLibImpl *pTypeLibImpl;
2716     SLTG_Header *pHeader;
2717     SLTG_BlkEntry *pBlkEntry;
2718     SLTG_Magic *pMagic;
2719     SLTG_Index *pIndex;
2720     SLTG_Pad9 *pPad9;
2721     LPVOID pBlk, pFirstBlk;
2722     SLTG_LibBlk *pLibBlk;
2723     SLTG_InternalOtherTypeInfo *pOtherTypeInfoBlks;
2724     char *pAfterOTIBlks = NULL;
2725     char *pNameTable, *ptr;
2726     int i;
2727     DWORD len, order;
2728     ITypeInfoImpl **ppTypeInfoImpl;
2729
2730     TRACE("%p, TLB length = %ld\n", pLib, dwTLBLength);
2731
2732     pTypeLibImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeLibImpl));
2733     if (!pTypeLibImpl) return NULL;
2734
2735     ICOM_VTBL(pTypeLibImpl) = &tlbvt;
2736     pTypeLibImpl->ref = 1;
2737
2738     pHeader = pLib;
2739     
2740     TRACE("header:\n");
2741     TRACE("\tmagic=0x%08lx, file blocks = %d\n", pHeader->SLTG_magic,
2742           pHeader->nrOfFileBlks );
2743     if (memcmp(&pHeader->SLTG_magic, TLBMAGIC1, 4)) {
2744         FIXME("Header type magic 0x%08lx not supported.\n",
2745               pHeader->SLTG_magic);
2746         return NULL;
2747     }
2748     
2749     /* There are pHeader->nrOfFileBlks - 2 TypeInfo records in this typelib */
2750     pTypeLibImpl->TypeInfoCount = pHeader->nrOfFileBlks - 2;
2751
2752     /* This points to pHeader->nrOfFileBlks - 1 of SLTG_BlkEntry */
2753     pBlkEntry = (SLTG_BlkEntry*)(pHeader + 1);
2754
2755     /* Next we have a magic block */
2756     pMagic = (SLTG_Magic*)(pBlkEntry + pHeader->nrOfFileBlks - 1);
2757
2758     /* Let's see if we're still in sync */
2759     if(memcmp(pMagic->CompObj_magic, SLTG_COMPOBJ_MAGIC,
2760               sizeof(SLTG_COMPOBJ_MAGIC))) {
2761         FIXME("CompObj magic = %s\n", pMagic->CompObj_magic);
2762         return NULL;
2763     }
2764     if(memcmp(pMagic->dir_magic, SLTG_DIR_MAGIC,
2765               sizeof(SLTG_DIR_MAGIC))) {
2766         FIXME("dir magic = %s\n", pMagic->dir_magic);
2767         return NULL;
2768     }
2769
2770     pIndex = (SLTG_Index*)(pMagic+1);
2771
2772     pPad9 = (SLTG_Pad9*)(pIndex + pTypeLibImpl->TypeInfoCount);
2773
2774     pFirstBlk = (LPVOID)(pPad9 + 1);
2775
2776     /* We'll set up a ptr to the main library block, which is the last one. */
2777
2778     for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0;
2779           pBlkEntry[order].next != 0;
2780           order = pBlkEntry[order].next - 1, i++) {
2781         pBlk += pBlkEntry[order].len;
2782     }
2783     pLibBlk = pBlk;
2784
2785     len = SLTG_ReadLibBlk(pLibBlk, pTypeLibImpl);
2786
2787     /* Now there's 0x40 bytes of 0xffff with the numbers 0 to TypeInfoCount
2788        interspersed */
2789
2790     len += 0x40;
2791
2792     /* And now TypeInfoCount of SLTG_OtherTypeInfo */
2793
2794     pOtherTypeInfoBlks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2795                                    sizeof(*pOtherTypeInfoBlks) *
2796                                    pTypeLibImpl->TypeInfoCount);
2797
2798
2799     ptr = (char*)pLibBlk + len;
2800     
2801     for(i = 0; i < pTypeLibImpl->TypeInfoCount; i++) {
2802         WORD w, extra;
2803         len = 0;
2804
2805         pOtherTypeInfoBlks[i].small_no = *(WORD*)ptr;
2806
2807         w = *(WORD*)(ptr + 2);
2808         if(w != 0xffff) {
2809             len += w;
2810             pOtherTypeInfoBlks[i].index_name = HeapAlloc(GetProcessHeap(),0,
2811                                                          w+1);
2812             memcpy(pOtherTypeInfoBlks[i].index_name, ptr + 4, w);
2813             pOtherTypeInfoBlks[i].index_name[w] = '\0';
2814         }
2815         w = *(WORD*)(ptr + 4 + len);
2816         if(w != 0xffff) {
2817             TRACE("\twith %s\n", debugstr_an(ptr + 6 + len, w));
2818             len += w;
2819             pOtherTypeInfoBlks[i].other_name = HeapAlloc(GetProcessHeap(),0,
2820                                                          w+1);
2821             memcpy(pOtherTypeInfoBlks[i].other_name, ptr + 6 + len, w);
2822             pOtherTypeInfoBlks[i].other_name[w] = '\0';
2823         }
2824         pOtherTypeInfoBlks[i].res1a = *(WORD*)(ptr + len + 6);
2825         pOtherTypeInfoBlks[i].name_offs = *(WORD*)(ptr + len + 8);
2826         extra = pOtherTypeInfoBlks[i].more_bytes = *(WORD*)(ptr + 10 + len);
2827         if(extra) {
2828             pOtherTypeInfoBlks[i].extra = HeapAlloc(GetProcessHeap(),0,
2829                                                     extra);
2830             memcpy(pOtherTypeInfoBlks[i].extra, ptr + 12, extra);
2831             len += extra;
2832         }
2833         pOtherTypeInfoBlks[i].res20 = *(WORD*)(ptr + 12 + len);
2834         pOtherTypeInfoBlks[i].helpcontext = *(DWORD*)(ptr + 14 + len);
2835         pOtherTypeInfoBlks[i].res26 = *(WORD*)(ptr + 18 + len);
2836         memcpy(&pOtherTypeInfoBlks[i].uuid, ptr + 20 + len, sizeof(GUID));
2837         len += sizeof(SLTG_OtherTypeInfo);
2838         ptr += len;
2839     }
2840
2841     pAfterOTIBlks = ptr;
2842
2843     /* Skip this WORD and get the next DWORD */
2844     len = *(DWORD*)(pAfterOTIBlks + 2);
2845
2846     /* Now add this to pLibBLk and then add 0x216, sprinkle a bit a
2847        magic dust and we should be pointing at the beginning of the name
2848        table */
2849
2850     pNameTable = (char*)pLibBlk + len + 0x216;
2851     
2852     pNameTable += 2;
2853
2854     TRACE("Library name is %s\n", pNameTable + pLibBlk->name);
2855
2856     pTypeLibImpl->Name = TLB_MultiByteToBSTR(pNameTable + pLibBlk->name);
2857
2858
2859     /* Hopefully we now have enough ptrs set up to actually read in
2860        some TypeInfos.  It's not clear which order to do them in, so
2861        I'll just follow the links along the BlkEntry chain and read
2862        them in in the order in which they're in the file */
2863
2864     ppTypeInfoImpl = &(pTypeLibImpl->pTypeInfo);
2865
2866     for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0;
2867         pBlkEntry[order].next != 0;
2868         order = pBlkEntry[order].next - 1, i++) {
2869
2870       SLTG_TypeInfoHeader *pTIHeader;
2871       SLTG_TypeInfoTail *pTITail;
2872
2873       if(strcmp(pBlkEntry[order].index_string + (char*)pMagic,
2874                 pOtherTypeInfoBlks[i].index_name)) {
2875         FIXME("Index strings don't match\n");
2876         return NULL;
2877       }
2878
2879       pTIHeader = pBlk;
2880       if(pTIHeader->magic != SLTG_TIHEADER_MAGIC) {
2881         FIXME("TypeInfoHeader magic = %04x\n", pTIHeader->magic);
2882         return NULL;
2883       }
2884       *ppTypeInfoImpl = (ITypeInfoImpl*)ITypeInfo_Constructor();
2885       (*ppTypeInfoImpl)->pTypeLib = pTypeLibImpl;
2886       (*ppTypeInfoImpl)->index = i;
2887       (*ppTypeInfoImpl)->Name = TLB_MultiByteToBSTR(
2888                                              pOtherTypeInfoBlks[i].name_offs +
2889                                              pNameTable);
2890       (*ppTypeInfoImpl)->dwHelpContext = pOtherTypeInfoBlks[i].helpcontext;
2891       memcpy(&((*ppTypeInfoImpl)->TypeAttr.guid), &pOtherTypeInfoBlks[i].uuid,
2892              sizeof(GUID));
2893       (*ppTypeInfoImpl)->TypeAttr.typekind = pTIHeader->typekind;
2894       (*ppTypeInfoImpl)->TypeAttr.wMajorVerNum = pTIHeader->major_version;
2895       (*ppTypeInfoImpl)->TypeAttr.wMinorVerNum = pTIHeader->minor_version;
2896       (*ppTypeInfoImpl)->TypeAttr.wTypeFlags =
2897         (pTIHeader->typeflags1 >> 3) | (pTIHeader->typeflags2 << 5);
2898       
2899       if((pTIHeader->typeflags1 & 7) != 2)
2900         FIXME("typeflags1 = %02x\n", pTIHeader->typeflags1);
2901       if(pTIHeader->typeflags3 != 2)
2902         FIXME("typeflags3 = %02x\n", pTIHeader->typeflags3);
2903
2904       TRACE("TypeInfo %s of kind %s guid %s typeflags %04x\n",
2905             debugstr_w((*ppTypeInfoImpl)->Name),
2906             typekind_desc[pTIHeader->typekind],
2907             debugstr_guid(&(*ppTypeInfoImpl)->TypeAttr.guid),
2908             (*ppTypeInfoImpl)->TypeAttr.wTypeFlags);
2909
2910       switch(pTIHeader->typekind) {
2911       case TKIND_ENUM:
2912         pTITail = SLTG_ProcessEnum(pBlk, *ppTypeInfoImpl, pNameTable); 
2913         break;
2914
2915       case TKIND_RECORD:
2916         pTITail = SLTG_ProcessRecord(pBlk, *ppTypeInfoImpl, pNameTable); 
2917         break;
2918
2919       case TKIND_INTERFACE:
2920         pTITail = SLTG_ProcessInterface(pBlk, *ppTypeInfoImpl, pNameTable);
2921         break;
2922
2923       case TKIND_COCLASS:
2924         pTITail = SLTG_ProcessCoClass(pBlk, *ppTypeInfoImpl, pNameTable);
2925         break;
2926
2927       default:
2928         FIXME("Not processing typekind %d\n", pTIHeader->typekind);
2929         pTITail = NULL;
2930         break;
2931
2932       }
2933
2934       if(pTITail) { /* could get cFuncs, cVars and cImplTypes from here
2935                        but we've already set those */
2936           (*ppTypeInfoImpl)->TypeAttr.cbAlignment = pTITail->cbAlignment;
2937           (*ppTypeInfoImpl)->TypeAttr.cbSizeInstance = pTITail->cbSizeInstance;
2938           (*ppTypeInfoImpl)->TypeAttr.cbSizeVft = pTITail->cbSizeVft;
2939       }
2940       ppTypeInfoImpl = &((*ppTypeInfoImpl)->next);
2941       pBlk += pBlkEntry[order].len;
2942     }
2943
2944     if(i != pTypeLibImpl->TypeInfoCount) {
2945       FIXME("Somehow processed %d TypeInfos\n", i);
2946       return NULL;
2947     }
2948
2949     HeapFree(GetProcessHeap(), 0, pOtherTypeInfoBlks);
2950     return (ITypeLib2*)pTypeLibImpl;
2951 }
2952
2953 /* ITypeLib::QueryInterface
2954  */
2955 static HRESULT WINAPI ITypeLib2_fnQueryInterface(
2956         ITypeLib2 * iface,
2957         REFIID riid,
2958         VOID **ppvObject)
2959 {
2960     ICOM_THIS( ITypeLibImpl, iface);
2961
2962     TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
2963
2964     *ppvObject=NULL;
2965     if(IsEqualIID(riid, &IID_IUnknown) || 
2966        IsEqualIID(riid,&IID_ITypeLib)||
2967        IsEqualIID(riid,&IID_ITypeLib2))
2968     {
2969         *ppvObject = This;
2970     }
2971
2972     if(*ppvObject)
2973     {
2974         ITypeLib2_AddRef(iface);
2975         TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
2976         return S_OK;
2977     }
2978     TRACE("-- Interface: E_NOINTERFACE\n");
2979     return E_NOINTERFACE;
2980 }
2981
2982 /* ITypeLib::AddRef
2983  */
2984 static ULONG WINAPI ITypeLib2_fnAddRef( ITypeLib2 *iface)
2985 {
2986     ICOM_THIS( ITypeLibImpl, iface);
2987
2988     TRACE("(%p)->ref is %u\n",This, This->ref);
2989
2990     return ++(This->ref);
2991 }
2992
2993 /* ITypeLib::Release
2994  */
2995 static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface)
2996 {
2997     ICOM_THIS( ITypeLibImpl, iface);
2998
2999     --(This->ref);
3000     
3001     TRACE("(%p)->(%u)\n",This, This->ref);
3002
3003     if (!This->ref)
3004     {
3005       /* FIXME destroy child objects */
3006
3007       TRACE(" destroying ITypeLib(%p)\n",This);
3008
3009       if (This->Name)
3010       {
3011           SysFreeString(This->Name);
3012           This->Name = NULL;
3013       }
3014
3015       if (This->DocString)
3016       {
3017           SysFreeString(This->DocString);
3018           This->DocString = NULL;
3019       }
3020
3021       if (This->HelpFile)
3022       {
3023           SysFreeString(This->HelpFile);
3024           This->HelpFile = NULL;
3025       }
3026
3027       if (This->HelpStringDll)
3028       {
3029           SysFreeString(This->HelpStringDll);
3030           This->HelpStringDll = NULL;
3031       }
3032     
3033       ITypeInfo_Release((ITypeInfo*) This->pTypeInfo);
3034       HeapFree(GetProcessHeap(),0,This);
3035       return 0;
3036     }
3037
3038     return This->ref;
3039 }
3040
3041 /* ITypeLib::GetTypeInfoCount
3042  * 
3043  * Returns the number of type descriptions in the type library
3044  */
3045 static UINT WINAPI ITypeLib2_fnGetTypeInfoCount( ITypeLib2 *iface)
3046 {
3047     ICOM_THIS( ITypeLibImpl, iface);
3048     TRACE("(%p)->count is %d\n",This, This->TypeInfoCount);
3049     return This->TypeInfoCount;
3050 }
3051
3052 /* ITypeLib::GetTypeInfo
3053  *
3054  * retrieves the specified type description in the library.
3055  */
3056 static HRESULT WINAPI ITypeLib2_fnGetTypeInfo(
3057     ITypeLib2 *iface,
3058     UINT index, 
3059     ITypeInfo **ppTInfo)
3060 {
3061     int i;
3062     
3063     ICOM_THIS( ITypeLibImpl, iface);
3064     ITypeInfoImpl *pTypeInfo = This->pTypeInfo;
3065
3066     TRACE("(%p)->(index=%d) \n", This, index);
3067
3068     if (!ppTInfo) return E_INVALIDARG;
3069     
3070     /* search element n in list */
3071     for(i=0; i < index; i++)
3072     {
3073       pTypeInfo = pTypeInfo->next;
3074       if (!pTypeInfo)
3075       {
3076         TRACE("-- element not found\n");
3077         return TYPE_E_ELEMENTNOTFOUND;
3078       }
3079     }   
3080
3081     *ppTInfo = (ITypeInfo *) pTypeInfo;
3082     
3083     ITypeInfo_AddRef(*ppTInfo);
3084     TRACE("-- found (%p)\n",*ppTInfo);
3085     return S_OK;
3086 }
3087
3088
3089 /* ITypeLibs::GetTypeInfoType
3090  *
3091  * Retrieves the type of a type description.
3092  */
3093 static HRESULT WINAPI ITypeLib2_fnGetTypeInfoType(
3094     ITypeLib2 *iface,
3095     UINT index,
3096     TYPEKIND *pTKind)
3097 {
3098     ICOM_THIS( ITypeLibImpl, iface);
3099     int i;
3100     ITypeInfoImpl *pTInfo = This->pTypeInfo;
3101
3102     TRACE("(%p) index %d \n",This, index);
3103
3104     if(!pTKind) return E_INVALIDARG;
3105     
3106     /* search element n in list */
3107     for(i=0; i < index; i++)
3108     {
3109       if(!pTInfo)
3110       {
3111         TRACE("-- element not found\n");
3112         return TYPE_E_ELEMENTNOTFOUND;
3113       }
3114       pTInfo = pTInfo->next;
3115     }
3116
3117     *pTKind = pTInfo->TypeAttr.typekind;
3118     TRACE("-- found Type (%d)\n", *pTKind);
3119     return S_OK;
3120 }
3121
3122 /* ITypeLib::GetTypeInfoOfGuid
3123  *
3124  * Retrieves the type description that corresponds to the specified GUID.
3125  *
3126  */
3127 static HRESULT WINAPI ITypeLib2_fnGetTypeInfoOfGuid(
3128     ITypeLib2 *iface,
3129     REFGUID guid,
3130     ITypeInfo **ppTInfo)
3131 {
3132     ICOM_THIS( ITypeLibImpl, iface);
3133     ITypeInfoImpl *pTypeInfo = This->pTypeInfo; /* head of list */
3134
3135     TRACE("(%p)\n\tguid:\t%s)\n",This,debugstr_guid(guid));
3136
3137     if (!pTypeInfo) return TYPE_E_ELEMENTNOTFOUND;
3138
3139     /* search linked list for guid */
3140     while( !IsEqualIID(guid,&pTypeInfo->TypeAttr.guid) )
3141     {
3142       pTypeInfo = pTypeInfo->next;
3143
3144       if (!pTypeInfo)
3145       {
3146         /* end of list reached */
3147         TRACE("-- element not found\n");
3148         return TYPE_E_ELEMENTNOTFOUND;
3149       }
3150     }
3151
3152     TRACE("-- found (%p, %s)\n", 
3153           pTypeInfo, 
3154           debugstr_w(pTypeInfo->Name));
3155
3156     *ppTInfo = (ITypeInfo*)pTypeInfo;
3157     ITypeInfo_AddRef(*ppTInfo);
3158     return S_OK;
3159 }
3160
3161 /* ITypeLib::GetLibAttr
3162  *
3163  * Retrieves the structure that contains the library's attributes.
3164  *
3165  */
3166 static HRESULT WINAPI ITypeLib2_fnGetLibAttr(
3167         ITypeLib2 *iface, 
3168         LPTLIBATTR *ppTLibAttr)
3169 {
3170     ICOM_THIS( ITypeLibImpl, iface);
3171     TRACE("(%p)\n",This);
3172     *ppTLibAttr = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppTLibAttr));
3173     memcpy(*ppTLibAttr, &This->LibAttr, sizeof(**ppTLibAttr));
3174     return S_OK;
3175 }
3176
3177 /* ITypeLib::GetTypeComp
3178  *
3179  * Enables a client compiler to bind to a library's types, variables,
3180  * constants, and global functions.
3181  *
3182  */
3183 static HRESULT WINAPI ITypeLib2_fnGetTypeComp(
3184         ITypeLib2 *iface,
3185         ITypeComp **ppTComp)
3186 {
3187     ICOM_THIS( ITypeLibImpl, iface);
3188     FIXME("(%p): stub!\n",This);
3189     return E_NOTIMPL;
3190 }
3191
3192 /* ITypeLib::GetDocumentation
3193  *
3194  * Retrieves the library's documentation string, the complete Help file name
3195  * and path, and the context identifier for the library Help topic in the Help
3196  * file.
3197  *
3198  * On a successful return all non-null BSTR pointers will have been set,
3199  * possibly to NULL.
3200  */
3201 static HRESULT WINAPI ITypeLib2_fnGetDocumentation(
3202     ITypeLib2 *iface,
3203     INT index,
3204     BSTR *pBstrName,
3205     BSTR *pBstrDocString,
3206     DWORD *pdwHelpContext, 
3207     BSTR *pBstrHelpFile)
3208 {
3209     ICOM_THIS( ITypeLibImpl, iface);
3210     
3211     HRESULT result = E_INVALIDARG;
3212     
3213     ITypeInfo *pTInfo;
3214
3215    
3216     TRACE("(%p) index %d Name(%p) DocString(%p) HelpContext(%p) HelpFile(%p)\n",
3217         This, index,
3218         pBstrName, pBstrDocString, 
3219         pdwHelpContext, pBstrHelpFile);
3220    
3221     if(index<0)
3222     { 
3223         /* documentation for the typelib */
3224         if(pBstrName)
3225         {
3226             if (This->Name)
3227                 if(!(*pBstrName = SysAllocString(This->Name))) goto memerr1;else;
3228             else
3229                 *pBstrName = NULL;
3230         }
3231         if(pBstrDocString)
3232         {
3233             if (This->DocString)
3234                 if(!(*pBstrDocString = SysAllocString(This->DocString))) goto memerr2;else;
3235             else if (This->Name)
3236                 if(!(*pBstrDocString = SysAllocString(This->Name))) goto memerr2;else;
3237             else
3238                 *pBstrDocString = NULL;
3239         }
3240         if(pdwHelpContext)
3241         {
3242             *pdwHelpContext = This->dwHelpContext;
3243         }
3244         if(pBstrHelpFile)
3245         {
3246             if (This->HelpFile)
3247                 if(!(*pBstrHelpFile = SysAllocString(This->HelpFile))) goto memerr3;else;
3248             else
3249                 *pBstrHelpFile = NULL;
3250         }
3251
3252         result = S_OK;
3253     }
3254     else 
3255     {
3256         /* for a typeinfo */
3257         result = ITypeLib2_fnGetTypeInfo(iface, index, &pTInfo);
3258
3259         if(SUCCEEDED(result))
3260         {
3261             result = ITypeInfo_GetDocumentation(pTInfo, 
3262                                           MEMBERID_NIL,  
3263                                           pBstrName,
3264                                           pBstrDocString, 
3265                                           pdwHelpContext, pBstrHelpFile);
3266             
3267             ITypeInfo_Release(pTInfo);
3268         }
3269     }
3270     return result;
3271 memerr3:
3272     if (pBstrDocString) SysFreeString (*pBstrDocString);
3273 memerr2:
3274     if (pBstrName) SysFreeString (*pBstrName);
3275 memerr1:
3276     return STG_E_INSUFFICIENTMEMORY;
3277 }
3278
3279 /* ITypeLib::IsName
3280  *
3281  * Indicates whether a passed-in string contains the name of a type or member
3282  * described in the library.
3283  *
3284  */
3285 static HRESULT WINAPI ITypeLib2_fnIsName(
3286         ITypeLib2 *iface,
3287         LPOLESTR szNameBuf,
3288         ULONG lHashVal,
3289         BOOL *pfName)
3290 {
3291     ICOM_THIS( ITypeLibImpl, iface);
3292     ITypeInfoImpl *pTInfo;
3293     TLBFuncDesc *pFInfo;
3294     TLBVarDesc *pVInfo;
3295     int i;
3296     UINT nNameBufLen = SysStringLen(szNameBuf);
3297
3298     TRACE("(%p)->(%s,%08lx,%p)\n", This, debugstr_w(szNameBuf), lHashVal,
3299           pfName);
3300
3301     *pfName=TRUE;
3302     for(pTInfo=This->pTypeInfo;pTInfo;pTInfo=pTInfo->next){
3303         if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
3304         for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
3305             if(!memcmp(szNameBuf,pFInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
3306             for(i=0;i<pFInfo->funcdesc.cParams;i++)
3307                 if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name, nNameBufLen))
3308                     goto ITypeLib2_fnIsName_exit;
3309         }
3310         for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next)
3311             if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
3312        
3313     }
3314     *pfName=FALSE;
3315
3316 ITypeLib2_fnIsName_exit:
3317     TRACE("(%p)slow! search for %s: %s found!\n", This,
3318           debugstr_w(szNameBuf), *pfName?"NOT":"");
3319     
3320     return S_OK;
3321 }
3322
3323 /* ITypeLib::FindName
3324  *
3325  * Finds occurrences of a type description in a type library. This may be used
3326  * to quickly verify that a name exists in a type library.
3327  *
3328  */
3329 static HRESULT WINAPI ITypeLib2_fnFindName(
3330         ITypeLib2 *iface,
3331         LPOLESTR szNameBuf,
3332         ULONG lHashVal,
3333         ITypeInfo **ppTInfo,
3334         MEMBERID *rgMemId,
3335         UINT16 *pcFound)
3336 {
3337     ICOM_THIS( ITypeLibImpl, iface);
3338     ITypeInfoImpl *pTInfo;
3339     TLBFuncDesc *pFInfo;
3340     TLBVarDesc *pVInfo;
3341     int i,j = 0;
3342    
3343     UINT nNameBufLen = SysStringLen(szNameBuf);
3344
3345     for(pTInfo=This->pTypeInfo;pTInfo && j<*pcFound; pTInfo=pTInfo->next){
3346         if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit;
3347         for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
3348             if(!memcmp(szNameBuf,pFInfo->Name,nNameBufLen)) goto ITypeLib2_fnFindName_exit;
3349             for(i=0;i<pFInfo->funcdesc.cParams;i++)
3350                 if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name,nNameBufLen))
3351                     goto ITypeLib2_fnFindName_exit;
3352         }
3353         for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next)
3354             if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit;
3355         continue;
3356 ITypeLib2_fnFindName_exit:
3357         ITypeInfo_AddRef((ITypeInfo*)pTInfo);
3358         ppTInfo[j]=(LPTYPEINFO)pTInfo;
3359         j++;
3360     }
3361     TRACE("(%p)slow! search for %d with %s: found %d TypeInfo's!\n",
3362           This, *pcFound, debugstr_w(szNameBuf), j);
3363
3364     *pcFound=j;
3365     
3366     return S_OK;
3367 }
3368
3369 /* ITypeLib::ReleaseTLibAttr
3370  *
3371  * Releases the TLIBATTR originally obtained from ITypeLib::GetLibAttr.
3372  *
3373  */
3374 static VOID WINAPI ITypeLib2_fnReleaseTLibAttr(
3375         ITypeLib2 *iface,
3376         TLIBATTR *pTLibAttr)
3377 {
3378     ICOM_THIS( ITypeLibImpl, iface);
3379     TRACE("freeing (%p)\n",This);
3380     HeapFree(GetProcessHeap(),0,pTLibAttr);
3381
3382 }
3383
3384 /* ITypeLib2::GetCustData
3385  *
3386  * gets the custom data
3387  */
3388 static HRESULT WINAPI ITypeLib2_fnGetCustData(
3389         ITypeLib2 * iface,
3390         REFGUID guid, 
3391         VARIANT *pVarVal)
3392 {
3393     ICOM_THIS( ITypeLibImpl, iface);
3394     TLBCustData *pCData;
3395
3396     for(pCData=This->pCustData; pCData; pCData = pCData->next)
3397     {
3398       if( IsEqualIID(guid, &pCData->guid)) break;
3399     }
3400     
3401     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
3402
3403     if(pCData)
3404     {
3405         VariantInit( pVarVal);
3406         VariantCopy( pVarVal, &pCData->data);
3407         return S_OK;
3408     }
3409     return E_INVALIDARG;  /* FIXME: correct? */
3410 }
3411
3412 /* ITypeLib2::GetLibStatistics
3413  *
3414  * Returns statistics about a type library that are required for efficient
3415  * sizing of hash tables.
3416  *
3417  */
3418 static HRESULT WINAPI ITypeLib2_fnGetLibStatistics(
3419         ITypeLib2 * iface, 
3420         ULONG *pcUniqueNames,
3421         ULONG *pcchUniqueNames)
3422 {
3423     ICOM_THIS( ITypeLibImpl, iface);
3424
3425     FIXME("(%p): stub!\n", This);
3426
3427     if(pcUniqueNames) *pcUniqueNames=1;
3428     if(pcchUniqueNames) *pcchUniqueNames=1;
3429     return S_OK;
3430 }
3431
3432 /* ITypeLib2::GetDocumentation2
3433  *
3434  * Retrieves the library's documentation string, the complete Help file name
3435  * and path, the localization context to use, and the context ID for the
3436  * library Help topic in the Help file.
3437  *
3438  */
3439 static HRESULT WINAPI ITypeLib2_fnGetDocumentation2(
3440         ITypeLib2 * iface, 
3441         INT index,
3442         LCID lcid,
3443         BSTR *pbstrHelpString,
3444         DWORD *pdwHelpStringContext,
3445         BSTR *pbstrHelpStringDll)
3446 {
3447     ICOM_THIS( ITypeLibImpl, iface);
3448     HRESULT result;
3449     ITypeInfo *pTInfo;
3450
3451     FIXME("(%p) index %d lcid %ld half implemented stub!\n", This, index, lcid);
3452
3453     /* the help string should be obtained from the helpstringdll,
3454      * using the _DLLGetDocumentation function, based on the supplied
3455      * lcid. Nice to do sometime...
3456      */
3457     if(index<0)
3458     {
3459       /* documentation for the typelib */
3460       if(pbstrHelpString)
3461         *pbstrHelpString=SysAllocString(This->DocString);
3462       if(pdwHelpStringContext)
3463         *pdwHelpStringContext=This->dwHelpContext;
3464       if(pbstrHelpStringDll)
3465         *pbstrHelpStringDll=SysAllocString(This->HelpStringDll);
3466
3467       result = S_OK;
3468     }
3469     else
3470     {
3471       /* for a typeinfo */
3472       result=ITypeLib2_GetTypeInfo(iface, index, &pTInfo);
3473       
3474       if(SUCCEEDED(result))
3475       { 
3476         ITypeInfo2 * pTInfo2;
3477         result = ITypeInfo_QueryInterface(pTInfo, 
3478                                           &IID_ITypeInfo2, 
3479                                           (LPVOID*) &pTInfo2);
3480
3481         if(SUCCEEDED(result))
3482         {
3483           result = ITypeInfo2_GetDocumentation2(pTInfo2, 
3484                                            MEMBERID_NIL, 
3485                                            lcid,
3486                                            pbstrHelpString, 
3487                                            pdwHelpStringContext, 
3488                                            pbstrHelpStringDll);
3489   
3490           ITypeInfo2_Release(pTInfo2);
3491         }
3492             
3493         ITypeInfo_Release(pTInfo);
3494       }
3495     }
3496     return result;
3497 }
3498
3499 /* ITypeLib2::GetAllCustData
3500  *
3501  * Gets all custom data items for the library. 
3502  *
3503  */
3504 static HRESULT WINAPI ITypeLib2_fnGetAllCustData(
3505         ITypeLib2 * iface,
3506         CUSTDATA *pCustData)
3507 {
3508     ICOM_THIS( ITypeLibImpl, iface);
3509     TLBCustData *pCData;
3510     int i;
3511     TRACE("(%p) returning %d items\n", This, This->ctCustData); 
3512     pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
3513     if(pCustData->prgCustData ){
3514         pCustData->cCustData=This->ctCustData;
3515         for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
3516             pCustData->prgCustData[i].guid=pCData->guid;
3517             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
3518         }
3519     }else{
3520         ERR(" OUT OF MEMORY! \n");
3521         return E_OUTOFMEMORY;
3522     }
3523     return S_OK;
3524 }
3525
3526 static ICOM_VTABLE(ITypeLib2) tlbvt = {
3527     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3528     ITypeLib2_fnQueryInterface,
3529     ITypeLib2_fnAddRef,
3530     ITypeLib2_fnRelease,
3531     ITypeLib2_fnGetTypeInfoCount,
3532     ITypeLib2_fnGetTypeInfo,
3533     ITypeLib2_fnGetTypeInfoType,
3534     ITypeLib2_fnGetTypeInfoOfGuid,
3535     ITypeLib2_fnGetLibAttr,
3536     ITypeLib2_fnGetTypeComp,
3537     ITypeLib2_fnGetDocumentation,
3538     ITypeLib2_fnIsName,
3539     ITypeLib2_fnFindName,
3540     ITypeLib2_fnReleaseTLibAttr,
3541
3542     ITypeLib2_fnGetCustData,
3543     ITypeLib2_fnGetLibStatistics,
3544     ITypeLib2_fnGetDocumentation2,
3545     ITypeLib2_fnGetAllCustData
3546  };
3547
3548 /*================== ITypeInfo(2) Methods ===================================*/
3549 static ITypeInfo2 * WINAPI ITypeInfo_Constructor(void)
3550 {
3551     ITypeInfoImpl * pTypeInfoImpl;
3552
3553     pTypeInfoImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeInfoImpl));
3554     if (pTypeInfoImpl)
3555     {
3556       ICOM_VTBL(pTypeInfoImpl) = &tinfvt;
3557       pTypeInfoImpl->ref=1;
3558     }
3559     TRACE("(%p)\n", pTypeInfoImpl);
3560     return (ITypeInfo2*) pTypeInfoImpl;
3561 }
3562
3563 /* ITypeInfo::QueryInterface
3564  */
3565 static HRESULT WINAPI ITypeInfo_fnQueryInterface(
3566         ITypeInfo2 *iface,
3567         REFIID riid,
3568         VOID **ppvObject)
3569 {
3570     ICOM_THIS( ITypeLibImpl, iface);
3571
3572     TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
3573
3574     *ppvObject=NULL;
3575     if(IsEqualIID(riid, &IID_IUnknown) || 
3576             IsEqualIID(riid,&IID_ITypeInfo)||
3577             IsEqualIID(riid,&IID_ITypeInfo2))
3578         *ppvObject = This;
3579
3580     if(*ppvObject){
3581         ITypeInfo_AddRef(iface);
3582         TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
3583         return S_OK;
3584     }
3585     TRACE("-- Interface: E_NOINTERFACE\n");
3586     return E_NOINTERFACE;
3587 }
3588
3589 /* ITypeInfo::AddRef
3590  */
3591 static ULONG WINAPI ITypeInfo_fnAddRef( ITypeInfo2 *iface)
3592 {
3593     ICOM_THIS( ITypeInfoImpl, iface);
3594
3595     ++(This->ref);
3596
3597     TRACE("(%p)->ref is %u\n",This, This->ref);
3598     return This->ref;
3599 }
3600
3601 /* ITypeInfo::Release
3602  */
3603 static ULONG WINAPI ITypeInfo_fnRelease( ITypeInfo2 *iface)
3604 {
3605     ICOM_THIS( ITypeInfoImpl, iface);
3606
3607     --(This->ref);
3608     
3609     TRACE("(%p)->(%u)\n",This, This->ref);
3610
3611     if (!This->ref)
3612     {
3613       FIXME("destroy child objects\n");
3614
3615       TRACE("destroying ITypeInfo(%p)\n",This); 
3616       if (This->Name)
3617       {
3618           SysFreeString(This->Name);
3619           This->Name = 0;
3620       }
3621       
3622       if (This->DocString)
3623       {
3624           SysFreeString(This->DocString);
3625           This->DocString = 0;
3626       }
3627
3628       if (This->next)
3629       {
3630         ITypeInfo_Release((ITypeInfo*)This->next);
3631       }
3632
3633       HeapFree(GetProcessHeap(),0,This);
3634       return 0;
3635     }
3636     return This->ref;
3637 }
3638
3639 /* ITypeInfo::GetTypeAttr
3640  *
3641  * Retrieves a TYPEATTR structure that contains the attributes of the type
3642  * description.
3643  *
3644  */
3645 static HRESULT WINAPI ITypeInfo_fnGetTypeAttr( ITypeInfo2 *iface,
3646         LPTYPEATTR  *ppTypeAttr)
3647 {
3648     ICOM_THIS( ITypeInfoImpl, iface);
3649     TRACE("(%p)\n",This);
3650     /* FIXME: must do a copy here */
3651     *ppTypeAttr=&This->TypeAttr;
3652     return S_OK;
3653 }
3654
3655 /* ITypeInfo::GetTypeComp
3656  *
3657  * Retrieves the ITypeComp interface for the type description, which enables a
3658  * client compiler to bind to the type description's members.
3659  *
3660  */
3661 static HRESULT WINAPI ITypeInfo_fnGetTypeComp( ITypeInfo2 *iface,
3662         ITypeComp  * *ppTComp)
3663 {
3664     ICOM_THIS( ITypeInfoImpl, iface);
3665     FIXME("(%p) stub!\n", This);
3666     return S_OK;
3667 }
3668
3669 /* ITypeInfo::GetFuncDesc
3670  *
3671  * Retrieves the FUNCDESC structure that contains information about a
3672  * specified function.
3673  *
3674  */
3675 static HRESULT WINAPI ITypeInfo_fnGetFuncDesc( ITypeInfo2 *iface, UINT index,
3676         LPFUNCDESC  *ppFuncDesc)
3677 {
3678     ICOM_THIS( ITypeInfoImpl, iface);
3679     int i;
3680     TLBFuncDesc * pFDesc; 
3681     TRACE("(%p) index %d\n", This, index);
3682     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++, pFDesc=pFDesc->next)
3683         ;
3684     if(pFDesc){
3685         /* FIXME: must do a copy here */
3686         *ppFuncDesc=&pFDesc->funcdesc;
3687         return S_OK;
3688     }
3689     return E_INVALIDARG;
3690 }
3691
3692 /* ITypeInfo::GetVarDesc
3693  *
3694  * Retrieves a VARDESC structure that describes the specified variable. 
3695  *
3696  */
3697 static HRESULT WINAPI ITypeInfo_fnGetVarDesc( ITypeInfo2 *iface, UINT index,
3698         LPVARDESC  *ppVarDesc)
3699 {
3700     ICOM_THIS( ITypeInfoImpl, iface);
3701     int i;
3702     TLBVarDesc * pVDesc; 
3703     TRACE("(%p) index %d\n", This, index);
3704     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next)
3705         ;
3706     if(pVDesc){
3707         /* FIXME: must do a copy here */
3708         *ppVarDesc=&pVDesc->vardesc;
3709         return S_OK;
3710     }
3711     return E_INVALIDARG;
3712 }
3713
3714 /* ITypeInfo_GetNames
3715  *
3716  * Retrieves the variable with the specified member ID (or the name of the
3717  * property or method and its parameters) that correspond to the specified
3718  * function ID.
3719  */
3720 static HRESULT WINAPI ITypeInfo_fnGetNames( ITypeInfo2 *iface, MEMBERID memid,
3721         BSTR  *rgBstrNames, UINT cMaxNames, UINT  *pcNames)
3722 {
3723     ICOM_THIS( ITypeInfoImpl, iface);
3724     TLBFuncDesc * pFDesc; 
3725     TLBVarDesc * pVDesc; 
3726     int i;
3727     TRACE("(%p) memid=0x%08lx Maxname=%d\n", This, memid, cMaxNames);
3728     for(pFDesc=This->funclist; pFDesc && pFDesc->funcdesc.memid != memid; pFDesc=pFDesc->next);
3729     if(pFDesc)
3730     {
3731       /* function found, now return function and parameter names */
3732       for(i=0; i<cMaxNames && i <= pFDesc->funcdesc.cParams; i++)
3733       {
3734         if(!i)
3735           *rgBstrNames=SysAllocString(pFDesc->Name);
3736         else
3737           rgBstrNames[i]=SysAllocString(pFDesc->pParamDesc[i-1].Name);
3738       }
3739       *pcNames=i;
3740     }
3741     else
3742     {
3743       for(pVDesc=This->varlist; pVDesc && pVDesc->vardesc.memid != memid; pVDesc=pVDesc->next);
3744       if(pVDesc)
3745       {
3746         *rgBstrNames=SysAllocString(pVDesc->Name);
3747         *pcNames=1;
3748       }
3749       else
3750       {
3751         if(This->TypeAttr.typekind==TKIND_INTERFACE && This->TypeAttr.cImplTypes )
3752         {
3753           /* recursive search */
3754           ITypeInfo *pTInfo;
3755           HRESULT result;
3756           result=ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef,
3757                                           &pTInfo);
3758           if(SUCCEEDED(result))
3759           {
3760             result=ITypeInfo_GetNames(pTInfo, memid, rgBstrNames, cMaxNames, pcNames);
3761             ITypeInfo_Release(pTInfo);
3762             return result;
3763           }
3764           WARN("Could not search inherited interface!\n");
3765         }
3766         else
3767         {
3768           WARN("no names found\n");
3769         }
3770         *pcNames=0;
3771         return TYPE_E_ELEMENTNOTFOUND;
3772       }
3773     }
3774     return S_OK;
3775 }
3776
3777
3778 /* ITypeInfo::GetRefTypeOfImplType
3779  *
3780  * If a type description describes a COM class, it retrieves the type
3781  * description of the implemented interface types. For an interface,
3782  * GetRefTypeOfImplType returns the type information for inherited interfaces,
3783  * if any exist.
3784  *
3785  */
3786 static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType(
3787         ITypeInfo2 *iface,
3788         UINT index,
3789         HREFTYPE  *pRefType)
3790 {
3791     ICOM_THIS( ITypeInfoImpl, iface);
3792     int(i);
3793     TLBImplType *pImpl = This->impltypelist;
3794
3795     TRACE("(%p) index %d\n", This, index);
3796     dump_TypeInfo(This);
3797
3798     if(index==(UINT)-1)
3799     {
3800       /* only valid on dual interfaces;
3801          retrieve the associated TKIND_INTERFACE handle for the current TKIND_DISPATCH
3802       */
3803       if( This->TypeAttr.typekind != TKIND_DISPATCH) return E_INVALIDARG;
3804       
3805       if (This->TypeAttr.wTypeFlags & TYPEFLAG_FDISPATCHABLE &&
3806           This->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL )
3807       {
3808         *pRefType = -1;
3809       }
3810       else
3811       {
3812         if (!pImpl) return TYPE_E_ELEMENTNOTFOUND;
3813         *pRefType = pImpl->hRef;
3814       }
3815     }
3816     else
3817     {
3818       /* get element n from linked list */
3819       for(i=0; pImpl && i<index; i++)
3820       {
3821         pImpl = pImpl->next;
3822       }
3823       
3824       if (!pImpl) return TYPE_E_ELEMENTNOTFOUND;
3825       
3826       *pRefType = pImpl->hRef;
3827       
3828       TRACE("-- 0x%08lx\n", pImpl->hRef );
3829     }
3830     
3831     return S_OK;
3832    
3833 }
3834
3835 /* ITypeInfo::GetImplTypeFlags
3836  * 
3837  * Retrieves the IMPLTYPEFLAGS enumeration for one implemented interface 
3838  * or base interface in a type description.
3839  */
3840 static HRESULT WINAPI ITypeInfo_fnGetImplTypeFlags( ITypeInfo2 *iface,
3841         UINT index, INT  *pImplTypeFlags)
3842 {
3843     ICOM_THIS( ITypeInfoImpl, iface);
3844     int i;
3845     TLBImplType *pImpl;
3846
3847     TRACE("(%p) index %d\n", This, index);
3848     for(i=0, pImpl=This->impltypelist; i<index && pImpl;
3849         i++, pImpl=pImpl->next)
3850         ;
3851     if(i==index && pImpl){
3852         *pImplTypeFlags=pImpl->implflags;
3853         return S_OK;
3854     }
3855     *pImplTypeFlags=0;
3856     return TYPE_E_ELEMENTNOTFOUND;
3857 }
3858
3859 /* GetIDsOfNames
3860  * Maps between member names and member IDs, and parameter names and
3861  * parameter IDs.
3862  */
3863 static HRESULT WINAPI ITypeInfo_fnGetIDsOfNames( ITypeInfo2 *iface,
3864         LPOLESTR  *rgszNames, UINT cNames, MEMBERID  *pMemId)
3865 {
3866     ICOM_THIS( ITypeInfoImpl, iface);
3867     TLBFuncDesc * pFDesc; 
3868     TLBVarDesc * pVDesc; 
3869     HRESULT ret=S_OK;
3870
3871     TRACE("(%p) Name %s cNames %d\n", This, debugstr_w(*rgszNames),
3872             cNames);
3873     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next) {
3874         int i, j;
3875         if(!lstrcmpiW(*rgszNames, pFDesc->Name)) {
3876             if(cNames) *pMemId=pFDesc->funcdesc.memid;
3877             for(i=1; i < cNames; i++){
3878                 for(j=0; j<pFDesc->funcdesc.cParams; j++)
3879                     if(!lstrcmpiW(rgszNames[i],pFDesc->pParamDesc[j].Name))
3880                             break;
3881                 if( j<pFDesc->funcdesc.cParams)
3882                     pMemId[i]=j;
3883                 else
3884                    ret=DISP_E_UNKNOWNNAME;
3885             };
3886             return ret;
3887         }
3888     }   
3889     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) {
3890         if(!lstrcmpiW(*rgszNames, pVDesc->Name)) {
3891             if(cNames) *pMemId=pVDesc->vardesc.memid;
3892             return ret;
3893         }
3894     }
3895     /* not found, see if this is and interface with an inheritance */       
3896     if(This->TypeAttr.typekind==TKIND_INTERFACE && 
3897             This->TypeAttr.cImplTypes ){
3898         /* recursive search */
3899         ITypeInfo *pTInfo;
3900         ret=ITypeInfo_GetRefTypeInfo(iface, 
3901                 This->impltypelist->hRef, &pTInfo);
3902         if(SUCCEEDED(ret)){
3903             ret=ITypeInfo_GetIDsOfNames(pTInfo, rgszNames, cNames, pMemId );
3904             ITypeInfo_Release(pTInfo);
3905             return ret;
3906         }
3907         WARN("Could not search inherited interface!\n");
3908     } else
3909         WARN("no names found\n");
3910     return DISP_E_UNKNOWNNAME;
3911 }
3912
3913 /* ITypeInfo::Invoke
3914  * 
3915  * Invokes a method, or accesses a property of an object, that implements the
3916  * interface described by the type description.
3917  */
3918 static DWORD _invoke(LPVOID func,CALLCONV callconv, int nrargs, DWORD *args) {
3919     DWORD res;
3920
3921     if (TRACE_ON(ole)) {
3922         int i;
3923         MESSAGE("Calling %p(",func);
3924         for (i=0;i<nrargs;i++) MESSAGE("%08lx,",args[i]);
3925         MESSAGE(")\n");
3926     }
3927
3928     switch (callconv) {
3929     case CC_STDCALL:
3930
3931         switch (nrargs) {
3932         case 0: {
3933                 DWORD (WINAPI *xfunc)() = func;
3934                 res = xfunc();
3935                 break;
3936         }
3937         case 1: {
3938                 DWORD (WINAPI *xfunc)(DWORD) = func;
3939                 res = xfunc(args[0]);
3940                 break;
3941         }
3942         case 2: {
3943                 DWORD (WINAPI *xfunc)(DWORD,DWORD) = func;
3944                 res = xfunc(args[0],args[1]);
3945                 break;
3946         }
3947         case 3: {
3948                 DWORD (WINAPI *xfunc)(DWORD,DWORD,DWORD) = func;
3949                 res = xfunc(args[0],args[1],args[2]);
3950                 break;
3951         }
3952         default:
3953                 FIXME("unsupported number of arguments %d in stdcall\n",nrargs);
3954                 res = -1;
3955                 break;
3956         }
3957         break;
3958     default:
3959         FIXME("unsupported calling convention %d\n",callconv);
3960         res = -1;
3961         break;
3962     }
3963     TRACE("returns %08lx\n",res);
3964     return res;
3965 }
3966
3967 static HRESULT WINAPI ITypeInfo_fnInvoke(
3968     ITypeInfo2 *iface,
3969     VOID  *pIUnk,
3970     MEMBERID memid,
3971     UINT16 dwFlags,
3972     DISPPARAMS  *pDispParams,
3973     VARIANT  *pVarResult,
3974     EXCEPINFO  *pExcepInfo,
3975     UINT  *pArgErr)
3976 {
3977     ICOM_THIS( ITypeInfoImpl, iface);
3978     TLBFuncDesc * pFDesc; 
3979     TLBVarDesc * pVDesc; 
3980     int i;
3981
3982     TRACE("(%p)(%p,id=%ld,flags=0x%08x,%p,%p,%p,%p) partial stub!\n",
3983       This,pIUnk,memid,dwFlags,pDispParams,pVarResult,pExcepInfo,pArgErr
3984     );
3985     dump_DispParms(pDispParams);
3986
3987     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
3988         if (pFDesc->funcdesc.memid == memid) {
3989             if (pFDesc->funcdesc.invkind & dwFlags)
3990                 break;
3991         }
3992     if (pFDesc) {
3993         dump_TLBFuncDescOne(pFDesc);
3994         switch (pFDesc->funcdesc.funckind) {
3995         case FUNC_PUREVIRTUAL:
3996         case FUNC_VIRTUAL: {
3997             DWORD res;
3998             DWORD *args = (DWORD*)HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*(pFDesc->funcdesc.cParams+1));
3999             DWORD *args2 = (DWORD*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD)*(pFDesc->funcdesc.cParams));
4000             args[0] = (DWORD)pIUnk;
4001
4002             for (i=0;i<pFDesc->funcdesc.cParams;i++) {
4003                 if (i<pDispParams->cArgs) {
4004                     TRACE("set %d to disparg type %d vs %d\n",i,
4005                             V_VT(&pDispParams->rgvarg[pDispParams->cArgs-i-1]),
4006                             pFDesc->funcdesc.lprgelemdescParam[i].tdesc.vt
4007                     );
4008                     args[i+1] = V_UNION(&pDispParams->rgvarg[pDispParams->cArgs-i-1],lVal);
4009                 } else {
4010                     TYPEDESC *tdesc = &(pFDesc->funcdesc.lprgelemdescParam[i].tdesc);
4011                     TRACE("set %d to pointer for get (type is %d)\n",i,tdesc->vt);
4012                     /*FIXME: give pointers for the rest, so propertyget works*/
4013                     args[i+1] = (DWORD)&args2[i];
4014
4015                     /* If pointer to variant, pass reference to variant
4016                      * in result variant array.
4017                      */
4018                     if ((tdesc->vt == VT_PTR) &&
4019                         (tdesc->u.lptdesc->vt == VT_VARIANT) &&
4020                         pVarResult
4021                     )
4022                         args[i+1] = (DWORD)(pVarResult+(i-pDispParams->cArgs));
4023                 }
4024             }
4025             if (pFDesc->funcdesc.cParamsOpt)
4026                 FIXME("Does not support optional parameters (%d)\n",
4027                         pFDesc->funcdesc.cParamsOpt
4028                 );
4029
4030             res = _invoke((*(DWORD***)pIUnk)[pFDesc->funcdesc.oVft/4],
4031                     pFDesc->funcdesc.callconv,
4032                     pFDesc->funcdesc.cParams+1,
4033                     args
4034             );
4035             if (pVarResult && (dwFlags & (DISPATCH_PROPERTYGET))) {
4036                 for (i=0;i<pFDesc->funcdesc.cParams-pDispParams->cArgs;i++) {
4037                     TYPEDESC *tdesc = &(pFDesc->funcdesc.lprgelemdescParam[i+pDispParams->cArgs].tdesc);
4038                     /* If we are a pointer to a variant, we are done already */
4039                     if ((tdesc->vt==VT_PTR)&&(tdesc->u.lptdesc->vt==VT_VARIANT))
4040                         continue;
4041
4042                     VariantInit(&pVarResult[i]);
4043                     V_UNION(pVarResult+i,intVal) = args2[i+pDispParams->cArgs];
4044
4045                     if (tdesc->vt == VT_PTR)
4046                         tdesc = tdesc->u.lptdesc;
4047                     V_VT(pVarResult+i) = tdesc->vt;
4048
4049                     /* HACK: VB5 likes this.
4050                      * I do not know why. There is 1 example in MSDN which uses
4051                      * this which appears broken (mixes int vals and
4052                      * IDispatch*.).
4053                      */
4054                     if ((tdesc->vt == VT_PTR) && (dwFlags & DISPATCH_METHOD))
4055                         V_VT(pVarResult+i) = VT_DISPATCH;
4056                     TRACE("storing into variant: [%d]\n", i);
4057                     dump_Variant(pVarResult+i);
4058                 }
4059             }
4060             HeapFree(GetProcessHeap(),0,args2);
4061             HeapFree(GetProcessHeap(),0,args);
4062             return S_OK;
4063         }
4064         case FUNC_DISPATCH:  {
4065            IDispatch *disp;
4066            HRESULT hr;
4067
4068            hr = IUnknown_QueryInterface((LPUNKNOWN)pIUnk,&IID_IDispatch,(LPVOID*)&disp);
4069            if (hr) {
4070                FIXME("FUNC_DISPATCH used on object without IDispatch iface?\n");
4071                return hr;
4072            }
4073            FIXME("Calling Invoke in IDispatch iface. untested!\n");
4074            hr = IDispatch_Invoke(
4075                disp,memid,&IID_NULL,LOCALE_USER_DEFAULT,dwFlags,pDispParams,
4076                pVarResult,pExcepInfo,pArgErr
4077            );
4078            if (hr)
4079                FIXME("IDispatch::Invoke failed with %08lx. (Could be not a real error?)\n",hr);
4080            IDispatch_Release(disp);
4081            return hr;
4082         }
4083         default:
4084            FIXME("Unknown function invocation type %d\n",pFDesc->funcdesc.funckind);
4085            return E_FAIL;
4086         }
4087     } else {
4088         for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) {
4089             if (pVDesc->vardesc.memid == memid) {
4090                 FIXME("varseek: Found memid name %s, but variable-based invoking not supported\n",debugstr_w(((LPWSTR)pVDesc->Name)));
4091                 dump_TLBVarDesc(pVDesc);
4092                 break;
4093             }
4094         }
4095     }
4096     /* not found, look for it in inherited interfaces */
4097     if (This->TypeAttr.typekind==TKIND_INTERFACE && This->TypeAttr.cImplTypes) {
4098         /* recursive search */
4099         ITypeInfo *pTInfo;
4100         HRESULT hr;
4101         hr=ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef, &pTInfo);
4102         if(SUCCEEDED(hr)){
4103             hr=ITypeInfo_Invoke(pTInfo,pIUnk,memid,dwFlags,pDispParams,pVarResult,pExcepInfo,pArgErr);
4104             ITypeInfo_Release(pTInfo);
4105             return hr;
4106         }
4107         WARN("Could not search inherited interface!\n");
4108     }
4109     ERR("did not find member id %d, flags %d!\n", (int)memid, dwFlags);
4110     return DISP_E_MEMBERNOTFOUND;
4111 }
4112
4113 /* ITypeInfo::GetDocumentation
4114  * 
4115  * Retrieves the documentation string, the complete Help file name and path,
4116  * and the context ID for the Help topic for a specified type description.
4117  */
4118 static HRESULT WINAPI ITypeInfo_fnGetDocumentation( ITypeInfo2 *iface,
4119         MEMBERID memid, BSTR  *pBstrName, BSTR  *pBstrDocString,
4120         DWORD  *pdwHelpContext, BSTR  *pBstrHelpFile)
4121 {
4122     ICOM_THIS( ITypeInfoImpl, iface);
4123     TLBFuncDesc * pFDesc; 
4124     TLBVarDesc * pVDesc; 
4125     TRACE("(%p) memid %ld Name(%p) DocString(%p)"
4126           " HelpContext(%p) HelpFile(%p)\n",
4127         This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
4128     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
4129         if(pBstrName)
4130             *pBstrName=SysAllocString(This->Name);
4131         if(pBstrDocString)
4132             *pBstrDocString=SysAllocString(This->DocString);
4133         if(pdwHelpContext)
4134             *pdwHelpContext=This->dwHelpContext;
4135         if(pBstrHelpFile)
4136             *pBstrHelpFile=SysAllocString(This->DocString);/* FIXME */
4137         return S_OK;
4138     }else {/* for a member */
4139     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
4140         if(pFDesc->funcdesc.memid==memid){
4141           if(pBstrName)
4142             *pBstrName = SysAllocString(pFDesc->Name);
4143           if(pBstrDocString)
4144             *pBstrDocString=SysAllocString(pFDesc->HelpString);
4145           if(pdwHelpContext)
4146             *pdwHelpContext=pFDesc->helpcontext;
4147           return S_OK;
4148         }
4149     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
4150         if(pVDesc->vardesc.memid==memid){
4151             FIXME("Not implemented\n");
4152             return S_OK;
4153         }
4154     }
4155     return TYPE_E_ELEMENTNOTFOUND;
4156 }
4157
4158 /*  ITypeInfo::GetDllEntry
4159  * 
4160  * Retrieves a description or specification of an entry point for a function
4161  * in a DLL.
4162  */
4163 static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid,
4164         INVOKEKIND invKind, BSTR  *pBstrDllName, BSTR  *pBstrName,
4165         WORD  *pwOrdinal)
4166 {
4167     ICOM_THIS( ITypeInfoImpl, iface);
4168     FIXME("(%p) stub!\n", This);
4169     return E_FAIL;
4170 }
4171
4172 /* ITypeInfo::GetRefTypeInfo
4173  * 
4174  * If a type description references other type descriptions, it retrieves
4175  * the referenced type descriptions.
4176  */
4177 static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo(
4178         ITypeInfo2 *iface,
4179         HREFTYPE hRefType,
4180         ITypeInfo  **ppTInfo)
4181 {
4182     ICOM_THIS( ITypeInfoImpl, iface);
4183     HRESULT result = E_FAIL;
4184
4185
4186     if (hRefType == -1 && 
4187         (((ITypeInfoImpl*) This)->TypeAttr.typekind   == TKIND_DISPATCH) &&
4188         (((ITypeInfoImpl*) This)->TypeAttr.wTypeFlags &  TYPEFLAG_FDUAL))
4189     {
4190           /* when we meet a DUAL dispinterface, we must create the interface 
4191           * version of it.
4192           */
4193           ITypeInfoImpl* pTypeInfoImpl = (ITypeInfoImpl*) ITypeInfo_Constructor();
4194
4195                 
4196           /* the interface version contains the same information as the dispinterface
4197            * copy the contents of the structs.
4198            */
4199           *pTypeInfoImpl = *This;
4200           pTypeInfoImpl->ref = 1;
4201                 
4202           /* change the type to interface */
4203           pTypeInfoImpl->TypeAttr.typekind = TKIND_INTERFACE;
4204           
4205           *ppTInfo = (ITypeInfo*) pTypeInfoImpl;
4206
4207           ITypeInfo_AddRef((ITypeInfo*) pTypeInfoImpl);
4208
4209           result = S_OK;
4210
4211     } else {
4212         TLBRefType *pRefType;
4213         for(pRefType = This->reflist; pRefType; pRefType = pRefType->next) {
4214             if(pRefType->reference == hRefType)
4215                 break;
4216         }
4217         if(!pRefType)
4218           FIXME("Can't find pRefType for ref %lx\n", hRefType);
4219         if(pRefType && hRefType != -1) {
4220             ITypeLib *pTLib;
4221
4222             if(pRefType->pImpTLInfo == TLB_REF_INTERNAL) {
4223                 int Index;
4224                 result = ITypeInfo_GetContainingTypeLib(iface, &pTLib, &Index);
4225             } else {
4226                 if(pRefType->pImpTLInfo->pImpTypeLib) {
4227                     TRACE("typeinfo in imported typelib that is already loaded\n");
4228                     pTLib = (ITypeLib*)pRefType->pImpTLInfo->pImpTypeLib;
4229                     ITypeLib2_AddRef((ITypeLib*) pTLib);
4230                     result = S_OK;
4231                 } else {
4232                     TRACE("typeinfo in imported typelib that isn't already loaded\n");
4233                     result = LoadRegTypeLib( &pRefType->pImpTLInfo->guid,
4234                                              pRefType->pImpTLInfo->wVersionMajor,
4235                                              pRefType->pImpTLInfo->wVersionMinor,
4236                                              pRefType->pImpTLInfo->lcid,
4237                                              &pTLib);
4238
4239                     if(!SUCCEEDED(result)) {
4240                         BSTR libnam=SysAllocString(pRefType->pImpTLInfo->name);
4241                         result=LoadTypeLib(libnam, &pTLib);
4242                         SysFreeString(libnam);
4243                     }
4244                     if(SUCCEEDED(result)) {
4245                         pRefType->pImpTLInfo->pImpTypeLib = (ITypeLibImpl*)pTLib;
4246                         ITypeLib2_AddRef(pTLib);
4247                     }
4248                 }
4249             }
4250             if(SUCCEEDED(result)) {
4251                 if(pRefType->index == TLB_REF_USE_GUID)
4252                     result = ITypeLib2_GetTypeInfoOfGuid(pTLib, 
4253                                                          &pRefType->guid, 
4254                                                          ppTInfo);
4255                 else
4256                     result = ITypeLib2_GetTypeInfo(pTLib, pRefType->index,
4257                                                    ppTInfo);
4258             }
4259         }
4260     }
4261
4262     TRACE("(%p) hreftype 0x%04lx loaded %s (%p)\n", This, hRefType,
4263           SUCCEEDED(result)? "SUCCESS":"FAILURE", *ppTInfo);
4264     return result;
4265 }
4266
4267 /* ITypeInfo::AddressOfMember
4268  * 
4269  * Retrieves the addresses of static functions or variables, such as those
4270  * defined in a DLL.
4271  */
4272 static HRESULT WINAPI ITypeInfo_fnAddressOfMember( ITypeInfo2 *iface,
4273         MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
4274 {
4275     ICOM_THIS( ITypeInfoImpl, iface);
4276     FIXME("(%p) stub!\n", This);
4277     return S_OK;
4278 }
4279
4280 /* ITypeInfo::CreateInstance
4281  * 
4282  * Creates a new instance of a type that describes a component object class 
4283  * (coclass).
4284  */
4285 static HRESULT WINAPI ITypeInfo_fnCreateInstance( ITypeInfo2 *iface, 
4286         IUnknown *pUnk, REFIID riid, VOID  **ppvObj) 
4287 {
4288     ICOM_THIS( ITypeInfoImpl, iface);
4289     FIXME("(%p) stub!\n", This);
4290     return S_OK;
4291 }
4292
4293 /* ITypeInfo::GetMops
4294  *
4295  * Retrieves marshaling information.
4296  */
4297 static HRESULT WINAPI ITypeInfo_fnGetMops( ITypeInfo2 *iface, MEMBERID memid,
4298                                 BSTR  *pBstrMops)
4299 {
4300     ICOM_THIS( ITypeInfoImpl, iface);
4301     FIXME("(%p) stub!\n", This);
4302     return S_OK;
4303 }
4304
4305 /* ITypeInfo::GetContainingTypeLib
4306  * 
4307  * Retrieves the containing type library and the index of the type description
4308  * within that type library.
4309  */
4310 static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( ITypeInfo2 *iface,
4311         ITypeLib  * *ppTLib, UINT  *pIndex)
4312 {
4313     ICOM_THIS( ITypeInfoImpl, iface);
4314     if (!pIndex)
4315         return E_INVALIDARG;
4316     *ppTLib=(LPTYPELIB )(This->pTypeLib);
4317     *pIndex=This->index;
4318     ITypeLib2_AddRef(*ppTLib);
4319     TRACE("(%p) returns (%p) index %d!\n", This, *ppTLib, *pIndex);
4320     return S_OK;
4321 }
4322
4323 /* ITypeInfo::ReleaseTypeAttr
4324  *
4325  * Releases a TYPEATTR previously returned by GetTypeAttr.
4326  *
4327  */
4328 static HRESULT WINAPI ITypeInfo_fnReleaseTypeAttr( ITypeInfo2 *iface,
4329         TYPEATTR* pTypeAttr)
4330 {
4331     ICOM_THIS( ITypeInfoImpl, iface);
4332     TRACE("(%p)->(%p)\n", This, pTypeAttr);
4333     return S_OK;
4334 }
4335
4336 /* ITypeInfo::ReleaseFuncDesc
4337  *
4338  * Releases a FUNCDESC previously returned by GetFuncDesc. *
4339  */
4340 static HRESULT WINAPI ITypeInfo_fnReleaseFuncDesc(
4341         ITypeInfo2 *iface,
4342         FUNCDESC *pFuncDesc)
4343 {
4344     ICOM_THIS( ITypeInfoImpl, iface);
4345     TRACE("(%p)->(%p)\n", This, pFuncDesc);
4346     return S_OK;
4347 }
4348
4349 /* ITypeInfo::ReleaseVarDesc
4350  *
4351  * Releases a VARDESC previously returned by GetVarDesc.
4352  */
4353 static HRESULT WINAPI ITypeInfo_fnReleaseVarDesc( ITypeInfo2 *iface,
4354         VARDESC *pVarDesc)
4355 {
4356     ICOM_THIS( ITypeInfoImpl, iface);
4357     TRACE("(%p)->(%p)\n", This, pVarDesc);
4358     return S_OK;
4359 }
4360
4361 /* ITypeInfo2::GetTypeKind
4362  *
4363  * Returns the TYPEKIND enumeration quickly, without doing any allocations.
4364  *
4365  */
4366 static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo2 * iface,
4367     TYPEKIND *pTypeKind)
4368 {
4369     ICOM_THIS( ITypeInfoImpl, iface);
4370     *pTypeKind=This->TypeAttr.typekind;
4371     TRACE("(%p) type 0x%0x\n", This,*pTypeKind);
4372     return S_OK;
4373 }
4374
4375 /* ITypeInfo2::GetTypeFlags
4376  *
4377  * Returns the type flags without any allocations. This returns a DWORD type
4378  * flag, which expands the type flags without growing the TYPEATTR (type
4379  * attribute). 
4380  *
4381  */
4382 static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo2 * iface,
4383     UINT *pTypeFlags)
4384 {
4385     ICOM_THIS( ITypeInfoImpl, iface);
4386     *pTypeFlags=This->TypeAttr.wTypeFlags;
4387     TRACE("(%p) flags 0x%04x\n", This,*pTypeFlags);
4388      return S_OK;
4389 }
4390
4391 /* ITypeInfo2::GetFuncIndexOfMemId
4392  * Binds to a specific member based on a known DISPID, where the member name
4393  * is not known (for example, when binding to a default member).
4394  *
4395  */
4396 static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo2 * iface,
4397     MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex)
4398 {
4399     ICOM_THIS( ITypeInfoImpl, iface);
4400     TLBFuncDesc *pFuncInfo;
4401     int i;
4402     HRESULT result;
4403     /* FIXME: should check for invKind??? */
4404     for(i=0, pFuncInfo=This->funclist;pFuncInfo && 
4405             memid != pFuncInfo->funcdesc.memid; i++, pFuncInfo=pFuncInfo->next);
4406     if(pFuncInfo){
4407         *pFuncIndex=i;
4408         result= S_OK;
4409     }else{
4410         *pFuncIndex=0;
4411         result=E_INVALIDARG;
4412     }
4413     TRACE("(%p) memid 0x%08lx invKind 0x%04x -> %s\n", This,
4414           memid, invKind, SUCCEEDED(result)? "SUCCES":"FAILED");
4415     return result;
4416 }
4417
4418 /* TypeInfo2::GetVarIndexOfMemId
4419  *
4420  * Binds to a specific member based on a known DISPID, where the member name
4421  * is not known (for example, when binding to a default member). 
4422  *
4423  */
4424 static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( ITypeInfo2 * iface,
4425     MEMBERID memid, UINT *pVarIndex)
4426 {
4427     ICOM_THIS( ITypeInfoImpl, iface);
4428     TLBVarDesc *pVarInfo;
4429     int i;
4430     HRESULT result;
4431     for(i=0, pVarInfo=This->varlist; pVarInfo && 
4432             memid != pVarInfo->vardesc.memid; i++, pVarInfo=pVarInfo->next)
4433         ;
4434     if(pVarInfo){
4435         *pVarIndex=i;
4436         result= S_OK;
4437     }else{
4438         *pVarIndex=0;
4439         result=E_INVALIDARG;
4440     }
4441     TRACE("(%p) memid 0x%08lx -> %s\n", This,
4442           memid, SUCCEEDED(result)? "SUCCES":"FAILED");
4443     return result;
4444 }
4445
4446 /* ITypeInfo2::GetCustData
4447  *
4448  * Gets the custom data
4449  */
4450 static HRESULT WINAPI ITypeInfo2_fnGetCustData(
4451         ITypeInfo2 * iface,
4452         REFGUID guid,
4453         VARIANT *pVarVal)
4454 {
4455     ICOM_THIS( ITypeInfoImpl, iface);
4456     TLBCustData *pCData;
4457
4458     for(pCData=This->pCustData; pCData; pCData = pCData->next)
4459         if( IsEqualIID(guid, &pCData->guid)) break;
4460
4461     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
4462
4463     if(pCData)
4464     {
4465         VariantInit( pVarVal);
4466         VariantCopy( pVarVal, &pCData->data);
4467         return S_OK;
4468     }
4469     return E_INVALIDARG;  /* FIXME: correct? */
4470 }
4471
4472 /* ITypeInfo2::GetFuncCustData
4473  *
4474  * Gets the custom data
4475  */
4476 static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData(
4477         ITypeInfo2 * iface,
4478         UINT index,
4479         REFGUID guid,
4480         VARIANT *pVarVal)
4481 {
4482     ICOM_THIS( ITypeInfoImpl, iface);
4483     TLBCustData *pCData=NULL;
4484     TLBFuncDesc * pFDesc; 
4485     int i;
4486     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
4487             pFDesc=pFDesc->next);
4488
4489     if(pFDesc)
4490         for(pCData=pFDesc->pCustData; pCData; pCData = pCData->next)
4491             if( IsEqualIID(guid, &pCData->guid)) break;
4492
4493     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
4494
4495     if(pCData){
4496         VariantInit( pVarVal);
4497         VariantCopy( pVarVal, &pCData->data);
4498         return S_OK;
4499     }
4500     return E_INVALIDARG;  /* FIXME: correct? */
4501 }
4502
4503 /* ITypeInfo2::GetParamCustData
4504  *
4505  * Gets the custom data
4506  */
4507 static HRESULT WINAPI ITypeInfo2_fnGetParamCustData(
4508         ITypeInfo2 * iface,
4509         UINT indexFunc,
4510         UINT indexParam,
4511         REFGUID guid,
4512         VARIANT *pVarVal)
4513 {   
4514     ICOM_THIS( ITypeInfoImpl, iface);
4515     TLBCustData *pCData=NULL;
4516     TLBFuncDesc * pFDesc; 
4517     int i;
4518
4519     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,pFDesc=pFDesc->next);
4520
4521     if(pFDesc && indexParam >=0 && indexParam<pFDesc->funcdesc.cParams)
4522         for(pCData=pFDesc->pParamDesc[indexParam].pCustData; pCData; 
4523                 pCData = pCData->next)
4524             if( IsEqualIID(guid, &pCData->guid)) break;
4525
4526     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
4527
4528     if(pCData)
4529     {
4530         VariantInit( pVarVal);
4531         VariantCopy( pVarVal, &pCData->data);
4532         return S_OK;
4533     }
4534     return E_INVALIDARG;  /* FIXME: correct? */
4535 }
4536
4537 /* ITypeInfo2::GetVarCustData
4538  *
4539  * Gets the custom data
4540  */
4541 static HRESULT WINAPI ITypeInfo2_fnGetVarCustData(
4542         ITypeInfo2 * iface,
4543         UINT index,
4544         REFGUID guid,
4545         VARIANT *pVarVal)
4546 {   
4547     ICOM_THIS( ITypeInfoImpl, iface);
4548     TLBCustData *pCData=NULL;
4549     TLBVarDesc * pVDesc; 
4550     int i;
4551
4552     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next);
4553
4554     if(pVDesc)
4555     {
4556       for(pCData=pVDesc->pCustData; pCData; pCData = pCData->next)
4557       {
4558         if( IsEqualIID(guid, &pCData->guid)) break;
4559       }
4560     }
4561
4562     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
4563
4564     if(pCData)
4565     {
4566         VariantInit( pVarVal);
4567         VariantCopy( pVarVal, &pCData->data);
4568         return S_OK;
4569     }
4570     return E_INVALIDARG;  /* FIXME: correct? */
4571 }
4572
4573 /* ITypeInfo2::GetImplCustData
4574  *
4575  * Gets the custom data
4576  */
4577 static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData(
4578         ITypeInfo2 * iface,
4579         UINT index,
4580         REFGUID guid,
4581         VARIANT *pVarVal)
4582 {   
4583     ICOM_THIS( ITypeInfoImpl, iface);
4584     TLBCustData *pCData=NULL;
4585     TLBImplType * pRDesc; 
4586     int i;
4587
4588     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++, pRDesc=pRDesc->next);
4589
4590     if(pRDesc)
4591     {
4592       for(pCData=pRDesc->pCustData; pCData; pCData = pCData->next)
4593       {
4594         if( IsEqualIID(guid, &pCData->guid)) break;
4595       }
4596     }
4597     
4598     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
4599
4600     if(pCData)
4601     {
4602         VariantInit( pVarVal);
4603         VariantCopy( pVarVal, &pCData->data);
4604         return S_OK;
4605     }
4606     return E_INVALIDARG;  /* FIXME: correct? */
4607 }
4608
4609 /* ITypeInfo2::GetDocumentation2
4610  * 
4611  * Retrieves the documentation string, the complete Help file name and path,
4612  * the localization context to use, and the context ID for the library Help
4613  * topic in the Help file.
4614  *
4615  */
4616 static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2(
4617         ITypeInfo2 * iface,
4618         MEMBERID memid,
4619         LCID lcid,
4620         BSTR *pbstrHelpString,
4621         DWORD *pdwHelpStringContext,
4622         BSTR *pbstrHelpStringDll)
4623 {
4624     ICOM_THIS( ITypeInfoImpl, iface);
4625     TLBFuncDesc * pFDesc; 
4626     TLBVarDesc * pVDesc; 
4627     TRACE("(%p) memid %ld lcid(0x%lx)  HelpString(%p) "
4628           "HelpStringContext(%p) HelpStringDll(%p)\n",
4629           This, memid, lcid, pbstrHelpString, pdwHelpStringContext,
4630           pbstrHelpStringDll );
4631     /* the help string should be obtained from the helpstringdll,
4632      * using the _DLLGetDocumentation function, based on the supplied
4633      * lcid. Nice to do sometime...
4634      */
4635     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
4636         if(pbstrHelpString)
4637             *pbstrHelpString=SysAllocString(This->Name);
4638         if(pdwHelpStringContext)
4639             *pdwHelpStringContext=This->dwHelpStringContext;
4640         if(pbstrHelpStringDll)
4641             *pbstrHelpStringDll=
4642                 SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
4643         return S_OK;
4644     }else {/* for a member */
4645     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
4646         if(pFDesc->funcdesc.memid==memid){
4647              if(pbstrHelpString)
4648                 *pbstrHelpString=SysAllocString(pFDesc->HelpString);
4649             if(pdwHelpStringContext)
4650                 *pdwHelpStringContext=pFDesc->HelpStringContext;
4651             if(pbstrHelpStringDll)
4652                 *pbstrHelpStringDll=
4653                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
4654         return S_OK;
4655     }
4656     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
4657         if(pVDesc->vardesc.memid==memid){
4658              if(pbstrHelpString)
4659                 *pbstrHelpString=SysAllocString(pVDesc->HelpString);
4660             if(pdwHelpStringContext)
4661                 *pdwHelpStringContext=pVDesc->HelpStringContext;
4662             if(pbstrHelpStringDll)
4663                 *pbstrHelpStringDll=
4664                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
4665             return S_OK;
4666         }
4667     }
4668     return TYPE_E_ELEMENTNOTFOUND;
4669 }
4670
4671 /* ITypeInfo2::GetAllCustData
4672  *
4673  * Gets all custom data items for the Type info. 
4674  *
4675  */
4676 static HRESULT WINAPI ITypeInfo2_fnGetAllCustData(
4677         ITypeInfo2 * iface,
4678         CUSTDATA *pCustData)
4679 {
4680     ICOM_THIS( ITypeInfoImpl, iface);
4681     TLBCustData *pCData;
4682     int i;
4683
4684     TRACE("(%p) returning %d items\n", This, This->ctCustData); 
4685
4686     pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
4687     if(pCustData->prgCustData ){
4688         pCustData->cCustData=This->ctCustData;
4689         for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
4690             pCustData->prgCustData[i].guid=pCData->guid;
4691             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
4692         }
4693     }else{
4694         ERR(" OUT OF MEMORY! \n");
4695         return E_OUTOFMEMORY;
4696     }
4697     return S_OK;
4698 }
4699
4700 /* ITypeInfo2::GetAllFuncCustData
4701  *
4702  * Gets all custom data items for the specified Function
4703  *
4704  */
4705 static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData(
4706         ITypeInfo2 * iface,
4707         UINT index,
4708         CUSTDATA *pCustData)
4709 {
4710     ICOM_THIS( ITypeInfoImpl, iface);
4711     TLBCustData *pCData;
4712     TLBFuncDesc * pFDesc; 
4713     int i;
4714     TRACE("(%p) index %d\n", This, index); 
4715     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
4716             pFDesc=pFDesc->next)
4717         ;
4718     if(pFDesc){
4719         pCustData->prgCustData =
4720             TLB_Alloc(pFDesc->ctCustData * sizeof(CUSTDATAITEM));
4721         if(pCustData->prgCustData ){
4722             pCustData->cCustData=pFDesc->ctCustData;
4723             for(i=0, pCData=pFDesc->pCustData; pCData; i++,
4724                     pCData = pCData->next){
4725                 pCustData->prgCustData[i].guid=pCData->guid;
4726                 VariantCopy(& pCustData->prgCustData[i].varValue,
4727                         & pCData->data);
4728             }
4729         }else{
4730             ERR(" OUT OF MEMORY! \n");
4731             return E_OUTOFMEMORY;
4732         }
4733         return S_OK;
4734     }
4735     return TYPE_E_ELEMENTNOTFOUND;
4736 }
4737
4738 /* ITypeInfo2::GetAllParamCustData
4739  *
4740  * Gets all custom data items for the Functions
4741  *
4742  */
4743 static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo2 * iface,
4744     UINT indexFunc, UINT indexParam, CUSTDATA *pCustData)
4745 {
4746     ICOM_THIS( ITypeInfoImpl, iface);
4747     TLBCustData *pCData=NULL;
4748     TLBFuncDesc * pFDesc; 
4749     int i;
4750     TRACE("(%p) index %d\n", This, indexFunc); 
4751     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,
4752             pFDesc=pFDesc->next)
4753         ;
4754     if(pFDesc && indexParam >=0 && indexParam<pFDesc->funcdesc.cParams){
4755         pCustData->prgCustData = 
4756             TLB_Alloc(pFDesc->pParamDesc[indexParam].ctCustData *
4757                     sizeof(CUSTDATAITEM));
4758         if(pCustData->prgCustData ){
4759             pCustData->cCustData=pFDesc->pParamDesc[indexParam].ctCustData;
4760             for(i=0, pCData=pFDesc->pParamDesc[indexParam].pCustData;
4761                     pCData; i++, pCData = pCData->next){
4762                 pCustData->prgCustData[i].guid=pCData->guid;
4763                 VariantCopy(& pCustData->prgCustData[i].varValue,
4764                         & pCData->data);
4765             }
4766         }else{
4767             ERR(" OUT OF MEMORY! \n");
4768             return E_OUTOFMEMORY;
4769         }
4770         return S_OK;
4771     }
4772     return TYPE_E_ELEMENTNOTFOUND;
4773 }
4774
4775 /* ITypeInfo2::GetAllVarCustData
4776  *
4777  * Gets all custom data items for the specified Variable
4778  *
4779  */
4780 static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo2 * iface,
4781     UINT index, CUSTDATA *pCustData)
4782 {
4783     ICOM_THIS( ITypeInfoImpl, iface);
4784     TLBCustData *pCData;
4785     TLBVarDesc * pVDesc; 
4786     int i;
4787     TRACE("(%p) index %d\n", This, index); 
4788     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++,
4789             pVDesc=pVDesc->next)
4790         ;
4791     if(pVDesc){
4792         pCustData->prgCustData =
4793             TLB_Alloc(pVDesc->ctCustData * sizeof(CUSTDATAITEM));
4794         if(pCustData->prgCustData ){
4795             pCustData->cCustData=pVDesc->ctCustData;
4796             for(i=0, pCData=pVDesc->pCustData; pCData; i++,
4797                     pCData = pCData->next){
4798                 pCustData->prgCustData[i].guid=pCData->guid;
4799                 VariantCopy(& pCustData->prgCustData[i].varValue,
4800                         & pCData->data);
4801             }
4802         }else{
4803             ERR(" OUT OF MEMORY! \n");
4804             return E_OUTOFMEMORY;
4805         }
4806         return S_OK;
4807     }
4808     return TYPE_E_ELEMENTNOTFOUND;
4809 }
4810
4811 /* ITypeInfo2::GetAllImplCustData
4812  *
4813  * Gets all custom data items for the specified implementation type
4814  *
4815  */
4816 static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData(
4817         ITypeInfo2 * iface,
4818         UINT index,
4819         CUSTDATA *pCustData)
4820 {
4821     ICOM_THIS( ITypeInfoImpl, iface);
4822     TLBCustData *pCData;
4823     TLBImplType * pRDesc; 
4824     int i;
4825     TRACE("(%p) index %d\n", This, index); 
4826     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++,
4827             pRDesc=pRDesc->next)
4828         ;
4829     if(pRDesc){
4830         pCustData->prgCustData =
4831             TLB_Alloc(pRDesc->ctCustData * sizeof(CUSTDATAITEM));
4832         if(pCustData->prgCustData ){
4833             pCustData->cCustData=pRDesc->ctCustData;
4834             for(i=0, pCData=pRDesc->pCustData; pCData; i++,
4835                     pCData = pCData->next){
4836                 pCustData->prgCustData[i].guid=pCData->guid;
4837                 VariantCopy(& pCustData->prgCustData[i].varValue,
4838                         & pCData->data);
4839             }
4840         }else{
4841             ERR(" OUT OF MEMORY! \n");
4842             return E_OUTOFMEMORY;
4843         }
4844         return S_OK;
4845     }
4846     return TYPE_E_ELEMENTNOTFOUND;
4847 }
4848
4849 static ICOM_VTABLE(ITypeInfo2) tinfvt = 
4850 {
4851     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
4852
4853     ITypeInfo_fnQueryInterface,
4854     ITypeInfo_fnAddRef,
4855     ITypeInfo_fnRelease,
4856
4857     ITypeInfo_fnGetTypeAttr,
4858     ITypeInfo_fnGetTypeComp,
4859     ITypeInfo_fnGetFuncDesc,
4860     ITypeInfo_fnGetVarDesc,
4861     ITypeInfo_fnGetNames,
4862     ITypeInfo_fnGetRefTypeOfImplType,
4863     ITypeInfo_fnGetImplTypeFlags,
4864     ITypeInfo_fnGetIDsOfNames,
4865     ITypeInfo_fnInvoke,
4866     ITypeInfo_fnGetDocumentation,
4867     ITypeInfo_fnGetDllEntry,
4868     ITypeInfo_fnGetRefTypeInfo,
4869     ITypeInfo_fnAddressOfMember,
4870     ITypeInfo_fnCreateInstance,
4871     ITypeInfo_fnGetMops,
4872     ITypeInfo_fnGetContainingTypeLib,
4873     ITypeInfo_fnReleaseTypeAttr,
4874     ITypeInfo_fnReleaseFuncDesc,
4875     ITypeInfo_fnReleaseVarDesc,
4876
4877     ITypeInfo2_fnGetTypeKind,
4878     ITypeInfo2_fnGetTypeFlags,
4879     ITypeInfo2_fnGetFuncIndexOfMemId,
4880     ITypeInfo2_fnGetVarIndexOfMemId,
4881     ITypeInfo2_fnGetCustData,
4882     ITypeInfo2_fnGetFuncCustData,
4883     ITypeInfo2_fnGetParamCustData,
4884     ITypeInfo2_fnGetVarCustData,
4885     ITypeInfo2_fnGetImplTypeCustData,
4886     ITypeInfo2_fnGetDocumentation2,
4887     ITypeInfo2_fnGetAllCustData,
4888     ITypeInfo2_fnGetAllFuncCustData,
4889     ITypeInfo2_fnGetAllParamCustData,
4890     ITypeInfo2_fnGetAllVarCustData,
4891     ITypeInfo2_fnGetAllImplTypeCustData,
4892 };