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