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