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