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