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