Added stubs for AccessCheckByType, AddAuditAccessAce,
[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 const 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               const 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             char *name;
2287             DWORD len;
2288
2289             *ppImpLib = TLB_Alloc(sizeof(TLBImpLib));
2290             (*ppImpLib)->offset = offset - tlbSegDir.pImpFiles.offset;
2291             MSFT_ReadLEDWords(&oGuid, sizeof(INT), &cx, offset);
2292
2293             MSFT_ReadLEDWords(&(*ppImpLib)->lcid,         sizeof(LCID),   &cx, DO_NOT_SEEK);
2294             MSFT_ReadLEWords(&(*ppImpLib)->wVersionMajor, sizeof(WORD),   &cx, DO_NOT_SEEK);
2295             MSFT_ReadLEWords(&(*ppImpLib)->wVersionMinor, sizeof(WORD),   &cx, DO_NOT_SEEK);
2296             MSFT_ReadLEWords(& size,                      sizeof(UINT16), &cx, DO_NOT_SEEK);
2297
2298             size >>= 2;
2299             name = TLB_Alloc(size+1);
2300             MSFT_Read(name, size, &cx, DO_NOT_SEEK);
2301             len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0 );
2302             (*ppImpLib)->name = TLB_Alloc(len * sizeof(WCHAR));
2303             MultiByteToWideChar(CP_ACP, 0, name, -1, (*ppImpLib)->name, len );
2304             TLB_Free(name);
2305
2306             MSFT_ReadGuid(&(*ppImpLib)->guid, oGuid, &cx);
2307             offset = (offset + sizeof(INT) + sizeof(DWORD) + sizeof(LCID) + sizeof(UINT16) + size + 3) & ~3;
2308
2309             ppImpLib = &(*ppImpLib)->next;
2310         }
2311     }
2312
2313     /* type info's */
2314     if(tlbHeader.nrtypeinfos >= 0 )
2315     {
2316         /*pTypeLibImpl->TypeInfoCount=tlbHeader.nrtypeinfos; */
2317         ITypeInfoImpl **ppTI = &(pTypeLibImpl->pTypeInfo);
2318         int i;
2319
2320         for(i = 0; i<(int)tlbHeader.nrtypeinfos; i++)
2321         {
2322             *ppTI = MSFT_DoTypeInfo(&cx, i, pTypeLibImpl);
2323
2324             ITypeInfo_AddRef((ITypeInfo*) *ppTI);
2325             ppTI = &((*ppTI)->next);
2326             (pTypeLibImpl->TypeInfoCount)++;
2327         }
2328     }
2329
2330     TRACE("(%p)\n", pTypeLibImpl);
2331     return (ITypeLib2*) pTypeLibImpl;
2332 }
2333
2334
2335 static BSTR TLB_MultiByteToBSTR(char *ptr)
2336 {
2337     DWORD len;
2338     WCHAR *nameW;
2339     BSTR ret;
2340
2341     len = MultiByteToWideChar(CP_ACP, 0, ptr, -1, NULL, 0);
2342     nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2343     MultiByteToWideChar(CP_ACP, 0, ptr, -1, nameW, len);
2344     ret = SysAllocString(nameW);
2345     HeapFree(GetProcessHeap(), 0, nameW);
2346     return ret;
2347 }
2348
2349 static BOOL TLB_GUIDFromString(char *str, GUID *guid)
2350 {
2351   char b[3];
2352   int i;
2353   short s;
2354
2355   if(sscanf(str, "%lx-%hx-%hx-%hx", &guid->Data1, &guid->Data2, &guid->Data3, &s) != 4) {
2356     FIXME("Can't parse guid %s\n", debugstr_guid(guid));
2357     return FALSE;
2358   }
2359
2360   guid->Data4[0] = s >> 8;
2361   guid->Data4[1] = s & 0xff;
2362
2363   b[2] = '\0';
2364   for(i = 0; i < 6; i++) {
2365     memcpy(b, str + 24 + 2 * i, 2);
2366     guid->Data4[i + 2] = strtol(b, NULL, 16);
2367   }
2368   return TRUE;
2369 }
2370
2371 static WORD SLTG_ReadString(char *ptr, BSTR *pBstr)
2372 {
2373     WORD bytelen;
2374     DWORD len;
2375     WCHAR *nameW;
2376
2377     *pBstr = NULL;
2378     bytelen = *(WORD*)ptr;
2379     if(bytelen == 0xffff) return 2;
2380     len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, NULL, 0);
2381     nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2382     len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, nameW, len);
2383     *pBstr = SysAllocStringLen(nameW, len);
2384     HeapFree(GetProcessHeap(), 0, nameW);
2385     return bytelen + 2;
2386 }
2387
2388 static WORD SLTG_ReadStringA(char *ptr, char **str)
2389 {
2390     WORD bytelen;
2391
2392     *str = NULL;
2393     bytelen = *(WORD*)ptr;
2394     if(bytelen == 0xffff) return 2;
2395     *str = HeapAlloc(GetProcessHeap(), 0, bytelen + 1);
2396     memcpy(*str, ptr + 2, bytelen);
2397     (*str)[bytelen] = '\0';
2398     return bytelen + 2;
2399 }
2400
2401 static DWORD SLTG_ReadLibBlk(LPVOID pLibBlk, ITypeLibImpl *pTypeLibImpl)
2402 {
2403     char *ptr = pLibBlk;
2404     WORD w;
2405
2406     if((w = *(WORD*)ptr) != SLTG_LIBBLK_MAGIC) {
2407         FIXME("libblk magic = %04x\n", w);
2408         return 0;
2409     }
2410
2411     ptr += 6;
2412     if((w = *(WORD*)ptr) != 0xffff) {
2413         FIXME("LibBlk.res06 = %04x. Assumung string and skipping\n", w);
2414         ptr += w;
2415     }
2416     ptr += 2;
2417
2418     ptr += SLTG_ReadString(ptr, &pTypeLibImpl->DocString);
2419
2420     ptr += SLTG_ReadString(ptr, &pTypeLibImpl->HelpFile);
2421
2422     pTypeLibImpl->dwHelpContext = *(DWORD*)ptr;
2423     ptr += 4;
2424
2425     pTypeLibImpl->LibAttr.syskind = *(WORD*)ptr;
2426     ptr += 2;
2427
2428     pTypeLibImpl->LibAttr.lcid = *(WORD*)ptr;
2429     ptr += 2;
2430
2431     ptr += 4; /* skip res12 */
2432
2433     pTypeLibImpl->LibAttr.wLibFlags = *(WORD*)ptr;
2434     ptr += 2;
2435
2436     pTypeLibImpl->LibAttr.wMajorVerNum = *(WORD*)ptr;
2437     ptr += 2;
2438
2439     pTypeLibImpl->LibAttr.wMinorVerNum = *(WORD*)ptr;
2440     ptr += 2;
2441
2442     memcpy(&pTypeLibImpl->LibAttr.guid, ptr, sizeof(GUID));
2443     ptr += sizeof(GUID);
2444
2445     return ptr - (char*)pLibBlk;
2446 }
2447
2448 static WORD *SLTG_DoType(WORD *pType, char *pBlk, ELEMDESC *pElem)
2449 {
2450     BOOL done = FALSE;
2451     TYPEDESC *pTD = &pElem->tdesc;
2452
2453     /* Handle [in/out] first */
2454     if((*pType & 0xc000) == 0xc000)
2455         pElem->u.paramdesc.wParamFlags = PARAMFLAG_NONE;
2456     else if(*pType & 0x8000)
2457         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN | PARAMFLAG_FOUT;
2458     else if(*pType & 0x4000)
2459         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FOUT;
2460     else
2461         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN;
2462
2463     if(*pType & 0x2000)
2464         pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FLCID;
2465
2466     if(*pType & 0x80)
2467         pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FRETVAL;
2468
2469     while(!done) {
2470         if((*pType & 0xe00) == 0xe00) {
2471             pTD->vt = VT_PTR;
2472             pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2473                                        sizeof(TYPEDESC));
2474             pTD = pTD->u.lptdesc;
2475         }
2476         switch(*pType & 0x7f) {
2477         case VT_PTR:
2478             pTD->vt = VT_PTR;
2479             pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2480                                        sizeof(TYPEDESC));
2481             pTD = pTD->u.lptdesc;
2482             break;
2483
2484         case VT_USERDEFINED:
2485             pTD->vt = VT_USERDEFINED;
2486             pTD->u.hreftype = *(++pType) / 4;
2487             done = TRUE;
2488             break;
2489
2490         case VT_CARRAY:
2491           {
2492             /* *(pType+1) is offset to a SAFEARRAY, *(pType+2) is type of
2493                array */
2494
2495             SAFEARRAY *pSA = (SAFEARRAY *)(pBlk + *(++pType));
2496
2497             pTD->vt = VT_CARRAY;
2498             pTD->u.lpadesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2499                                 sizeof(ARRAYDESC) +
2500                                 (pSA->cDims - 1) * sizeof(SAFEARRAYBOUND));
2501             pTD->u.lpadesc->cDims = pSA->cDims;
2502             memcpy(pTD->u.lpadesc->rgbounds, pSA->rgsabound,
2503                    pSA->cDims * sizeof(SAFEARRAYBOUND));
2504
2505             pTD = &pTD->u.lpadesc->tdescElem;
2506             break;
2507           }
2508
2509         case VT_SAFEARRAY:
2510           {
2511             /* FIXME: *(pType+1) gives an offset to SAFEARRAY, is this
2512                useful? */
2513
2514             pType++;
2515             pTD->vt = VT_SAFEARRAY;
2516             pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2517                                        sizeof(TYPEDESC));
2518             pTD = pTD->u.lptdesc;
2519             break;
2520           }
2521         default:
2522             pTD->vt = *pType & 0x7f;
2523             done = TRUE;
2524             break;
2525         }
2526         pType++;
2527     }
2528     return pType;
2529 }
2530
2531
2532 static void SLTG_DoRefs(SLTG_RefInfo *pRef, ITypeInfoImpl *pTI,
2533                         char *pNameTable)
2534 {
2535     int ref;
2536     char *name;
2537     TLBRefType **ppRefType;
2538
2539     if(pRef->magic != SLTG_REF_MAGIC) {
2540         FIXME("Ref magic = %x\n", pRef->magic);
2541         return;
2542     }
2543     name = ( (char*)(&pRef->names) + pRef->number);
2544
2545     ppRefType = &pTI->reflist;
2546     for(ref = 0; ref < pRef->number >> 3; ref++) {
2547         char *refname;
2548         unsigned int lib_offs, type_num;
2549
2550         *ppRefType = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2551                                sizeof(**ppRefType));
2552
2553         name += SLTG_ReadStringA(name, &refname);
2554         if(sscanf(refname, "*\\R%x*#%x", &lib_offs, &type_num) != 2)
2555             FIXME("Can't sscanf ref\n");
2556         if(lib_offs != 0xffff) {
2557             TLBImpLib **import = &pTI->pTypeLib->pImpLibs;
2558
2559             while(*import) {
2560                 if((*import)->offset == lib_offs)
2561                     break;
2562                 import = &(*import)->next;
2563             }
2564             if(!*import) {
2565                 char fname[MAX_PATH+1];
2566                 int len;
2567
2568                 *import = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2569                                     sizeof(**import));
2570                 (*import)->offset = lib_offs;
2571                 TLB_GUIDFromString( pNameTable + lib_offs + 4,
2572                                     &(*import)->guid);
2573                 if(sscanf(pNameTable + lib_offs + 40, "}#%hd.%hd#%lx#%s",
2574                           &(*import)->wVersionMajor,
2575                           &(*import)->wVersionMinor,
2576                           &(*import)->lcid, fname) != 4) {
2577                   FIXME("can't sscanf ref %s\n",
2578                         pNameTable + lib_offs + 40);
2579                 }
2580                 len = strlen(fname);
2581                 if(fname[len-1] != '#')
2582                     FIXME("fname = %s\n", fname);
2583                 fname[len-1] = '\0';
2584                 (*import)->name = TLB_MultiByteToBSTR(fname);
2585             }
2586             (*ppRefType)->pImpTLInfo = *import;
2587         } else { /* internal ref */
2588           (*ppRefType)->pImpTLInfo = TLB_REF_INTERNAL;
2589         }
2590         (*ppRefType)->reference = ref;
2591         (*ppRefType)->index = type_num;
2592
2593         HeapFree(GetProcessHeap(), 0, refname);
2594         ppRefType = &(*ppRefType)->next;
2595     }
2596     if((BYTE)*name != SLTG_REF_MAGIC)
2597       FIXME("End of ref block magic = %x\n", *name);
2598     dump_TLBRefType(pTI->reflist);
2599 }
2600
2601 static char *SLTG_DoImpls(char *pBlk, ITypeInfoImpl *pTI,
2602                           BOOL OneOnly)
2603 {
2604     SLTG_ImplInfo *info;
2605     TLBImplType **ppImplType = &pTI->impltypelist;
2606     /* I don't really get this structure, usually it's 0x16 bytes
2607        long, but iuser.tlb contains some that are 0x18 bytes long.
2608        That's ok because we can use the next ptr to jump to the next
2609        one. But how do we know the length of the last one?  The WORD
2610        at offs 0x8 might be the clue.  For now I'm just assuming that
2611        the last one is the regular 0x16 bytes. */
2612
2613     info = (SLTG_ImplInfo*)pBlk;
2614     while(1) {
2615         *ppImplType = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2616                                 sizeof(**ppImplType));
2617         (*ppImplType)->hRef = info->ref;
2618         (*ppImplType)->implflags = info->impltypeflags;
2619         pTI->TypeAttr.cImplTypes++;
2620         ppImplType = &(*ppImplType)->next;
2621
2622         if(info->next == 0xffff)
2623             break;
2624         if(OneOnly)
2625             FIXME("Interface inheriting more than one interface\n");
2626         info = (SLTG_ImplInfo*)(pBlk + info->next);
2627     }
2628     info++; /* see comment at top of function */
2629     return (char*)info;
2630 }
2631
2632 static SLTG_TypeInfoTail *SLTG_ProcessCoClass(char *pBlk, ITypeInfoImpl *pTI,
2633                                               char *pNameTable)
2634 {
2635     SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk;
2636     SLTG_MemberHeader *pMemHeader;
2637     char *pFirstItem, *pNextItem;
2638
2639     if(pTIHeader->href_table != 0xffffffff) {
2640         SLTG_DoRefs((SLTG_RefInfo*)(pBlk + pTIHeader->href_table), pTI,
2641                     pNameTable);
2642     }
2643
2644
2645     pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table);
2646
2647     pFirstItem = pNextItem = (char*)(pMemHeader + 1);
2648
2649     if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
2650         pNextItem = SLTG_DoImpls(pFirstItem, pTI, FALSE);
2651     }
2652
2653     return (SLTG_TypeInfoTail*)(pFirstItem + pMemHeader->cbExtra);
2654 }
2655
2656
2657 static SLTG_TypeInfoTail *SLTG_ProcessInterface(char *pBlk, ITypeInfoImpl *pTI,
2658                                                 char *pNameTable)
2659 {
2660     SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk;
2661     SLTG_MemberHeader *pMemHeader;
2662     SLTG_Function *pFunc;
2663     char *pFirstItem, *pNextItem;
2664     TLBFuncDesc **ppFuncDesc = &pTI->funclist;
2665     int num = 0;
2666
2667     if(pTIHeader->href_table != 0xffffffff) {
2668         SLTG_DoRefs((SLTG_RefInfo*)(pBlk + pTIHeader->href_table), pTI,
2669                     pNameTable);
2670     }
2671
2672     pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table);
2673
2674     pFirstItem = pNextItem = (char*)(pMemHeader + 1);
2675
2676     if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
2677         pNextItem = SLTG_DoImpls(pFirstItem, pTI, TRUE);
2678     }
2679
2680     for(pFunc = (SLTG_Function*)pNextItem, num = 1; 1;
2681         pFunc = (SLTG_Function*)(pFirstItem + pFunc->next), num++) {
2682
2683         int param;
2684         WORD *pType, *pArg;
2685
2686         if(pFunc->magic != SLTG_FUNCTION_MAGIC &&
2687            pFunc->magic != SLTG_FUNCTION_WITH_FLAGS_MAGIC) {
2688             FIXME("func magic = %02x\n", pFunc->magic);
2689             return NULL;
2690         }
2691         *ppFuncDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2692                                 sizeof(**ppFuncDesc));
2693         (*ppFuncDesc)->Name = TLB_MultiByteToBSTR(pFunc->name + pNameTable);
2694
2695         (*ppFuncDesc)->funcdesc.memid = pFunc->dispid;
2696         (*ppFuncDesc)->funcdesc.invkind = pFunc->inv >> 4;
2697         (*ppFuncDesc)->funcdesc.callconv = pFunc->nacc & 0x7;
2698         (*ppFuncDesc)->funcdesc.cParams = pFunc->nacc >> 3;
2699         (*ppFuncDesc)->funcdesc.cParamsOpt = (pFunc->retnextopt & 0x7e) >> 1;
2700         (*ppFuncDesc)->funcdesc.oVft = pFunc->vtblpos;
2701
2702         if(pFunc->magic == SLTG_FUNCTION_WITH_FLAGS_MAGIC)
2703             (*ppFuncDesc)->funcdesc.wFuncFlags = pFunc->funcflags;
2704
2705         if(pFunc->retnextopt & 0x80)
2706             pType = &pFunc->rettype;
2707         else
2708             pType = (WORD*)(pFirstItem + pFunc->rettype);
2709
2710
2711         SLTG_DoType(pType, pFirstItem, &(*ppFuncDesc)->funcdesc.elemdescFunc);
2712
2713         (*ppFuncDesc)->funcdesc.lprgelemdescParam =
2714           HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2715                     (*ppFuncDesc)->funcdesc.cParams * sizeof(ELEMDESC));
2716         (*ppFuncDesc)->pParamDesc =
2717           HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2718                     (*ppFuncDesc)->funcdesc.cParams * sizeof(TLBParDesc));
2719
2720         pArg = (WORD*)(pFirstItem + pFunc->arg_off);
2721
2722         for(param = 0; param < (*ppFuncDesc)->funcdesc.cParams; param++) {
2723             char *paramName = pNameTable + *pArg;
2724             BOOL HaveOffs;
2725             /* If arg type follows then paramName points to the 2nd
2726                letter of the name, else the next WORD is an offset to
2727                the arg type and paramName points to the first letter.
2728                So let's take one char off paramName and see if we're
2729                pointing at an alpha-numeric char.  However if *pArg is
2730                0xffff or 0xfffe then the param has no name, the former
2731                meaning that the next WORD is the type, the latter
2732                meaning the the next WORD is an offset to the type. */
2733
2734             HaveOffs = FALSE;
2735             if(*pArg == 0xffff)
2736                 paramName = NULL;
2737             else if(*pArg == 0xfffe) {
2738                 paramName = NULL;
2739                 HaveOffs = TRUE;
2740             }
2741             else if(!isalnum(*(paramName-1)))
2742                 HaveOffs = TRUE;
2743
2744             pArg++;
2745
2746             if(HaveOffs) { /* the next word is an offset to type */
2747                 pType = (WORD*)(pFirstItem + *pArg);
2748                 SLTG_DoType(pType, pFirstItem,
2749                             &(*ppFuncDesc)->funcdesc.lprgelemdescParam[param]);
2750                 pArg++;
2751             } else {
2752                 if(paramName)
2753                   paramName--;
2754                 pArg = SLTG_DoType(pArg, pFirstItem,
2755                            &(*ppFuncDesc)->funcdesc.lprgelemdescParam[param]);
2756             }
2757
2758             /* Are we an optional param ? */
2759             if((*ppFuncDesc)->funcdesc.cParams - param <=
2760                (*ppFuncDesc)->funcdesc.cParamsOpt)
2761               (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].u.paramdesc.wParamFlags |= PARAMFLAG_FOPT;
2762
2763             if(paramName) {
2764                 (*ppFuncDesc)->pParamDesc[param].Name =
2765                   TLB_MultiByteToBSTR(paramName);
2766             }
2767         }
2768
2769         ppFuncDesc = &((*ppFuncDesc)->next);
2770         if(pFunc->next == 0xffff) break;
2771     }
2772     pTI->TypeAttr.cFuncs = num;
2773     dump_TLBFuncDesc(pTI->funclist);
2774     return (SLTG_TypeInfoTail*)(pFirstItem + pMemHeader->cbExtra);
2775 }
2776
2777 static SLTG_TypeInfoTail *SLTG_ProcessRecord(char *pBlk, ITypeInfoImpl *pTI,
2778                                              char *pNameTable)
2779 {
2780   SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk;
2781   SLTG_MemberHeader *pMemHeader;
2782   SLTG_RecordItem *pItem;
2783   char *pFirstItem;
2784   TLBVarDesc **ppVarDesc = &pTI->varlist;
2785   int num = 0;
2786   WORD *pType;
2787   char buf[300];
2788
2789   pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table);
2790
2791   pFirstItem = (char*)(pMemHeader + 1);
2792   for(pItem = (SLTG_RecordItem *)pFirstItem, num = 1; 1;
2793       pItem = (SLTG_RecordItem *)(pFirstItem + pItem->next), num++) {
2794       if(pItem->magic != SLTG_RECORD_MAGIC) {
2795           FIXME("record magic = %02x\n", pItem->magic);
2796           return NULL;
2797       }
2798       *ppVarDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2799                              sizeof(**ppVarDesc));
2800       (*ppVarDesc)->Name = TLB_MultiByteToBSTR(pItem->name + pNameTable);
2801       (*ppVarDesc)->vardesc.memid = pItem->memid;
2802       (*ppVarDesc)->vardesc.u.oInst = pItem->byte_offs;
2803       (*ppVarDesc)->vardesc.varkind = VAR_PERINSTANCE;
2804
2805       if(pItem->typepos == 0x02)
2806           pType = &pItem->type;
2807       else if(pItem->typepos == 0x00)
2808           pType = (WORD*)(pFirstItem + pItem->type);
2809       else {
2810           FIXME("typepos = %02x\n", pItem->typepos);
2811           break;
2812       }
2813
2814       SLTG_DoType(pType, pFirstItem,
2815                   &(*ppVarDesc)->vardesc.elemdescVar);
2816
2817       /* FIXME("helpcontext, helpstring\n"); */
2818
2819       dump_TypeDesc(&(*ppVarDesc)->vardesc.elemdescVar.tdesc, buf);
2820
2821       ppVarDesc = &((*ppVarDesc)->next);
2822       if(pItem->next == 0xffff) break;
2823   }
2824   pTI->TypeAttr.cVars = num;
2825   return (SLTG_TypeInfoTail*)(pFirstItem + pMemHeader->cbExtra);
2826 }
2827
2828 static SLTG_TypeInfoTail *SLTG_ProcessAlias(char *pBlk, ITypeInfoImpl *pTI,
2829                                            char *pNameTable)
2830 {
2831   SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk;
2832   SLTG_MemberHeader *pMemHeader;
2833   SLTG_AliasItem *pItem;
2834   int i, mustbelast;
2835
2836   pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table);
2837   pItem = (SLTG_AliasItem*)(pMemHeader + 1);
2838
2839   mustbelast = 0;
2840   /* This is used for creating a TYPEDESC chain in case of VT_USERDEFINED */
2841   for (i = 0 ; i<pMemHeader->cbExtra/4 ; i++) {
2842     if (pItem->vt == 0xffff) {
2843       if (i<(pMemHeader->cbExtra/4-1))
2844         FIXME("Endmarker too early in process alias data!\n");
2845       break;
2846     }
2847     if (mustbelast) {
2848       FIXME("Chain extends over last entry?\n");
2849       break;
2850     }
2851     if (pItem->vt == VT_USERDEFINED) {
2852       pTI->TypeAttr.tdescAlias.vt = pItem->vt;
2853       /* guessing here ... */
2854       FIXME("Guessing TKIND_ALIAS of VT_USERDEFINED with hreftype 0x%x\n",pItem->res02);
2855       pTI->TypeAttr.tdescAlias.u.hreftype = pItem->res02;
2856       mustbelast = 1;
2857     } else {
2858       FIXME("alias %d: 0x%x\n",i,pItem->vt);
2859       FIXME("alias %d: 0x%x\n",i,pItem->res02);
2860     }
2861     pItem++;
2862   }
2863   return (SLTG_TypeInfoTail*)((char*)(pMemHeader + 1)+pMemHeader->cbExtra);
2864 }
2865
2866 static SLTG_TypeInfoTail *SLTG_ProcessDispatch(char *pBlk, ITypeInfoImpl *pTI,
2867                                            char *pNameTable)
2868 {
2869   SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk;
2870   SLTG_MemberHeader *pMemHeader;
2871   SLTG_AliasItem *pItem;
2872
2873   pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table);
2874   pItem = (SLTG_AliasItem*)(pMemHeader + 1);
2875   FIXME("memh.cbExtra is %ld\n",pMemHeader->cbExtra);
2876   FIXME("offset 0 0x%x\n",*(WORD*)pItem);
2877   return (SLTG_TypeInfoTail*)((char*)(pMemHeader + 1)+pMemHeader->cbExtra);
2878 }
2879
2880 static SLTG_TypeInfoTail *SLTG_ProcessEnum(char *pBlk, ITypeInfoImpl *pTI,
2881                                            char *pNameTable)
2882 {
2883   SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk;
2884   SLTG_MemberHeader *pMemHeader;
2885   SLTG_EnumItem *pItem;
2886   char *pFirstItem;
2887   TLBVarDesc **ppVarDesc = &pTI->varlist;
2888   int num = 0;
2889
2890   pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table);
2891
2892   pFirstItem = (char*)(pMemHeader + 1);
2893   for(pItem = (SLTG_EnumItem *)pFirstItem, num = 1; 1;
2894       pItem = (SLTG_EnumItem *)(pFirstItem + pItem->next), num++) {
2895       if(pItem->magic != SLTG_ENUMITEM_MAGIC) {
2896           FIXME("enumitem magic = %04x\n", pItem->magic);
2897           return NULL;
2898       }
2899       *ppVarDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2900                              sizeof(**ppVarDesc));
2901       (*ppVarDesc)->Name = TLB_MultiByteToBSTR(pItem->name + pNameTable);
2902       (*ppVarDesc)->vardesc.memid = pItem->memid;
2903       (*ppVarDesc)->vardesc.u.lpvarValue = HeapAlloc(GetProcessHeap(), 0,
2904                                                      sizeof(VARIANT));
2905       V_VT((*ppVarDesc)->vardesc.u.lpvarValue) = VT_INT;
2906       V_UNION((*ppVarDesc)->vardesc.u.lpvarValue, intVal) =
2907         *(INT*)(pItem->value + pFirstItem);
2908       (*ppVarDesc)->vardesc.elemdescVar.tdesc.vt = VT_I4;
2909       (*ppVarDesc)->vardesc.varkind = VAR_CONST;
2910       /* FIXME("helpcontext, helpstring\n"); */
2911
2912       ppVarDesc = &((*ppVarDesc)->next);
2913       if(pItem->next == 0xffff) break;
2914   }
2915   pTI->TypeAttr.cVars = num;
2916   return (SLTG_TypeInfoTail*)(pFirstItem + pMemHeader->cbExtra);
2917 }
2918
2919 /* Because SLTG_OtherTypeInfo is such a painfull struct, we make a more
2920    managable copy of it into this */
2921 typedef struct {
2922   WORD small_no;
2923   char *index_name;
2924   char *other_name;
2925   WORD res1a;
2926   WORD name_offs;
2927   WORD more_bytes;
2928   char *extra;
2929   WORD res20;
2930   DWORD helpcontext;
2931   WORD res26;
2932   GUID uuid;
2933 } SLTG_InternalOtherTypeInfo;
2934
2935 /****************************************************************************
2936  *      ITypeLib2_Constructor_SLTG
2937  *
2938  * loading a SLTG typelib from an in-memory image
2939  */
2940 static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength)
2941 {
2942     ITypeLibImpl *pTypeLibImpl;
2943     SLTG_Header *pHeader;
2944     SLTG_BlkEntry *pBlkEntry;
2945     SLTG_Magic *pMagic;
2946     SLTG_Index *pIndex;
2947     SLTG_Pad9 *pPad9;
2948     LPVOID pBlk, pFirstBlk;
2949     SLTG_LibBlk *pLibBlk;
2950     SLTG_InternalOtherTypeInfo *pOtherTypeInfoBlks;
2951     char *pAfterOTIBlks = NULL;
2952     char *pNameTable, *ptr;
2953     int i;
2954     DWORD len, order;
2955     ITypeInfoImpl **ppTypeInfoImpl;
2956
2957     TRACE("%p, TLB length = %ld\n", pLib, dwTLBLength);
2958
2959     pTypeLibImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeLibImpl));
2960     if (!pTypeLibImpl) return NULL;
2961
2962     pTypeLibImpl->lpVtbl = &tlbvt;
2963     pTypeLibImpl->ref = 1;
2964
2965     pHeader = pLib;
2966
2967     TRACE("header:\n");
2968     TRACE("\tmagic=0x%08lx, file blocks = %d\n", pHeader->SLTG_magic,
2969           pHeader->nrOfFileBlks );
2970     if (pHeader->SLTG_magic != SLTG_SIGNATURE) {
2971         FIXME("Header type magic 0x%08lx not supported.\n",
2972               pHeader->SLTG_magic);
2973         return NULL;
2974     }
2975
2976     /* There are pHeader->nrOfFileBlks - 2 TypeInfo records in this typelib */
2977     pTypeLibImpl->TypeInfoCount = pHeader->nrOfFileBlks - 2;
2978
2979     /* This points to pHeader->nrOfFileBlks - 1 of SLTG_BlkEntry */
2980     pBlkEntry = (SLTG_BlkEntry*)(pHeader + 1);
2981
2982     /* Next we have a magic block */
2983     pMagic = (SLTG_Magic*)(pBlkEntry + pHeader->nrOfFileBlks - 1);
2984
2985     /* Let's see if we're still in sync */
2986     if(memcmp(pMagic->CompObj_magic, SLTG_COMPOBJ_MAGIC,
2987               sizeof(SLTG_COMPOBJ_MAGIC))) {
2988         FIXME("CompObj magic = %s\n", pMagic->CompObj_magic);
2989         return NULL;
2990     }
2991     if(memcmp(pMagic->dir_magic, SLTG_DIR_MAGIC,
2992               sizeof(SLTG_DIR_MAGIC))) {
2993         FIXME("dir magic = %s\n", pMagic->dir_magic);
2994         return NULL;
2995     }
2996
2997     pIndex = (SLTG_Index*)(pMagic+1);
2998
2999     pPad9 = (SLTG_Pad9*)(pIndex + pTypeLibImpl->TypeInfoCount);
3000
3001     pFirstBlk = (LPVOID)(pPad9 + 1);
3002
3003     /* We'll set up a ptr to the main library block, which is the last one. */
3004
3005     for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0;
3006           pBlkEntry[order].next != 0;
3007           order = pBlkEntry[order].next - 1, i++) {
3008        pBlk = (char*)pBlk + pBlkEntry[order].len;
3009     }
3010     pLibBlk = pBlk;
3011
3012     len = SLTG_ReadLibBlk(pLibBlk, pTypeLibImpl);
3013
3014     /* Now there's 0x40 bytes of 0xffff with the numbers 0 to TypeInfoCount
3015        interspersed */
3016
3017     len += 0x40;
3018
3019     /* And now TypeInfoCount of SLTG_OtherTypeInfo */
3020
3021     pOtherTypeInfoBlks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3022                                    sizeof(*pOtherTypeInfoBlks) *
3023                                    pTypeLibImpl->TypeInfoCount);
3024
3025
3026     ptr = (char*)pLibBlk + len;
3027
3028     for(i = 0; i < pTypeLibImpl->TypeInfoCount; i++) {
3029         WORD w, extra;
3030         len = 0;
3031
3032         pOtherTypeInfoBlks[i].small_no = *(WORD*)ptr;
3033
3034         w = *(WORD*)(ptr + 2);
3035         if(w != 0xffff) {
3036             len += w;
3037             pOtherTypeInfoBlks[i].index_name = HeapAlloc(GetProcessHeap(),0,
3038                                                          w+1);
3039             memcpy(pOtherTypeInfoBlks[i].index_name, ptr + 4, w);
3040             pOtherTypeInfoBlks[i].index_name[w] = '\0';
3041         }
3042         w = *(WORD*)(ptr + 4 + len);
3043         if(w != 0xffff) {
3044             TRACE("\twith %s\n", debugstr_an(ptr + 6 + len, w));
3045             len += w;
3046             pOtherTypeInfoBlks[i].other_name = HeapAlloc(GetProcessHeap(),0,
3047                                                          w+1);
3048             memcpy(pOtherTypeInfoBlks[i].other_name, ptr + 6 + len, w);
3049             pOtherTypeInfoBlks[i].other_name[w] = '\0';
3050         }
3051         pOtherTypeInfoBlks[i].res1a = *(WORD*)(ptr + len + 6);
3052         pOtherTypeInfoBlks[i].name_offs = *(WORD*)(ptr + len + 8);
3053         extra = pOtherTypeInfoBlks[i].more_bytes = *(WORD*)(ptr + 10 + len);
3054         if(extra) {
3055             pOtherTypeInfoBlks[i].extra = HeapAlloc(GetProcessHeap(),0,
3056                                                     extra);
3057             memcpy(pOtherTypeInfoBlks[i].extra, ptr + 12, extra);
3058             len += extra;
3059         }
3060         pOtherTypeInfoBlks[i].res20 = *(WORD*)(ptr + 12 + len);
3061         pOtherTypeInfoBlks[i].helpcontext = *(DWORD*)(ptr + 14 + len);
3062         pOtherTypeInfoBlks[i].res26 = *(WORD*)(ptr + 18 + len);
3063         memcpy(&pOtherTypeInfoBlks[i].uuid, ptr + 20 + len, sizeof(GUID));
3064         len += sizeof(SLTG_OtherTypeInfo);
3065         ptr += len;
3066     }
3067
3068     pAfterOTIBlks = ptr;
3069
3070     /* Skip this WORD and get the next DWORD */
3071     len = *(DWORD*)(pAfterOTIBlks + 2);
3072
3073     /* Now add this to pLibBLk look at what we're pointing at and
3074        possibly add 0x20, then add 0x216, sprinkle a bit a magic
3075        dust and we should be pointing at the beginning of the name
3076        table */
3077
3078     pNameTable = (char*)pLibBlk + len;
3079
3080    switch(*(WORD*)pNameTable) {
3081    case 0xffff:
3082        break;
3083    case 0x0200:
3084        pNameTable += 0x20;
3085        break;
3086    default:
3087        FIXME("pNameTable jump = %x\n", *(WORD*)pNameTable);
3088        break;
3089    }
3090
3091     pNameTable += 0x216;
3092
3093     pNameTable += 2;
3094
3095     TRACE("Library name is %s\n", pNameTable + pLibBlk->name);
3096
3097     pTypeLibImpl->Name = TLB_MultiByteToBSTR(pNameTable + pLibBlk->name);
3098
3099
3100     /* Hopefully we now have enough ptrs set up to actually read in
3101        some TypeInfos.  It's not clear which order to do them in, so
3102        I'll just follow the links along the BlkEntry chain and read
3103        them in in the order in which they're in the file */
3104
3105     ppTypeInfoImpl = &(pTypeLibImpl->pTypeInfo);
3106
3107     for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0;
3108         pBlkEntry[order].next != 0;
3109         order = pBlkEntry[order].next - 1, i++) {
3110
3111       SLTG_TypeInfoHeader *pTIHeader;
3112       SLTG_TypeInfoTail *pTITail;
3113
3114       if(strcmp(pBlkEntry[order].index_string + (char*)pMagic,
3115                 pOtherTypeInfoBlks[i].index_name)) {
3116         FIXME("Index strings don't match\n");
3117         return NULL;
3118       }
3119
3120       pTIHeader = pBlk;
3121       if(pTIHeader->magic != SLTG_TIHEADER_MAGIC) {
3122         FIXME("TypeInfoHeader magic = %04x\n", pTIHeader->magic);
3123         return NULL;
3124       }
3125       *ppTypeInfoImpl = (ITypeInfoImpl*)ITypeInfo_Constructor();
3126       (*ppTypeInfoImpl)->pTypeLib = pTypeLibImpl;
3127       (*ppTypeInfoImpl)->index = i;
3128       (*ppTypeInfoImpl)->Name = TLB_MultiByteToBSTR(
3129                                              pOtherTypeInfoBlks[i].name_offs +
3130                                              pNameTable);
3131       (*ppTypeInfoImpl)->dwHelpContext = pOtherTypeInfoBlks[i].helpcontext;
3132       memcpy(&((*ppTypeInfoImpl)->TypeAttr.guid), &pOtherTypeInfoBlks[i].uuid,
3133              sizeof(GUID));
3134       (*ppTypeInfoImpl)->TypeAttr.typekind = pTIHeader->typekind;
3135       (*ppTypeInfoImpl)->TypeAttr.wMajorVerNum = pTIHeader->major_version;
3136       (*ppTypeInfoImpl)->TypeAttr.wMinorVerNum = pTIHeader->minor_version;
3137       (*ppTypeInfoImpl)->TypeAttr.wTypeFlags =
3138         (pTIHeader->typeflags1 >> 3) | (pTIHeader->typeflags2 << 5);
3139
3140       if((pTIHeader->typeflags1 & 7) != 2)
3141         FIXME("typeflags1 = %02x\n", pTIHeader->typeflags1);
3142       if(pTIHeader->typeflags3 != 2)
3143         FIXME("typeflags3 = %02x\n", pTIHeader->typeflags3);
3144
3145       TRACE("TypeInfo %s of kind %s guid %s typeflags %04x\n",
3146             debugstr_w((*ppTypeInfoImpl)->Name),
3147             typekind_desc[pTIHeader->typekind],
3148             debugstr_guid(&(*ppTypeInfoImpl)->TypeAttr.guid),
3149             (*ppTypeInfoImpl)->TypeAttr.wTypeFlags);
3150
3151       switch(pTIHeader->typekind) {
3152       case TKIND_ENUM:
3153         pTITail = SLTG_ProcessEnum(pBlk, *ppTypeInfoImpl, pNameTable);
3154         break;
3155
3156       case TKIND_RECORD:
3157         pTITail = SLTG_ProcessRecord(pBlk, *ppTypeInfoImpl, pNameTable);
3158         break;
3159
3160       case TKIND_INTERFACE:
3161         pTITail = SLTG_ProcessInterface(pBlk, *ppTypeInfoImpl, pNameTable);
3162         break;
3163
3164       case TKIND_COCLASS:
3165         pTITail = SLTG_ProcessCoClass(pBlk, *ppTypeInfoImpl, pNameTable);
3166         break;
3167
3168       case TKIND_ALIAS:
3169         pTITail = SLTG_ProcessAlias(pBlk, *ppTypeInfoImpl, pNameTable);
3170         if (pTITail->tdescalias_vt)
3171           (*ppTypeInfoImpl)->TypeAttr.tdescAlias.vt = pTITail->tdescalias_vt;
3172         break;
3173
3174       case TKIND_DISPATCH:
3175         pTITail = SLTG_ProcessDispatch(pBlk, *ppTypeInfoImpl, pNameTable);
3176         break;
3177
3178       default:
3179         FIXME("Not processing typekind %d\n", pTIHeader->typekind);
3180         pTITail = NULL;
3181         break;
3182
3183       }
3184
3185       if(pTITail) { /* could get cFuncs, cVars and cImplTypes from here
3186                        but we've already set those */
3187           (*ppTypeInfoImpl)->TypeAttr.cbAlignment = pTITail->cbAlignment;
3188           (*ppTypeInfoImpl)->TypeAttr.cbSizeInstance = pTITail->cbSizeInstance;
3189           (*ppTypeInfoImpl)->TypeAttr.cbSizeVft = pTITail->cbSizeVft;
3190
3191 #define X(x) TRACE("tt "#x": %x\n",pTITail->res##x);
3192           X(06);
3193           X(08);
3194           X(0a);
3195           X(0c);
3196           X(0e);
3197           X(10);
3198           X(12);
3199           X(16);
3200           X(18);
3201           X(1a);
3202           X(1c);
3203           X(1e);
3204           X(24);
3205           X(26);
3206           X(2a);
3207           X(2c);
3208           X(2e);
3209           X(30);
3210           X(32);
3211           X(34);
3212       }
3213       ppTypeInfoImpl = &((*ppTypeInfoImpl)->next);
3214       pBlk = (char*)pBlk + pBlkEntry[order].len;
3215     }
3216
3217     if(i != pTypeLibImpl->TypeInfoCount) {
3218       FIXME("Somehow processed %d TypeInfos\n", i);
3219       return NULL;
3220     }
3221
3222     HeapFree(GetProcessHeap(), 0, pOtherTypeInfoBlks);
3223     return (ITypeLib2*)pTypeLibImpl;
3224 }
3225
3226 /* ITypeLib::QueryInterface
3227  */
3228 static HRESULT WINAPI ITypeLib2_fnQueryInterface(
3229         ITypeLib2 * iface,
3230         REFIID riid,
3231         VOID **ppvObject)
3232 {
3233     ICOM_THIS( ITypeLibImpl, iface);
3234
3235     TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
3236
3237     *ppvObject=NULL;
3238     if(IsEqualIID(riid, &IID_IUnknown) ||
3239        IsEqualIID(riid,&IID_ITypeLib)||
3240        IsEqualIID(riid,&IID_ITypeLib2))
3241     {
3242         *ppvObject = This;
3243     }
3244
3245     if(*ppvObject)
3246     {
3247         ITypeLib2_AddRef(iface);
3248         TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
3249         return S_OK;
3250     }
3251     TRACE("-- Interface: E_NOINTERFACE\n");
3252     return E_NOINTERFACE;
3253 }
3254
3255 /* ITypeLib::AddRef
3256  */
3257 static ULONG WINAPI ITypeLib2_fnAddRef( ITypeLib2 *iface)
3258 {
3259     ICOM_THIS( ITypeLibImpl, iface);
3260
3261     TRACE("(%p)->ref was %u\n",This, This->ref);
3262
3263     return ++(This->ref);
3264 }
3265
3266 /* ITypeLib::Release
3267  */
3268 static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface)
3269 {
3270     ICOM_THIS( ITypeLibImpl, iface);
3271
3272     --(This->ref);
3273
3274     TRACE("(%p)->(%u)\n",This, This->ref);
3275
3276     if (!This->ref)
3277     {
3278       /* remove cache entry */
3279       TRACE("removing from cache list\n");
3280       EnterCriticalSection(&cache_section);
3281       if (This->next) This->next->prev = This->prev;
3282       if (This->prev) This->prev->next = This->next;
3283       else tlb_cache_first = This->next;
3284       LeaveCriticalSection(&cache_section);
3285
3286       /* FIXME destroy child objects */
3287       TRACE(" destroying ITypeLib(%p)\n",This);
3288
3289       if (This->Name)
3290       {
3291           SysFreeString(This->Name);
3292           This->Name = NULL;
3293       }
3294
3295       if (This->DocString)
3296       {
3297           SysFreeString(This->DocString);
3298           This->DocString = NULL;
3299       }
3300
3301       if (This->HelpFile)
3302       {
3303           SysFreeString(This->HelpFile);
3304           This->HelpFile = NULL;
3305       }
3306
3307       if (This->HelpStringDll)
3308       {
3309           SysFreeString(This->HelpStringDll);
3310           This->HelpStringDll = NULL;
3311       }
3312
3313       if (This->pTypeInfo) /* can be NULL */
3314           ITypeInfo_Release((ITypeInfo*) This->pTypeInfo);
3315       HeapFree(GetProcessHeap(),0,This);
3316       return 0;
3317     }
3318
3319     return This->ref;
3320 }
3321
3322 /* ITypeLib::GetTypeInfoCount
3323  *
3324  * Returns the number of type descriptions in the type library
3325  */
3326 static UINT WINAPI ITypeLib2_fnGetTypeInfoCount( ITypeLib2 *iface)
3327 {
3328     ICOM_THIS( ITypeLibImpl, iface);
3329     TRACE("(%p)->count is %d\n",This, This->TypeInfoCount);
3330     return This->TypeInfoCount;
3331 }
3332
3333 /* ITypeLib::GetTypeInfo
3334  *
3335  * retrieves the specified type description in the library.
3336  */
3337 static HRESULT WINAPI ITypeLib2_fnGetTypeInfo(
3338     ITypeLib2 *iface,
3339     UINT index,
3340     ITypeInfo **ppTInfo)
3341 {
3342     int i;
3343
3344     ICOM_THIS( ITypeLibImpl, iface);
3345     ITypeInfoImpl *pTypeInfo = This->pTypeInfo;
3346
3347     TRACE("(%p)->(index=%d) \n", This, index);
3348
3349     if (!ppTInfo) return E_INVALIDARG;
3350
3351     /* search element n in list */
3352     for(i=0; i < index; i++)
3353     {
3354       pTypeInfo = pTypeInfo->next;
3355       if (!pTypeInfo)
3356       {
3357         TRACE("-- element not found\n");
3358         return TYPE_E_ELEMENTNOTFOUND;
3359       }
3360     }
3361
3362     *ppTInfo = (ITypeInfo *) pTypeInfo;
3363
3364     ITypeInfo_AddRef(*ppTInfo);
3365     TRACE("-- found (%p)\n",*ppTInfo);
3366     return S_OK;
3367 }
3368
3369
3370 /* ITypeLibs::GetTypeInfoType
3371  *
3372  * Retrieves the type of a type description.
3373  */
3374 static HRESULT WINAPI ITypeLib2_fnGetTypeInfoType(
3375     ITypeLib2 *iface,
3376     UINT index,
3377     TYPEKIND *pTKind)
3378 {
3379     ICOM_THIS( ITypeLibImpl, iface);
3380     int i;
3381     ITypeInfoImpl *pTInfo = This->pTypeInfo;
3382
3383     TRACE("(%p) index %d \n",This, index);
3384
3385     if(!pTKind) return E_INVALIDARG;
3386
3387     /* search element n in list */
3388     for(i=0; i < index; i++)
3389     {
3390       if(!pTInfo)
3391       {
3392         TRACE("-- element not found\n");
3393         return TYPE_E_ELEMENTNOTFOUND;
3394       }
3395       pTInfo = pTInfo->next;
3396     }
3397
3398     *pTKind = pTInfo->TypeAttr.typekind;
3399     TRACE("-- found Type (%d)\n", *pTKind);
3400     return S_OK;
3401 }
3402
3403 /* ITypeLib::GetTypeInfoOfGuid
3404  *
3405  * Retrieves the type description that corresponds to the specified GUID.
3406  *
3407  */
3408 static HRESULT WINAPI ITypeLib2_fnGetTypeInfoOfGuid(
3409     ITypeLib2 *iface,
3410     REFGUID guid,
3411     ITypeInfo **ppTInfo)
3412 {
3413     ICOM_THIS( ITypeLibImpl, iface);
3414     ITypeInfoImpl *pTypeInfo = This->pTypeInfo; /* head of list */
3415
3416     TRACE("(%p)\n\tguid:\t%s)\n",This,debugstr_guid(guid));
3417
3418     if (!pTypeInfo) return TYPE_E_ELEMENTNOTFOUND;
3419
3420     /* search linked list for guid */
3421     while( !IsEqualIID(guid,&pTypeInfo->TypeAttr.guid) )
3422     {
3423       pTypeInfo = pTypeInfo->next;
3424
3425       if (!pTypeInfo)
3426       {
3427         /* end of list reached */
3428         TRACE("-- element not found\n");
3429         return TYPE_E_ELEMENTNOTFOUND;
3430       }
3431     }
3432
3433     TRACE("-- found (%p, %s)\n",
3434           pTypeInfo,
3435           debugstr_w(pTypeInfo->Name));
3436
3437     *ppTInfo = (ITypeInfo*)pTypeInfo;
3438     ITypeInfo_AddRef(*ppTInfo);
3439     return S_OK;
3440 }
3441
3442 /* ITypeLib::GetLibAttr
3443  *
3444  * Retrieves the structure that contains the library's attributes.
3445  *
3446  */
3447 static HRESULT WINAPI ITypeLib2_fnGetLibAttr(
3448         ITypeLib2 *iface,
3449         LPTLIBATTR *ppTLibAttr)
3450 {
3451     ICOM_THIS( ITypeLibImpl, iface);
3452     TRACE("(%p)\n",This);
3453     *ppTLibAttr = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppTLibAttr));
3454     memcpy(*ppTLibAttr, &This->LibAttr, sizeof(**ppTLibAttr));
3455     return S_OK;
3456 }
3457
3458 /* ITypeLib::GetTypeComp
3459  *
3460  * Enables a client compiler to bind to a library's types, variables,
3461  * constants, and global functions.
3462  *
3463  */
3464 static HRESULT WINAPI ITypeLib2_fnGetTypeComp(
3465         ITypeLib2 *iface,
3466         ITypeComp **ppTComp)
3467 {
3468     ICOM_THIS( ITypeLibImpl, iface);
3469
3470     TRACE("(%p)->(%p)\n",This,ppTComp);
3471     *ppTComp = (ITypeComp *)&This->lpVtblTypeComp;
3472     ITypeComp_AddRef(*ppTComp);
3473
3474     return S_OK;
3475 }
3476
3477 /* ITypeLib::GetDocumentation
3478  *
3479  * Retrieves the library's documentation string, the complete Help file name
3480  * and path, and the context identifier for the library Help topic in the Help
3481  * file.
3482  *
3483  * On a successful return all non-null BSTR pointers will have been set,
3484  * possibly to NULL.
3485  */
3486 static HRESULT WINAPI ITypeLib2_fnGetDocumentation(
3487     ITypeLib2 *iface,
3488     INT index,
3489     BSTR *pBstrName,
3490     BSTR *pBstrDocString,
3491     DWORD *pdwHelpContext,
3492     BSTR *pBstrHelpFile)
3493 {
3494     ICOM_THIS( ITypeLibImpl, iface);
3495
3496     HRESULT result = E_INVALIDARG;
3497
3498     ITypeInfo *pTInfo;
3499
3500
3501     TRACE("(%p) index %d Name(%p) DocString(%p) HelpContext(%p) HelpFile(%p)\n",
3502         This, index,
3503         pBstrName, pBstrDocString,
3504         pdwHelpContext, pBstrHelpFile);
3505
3506     if(index<0)
3507     {
3508         /* documentation for the typelib */
3509         if(pBstrName)
3510         {
3511             if (This->Name)
3512                 if(!(*pBstrName = SysAllocString(This->Name))) goto memerr1;else;
3513             else
3514                 *pBstrName = NULL;
3515         }
3516         if(pBstrDocString)
3517         {
3518             if (This->DocString)
3519                 if(!(*pBstrDocString = SysAllocString(This->DocString))) goto memerr2;else;
3520             else if (This->Name)
3521                 if(!(*pBstrDocString = SysAllocString(This->Name))) goto memerr2;else;
3522             else
3523                 *pBstrDocString = NULL;
3524         }
3525         if(pdwHelpContext)
3526         {
3527             *pdwHelpContext = This->dwHelpContext;
3528         }
3529         if(pBstrHelpFile)
3530         {
3531             if (This->HelpFile)
3532                 if(!(*pBstrHelpFile = SysAllocString(This->HelpFile))) goto memerr3;else;
3533             else
3534                 *pBstrHelpFile = NULL;
3535         }
3536
3537         result = S_OK;
3538     }
3539     else
3540     {
3541         /* for a typeinfo */
3542         result = ITypeLib2_fnGetTypeInfo(iface, index, &pTInfo);
3543
3544         if(SUCCEEDED(result))
3545         {
3546             result = ITypeInfo_GetDocumentation(pTInfo,
3547                                           MEMBERID_NIL,
3548                                           pBstrName,
3549                                           pBstrDocString,
3550                                           pdwHelpContext, pBstrHelpFile);
3551
3552             ITypeInfo_Release(pTInfo);
3553         }
3554     }
3555     return result;
3556 memerr3:
3557     if (pBstrDocString) SysFreeString (*pBstrDocString);
3558 memerr2:
3559     if (pBstrName) SysFreeString (*pBstrName);
3560 memerr1:
3561     return STG_E_INSUFFICIENTMEMORY;
3562 }
3563
3564 /* ITypeLib::IsName
3565  *
3566  * Indicates whether a passed-in string contains the name of a type or member
3567  * described in the library.
3568  *
3569  */
3570 static HRESULT WINAPI ITypeLib2_fnIsName(
3571         ITypeLib2 *iface,
3572         LPOLESTR szNameBuf,
3573         ULONG lHashVal,
3574         BOOL *pfName)
3575 {
3576     ICOM_THIS( ITypeLibImpl, iface);
3577     ITypeInfoImpl *pTInfo;
3578     TLBFuncDesc *pFInfo;
3579     TLBVarDesc *pVInfo;
3580     int i;
3581     UINT nNameBufLen = SysStringLen(szNameBuf);
3582
3583     TRACE("(%p)->(%s,%08lx,%p)\n", This, debugstr_w(szNameBuf), lHashVal,
3584           pfName);
3585
3586     *pfName=TRUE;
3587     for(pTInfo=This->pTypeInfo;pTInfo;pTInfo=pTInfo->next){
3588         if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
3589         for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
3590             if(!memcmp(szNameBuf,pFInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
3591             for(i=0;i<pFInfo->funcdesc.cParams;i++)
3592                 if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name, nNameBufLen))
3593                     goto ITypeLib2_fnIsName_exit;
3594         }
3595         for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next)
3596             if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
3597
3598     }
3599     *pfName=FALSE;
3600
3601 ITypeLib2_fnIsName_exit:
3602     TRACE("(%p)slow! search for %s: %s found!\n", This,
3603           debugstr_w(szNameBuf), *pfName?"NOT":"");
3604
3605     return S_OK;
3606 }
3607
3608 /* ITypeLib::FindName
3609  *
3610  * Finds occurrences of a type description in a type library. This may be used
3611  * to quickly verify that a name exists in a type library.
3612  *
3613  */
3614 static HRESULT WINAPI ITypeLib2_fnFindName(
3615         ITypeLib2 *iface,
3616         LPOLESTR szNameBuf,
3617         ULONG lHashVal,
3618         ITypeInfo **ppTInfo,
3619         MEMBERID *rgMemId,
3620         UINT16 *pcFound)
3621 {
3622     ICOM_THIS( ITypeLibImpl, iface);
3623     ITypeInfoImpl *pTInfo;
3624     TLBFuncDesc *pFInfo;
3625     TLBVarDesc *pVInfo;
3626     int i,j = 0;
3627
3628     UINT nNameBufLen = SysStringLen(szNameBuf);
3629
3630     for(pTInfo=This->pTypeInfo;pTInfo && j<*pcFound; pTInfo=pTInfo->next){
3631         if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit;
3632         for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
3633             if(!memcmp(szNameBuf,pFInfo->Name,nNameBufLen)) goto ITypeLib2_fnFindName_exit;
3634             for(i=0;i<pFInfo->funcdesc.cParams;i++)
3635                 if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name,nNameBufLen))
3636                     goto ITypeLib2_fnFindName_exit;
3637         }
3638         for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next)
3639             if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit;
3640         continue;
3641 ITypeLib2_fnFindName_exit:
3642         ITypeInfo_AddRef((ITypeInfo*)pTInfo);
3643         ppTInfo[j]=(LPTYPEINFO)pTInfo;
3644         j++;
3645     }
3646     TRACE("(%p)slow! search for %d with %s: found %d TypeInfo's!\n",
3647           This, *pcFound, debugstr_w(szNameBuf), j);
3648
3649     *pcFound=j;
3650
3651     return S_OK;
3652 }
3653
3654 /* ITypeLib::ReleaseTLibAttr
3655  *
3656  * Releases the TLIBATTR originally obtained from ITypeLib::GetLibAttr.
3657  *
3658  */
3659 static VOID WINAPI ITypeLib2_fnReleaseTLibAttr(
3660         ITypeLib2 *iface,
3661         TLIBATTR *pTLibAttr)
3662 {
3663     ICOM_THIS( ITypeLibImpl, iface);
3664     TRACE("freeing (%p)\n",This);
3665     HeapFree(GetProcessHeap(),0,pTLibAttr);
3666
3667 }
3668
3669 /* ITypeLib2::GetCustData
3670  *
3671  * gets the custom data
3672  */
3673 static HRESULT WINAPI ITypeLib2_fnGetCustData(
3674         ITypeLib2 * iface,
3675         REFGUID guid,
3676         VARIANT *pVarVal)
3677 {
3678     ICOM_THIS( ITypeLibImpl, iface);
3679     TLBCustData *pCData;
3680
3681     for(pCData=This->pCustData; pCData; pCData = pCData->next)
3682     {
3683       if( IsEqualIID(guid, &pCData->guid)) break;
3684     }
3685
3686     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
3687
3688     if(pCData)
3689     {
3690         VariantInit( pVarVal);
3691         VariantCopy( pVarVal, &pCData->data);
3692         return S_OK;
3693     }
3694     return E_INVALIDARG;  /* FIXME: correct? */
3695 }
3696
3697 /* ITypeLib2::GetLibStatistics
3698  *
3699  * Returns statistics about a type library that are required for efficient
3700  * sizing of hash tables.
3701  *
3702  */
3703 static HRESULT WINAPI ITypeLib2_fnGetLibStatistics(
3704         ITypeLib2 * iface,
3705         ULONG *pcUniqueNames,
3706         ULONG *pcchUniqueNames)
3707 {
3708     ICOM_THIS( ITypeLibImpl, iface);
3709
3710     FIXME("(%p): stub!\n", This);
3711
3712     if(pcUniqueNames) *pcUniqueNames=1;
3713     if(pcchUniqueNames) *pcchUniqueNames=1;
3714     return S_OK;
3715 }
3716
3717 /* ITypeLib2::GetDocumentation2
3718  *
3719  * Retrieves the library's documentation string, the complete Help file name
3720  * and path, the localization context to use, and the context ID for the
3721  * library Help topic in the Help file.
3722  *
3723  */
3724 static HRESULT WINAPI ITypeLib2_fnGetDocumentation2(
3725         ITypeLib2 * iface,
3726         INT index,
3727         LCID lcid,
3728         BSTR *pbstrHelpString,
3729         DWORD *pdwHelpStringContext,
3730         BSTR *pbstrHelpStringDll)
3731 {
3732     ICOM_THIS( ITypeLibImpl, iface);
3733     HRESULT result;
3734     ITypeInfo *pTInfo;
3735
3736     FIXME("(%p) index %d lcid %ld half implemented stub!\n", This, index, lcid);
3737
3738     /* the help string should be obtained from the helpstringdll,
3739      * using the _DLLGetDocumentation function, based on the supplied
3740      * lcid. Nice to do sometime...
3741      */
3742     if(index<0)
3743     {
3744       /* documentation for the typelib */
3745       if(pbstrHelpString)
3746         *pbstrHelpString=SysAllocString(This->DocString);
3747       if(pdwHelpStringContext)
3748         *pdwHelpStringContext=This->dwHelpContext;
3749       if(pbstrHelpStringDll)
3750         *pbstrHelpStringDll=SysAllocString(This->HelpStringDll);
3751
3752       result = S_OK;
3753     }
3754     else
3755     {
3756       /* for a typeinfo */
3757       result=ITypeLib2_GetTypeInfo(iface, index, &pTInfo);
3758
3759       if(SUCCEEDED(result))
3760       {
3761         ITypeInfo2 * pTInfo2;
3762         result = ITypeInfo_QueryInterface(pTInfo,
3763                                           &IID_ITypeInfo2,
3764                                           (LPVOID*) &pTInfo2);
3765
3766         if(SUCCEEDED(result))
3767         {
3768           result = ITypeInfo2_GetDocumentation2(pTInfo2,
3769                                            MEMBERID_NIL,
3770                                            lcid,
3771                                            pbstrHelpString,
3772                                            pdwHelpStringContext,
3773                                            pbstrHelpStringDll);
3774
3775           ITypeInfo2_Release(pTInfo2);
3776         }
3777
3778         ITypeInfo_Release(pTInfo);
3779       }
3780     }
3781     return result;
3782 }
3783
3784 /* ITypeLib2::GetAllCustData
3785  *
3786  * Gets all custom data items for the library.
3787  *
3788  */
3789 static HRESULT WINAPI ITypeLib2_fnGetAllCustData(
3790         ITypeLib2 * iface,
3791         CUSTDATA *pCustData)
3792 {
3793     ICOM_THIS( ITypeLibImpl, iface);
3794     TLBCustData *pCData;
3795     int i;
3796     TRACE("(%p) returning %d items\n", This, This->ctCustData);
3797     pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
3798     if(pCustData->prgCustData ){
3799         pCustData->cCustData=This->ctCustData;
3800         for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
3801             pCustData->prgCustData[i].guid=pCData->guid;
3802             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
3803         }
3804     }else{
3805         ERR(" OUT OF MEMORY! \n");
3806         return E_OUTOFMEMORY;
3807     }
3808     return S_OK;
3809 }
3810
3811 static ICOM_VTABLE(ITypeLib2) tlbvt = {
3812     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3813     ITypeLib2_fnQueryInterface,
3814     ITypeLib2_fnAddRef,
3815     ITypeLib2_fnRelease,
3816     ITypeLib2_fnGetTypeInfoCount,
3817     ITypeLib2_fnGetTypeInfo,
3818     ITypeLib2_fnGetTypeInfoType,
3819     ITypeLib2_fnGetTypeInfoOfGuid,
3820     ITypeLib2_fnGetLibAttr,
3821     ITypeLib2_fnGetTypeComp,
3822     ITypeLib2_fnGetDocumentation,
3823     ITypeLib2_fnIsName,
3824     ITypeLib2_fnFindName,
3825     ITypeLib2_fnReleaseTLibAttr,
3826
3827     ITypeLib2_fnGetCustData,
3828     ITypeLib2_fnGetLibStatistics,
3829     ITypeLib2_fnGetDocumentation2,
3830     ITypeLib2_fnGetAllCustData
3831  };
3832
3833
3834 static HRESULT WINAPI ITypeLibComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
3835 {
3836     ICOM_THIS_From_ITypeComp(ITypeLibImpl, iface);
3837
3838     return ITypeInfo_QueryInterface((ITypeInfo *)This, riid, ppv);
3839 }
3840
3841 static ULONG WINAPI ITypeLibComp_fnAddRef(ITypeComp * iface)
3842 {
3843     ICOM_THIS_From_ITypeComp(ITypeLibImpl, iface);
3844
3845     return ITypeInfo_AddRef((ITypeInfo *)This);
3846 }
3847
3848 static ULONG WINAPI ITypeLibComp_fnRelease(ITypeComp * iface)
3849 {
3850     ICOM_THIS_From_ITypeComp(ITypeLibImpl, iface);
3851
3852     return ITypeInfo_Release((ITypeInfo *)This);
3853 }
3854
3855 static HRESULT WINAPI ITypeLibComp_fnBind(
3856     ITypeComp * iface,
3857     OLECHAR * szName,
3858     unsigned long lHash,
3859     unsigned short wFlags,
3860     ITypeInfo ** ppTInfo,
3861     DESCKIND * pDescKind,
3862     BINDPTR * pBindPtr)
3863 {
3864     FIXME("(%s, %lx, 0x%x, %p, %p, %p): stub\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
3865     return E_NOTIMPL;
3866 }
3867
3868 static HRESULT WINAPI ITypeLibComp_fnBindType(
3869     ITypeComp * iface,
3870     OLECHAR * szName,
3871     unsigned long lHash,
3872     ITypeInfo ** ppTInfo,
3873     ITypeComp ** ppTComp)
3874 {
3875     FIXME("(%s, %lx, %p, %p): stub\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
3876     return E_NOTIMPL;
3877 }
3878
3879 static ICOM_VTABLE(ITypeComp) tlbtcvt =
3880 {
3881     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3882
3883     ITypeLibComp_fnQueryInterface,
3884     ITypeLibComp_fnAddRef,
3885     ITypeLibComp_fnRelease,
3886
3887     ITypeLibComp_fnBind,
3888     ITypeLibComp_fnBindType
3889 };
3890
3891 /*================== ITypeInfo(2) Methods ===================================*/
3892 static ITypeInfo2 * WINAPI ITypeInfo_Constructor(void)
3893 {
3894     ITypeInfoImpl * pTypeInfoImpl;
3895
3896     pTypeInfoImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeInfoImpl));
3897     if (pTypeInfoImpl)
3898     {
3899       pTypeInfoImpl->lpVtbl = &tinfvt;
3900       pTypeInfoImpl->lpVtblTypeComp = &tcompvt;
3901       pTypeInfoImpl->ref=1;
3902     }
3903     TRACE("(%p)\n", pTypeInfoImpl);
3904     return (ITypeInfo2*) pTypeInfoImpl;
3905 }
3906
3907 /* ITypeInfo::QueryInterface
3908  */
3909 static HRESULT WINAPI ITypeInfo_fnQueryInterface(
3910         ITypeInfo2 *iface,
3911         REFIID riid,
3912         VOID **ppvObject)
3913 {
3914     ICOM_THIS( ITypeLibImpl, iface);
3915
3916     TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
3917
3918     *ppvObject=NULL;
3919     if(IsEqualIID(riid, &IID_IUnknown) ||
3920             IsEqualIID(riid,&IID_ITypeInfo)||
3921             IsEqualIID(riid,&IID_ITypeInfo2))
3922         *ppvObject = This;
3923
3924     if(*ppvObject){
3925         ITypeInfo_AddRef(iface);
3926         TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
3927         return S_OK;
3928     }
3929     TRACE("-- Interface: E_NOINTERFACE\n");
3930     return E_NOINTERFACE;
3931 }
3932
3933 /* ITypeInfo::AddRef
3934  */
3935 static ULONG WINAPI ITypeInfo_fnAddRef( ITypeInfo2 *iface)
3936 {
3937     ICOM_THIS( ITypeInfoImpl, iface);
3938
3939     ++(This->ref);
3940
3941     TRACE("(%p)->ref is %u\n",This, This->ref);
3942     return This->ref;
3943 }
3944
3945 /* ITypeInfo::Release
3946  */
3947 static ULONG WINAPI ITypeInfo_fnRelease( ITypeInfo2 *iface)
3948 {
3949     ICOM_THIS( ITypeInfoImpl, iface);
3950
3951     --(This->ref);
3952
3953     TRACE("(%p)->(%u)\n",This, This->ref);
3954
3955     if (!This->ref)
3956     {
3957       FIXME("destroy child objects\n");
3958
3959       TRACE("destroying ITypeInfo(%p)\n",This);
3960       if (This->Name)
3961       {
3962           SysFreeString(This->Name);
3963           This->Name = 0;
3964       }
3965
3966       if (This->DocString)
3967       {
3968           SysFreeString(This->DocString);
3969           This->DocString = 0;
3970       }
3971
3972       if (This->next)
3973       {
3974         ITypeInfo_Release((ITypeInfo*)This->next);
3975       }
3976
3977       HeapFree(GetProcessHeap(),0,This);
3978       return 0;
3979     }
3980     return This->ref;
3981 }
3982
3983 /* ITypeInfo::GetTypeAttr
3984  *
3985  * Retrieves a TYPEATTR structure that contains the attributes of the type
3986  * description.
3987  *
3988  */
3989 static HRESULT WINAPI ITypeInfo_fnGetTypeAttr( ITypeInfo2 *iface,
3990         LPTYPEATTR  *ppTypeAttr)
3991 {
3992     ICOM_THIS( ITypeInfoImpl, iface);
3993     TRACE("(%p)\n",This);
3994     /* FIXME: must do a copy here */
3995     *ppTypeAttr=&This->TypeAttr;
3996     return S_OK;
3997 }
3998
3999 /* ITypeInfo::GetTypeComp
4000  *
4001  * Retrieves the ITypeComp interface for the type description, which enables a
4002  * client compiler to bind to the type description's members.
4003  *
4004  */
4005 static HRESULT WINAPI ITypeInfo_fnGetTypeComp( ITypeInfo2 *iface,
4006         ITypeComp  * *ppTComp)
4007 {
4008     ICOM_THIS( ITypeInfoImpl, iface);
4009
4010     TRACE("(%p)->(%p) stub!\n", This, ppTComp);
4011
4012     *ppTComp = (ITypeComp *)&This->lpVtblTypeComp;
4013     ITypeComp_AddRef(*ppTComp);
4014     return S_OK;
4015 }
4016
4017 /* ITypeInfo::GetFuncDesc
4018  *
4019  * Retrieves the FUNCDESC structure that contains information about a
4020  * specified function.
4021  *
4022  */
4023 static HRESULT WINAPI ITypeInfo_fnGetFuncDesc( ITypeInfo2 *iface, UINT index,
4024         LPFUNCDESC  *ppFuncDesc)
4025 {
4026     ICOM_THIS( ITypeInfoImpl, iface);
4027     int i;
4028     TLBFuncDesc * pFDesc;
4029     TRACE("(%p) index %d\n", This, index);
4030     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++, pFDesc=pFDesc->next)
4031         ;
4032     if(pFDesc){
4033         /* FIXME: must do a copy here */
4034         *ppFuncDesc=&pFDesc->funcdesc;
4035         return S_OK;
4036     }
4037     return E_INVALIDARG;
4038 }
4039
4040 /* ITypeInfo::GetVarDesc
4041  *
4042  * Retrieves a VARDESC structure that describes the specified variable.
4043  *
4044  */
4045 static HRESULT WINAPI ITypeInfo_fnGetVarDesc( ITypeInfo2 *iface, UINT index,
4046         LPVARDESC  *ppVarDesc)
4047 {
4048     ICOM_THIS( ITypeInfoImpl, iface);
4049     int i;
4050     TLBVarDesc * pVDesc;
4051     TRACE("(%p) index %d\n", This, index);
4052     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next)
4053         ;
4054     if(pVDesc){
4055         /* FIXME: must do a copy here */
4056         *ppVarDesc=&pVDesc->vardesc;
4057         return S_OK;
4058     }
4059     return E_INVALIDARG;
4060 }
4061
4062 /* ITypeInfo_GetNames
4063  *
4064  * Retrieves the variable with the specified member ID (or the name of the
4065  * property or method and its parameters) that correspond to the specified
4066  * function ID.
4067  */
4068 static HRESULT WINAPI ITypeInfo_fnGetNames( ITypeInfo2 *iface, MEMBERID memid,
4069         BSTR  *rgBstrNames, UINT cMaxNames, UINT  *pcNames)
4070 {
4071     ICOM_THIS( ITypeInfoImpl, iface);
4072     TLBFuncDesc * pFDesc;
4073     TLBVarDesc * pVDesc;
4074     int i;
4075     TRACE("(%p) memid=0x%08lx Maxname=%d\n", This, memid, cMaxNames);
4076     for(pFDesc=This->funclist; pFDesc && pFDesc->funcdesc.memid != memid; pFDesc=pFDesc->next);
4077     if(pFDesc)
4078     {
4079       /* function found, now return function and parameter names */
4080       for(i=0; i<cMaxNames && i <= pFDesc->funcdesc.cParams; i++)
4081       {
4082         if(!i)
4083           *rgBstrNames=SysAllocString(pFDesc->Name);
4084         else
4085           rgBstrNames[i]=SysAllocString(pFDesc->pParamDesc[i-1].Name);
4086       }
4087       *pcNames=i;
4088     }
4089     else
4090     {
4091       for(pVDesc=This->varlist; pVDesc && pVDesc->vardesc.memid != memid; pVDesc=pVDesc->next);
4092       if(pVDesc)
4093       {
4094         *rgBstrNames=SysAllocString(pVDesc->Name);
4095         *pcNames=1;
4096       }
4097       else
4098       {
4099         if(This->TypeAttr.typekind==TKIND_INTERFACE && This->TypeAttr.cImplTypes )
4100         {
4101           /* recursive search */
4102           ITypeInfo *pTInfo;
4103           HRESULT result;
4104           result=ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef,
4105                                           &pTInfo);
4106           if(SUCCEEDED(result))
4107           {
4108             result=ITypeInfo_GetNames(pTInfo, memid, rgBstrNames, cMaxNames, pcNames);
4109             ITypeInfo_Release(pTInfo);
4110             return result;
4111           }
4112           WARN("Could not search inherited interface!\n");
4113         }
4114         else
4115         {
4116           WARN("no names found\n");
4117         }
4118         *pcNames=0;
4119         return TYPE_E_ELEMENTNOTFOUND;
4120       }
4121     }
4122     return S_OK;
4123 }
4124
4125
4126 /* ITypeInfo::GetRefTypeOfImplType
4127  *
4128  * If a type description describes a COM class, it retrieves the type
4129  * description of the implemented interface types. For an interface,
4130  * GetRefTypeOfImplType returns the type information for inherited interfaces,
4131  * if any exist.
4132  *
4133  */
4134 static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType(
4135         ITypeInfo2 *iface,
4136         UINT index,
4137         HREFTYPE  *pRefType)
4138 {
4139     ICOM_THIS( ITypeInfoImpl, iface);
4140     int(i);
4141     TLBImplType *pImpl = This->impltypelist;
4142
4143     TRACE("(%p) index %d\n", This, index);
4144     if (TRACE_ON(ole)) dump_TypeInfo(This);
4145
4146     if(index==(UINT)-1)
4147     {
4148       /* only valid on dual interfaces;
4149          retrieve the associated TKIND_INTERFACE handle for the current TKIND_DISPATCH
4150       */
4151       if( This->TypeAttr.typekind != TKIND_DISPATCH) return E_INVALIDARG;
4152
4153       if (This->TypeAttr.wTypeFlags & TYPEFLAG_FDISPATCHABLE &&
4154           This->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL )
4155       {
4156         *pRefType = -1;
4157       }
4158       else
4159       {
4160         if (!pImpl) return TYPE_E_ELEMENTNOTFOUND;
4161         *pRefType = pImpl->hRef;
4162       }
4163     }
4164     else
4165     {
4166       /* get element n from linked list */
4167       for(i=0; pImpl && i<index; i++)
4168       {
4169         pImpl = pImpl->next;
4170       }
4171
4172       if (!pImpl) return TYPE_E_ELEMENTNOTFOUND;
4173
4174       *pRefType = pImpl->hRef;
4175
4176       TRACE("-- 0x%08lx\n", pImpl->hRef );
4177     }
4178
4179     return S_OK;
4180
4181 }
4182
4183 /* ITypeInfo::GetImplTypeFlags
4184  *
4185  * Retrieves the IMPLTYPEFLAGS enumeration for one implemented interface
4186  * or base interface in a type description.
4187  */
4188 static HRESULT WINAPI ITypeInfo_fnGetImplTypeFlags( ITypeInfo2 *iface,
4189         UINT index, INT  *pImplTypeFlags)
4190 {
4191     ICOM_THIS( ITypeInfoImpl, iface);
4192     int i;
4193     TLBImplType *pImpl;
4194
4195     TRACE("(%p) index %d\n", This, index);
4196     for(i=0, pImpl=This->impltypelist; i<index && pImpl;
4197         i++, pImpl=pImpl->next)
4198         ;
4199     if(i==index && pImpl){
4200         *pImplTypeFlags=pImpl->implflags;
4201         return S_OK;
4202     }
4203     *pImplTypeFlags=0;
4204     return TYPE_E_ELEMENTNOTFOUND;
4205 }
4206
4207 /* GetIDsOfNames
4208  * Maps between member names and member IDs, and parameter names and
4209  * parameter IDs.
4210  */
4211 static HRESULT WINAPI ITypeInfo_fnGetIDsOfNames( ITypeInfo2 *iface,
4212         LPOLESTR  *rgszNames, UINT cNames, MEMBERID  *pMemId)
4213 {
4214     ICOM_THIS( ITypeInfoImpl, iface);
4215     TLBFuncDesc * pFDesc;
4216     TLBVarDesc * pVDesc;
4217     HRESULT ret=S_OK;
4218
4219     TRACE("(%p) Name %s cNames %d\n", This, debugstr_w(*rgszNames),
4220             cNames);
4221     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next) {
4222         int i, j;
4223         if(!lstrcmpiW(*rgszNames, pFDesc->Name)) {
4224             if(cNames) *pMemId=pFDesc->funcdesc.memid;
4225             for(i=1; i < cNames; i++){
4226                 for(j=0; j<pFDesc->funcdesc.cParams; j++)
4227                     if(!lstrcmpiW(rgszNames[i],pFDesc->pParamDesc[j].Name))
4228                             break;
4229                 if( j<pFDesc->funcdesc.cParams)
4230                     pMemId[i]=j;
4231                 else
4232                    ret=DISP_E_UNKNOWNNAME;
4233             };
4234             return ret;
4235         }
4236     }
4237     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) {
4238         if(!lstrcmpiW(*rgszNames, pVDesc->Name)) {
4239             if(cNames) *pMemId=pVDesc->vardesc.memid;
4240             return ret;
4241         }
4242     }
4243     /* not found, see if this is and interface with an inheritance */
4244     if(This->TypeAttr.typekind==TKIND_INTERFACE &&
4245             This->TypeAttr.cImplTypes ){
4246         /* recursive search */
4247         ITypeInfo *pTInfo;
4248         ret=ITypeInfo_GetRefTypeInfo(iface,
4249                 This->impltypelist->hRef, &pTInfo);
4250         if(SUCCEEDED(ret)){
4251             ret=ITypeInfo_GetIDsOfNames(pTInfo, rgszNames, cNames, pMemId );
4252             ITypeInfo_Release(pTInfo);
4253             return ret;
4254         }
4255         WARN("Could not search inherited interface!\n");
4256     } else
4257         WARN("no names found\n");
4258     return DISP_E_UNKNOWNNAME;
4259 }
4260
4261 /* ITypeInfo::Invoke
4262  *
4263  * Invokes a method, or accesses a property of an object, that implements the
4264  * interface described by the type description.
4265  */
4266 DWORD
4267 _invoke(FARPROC func,CALLCONV callconv, int nrargs, DWORD *args) {
4268     DWORD res;
4269
4270     if (TRACE_ON(ole)) {
4271         int i;
4272         TRACE("Calling %p(",func);
4273         for (i=0;i<nrargs;i++) TRACE("%08lx,",args[i]);
4274         TRACE(")\n");
4275     }
4276
4277     switch (callconv) {
4278     case CC_STDCALL:
4279
4280         switch (nrargs) {
4281         case 0:
4282                 res = func();
4283                 break;
4284         case 1:
4285                 res = func(args[0]);
4286                 break;
4287         case 2:
4288                 res = func(args[0],args[1]);
4289                 break;
4290         case 3:
4291                 res = func(args[0],args[1],args[2]);
4292                 break;
4293         case 4:
4294                 res = func(args[0],args[1],args[2],args[3]);
4295                 break;
4296         case 5:
4297                 res = func(args[0],args[1],args[2],args[3],args[4]);
4298                 break;
4299         case 6:
4300                 res = func(args[0],args[1],args[2],args[3],args[4],args[5]);
4301                 break;
4302         case 7:
4303                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
4304                 break;
4305         case 8:
4306                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]);
4307                 break;
4308         case 9:
4309                 res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]);
4310                 break;
4311         default:
4312                 FIXME("unsupported number of arguments %d in stdcall\n",nrargs);
4313                 res = -1;
4314                 break;
4315         }
4316         break;
4317     default:
4318         FIXME("unsupported calling convention %d\n",callconv);
4319         res = -1;
4320         break;
4321     }
4322     TRACE("returns %08lx\n",res);
4323     return res;
4324 }
4325
4326 extern int const _argsize(DWORD vt);
4327
4328 /****************************************************************************
4329  * Helper functions for Dispcall / Invoke, which copies one variant
4330  * with target type onto the argument stack.
4331  */
4332 static HRESULT
4333 _copy_arg(      ITypeInfo2 *tinfo, TYPEDESC *tdesc,
4334                 DWORD *argpos, VARIANT *arg, VARTYPE vt
4335 ) {
4336     UINT arglen = _argsize(vt)*sizeof(DWORD);
4337     VARTYPE     oldvt;
4338     VARIANT     va;
4339
4340     if ((vt==VT_PTR) && tdesc && (tdesc->u.lptdesc->vt == VT_VARIANT)) {
4341         memcpy(argpos,&arg,sizeof(void*));
4342         return S_OK;
4343     }
4344
4345     if (V_VT(arg) == vt) {
4346         memcpy(argpos, &V_UNION(arg,lVal), arglen);
4347         return S_OK;
4348     }
4349
4350     if (V_ISARRAY(arg) && (vt == VT_SAFEARRAY)) {
4351         memcpy(argpos, &V_UNION(arg,parray), sizeof(SAFEARRAY*));
4352         return S_OK;
4353     }
4354
4355     if (vt == VT_VARIANT) {
4356         memcpy(argpos, arg, arglen);
4357         return S_OK;
4358     }
4359     /* Deref BYREF vars if there is need */
4360     if(V_ISBYREF(arg) && ((V_VT(arg) & ~VT_BYREF)==vt)) {
4361         memcpy(argpos,(void*)V_UNION(arg,lVal), arglen);
4362         return S_OK;
4363     }
4364     if (vt==VT_UNKNOWN && V_VT(arg)==VT_DISPATCH) {
4365         /* in this context, if the type lib specifies IUnknown*, giving an IDispatch* is correct; so, don't invoke VariantChangeType */
4366         memcpy(argpos,&V_UNION(arg,lVal), arglen);
4367         return S_OK;
4368     }
4369     if ((vt == VT_PTR) && tdesc)
4370         return _copy_arg(tinfo, tdesc->u.lptdesc, argpos, arg, tdesc->u.lptdesc->vt);
4371
4372     if ((vt == VT_USERDEFINED) && tdesc && tinfo) {
4373         ITypeInfo       *tinfo2;
4374         TYPEATTR        *tattr;
4375         HRESULT         hres;
4376
4377         hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
4378         if (hres) {
4379             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));
4380             memcpy(argpos, &V_UNION(arg,lVal), 4);
4381             return S_OK;
4382         }
4383         ITypeInfo_GetTypeAttr(tinfo2,&tattr);
4384         switch (tattr->typekind) {
4385         case TKIND_ENUM:
4386           switch ( V_VT( arg ) ) {
4387           case VT_I2:
4388              *argpos = V_UNION(arg,iVal);
4389              return S_OK;
4390           case VT_I4:
4391              memcpy(argpos, &V_UNION(arg,lVal), 4);
4392              return S_OK;
4393           default:
4394              FIXME("vt 0x%x -> TKIND_ENUM unhandled.\n",V_VT(arg));
4395              break;
4396           }
4397
4398         case TKIND_ALIAS:
4399             tdesc = &(tattr->tdescAlias);
4400             hres = _copy_arg((ITypeInfo2*)tinfo2, tdesc, argpos, arg, tdesc->vt);
4401             ITypeInfo_Release(tinfo2);
4402             return hres;
4403
4404         case TKIND_INTERFACE:
4405             if (V_VT(arg) == VT_DISPATCH) {
4406                 IDispatch *disp;
4407                 if (IsEqualIID(&IID_IDispatch,&(tattr->guid))) {
4408                     memcpy(argpos, &V_UNION(arg,pdispVal), 4);
4409                     return S_OK;
4410                 }
4411                 hres=IUnknown_QueryInterface(V_UNION(arg,pdispVal),&IID_IDispatch,(LPVOID*)&disp);
4412                 if (SUCCEEDED(hres)) {
4413                     memcpy(argpos,&disp,4);
4414                     IUnknown_Release(V_UNION(arg,pdispVal));
4415                     return S_OK;
4416                 }
4417                 FIXME("Failed to query IDispatch interface from %s while converting to VT_DISPATCH!\n",debugstr_guid(&(tattr->guid)));
4418                 return E_FAIL;
4419             }
4420             if (V_VT(arg) == VT_UNKNOWN) {
4421                 memcpy(argpos, &V_UNION(arg,punkVal), 4);
4422                 return S_OK;
4423             }
4424             FIXME("vt 0x%x -> TKIND_INTERFACE(%s) unhandled\n",V_VT(arg),debugstr_guid(&(tattr->guid)));
4425             break;
4426         case TKIND_DISPATCH:
4427             if (V_VT(arg) == VT_DISPATCH) {
4428                 memcpy(argpos, &V_UNION(arg,pdispVal), 4);
4429                 return S_OK;
4430             }
4431             FIXME("TKIND_DISPATCH unhandled for target vt 0x%x.\n",V_VT(arg));
4432             break;
4433         case TKIND_RECORD:
4434             FIXME("TKIND_RECORD unhandled.\n");
4435             break;
4436         default:
4437             FIXME("TKIND %d unhandled.\n",tattr->typekind);
4438             break;
4439         }
4440         return E_FAIL;
4441     }
4442
4443     oldvt = V_VT(arg);
4444     VariantInit(&va);
4445     if (VariantChangeType(&va,arg,0,vt)==S_OK) {
4446         memcpy(argpos,&V_UNION(&va,lVal), arglen);
4447         FIXME("Should not use VariantChangeType here. (conversion from 0x%x -> 0x%x)\n",
4448                 V_VT(arg), vt
4449         );
4450         return S_OK;
4451     }
4452     ERR("Set arg to disparg type 0x%x vs 0x%x\n",V_VT(arg),vt);
4453     return E_FAIL;
4454 }
4455
4456 /***********************************************************************
4457  *              DispCallFunc (OLEAUT32.@)
4458  */
4459 HRESULT WINAPI
4460 DispCallFunc(
4461     void* pvInstance, ULONG oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals,
4462     VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult
4463 ) {
4464     int i, argsize, argspos;
4465     DWORD *args;
4466     HRESULT hres;
4467
4468     TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
4469         pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg, pvargResult, V_VT(pvargResult)
4470     );
4471     /* DispCallFunc is only used to invoke methods belonging to an IDispatch-derived COM interface.
4472     So we need to add a first parameter to the list of arguments, to supply the interface pointer */
4473     argsize = 1;
4474     for (i=0;i<cActuals;i++) {
4475         TRACE("arg %d: type %d, size %d\n",i,prgvt[i],_argsize(prgvt[i]));
4476         dump_Variant(prgpvarg[i]);
4477         argsize += _argsize(prgvt[i]);
4478     }
4479     args = (DWORD*)HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*argsize);
4480     args[0] = (DWORD)pvInstance;      /* this is the fake IDispatch interface pointer */
4481     argspos = 1;
4482     for (i=0;i<cActuals;i++) {
4483         VARIANT *arg = prgpvarg[i];
4484         TRACE("Storing arg %d (%d as %d)\n",i,V_VT(arg),prgvt[i]);
4485         _copy_arg(NULL, NULL, &args[argspos], arg, prgvt[i]);
4486         argspos += _argsize(prgvt[i]);
4487     }
4488
4489     if(pvargResult!=NULL && V_VT(pvargResult)==VT_EMPTY)
4490     {
4491         _invoke((*(FARPROC**)pvInstance)[oVft/4],cc,argsize,args);
4492         hres=S_OK;
4493     }
4494     else
4495     {
4496         FIXME("Do not know how to handle pvargResult %p. Expect crash ...\n",pvargResult);
4497         hres = _invoke((*(FARPROC**)pvInstance)[oVft/4],cc,argsize,args);
4498         FIXME("Method returned %lx\n",hres);
4499     }
4500     HeapFree(GetProcessHeap(),0,args);
4501     return hres;
4502 }
4503
4504 static HRESULT WINAPI ITypeInfo_fnInvoke(
4505     ITypeInfo2 *iface,
4506     VOID  *pIUnk,
4507     MEMBERID memid,
4508     UINT16 dwFlags,
4509     DISPPARAMS  *pDispParams,
4510     VARIANT  *pVarResult,
4511     EXCEPINFO  *pExcepInfo,
4512     UINT  *pArgErr)
4513 {
4514     ICOM_THIS( ITypeInfoImpl, iface);
4515     TLBFuncDesc * pFDesc;
4516     TLBVarDesc * pVDesc;
4517     int i;
4518     HRESULT hres;
4519
4520     TRACE("(%p)(%p,id=%ld,flags=0x%08x,%p,%p,%p,%p) partial stub!\n",
4521       This,pIUnk,memid,dwFlags,pDispParams,pVarResult,pExcepInfo,pArgErr
4522     );
4523     dump_DispParms(pDispParams);
4524
4525     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
4526         if (pFDesc->funcdesc.memid == memid) {
4527             if (pFDesc->funcdesc.invkind & dwFlags)
4528                 break;
4529         }
4530     
4531     if (pFDesc) {
4532         if (TRACE_ON(typelib)) dump_TLBFuncDescOne(pFDesc);
4533         /* dump_FUNCDESC(&pFDesc->funcdesc);*/
4534         switch (pFDesc->funcdesc.funckind) {
4535         case FUNC_PUREVIRTUAL:
4536         case FUNC_VIRTUAL: {
4537             DWORD res;
4538             int   numargs, numargs2, argspos, args2pos;
4539             DWORD *args , *args2;
4540
4541
4542             numargs = 1; numargs2 = 0;
4543             for (i=0;i<pFDesc->funcdesc.cParams;i++) {
4544                 if (i<pDispParams->cArgs)
4545                     numargs += _argsize(pFDesc->funcdesc.lprgelemdescParam[i].tdesc.vt);
4546                 else {
4547                     numargs     += 1; /* sizeof(lpvoid) */
4548                     numargs2    += _argsize(pFDesc->funcdesc.lprgelemdescParam[i].tdesc.vt);
4549                 }
4550             }
4551
4552             args = (DWORD*)HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*numargs);
4553             args2 = (DWORD*)HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*numargs2);
4554
4555             args[0] = (DWORD)pIUnk;
4556             argspos = 1; args2pos = 0;
4557             for (i=0;i<pFDesc->funcdesc.cParams;i++) {
4558                 int arglen = _argsize(pFDesc->funcdesc.lprgelemdescParam[i].tdesc.vt);
4559                 if (i<pDispParams->cArgs) {
4560                     VARIANT *arg = &pDispParams->rgvarg[pDispParams->cArgs-i-1];
4561                     TYPEDESC *tdesc = &pFDesc->funcdesc.lprgelemdescParam[i].tdesc;
4562                     hres = _copy_arg(iface, tdesc, &args[argspos], arg, tdesc->vt);
4563                     if (FAILED(hres)) return hres;
4564                     argspos += arglen;
4565                 } else {
4566                     TYPEDESC *tdesc = &(pFDesc->funcdesc.lprgelemdescParam[i].tdesc);
4567                     if (tdesc->vt != VT_PTR)
4568                         FIXME("set %d to pointer for get (type is %d)\n",i,tdesc->vt);
4569                     /*FIXME: give pointers for the rest, so propertyget works*/
4570                     args[argspos] = (DWORD)&args2[args2pos];
4571
4572                     /* If pointer to variant, pass reference it. */
4573                     if ((tdesc->vt == VT_PTR) &&
4574                         (tdesc->u.lptdesc->vt == VT_VARIANT) &&
4575                         pVarResult
4576                     )
4577                         args[argspos]= (DWORD)pVarResult;
4578                     argspos     += 1;
4579                     args2pos    += arglen;
4580                 }
4581             }
4582             if (pFDesc->funcdesc.cParamsOpt)
4583                 FIXME("Does not support optional parameters (%d)\n",
4584                         pFDesc->funcdesc.cParamsOpt
4585                 );
4586
4587             res = _invoke((*(FARPROC**)pIUnk)[pFDesc->funcdesc.oVft/4],
4588                     pFDesc->funcdesc.callconv,
4589                     numargs,
4590                     args
4591             );
4592             if (pVarResult && (dwFlags & (DISPATCH_PROPERTYGET))) {
4593                 args2pos = 0;
4594                 for (i=0;i<pFDesc->funcdesc.cParams-pDispParams->cArgs;i++) {
4595                     int arglen = _argsize(pFDesc->funcdesc.lprgelemdescParam[i].tdesc.vt);
4596                     TYPEDESC *tdesc = &(pFDesc->funcdesc.lprgelemdescParam[i+pDispParams->cArgs].tdesc);
4597                    TYPEDESC i4_tdesc;
4598                    i4_tdesc.vt = VT_I4;
4599
4600                     /* If we are a pointer to a variant, we are done already */
4601                     if ((tdesc->vt==VT_PTR)&&(tdesc->u.lptdesc->vt==VT_VARIANT))
4602                         continue;
4603
4604                     VariantInit(pVarResult);
4605                     memcpy(&V_UNION(pVarResult,intVal),&args2[args2pos],arglen*sizeof(DWORD));
4606
4607                     if (tdesc->vt == VT_PTR)
4608                         tdesc = tdesc->u.lptdesc;
4609                     if (tdesc->vt == VT_USERDEFINED) {
4610                         ITypeInfo       *tinfo2;
4611                         TYPEATTR        *tattr;
4612
4613                         hres = ITypeInfo_GetRefTypeInfo(iface,tdesc->u.hreftype,&tinfo2);
4614                         if (hres) {
4615                             FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED, while coercing. Copying 4 byte.\n",tdesc->u.hreftype);
4616                             return E_FAIL;
4617                         }
4618                         ITypeInfo_GetTypeAttr(tinfo2,&tattr);
4619                         switch (tattr->typekind) {
4620                         case TKIND_ENUM:
4621                            /* force the return type to be VT_I4 */
4622                            tdesc = &i4_tdesc;
4623                             break;
4624                         case TKIND_ALIAS:
4625                             TRACE("TKIND_ALIAS to vt 0x%x\n",tattr->tdescAlias.vt);
4626                             tdesc = &(tattr->tdescAlias);
4627                             break;
4628
4629                         case TKIND_INTERFACE:
4630                             FIXME("TKIND_INTERFACE unhandled.\n");
4631                             break;
4632                         case TKIND_DISPATCH:
4633                             FIXME("TKIND_DISPATCH unhandled.\n");
4634                             break;
4635                         case TKIND_RECORD:
4636                             FIXME("TKIND_RECORD unhandled.\n");
4637                             break;
4638                         default:
4639                             FIXME("TKIND %d unhandled.\n",tattr->typekind);
4640                             break;
4641                         }
4642                         ITypeInfo_Release(tinfo2);
4643                     }
4644                     V_VT(pVarResult) = tdesc->vt;
4645
4646                     /* HACK: VB5 likes this.
4647                      * I do not know why. There is 1 example in MSDN which uses
4648                      * this which appears broken (mixes int vals and
4649                      * IDispatch*.).
4650                      */
4651                     if ((tdesc->vt == VT_PTR) && (dwFlags & DISPATCH_METHOD))
4652                         V_VT(pVarResult) = VT_DISPATCH;
4653                     TRACE("storing into variant:\n");
4654                     dump_Variant(pVarResult);
4655                     args2pos += arglen;
4656                 }
4657             }
4658             HeapFree(GetProcessHeap(),0,args2);
4659             HeapFree(GetProcessHeap(),0,args);
4660             return S_OK;
4661         }
4662         case FUNC_DISPATCH:  {
4663            IDispatch *disp;
4664            HRESULT hr;
4665
4666            hr = IUnknown_QueryInterface((LPUNKNOWN)pIUnk,&IID_IDispatch,(LPVOID*)&disp);
4667            if (hr) {
4668                FIXME("FUNC_DISPATCH used on object without IDispatch iface?\n");
4669                return hr;
4670            }
4671            FIXME("Calling Invoke in IDispatch iface. untested!\n");
4672            hr = IDispatch_Invoke(
4673                disp,memid,&IID_NULL,LOCALE_USER_DEFAULT,dwFlags,pDispParams,
4674                pVarResult,pExcepInfo,pArgErr
4675            );
4676            if (hr)
4677                FIXME("IDispatch::Invoke failed with %08lx. (Could be not a real error?)\n",hr);
4678            IDispatch_Release(disp);
4679            return hr;
4680         }
4681         default:
4682            FIXME("Unknown function invocation type %d\n",pFDesc->funcdesc.funckind);
4683            return E_FAIL;
4684         }
4685     } else {
4686         for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) {
4687             if (pVDesc->vardesc.memid == memid) {
4688                 FIXME("varseek: Found memid name %s, but variable-based invoking not supported\n",debugstr_w(((LPWSTR)pVDesc->Name)));
4689                 dump_TLBVarDesc(pVDesc);
4690                 break;
4691             }
4692         }
4693     }
4694     /* not found, look for it in inherited interfaces */
4695     if (This->TypeAttr.typekind==TKIND_INTERFACE && This->TypeAttr.cImplTypes) {
4696         /* recursive search */
4697         ITypeInfo *pTInfo;
4698         HRESULT hr;
4699         hr=ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef, &pTInfo);
4700         if(SUCCEEDED(hr)){
4701             hr=ITypeInfo_Invoke(pTInfo,pIUnk,memid,dwFlags,pDispParams,pVarResult,pExcepInfo,pArgErr);
4702             ITypeInfo_Release(pTInfo);
4703             return hr;
4704         }
4705         WARN("Could not search inherited interface!\n");
4706     }
4707     ERR("did not find member id %d, flags %d!\n", (int)memid, dwFlags);
4708     return DISP_E_MEMBERNOTFOUND;
4709 }
4710
4711 /* ITypeInfo::GetDocumentation
4712  *
4713  * Retrieves the documentation string, the complete Help file name and path,
4714  * and the context ID for the Help topic for a specified type description.
4715  *
4716  * (Can be tested by the Visual Basic Editor in Word for instance.)
4717  */
4718 static HRESULT WINAPI ITypeInfo_fnGetDocumentation( ITypeInfo2 *iface,
4719         MEMBERID memid, BSTR  *pBstrName, BSTR  *pBstrDocString,
4720         DWORD  *pdwHelpContext, BSTR  *pBstrHelpFile)
4721 {
4722     ICOM_THIS( ITypeInfoImpl, iface);
4723     TLBFuncDesc * pFDesc;
4724     TLBVarDesc * pVDesc;
4725     TRACE("(%p) memid %ld Name(%p) DocString(%p)"
4726           " HelpContext(%p) HelpFile(%p)\n",
4727         This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
4728     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
4729         if(pBstrName)
4730             *pBstrName=SysAllocString(This->Name);
4731         if(pBstrDocString)
4732             *pBstrDocString=SysAllocString(This->DocString);
4733         if(pdwHelpContext)
4734             *pdwHelpContext=This->dwHelpContext;
4735         if(pBstrHelpFile)
4736             *pBstrHelpFile=SysAllocString(This->DocString);/* FIXME */
4737         return S_OK;
4738     }else {/* for a member */
4739     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
4740         if(pFDesc->funcdesc.memid==memid){
4741           if(pBstrName)
4742             *pBstrName = SysAllocString(pFDesc->Name);
4743           if(pBstrDocString)
4744             *pBstrDocString=SysAllocString(pFDesc->HelpString);
4745           if(pdwHelpContext)
4746             *pdwHelpContext=pFDesc->helpcontext;
4747           return S_OK;
4748         }
4749     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
4750         if(pVDesc->vardesc.memid==memid){
4751             if(pBstrName)
4752               *pBstrName = SysAllocString(pVDesc->Name);
4753             if(pBstrDocString)
4754               *pBstrDocString=SysAllocString(pVDesc->HelpString);
4755             if(pdwHelpContext)
4756               *pdwHelpContext=pVDesc->HelpContext;
4757             return S_OK;
4758         }
4759     }
4760     return TYPE_E_ELEMENTNOTFOUND;
4761 }
4762
4763 /*  ITypeInfo::GetDllEntry
4764  *
4765  * Retrieves a description or specification of an entry point for a function
4766  * in a DLL.
4767  */
4768 static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid,
4769         INVOKEKIND invKind, BSTR  *pBstrDllName, BSTR  *pBstrName,
4770         WORD  *pwOrdinal)
4771 {
4772     ICOM_THIS( ITypeInfoImpl, iface);
4773     TLBFuncDesc *pFDesc;
4774
4775     FIXME("(%p, memid %lx, %d, %p, %p, %p), partial stub!\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
4776
4777     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
4778         if(pFDesc->funcdesc.memid==memid){
4779             dump_TypeInfo(This);
4780             dump_TLBFuncDescOne(pFDesc);
4781
4782             /* FIXME: This is wrong, but how do you find that out? */
4783             if (pBstrDllName) {
4784                 const WCHAR oleaut32W[] = {'O','L','E','A','U','T','3','2','.','D','L','L',0};
4785                 *pBstrDllName = SysAllocString(oleaut32W);
4786             }
4787
4788             if (HIWORD(pFDesc->Entry) && (pFDesc->Entry != (void*)-1)) {
4789                 if (pBstrName)
4790                     *pBstrName = SysAllocString(pFDesc->Entry);
4791                 if (pwOrdinal)
4792                     *pwOrdinal = -1;
4793                 return S_OK;
4794             }
4795             if (pBstrName)
4796                 *pBstrName = NULL;
4797             if (pwOrdinal)
4798                 *pwOrdinal = (DWORD)pFDesc->Entry;
4799             return S_OK;
4800         }
4801     return E_FAIL;
4802 }
4803
4804 /* ITypeInfo::GetRefTypeInfo
4805  *
4806  * If a type description references other type descriptions, it retrieves
4807  * the referenced type descriptions.
4808  */
4809 static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo(
4810         ITypeInfo2 *iface,
4811         HREFTYPE hRefType,
4812         ITypeInfo  **ppTInfo)
4813 {
4814     ICOM_THIS( ITypeInfoImpl, iface);
4815     HRESULT result = E_FAIL;
4816
4817
4818     if (hRefType == -1 &&
4819         (((ITypeInfoImpl*) This)->TypeAttr.typekind   == TKIND_DISPATCH) &&
4820         (((ITypeInfoImpl*) This)->TypeAttr.wTypeFlags &  TYPEFLAG_FDUAL))
4821     {
4822           /* when we meet a DUAL dispinterface, we must create the interface
4823           * version of it.
4824           */
4825           ITypeInfoImpl* pTypeInfoImpl = (ITypeInfoImpl*) ITypeInfo_Constructor();
4826
4827
4828           /* the interface version contains the same information as the dispinterface
4829            * copy the contents of the structs.
4830            */
4831           *pTypeInfoImpl = *This;
4832           pTypeInfoImpl->ref = 1;
4833
4834           /* change the type to interface */
4835           pTypeInfoImpl->TypeAttr.typekind = TKIND_INTERFACE;
4836
4837           *ppTInfo = (ITypeInfo*) pTypeInfoImpl;
4838
4839           ITypeInfo_AddRef((ITypeInfo*) pTypeInfoImpl);
4840
4841           result = S_OK;
4842
4843     } else {
4844         TLBRefType *pRefType;
4845         for(pRefType = This->reflist; pRefType; pRefType = pRefType->next) {
4846             if(pRefType->reference == hRefType)
4847                 break;
4848         }
4849         if(!pRefType)
4850           FIXME("Can't find pRefType for ref %lx\n", hRefType);
4851         if(pRefType && hRefType != -1) {
4852             ITypeLib *pTLib = NULL;
4853
4854             if(pRefType->pImpTLInfo == TLB_REF_INTERNAL) {
4855                 int Index;
4856                 result = ITypeInfo_GetContainingTypeLib(iface, &pTLib, &Index);
4857             } else {
4858                 if(pRefType->pImpTLInfo->pImpTypeLib) {
4859                     TRACE("typeinfo in imported typelib that is already loaded\n");
4860                     pTLib = (ITypeLib*)pRefType->pImpTLInfo->pImpTypeLib;
4861                     ITypeLib2_AddRef((ITypeLib*) pTLib);
4862                     result = S_OK;
4863                 } else {
4864                     TRACE("typeinfo in imported typelib that isn't already loaded\n");
4865                     result = LoadRegTypeLib( &pRefType->pImpTLInfo->guid,
4866                                              pRefType->pImpTLInfo->wVersionMajor,
4867                                              pRefType->pImpTLInfo->wVersionMinor,
4868                                              pRefType->pImpTLInfo->lcid,
4869                                              &pTLib);
4870
4871                     if(!SUCCEEDED(result)) {
4872                         BSTR libnam=SysAllocString(pRefType->pImpTLInfo->name);
4873                         result=LoadTypeLib(libnam, &pTLib);
4874                         SysFreeString(libnam);
4875                     }
4876                     if(SUCCEEDED(result)) {
4877                         pRefType->pImpTLInfo->pImpTypeLib = (ITypeLibImpl*)pTLib;
4878                         ITypeLib2_AddRef(pTLib);
4879                     }
4880                 }
4881             }
4882             if(SUCCEEDED(result)) {
4883                 if(pRefType->index == TLB_REF_USE_GUID)
4884                     result = ITypeLib2_GetTypeInfoOfGuid(pTLib,
4885                                                          &pRefType->guid,
4886                                                          ppTInfo);
4887                 else
4888                     result = ITypeLib2_GetTypeInfo(pTLib, pRefType->index,
4889                                                    ppTInfo);
4890             }
4891             if (pTLib != NULL)
4892                 ITypeLib2_Release(pTLib);
4893         }
4894     }
4895
4896     TRACE("(%p) hreftype 0x%04lx loaded %s (%p)\n", This, hRefType,
4897           SUCCEEDED(result)? "SUCCESS":"FAILURE", *ppTInfo);
4898     return result;
4899 }
4900
4901 /* ITypeInfo::AddressOfMember
4902  *
4903  * Retrieves the addresses of static functions or variables, such as those
4904  * defined in a DLL.
4905  */
4906 static HRESULT WINAPI ITypeInfo_fnAddressOfMember( ITypeInfo2 *iface,
4907         MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
4908 {
4909     ICOM_THIS( ITypeInfoImpl, iface);
4910     FIXME("(%p) stub!\n", This);
4911     return S_OK;
4912 }
4913
4914 /* ITypeInfo::CreateInstance
4915  *
4916  * Creates a new instance of a type that describes a component object class
4917  * (coclass).
4918  */
4919 static HRESULT WINAPI ITypeInfo_fnCreateInstance( ITypeInfo2 *iface,
4920         IUnknown *pUnk, REFIID riid, VOID  **ppvObj)
4921 {
4922     ICOM_THIS( ITypeInfoImpl, iface);
4923     FIXME("(%p) stub!\n", This);
4924     return S_OK;
4925 }
4926
4927 /* ITypeInfo::GetMops
4928  *
4929  * Retrieves marshalling information.
4930  */
4931 static HRESULT WINAPI ITypeInfo_fnGetMops( ITypeInfo2 *iface, MEMBERID memid,
4932                                 BSTR  *pBstrMops)
4933 {
4934     ICOM_THIS( ITypeInfoImpl, iface);
4935     FIXME("(%p) stub!\n", This);
4936     return S_OK;
4937 }
4938
4939 /* ITypeInfo::GetContainingTypeLib
4940  *
4941  * Retrieves the containing type library and the index of the type description
4942  * within that type library.
4943  */
4944 static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( ITypeInfo2 *iface,
4945         ITypeLib  * *ppTLib, UINT  *pIndex)
4946 {
4947     ICOM_THIS( ITypeInfoImpl, iface);
4948     
4949     /* If a pointer is null, we simply ignore it, the ATL in particular passes pIndex as 0 */
4950     if (pIndex) {
4951       *pIndex=This->index;
4952       TRACE("returning pIndex=%d\n", *pIndex);
4953     }
4954     
4955     if (ppTLib) {
4956       *ppTLib=(LPTYPELIB )(This->pTypeLib);
4957       ITypeLib2_AddRef(*ppTLib);
4958       TRACE("returning ppTLib=%p\n", *ppTLib);
4959     }
4960     
4961     return S_OK;
4962 }
4963
4964 /* ITypeInfo::ReleaseTypeAttr
4965  *
4966  * Releases a TYPEATTR previously returned by GetTypeAttr.
4967  *
4968  */
4969 static void WINAPI ITypeInfo_fnReleaseTypeAttr( ITypeInfo2 *iface,
4970         TYPEATTR* pTypeAttr)
4971 {
4972     ICOM_THIS( ITypeInfoImpl, iface);
4973     TRACE("(%p)->(%p)\n", This, pTypeAttr);
4974 }
4975
4976 /* ITypeInfo::ReleaseFuncDesc
4977  *
4978  * Releases a FUNCDESC previously returned by GetFuncDesc. *
4979  */
4980 static void WINAPI ITypeInfo_fnReleaseFuncDesc(
4981         ITypeInfo2 *iface,
4982         FUNCDESC *pFuncDesc)
4983 {
4984     ICOM_THIS( ITypeInfoImpl, iface);
4985     TRACE("(%p)->(%p)\n", This, pFuncDesc);
4986 }
4987
4988 /* ITypeInfo::ReleaseVarDesc
4989  *
4990  * Releases a VARDESC previously returned by GetVarDesc.
4991  */
4992 static void WINAPI ITypeInfo_fnReleaseVarDesc( ITypeInfo2 *iface,
4993         VARDESC *pVarDesc)
4994 {
4995     ICOM_THIS( ITypeInfoImpl, iface);
4996     TRACE("(%p)->(%p)\n", This, pVarDesc);
4997 }
4998
4999 /* ITypeInfo2::GetTypeKind
5000  *
5001  * Returns the TYPEKIND enumeration quickly, without doing any allocations.
5002  *
5003  */
5004 static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo2 * iface,
5005     TYPEKIND *pTypeKind)
5006 {
5007     ICOM_THIS( ITypeInfoImpl, iface);
5008     *pTypeKind=This->TypeAttr.typekind;
5009     TRACE("(%p) type 0x%0x\n", This,*pTypeKind);
5010     return S_OK;
5011 }
5012
5013 /* ITypeInfo2::GetTypeFlags
5014  *
5015  * Returns the type flags without any allocations. This returns a DWORD type
5016  * flag, which expands the type flags without growing the TYPEATTR (type
5017  * attribute).
5018  *
5019  */
5020 static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo2 *iface, ULONG *pTypeFlags)
5021 {
5022     ICOM_THIS( ITypeInfoImpl, iface);
5023     *pTypeFlags=This->TypeAttr.wTypeFlags;
5024     TRACE("(%p) flags 0x%lx\n", This,*pTypeFlags);
5025     return S_OK;
5026 }
5027
5028 /* ITypeInfo2::GetFuncIndexOfMemId
5029  * Binds to a specific member based on a known DISPID, where the member name
5030  * is not known (for example, when binding to a default member).
5031  *
5032  */
5033 static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo2 * iface,
5034     MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex)
5035 {
5036     ICOM_THIS( ITypeInfoImpl, iface);
5037     TLBFuncDesc *pFuncInfo;
5038     int i;
5039     HRESULT result;
5040     /* FIXME: should check for invKind??? */
5041     for(i=0, pFuncInfo=This->funclist;pFuncInfo &&
5042             memid != pFuncInfo->funcdesc.memid; i++, pFuncInfo=pFuncInfo->next);
5043     if(pFuncInfo){
5044         *pFuncIndex=i;
5045         result= S_OK;
5046     }else{
5047         *pFuncIndex=0;
5048         result=E_INVALIDARG;
5049     }
5050     TRACE("(%p) memid 0x%08lx invKind 0x%04x -> %s\n", This,
5051           memid, invKind, SUCCEEDED(result)? "SUCCES":"FAILED");
5052     return result;
5053 }
5054
5055 /* TypeInfo2::GetVarIndexOfMemId
5056  *
5057  * Binds to a specific member based on a known DISPID, where the member name
5058  * is not known (for example, when binding to a default member).
5059  *
5060  */
5061 static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( ITypeInfo2 * iface,
5062     MEMBERID memid, UINT *pVarIndex)
5063 {
5064     ICOM_THIS( ITypeInfoImpl, iface);
5065     TLBVarDesc *pVarInfo;
5066     int i;
5067     HRESULT result;
5068     for(i=0, pVarInfo=This->varlist; pVarInfo &&
5069             memid != pVarInfo->vardesc.memid; i++, pVarInfo=pVarInfo->next)
5070         ;
5071     if(pVarInfo){
5072         *pVarIndex=i;
5073         result= S_OK;
5074     }else{
5075         *pVarIndex=0;
5076         result=E_INVALIDARG;
5077     }
5078     TRACE("(%p) memid 0x%08lx -> %s\n", This,
5079           memid, SUCCEEDED(result)? "SUCCES":"FAILED");
5080     return result;
5081 }
5082
5083 /* ITypeInfo2::GetCustData
5084  *
5085  * Gets the custom data
5086  */
5087 static HRESULT WINAPI ITypeInfo2_fnGetCustData(
5088         ITypeInfo2 * iface,
5089         REFGUID guid,
5090         VARIANT *pVarVal)
5091 {
5092     ICOM_THIS( ITypeInfoImpl, iface);
5093     TLBCustData *pCData;
5094
5095     for(pCData=This->pCustData; pCData; pCData = pCData->next)
5096         if( IsEqualIID(guid, &pCData->guid)) break;
5097
5098     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
5099
5100     if(pCData)
5101     {
5102         VariantInit( pVarVal);
5103         VariantCopy( pVarVal, &pCData->data);
5104         return S_OK;
5105     }
5106     return E_INVALIDARG;  /* FIXME: correct? */
5107 }
5108
5109 /* ITypeInfo2::GetFuncCustData
5110  *
5111  * Gets the custom data
5112  */
5113 static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData(
5114         ITypeInfo2 * iface,
5115         UINT index,
5116         REFGUID guid,
5117         VARIANT *pVarVal)
5118 {
5119     ICOM_THIS( ITypeInfoImpl, iface);
5120     TLBCustData *pCData=NULL;
5121     TLBFuncDesc * pFDesc;
5122     int i;
5123     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
5124             pFDesc=pFDesc->next);
5125
5126     if(pFDesc)
5127         for(pCData=pFDesc->pCustData; pCData; pCData = pCData->next)
5128             if( IsEqualIID(guid, &pCData->guid)) break;
5129
5130     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
5131
5132     if(pCData){
5133         VariantInit( pVarVal);
5134         VariantCopy( pVarVal, &pCData->data);
5135         return S_OK;
5136     }
5137     return E_INVALIDARG;  /* FIXME: correct? */
5138 }
5139
5140 /* ITypeInfo2::GetParamCustData
5141  *
5142  * Gets the custom data
5143  */
5144 static HRESULT WINAPI ITypeInfo2_fnGetParamCustData(
5145         ITypeInfo2 * iface,
5146         UINT indexFunc,
5147         UINT indexParam,
5148         REFGUID guid,
5149         VARIANT *pVarVal)
5150 {
5151     ICOM_THIS( ITypeInfoImpl, iface);
5152     TLBCustData *pCData=NULL;
5153     TLBFuncDesc * pFDesc;
5154     int i;
5155
5156     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,pFDesc=pFDesc->next);
5157
5158     if(pFDesc && indexParam >=0 && indexParam<pFDesc->funcdesc.cParams)
5159         for(pCData=pFDesc->pParamDesc[indexParam].pCustData; pCData;
5160                 pCData = pCData->next)
5161             if( IsEqualIID(guid, &pCData->guid)) break;
5162
5163     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
5164
5165     if(pCData)
5166     {
5167         VariantInit( pVarVal);
5168         VariantCopy( pVarVal, &pCData->data);
5169         return S_OK;
5170     }
5171     return E_INVALIDARG;  /* FIXME: correct? */
5172 }
5173
5174 /* ITypeInfo2::GetVarCustData
5175  *
5176  * Gets the custom data
5177  */
5178 static HRESULT WINAPI ITypeInfo2_fnGetVarCustData(
5179         ITypeInfo2 * iface,
5180         UINT index,
5181         REFGUID guid,
5182         VARIANT *pVarVal)
5183 {
5184     ICOM_THIS( ITypeInfoImpl, iface);
5185     TLBCustData *pCData=NULL;
5186     TLBVarDesc * pVDesc;
5187     int i;
5188
5189     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next);
5190
5191     if(pVDesc)
5192     {
5193       for(pCData=pVDesc->pCustData; pCData; pCData = pCData->next)
5194       {
5195         if( IsEqualIID(guid, &pCData->guid)) break;
5196       }
5197     }
5198
5199     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
5200
5201     if(pCData)
5202     {
5203         VariantInit( pVarVal);
5204         VariantCopy( pVarVal, &pCData->data);
5205         return S_OK;
5206     }
5207     return E_INVALIDARG;  /* FIXME: correct? */
5208 }
5209
5210 /* ITypeInfo2::GetImplCustData
5211  *
5212  * Gets the custom data
5213  */
5214 static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData(
5215         ITypeInfo2 * iface,
5216         UINT index,
5217         REFGUID guid,
5218         VARIANT *pVarVal)
5219 {
5220     ICOM_THIS( ITypeInfoImpl, iface);
5221     TLBCustData *pCData=NULL;
5222     TLBImplType * pRDesc;
5223     int i;
5224
5225     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++, pRDesc=pRDesc->next);
5226
5227     if(pRDesc)
5228     {
5229       for(pCData=pRDesc->pCustData; pCData; pCData = pCData->next)
5230       {
5231         if( IsEqualIID(guid, &pCData->guid)) break;
5232       }
5233     }
5234
5235     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
5236
5237     if(pCData)
5238     {
5239         VariantInit( pVarVal);
5240         VariantCopy( pVarVal, &pCData->data);
5241         return S_OK;
5242     }
5243     return E_INVALIDARG;  /* FIXME: correct? */
5244 }
5245
5246 /* ITypeInfo2::GetDocumentation2
5247  *
5248  * Retrieves the documentation string, the complete Help file name and path,
5249  * the localization context to use, and the context ID for the library Help
5250  * topic in the Help file.
5251  *
5252  */
5253 static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2(
5254         ITypeInfo2 * iface,
5255         MEMBERID memid,
5256         LCID lcid,
5257         BSTR *pbstrHelpString,
5258         DWORD *pdwHelpStringContext,
5259         BSTR *pbstrHelpStringDll)
5260 {
5261     ICOM_THIS( ITypeInfoImpl, iface);
5262     TLBFuncDesc * pFDesc;
5263     TLBVarDesc * pVDesc;
5264     TRACE("(%p) memid %ld lcid(0x%lx)  HelpString(%p) "
5265           "HelpStringContext(%p) HelpStringDll(%p)\n",
5266           This, memid, lcid, pbstrHelpString, pdwHelpStringContext,
5267           pbstrHelpStringDll );
5268     /* the help string should be obtained from the helpstringdll,
5269      * using the _DLLGetDocumentation function, based on the supplied
5270      * lcid. Nice to do sometime...
5271      */
5272     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
5273         if(pbstrHelpString)
5274             *pbstrHelpString=SysAllocString(This->Name);
5275         if(pdwHelpStringContext)
5276             *pdwHelpStringContext=This->dwHelpStringContext;
5277         if(pbstrHelpStringDll)
5278             *pbstrHelpStringDll=
5279                 SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
5280         return S_OK;
5281     }else {/* for a member */
5282     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
5283         if(pFDesc->funcdesc.memid==memid){
5284              if(pbstrHelpString)
5285                 *pbstrHelpString=SysAllocString(pFDesc->HelpString);
5286             if(pdwHelpStringContext)
5287                 *pdwHelpStringContext=pFDesc->HelpStringContext;
5288             if(pbstrHelpStringDll)
5289                 *pbstrHelpStringDll=
5290                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
5291         return S_OK;
5292     }
5293     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
5294         if(pVDesc->vardesc.memid==memid){
5295              if(pbstrHelpString)
5296                 *pbstrHelpString=SysAllocString(pVDesc->HelpString);
5297             if(pdwHelpStringContext)
5298                 *pdwHelpStringContext=pVDesc->HelpStringContext;
5299             if(pbstrHelpStringDll)
5300                 *pbstrHelpStringDll=
5301                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
5302             return S_OK;
5303         }
5304     }
5305     return TYPE_E_ELEMENTNOTFOUND;
5306 }
5307
5308 /* ITypeInfo2::GetAllCustData
5309  *
5310  * Gets all custom data items for the Type info.
5311  *
5312  */
5313 static HRESULT WINAPI ITypeInfo2_fnGetAllCustData(
5314         ITypeInfo2 * iface,
5315         CUSTDATA *pCustData)
5316 {
5317     ICOM_THIS( ITypeInfoImpl, iface);
5318     TLBCustData *pCData;
5319     int i;
5320
5321     TRACE("(%p) returning %d items\n", This, This->ctCustData);
5322
5323     pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
5324     if(pCustData->prgCustData ){
5325         pCustData->cCustData=This->ctCustData;
5326         for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
5327             pCustData->prgCustData[i].guid=pCData->guid;
5328             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
5329         }
5330     }else{
5331         ERR(" OUT OF MEMORY! \n");
5332         return E_OUTOFMEMORY;
5333     }
5334     return S_OK;
5335 }
5336
5337 /* ITypeInfo2::GetAllFuncCustData
5338  *
5339  * Gets all custom data items for the specified Function
5340  *
5341  */
5342 static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData(
5343         ITypeInfo2 * iface,
5344         UINT index,
5345         CUSTDATA *pCustData)
5346 {
5347     ICOM_THIS( ITypeInfoImpl, iface);
5348     TLBCustData *pCData;
5349     TLBFuncDesc * pFDesc;
5350     int i;
5351     TRACE("(%p) index %d\n", This, index);
5352     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
5353             pFDesc=pFDesc->next)
5354         ;
5355     if(pFDesc){
5356         pCustData->prgCustData =
5357             TLB_Alloc(pFDesc->ctCustData * sizeof(CUSTDATAITEM));
5358         if(pCustData->prgCustData ){
5359             pCustData->cCustData=pFDesc->ctCustData;
5360             for(i=0, pCData=pFDesc->pCustData; pCData; i++,
5361                     pCData = pCData->next){
5362                 pCustData->prgCustData[i].guid=pCData->guid;
5363                 VariantCopy(& pCustData->prgCustData[i].varValue,
5364                         & pCData->data);
5365             }
5366         }else{
5367             ERR(" OUT OF MEMORY! \n");
5368             return E_OUTOFMEMORY;
5369         }
5370         return S_OK;
5371     }
5372     return TYPE_E_ELEMENTNOTFOUND;
5373 }
5374
5375 /* ITypeInfo2::GetAllParamCustData
5376  *
5377  * Gets all custom data items for the Functions
5378  *
5379  */
5380 static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo2 * iface,
5381     UINT indexFunc, UINT indexParam, CUSTDATA *pCustData)
5382 {
5383     ICOM_THIS( ITypeInfoImpl, iface);
5384     TLBCustData *pCData=NULL;
5385     TLBFuncDesc * pFDesc;
5386     int i;
5387     TRACE("(%p) index %d\n", This, indexFunc);
5388     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,
5389             pFDesc=pFDesc->next)
5390         ;
5391     if(pFDesc && indexParam >=0 && indexParam<pFDesc->funcdesc.cParams){
5392         pCustData->prgCustData =
5393             TLB_Alloc(pFDesc->pParamDesc[indexParam].ctCustData *
5394                     sizeof(CUSTDATAITEM));
5395         if(pCustData->prgCustData ){
5396             pCustData->cCustData=pFDesc->pParamDesc[indexParam].ctCustData;
5397             for(i=0, pCData=pFDesc->pParamDesc[indexParam].pCustData;
5398                     pCData; i++, pCData = pCData->next){
5399                 pCustData->prgCustData[i].guid=pCData->guid;
5400                 VariantCopy(& pCustData->prgCustData[i].varValue,
5401                         & pCData->data);
5402             }
5403         }else{
5404             ERR(" OUT OF MEMORY! \n");
5405             return E_OUTOFMEMORY;
5406         }
5407         return S_OK;
5408     }
5409     return TYPE_E_ELEMENTNOTFOUND;
5410 }
5411
5412 /* ITypeInfo2::GetAllVarCustData
5413  *
5414  * Gets all custom data items for the specified Variable
5415  *
5416  */
5417 static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo2 * iface,
5418     UINT index, CUSTDATA *pCustData)
5419 {
5420     ICOM_THIS( ITypeInfoImpl, iface);
5421     TLBCustData *pCData;
5422     TLBVarDesc * pVDesc;
5423     int i;
5424     TRACE("(%p) index %d\n", This, index);
5425     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++,
5426             pVDesc=pVDesc->next)
5427         ;
5428     if(pVDesc){
5429         pCustData->prgCustData =
5430             TLB_Alloc(pVDesc->ctCustData * sizeof(CUSTDATAITEM));
5431         if(pCustData->prgCustData ){
5432             pCustData->cCustData=pVDesc->ctCustData;
5433             for(i=0, pCData=pVDesc->pCustData; pCData; i++,
5434                     pCData = pCData->next){
5435                 pCustData->prgCustData[i].guid=pCData->guid;
5436                 VariantCopy(& pCustData->prgCustData[i].varValue,
5437                         & pCData->data);
5438             }
5439         }else{
5440             ERR(" OUT OF MEMORY! \n");
5441             return E_OUTOFMEMORY;
5442         }
5443         return S_OK;
5444     }
5445     return TYPE_E_ELEMENTNOTFOUND;
5446 }
5447
5448 /* ITypeInfo2::GetAllImplCustData
5449  *
5450  * Gets all custom data items for the specified implementation type
5451  *
5452  */
5453 static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData(
5454         ITypeInfo2 * iface,
5455         UINT index,
5456         CUSTDATA *pCustData)
5457 {
5458     ICOM_THIS( ITypeInfoImpl, iface);
5459     TLBCustData *pCData;
5460     TLBImplType * pRDesc;
5461     int i;
5462     TRACE("(%p) index %d\n", This, index);
5463     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++,
5464             pRDesc=pRDesc->next)
5465         ;
5466     if(pRDesc){
5467         pCustData->prgCustData =
5468             TLB_Alloc(pRDesc->ctCustData * sizeof(CUSTDATAITEM));
5469         if(pCustData->prgCustData ){
5470             pCustData->cCustData=pRDesc->ctCustData;
5471             for(i=0, pCData=pRDesc->pCustData; pCData; i++,
5472                     pCData = pCData->next){
5473                 pCustData->prgCustData[i].guid=pCData->guid;
5474                 VariantCopy(& pCustData->prgCustData[i].varValue,
5475                         & pCData->data);
5476             }
5477         }else{
5478             ERR(" OUT OF MEMORY! \n");
5479             return E_OUTOFMEMORY;
5480         }
5481         return S_OK;
5482     }
5483     return TYPE_E_ELEMENTNOTFOUND;
5484 }
5485
5486 static ICOM_VTABLE(ITypeInfo2) tinfvt =
5487 {
5488     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
5489
5490     ITypeInfo_fnQueryInterface,
5491     ITypeInfo_fnAddRef,
5492     ITypeInfo_fnRelease,
5493
5494     ITypeInfo_fnGetTypeAttr,
5495     ITypeInfo_fnGetTypeComp,
5496     ITypeInfo_fnGetFuncDesc,
5497     ITypeInfo_fnGetVarDesc,
5498     ITypeInfo_fnGetNames,
5499     ITypeInfo_fnGetRefTypeOfImplType,
5500     ITypeInfo_fnGetImplTypeFlags,
5501     ITypeInfo_fnGetIDsOfNames,
5502     ITypeInfo_fnInvoke,
5503     ITypeInfo_fnGetDocumentation,
5504     ITypeInfo_fnGetDllEntry,
5505     ITypeInfo_fnGetRefTypeInfo,
5506     ITypeInfo_fnAddressOfMember,
5507     ITypeInfo_fnCreateInstance,
5508     ITypeInfo_fnGetMops,
5509     ITypeInfo_fnGetContainingTypeLib,
5510     ITypeInfo_fnReleaseTypeAttr,
5511     ITypeInfo_fnReleaseFuncDesc,
5512     ITypeInfo_fnReleaseVarDesc,
5513
5514     ITypeInfo2_fnGetTypeKind,
5515     ITypeInfo2_fnGetTypeFlags,
5516     ITypeInfo2_fnGetFuncIndexOfMemId,
5517     ITypeInfo2_fnGetVarIndexOfMemId,
5518     ITypeInfo2_fnGetCustData,
5519     ITypeInfo2_fnGetFuncCustData,
5520     ITypeInfo2_fnGetParamCustData,
5521     ITypeInfo2_fnGetVarCustData,
5522     ITypeInfo2_fnGetImplTypeCustData,
5523     ITypeInfo2_fnGetDocumentation2,
5524     ITypeInfo2_fnGetAllCustData,
5525     ITypeInfo2_fnGetAllFuncCustData,
5526     ITypeInfo2_fnGetAllParamCustData,
5527     ITypeInfo2_fnGetAllVarCustData,
5528     ITypeInfo2_fnGetAllImplTypeCustData,
5529 };
5530
5531 static HRESULT WINAPI ITypeComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
5532 {
5533     ICOM_THIS_From_ITypeComp(ITypeInfoImpl, iface);
5534
5535     return ITypeInfo_QueryInterface((ITypeInfo *)This, riid, ppv);
5536 }
5537
5538 static ULONG WINAPI ITypeComp_fnAddRef(ITypeComp * iface)
5539 {
5540     ICOM_THIS_From_ITypeComp(ITypeInfoImpl, iface);
5541
5542     return ITypeInfo_AddRef((ITypeInfo *)This);
5543 }
5544
5545 static ULONG WINAPI ITypeComp_fnRelease(ITypeComp * iface)
5546 {
5547     ICOM_THIS_From_ITypeComp(ITypeInfoImpl, iface);
5548
5549     return ITypeInfo_Release((ITypeInfo *)This);
5550 }
5551
5552 static HRESULT WINAPI ITypeComp_fnBind(
5553     ITypeComp * iface,
5554     OLECHAR * szName,
5555     unsigned long lHash,
5556     unsigned short wFlags,
5557     ITypeInfo ** ppTInfo,
5558     DESCKIND * pDescKind,
5559     BINDPTR * pBindPtr)
5560 {
5561     ICOM_THIS_From_ITypeComp(ITypeInfoImpl, iface);
5562     TLBFuncDesc * pFDesc;
5563     TLBVarDesc * pVDesc;
5564
5565     TRACE("(%s, %lx, 0x%x, %p, %p, %p)\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
5566
5567     for(pFDesc = This->funclist; pFDesc; pFDesc = pFDesc->next)
5568         if (pFDesc->funcdesc.invkind & wFlags)
5569             if (!strcmpW(pFDesc->Name, szName)) {
5570                 break;
5571             }
5572
5573     if (pFDesc)
5574     {
5575         *pDescKind = DESCKIND_FUNCDESC;
5576         pBindPtr->lpfuncdesc = &pFDesc->funcdesc;
5577         *ppTInfo = (ITypeInfo *)&This->lpVtbl;
5578         return S_OK;
5579     } else {
5580         if (!(wFlags & ~(INVOKE_PROPERTYGET)))
5581         {
5582             for(pVDesc = This->varlist; pVDesc; pVDesc = pVDesc->next) {
5583                 if (!strcmpW(pVDesc->Name, szName)) {
5584                     *pDescKind = DESCKIND_VARDESC;
5585                     pBindPtr->lpvardesc = &pVDesc->vardesc;
5586                     *ppTInfo = (ITypeInfo *)&This->lpVtbl;
5587                     return S_OK;
5588                 }
5589             }
5590         }
5591     }
5592     /* not found, look for it in inherited interfaces */
5593     if ((This->TypeAttr.typekind == TKIND_INTERFACE) && This->TypeAttr.cImplTypes) {
5594         /* recursive search */
5595         ITypeInfo *pTInfo;
5596         ITypeComp *pTComp;
5597         HRESULT hr;
5598         hr=ITypeInfo_GetRefTypeInfo((ITypeInfo *)&This->lpVtbl, This->impltypelist->hRef, &pTInfo);
5599         if (SUCCEEDED(hr))
5600         {
5601             hr = ITypeInfo_GetTypeComp(pTInfo,&pTComp);
5602             ITypeInfo_Release(pTInfo);
5603         }
5604         if (SUCCEEDED(hr))
5605         {
5606             hr = ITypeComp_Bind(pTComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
5607             ITypeComp_Release(pTComp);
5608             return hr;
5609         }
5610         WARN("Could not search inherited interface!\n");
5611     }
5612     ERR("did not find member with name %s, flags 0x%x!\n", debugstr_w(szName), wFlags);
5613     *pDescKind = DESCKIND_NONE;
5614     pBindPtr->lpfuncdesc = NULL;
5615     *ppTInfo = NULL;
5616     return DISP_E_MEMBERNOTFOUND;
5617 }
5618
5619 static HRESULT WINAPI ITypeComp_fnBindType(
5620     ITypeComp * iface,
5621     OLECHAR * szName,
5622     unsigned long lHash,
5623     ITypeInfo ** ppTInfo,
5624     ITypeComp ** ppTComp)
5625 {
5626     TRACE("(%s, %lx, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
5627
5628     /* strange behaviour (does nothing) but like the
5629      * original */
5630
5631     if (!ppTInfo || !ppTComp)
5632         return E_POINTER;
5633
5634     *ppTInfo = NULL;
5635     *ppTComp = NULL;
5636
5637     return S_OK;
5638 }
5639
5640 static ICOM_VTABLE(ITypeComp) tcompvt =
5641 {
5642     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
5643
5644     ITypeComp_fnQueryInterface,
5645     ITypeComp_fnAddRef,
5646     ITypeComp_fnRelease,
5647
5648     ITypeComp_fnBind,
5649     ITypeComp_fnBindType
5650 };