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