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