~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/oleaut32/typelib.c

Version: ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

  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  *                    2005  Robert Shearman, for CodeWeavers
  9  *
 10  * This library is free software; you can redistribute it and/or
 11  * modify it under the terms of the GNU Lesser General Public
 12  * License as published by the Free Software Foundation; either
 13  * version 2.1 of the License, or (at your option) any later version.
 14  *
 15  * This library is distributed in the hope that it will be useful,
 16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 18  * Lesser General Public License for more details.
 19  *
 20  * You should have received a copy of the GNU Lesser General Public
 21  * License along with this library; if not, write to the Free Software
 22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 23  *
 24  * --------------------------------------------------------------------------------------
 25  * Known problems (2000, Francois Jacques)
 26  *
 27  * - Tested using OLEVIEW (Platform SDK tool) only.
 28  *
 29  * - dual interface dispinterfaces. vtable-interface ITypeInfo instances are
 30  *   creating by doing a straight copy of the dispinterface instance and just changing
 31  *   its typekind. Pointed structures aren't copied - only the address of the pointers.
 32  *
 33  * - locale stuff is partially implemented but hasn't been tested.
 34  *
 35  * - typelib file is still read in its entirety, but it is released now.
 36  *
 37  * --------------------------------------------------------------------------------------
 38  *  Known problems left from previous implementation (1999, Rein Klazes) :
 39  *
 40  * -. Data structures are straightforward, but slow for look-ups.
 41  * -. (related) nothing is hashed
 42  * -. Most error return values are just guessed not checked with windows
 43  *      behaviour.
 44  * -. lousy fatal error handling
 45  *
 46  */
 47 
 48 #include "config.h"
 49 #include "wine/port.h"
 50 
 51 #include <stdlib.h>
 52 #include <string.h>
 53 #include <stdarg.h>
 54 #include <stdio.h>
 55 #include <ctype.h>
 56 
 57 #define COBJMACROS
 58 #define NONAMELESSUNION
 59 #define NONAMELESSSTRUCT
 60 
 61 #include "winerror.h"
 62 #include "windef.h"
 63 #include "winbase.h"
 64 #include "winnls.h"
 65 #include "winreg.h"
 66 #include "winuser.h"
 67 #include "lzexpand.h"
 68 
 69 #include "wine/unicode.h"
 70 #include "objbase.h"
 71 #include "typelib.h"
 72 #include "wine/debug.h"
 73 #include "variant.h"
 74 #include "wine/list.h"
 75 
 76 WINE_DEFAULT_DEBUG_CHANNEL(ole);
 77 WINE_DECLARE_DEBUG_CHANNEL(typelib);
 78 
 79 typedef struct
 80 {
 81     WORD     offset;
 82     WORD     length;
 83     WORD     flags;
 84     WORD     id;
 85     WORD     handle;
 86     WORD     usage;
 87 } NE_NAMEINFO;
 88 
 89 typedef struct
 90 {
 91     WORD        type_id;   /* Type identifier */
 92     WORD        count;     /* Number of resources of this type */
 93     DWORD       resloader; /* SetResourceHandler() */
 94     /*
 95      * Name info array.
 96      */
 97 } NE_TYPEINFO;
 98 
 99 static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt);
100 static HRESULT TLB_AllocAndInitVarDesc(const VARDESC *src, VARDESC **dest_ptr);
101 
102 /****************************************************************************
103  *              FromLExxx
104  *
105  * Takes p_iVal (which is in little endian) and returns it
106  *   in the host machine's byte order.
107  */
108 #ifdef WORDS_BIGENDIAN
109 static WORD FromLEWord(WORD p_iVal)
110 {
111   return (((p_iVal & 0x00FF) << 8) |
112           ((p_iVal & 0xFF00) >> 8));
113 }
114 
115 
116 static DWORD FromLEDWord(DWORD p_iVal)
117 {
118   return (((p_iVal & 0x000000FF) << 24) |
119           ((p_iVal & 0x0000FF00) <<  8) |
120           ((p_iVal & 0x00FF0000) >>  8) |
121           ((p_iVal & 0xFF000000) >> 24));
122 }
123 #else
124 #define FromLEWord(X)  (X)
125 #define FromLEDWord(X) (X)
126 #endif
127 
128 #define DISPATCH_HREF_OFFSET 0x01000000
129 #define DISPATCH_HREF_MASK   0xff000000
130 
131 /****************************************************************************
132  *              FromLExxx
133  *
134  * Fix byte order in any structure if necessary
135  */
136 #ifdef WORDS_BIGENDIAN
137 static void FromLEWords(void *p_Val, int p_iSize)
138 {
139   WORD *Val = p_Val;
140 
141   p_iSize /= sizeof(WORD);
142 
143   while (p_iSize) {
144     *Val = FromLEWord(*Val);
145     Val++;
146     p_iSize--;
147   }
148 }
149 
150 
151 static void FromLEDWords(void *p_Val, int p_iSize)
152 {
153   DWORD *Val = p_Val;
154 
155   p_iSize /= sizeof(DWORD);
156 
157   while (p_iSize) {
158     *Val = FromLEDWord(*Val);
159     Val++;
160     p_iSize--;
161   }
162 }
163 #else
164 #define FromLEWords(X,Y) /*nothing*/
165 #define FromLEDWords(X,Y) /*nothing*/
166 #endif
167 
168 /*
169  * Find a typelib key which matches a requested maj.min version.
170  */
171 static BOOL find_typelib_key( REFGUID guid, WORD wMaj, WORD *wMin )
172 {
173     static const WCHAR typelibW[] = {'T','y','p','e','l','i','b','\\',0};
174     WCHAR buffer[60];
175     char key_name[16];
176     DWORD len, i;
177     INT best_min = -1;
178     HKEY hkey;
179 
180     memcpy( buffer, typelibW, sizeof(typelibW) );
181     StringFromGUID2( guid, buffer + strlenW(buffer), 40 );
182 
183     if (RegOpenKeyExW( HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hkey ) != ERROR_SUCCESS)
184         return FALSE;
185 
186     len = sizeof(key_name);
187     i = 0;
188     while (RegEnumKeyExA(hkey, i++, key_name, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
189     {
190         INT v_maj, v_min;
191 
192         if (sscanf(key_name, "%x.%x", &v_maj, &v_min) == 2)
193         {
194             TRACE("found %s: %x.%x\n", debugstr_w(buffer), v_maj, v_min);
195 
196             if (wMaj == v_maj)
197             {
198                 if (*wMin == v_min)
199                 {
200                     best_min = v_min;
201                     break; /* exact match */
202                 }
203                 if (v_min > best_min) best_min = v_min;
204             }
205         }
206         len = sizeof(key_name);
207     }
208     RegCloseKey( hkey );
209     if (best_min >= 0)
210     {
211         *wMin = best_min;
212         return TRUE;
213     }
214     return FALSE;
215 }
216 
217 /* get the path of a typelib key, in the form "Typelib\\<guid>\\<maj>.<min>" */
218 /* buffer must be at least 60 characters long */
219 static WCHAR *get_typelib_key( REFGUID guid, WORD wMaj, WORD wMin, WCHAR *buffer )
220 {
221     static const WCHAR TypelibW[] = {'T','y','p','e','l','i','b','\\',0};
222     static const WCHAR VersionFormatW[] = {'\\','%','x','.','%','x',0};
223 
224     memcpy( buffer, TypelibW, sizeof(TypelibW) );
225     StringFromGUID2( guid, buffer + strlenW(buffer), 40 );
226     sprintfW( buffer + strlenW(buffer), VersionFormatW, wMaj, wMin );
227     return buffer;
228 }
229 
230 /* get the path of an interface key, in the form "Interface\\<guid>" */
231 /* buffer must be at least 50 characters long */
232 static WCHAR *get_interface_key( REFGUID guid, WCHAR *buffer )
233 {
234     static const WCHAR InterfaceW[] = {'I','n','t','e','r','f','a','c','e','\\',0};
235 
236     memcpy( buffer, InterfaceW, sizeof(InterfaceW) );
237     StringFromGUID2( guid, buffer + strlenW(buffer), 40 );
238     return buffer;
239 }
240 
241 /* get the lcid subkey for a typelib, in the form "<lcid>\\<syskind>" */
242 /* buffer must be at least 16 characters long */
243 static WCHAR *get_lcid_subkey( LCID lcid, SYSKIND syskind, WCHAR *buffer )
244 {
245     static const WCHAR LcidFormatW[] = {'%','l','x','\\',0};
246     static const WCHAR win16W[] = {'w','i','n','1','6',0};
247     static const WCHAR win32W[] = {'w','i','n','3','2',0};
248 
249     sprintfW( buffer, LcidFormatW, lcid );
250     switch(syskind)
251     {
252     case SYS_WIN16: strcatW( buffer, win16W ); break;
253     case SYS_WIN32: strcatW( buffer, win32W ); break;
254     default:
255         TRACE("Typelib is for unsupported syskind %i\n", syskind);
256         return NULL;
257     }
258     return buffer;
259 }
260 
261 static HRESULT TLB_ReadTypeLib(LPCWSTR pszFileName, LPWSTR pszPath, UINT cchPath, ITypeLib2 **ppTypeLib);
262 
263 
264 /****************************************************************************
265  *              QueryPathOfRegTypeLib   [OLEAUT32.164]
266  *
267  * Gets the path to a registered type library.
268  *
269  * PARAMS
270  *  guid [I] referenced guid
271  *  wMaj [I] major version
272  *  wMin [I] minor version
273  *  lcid [I] locale id
274  *  path [O] path of typelib
275  *
276  * RETURNS
277  *  Success: S_OK.
278  *  Failure: If the type library is not registered then TYPE_E_LIBNOTREGISTERED
279  *  or TYPE_E_REGISTRYACCESS if the type library registration key couldn't be
280  *  opened.
281  */
282 HRESULT WINAPI QueryPathOfRegTypeLib(
283         REFGUID guid,
284         WORD wMaj,
285         WORD wMin,
286         LCID lcid,
287         LPBSTR path )
288 {
289     HRESULT hr = TYPE_E_LIBNOTREGISTERED;
290     LCID myLCID = lcid;
291     HKEY hkey;
292     WCHAR buffer[60];
293     WCHAR Path[MAX_PATH];
294     LONG res;
295 
296     TRACE_(typelib)("(%s, %x.%x, 0x%x, %p)\n", debugstr_guid(guid), wMaj, wMin, lcid, path);
297 
298     if (!find_typelib_key( guid, wMaj, &wMin )) return TYPE_E_LIBNOTREGISTERED;
299     get_typelib_key( guid, wMaj, wMin, buffer );
300 
301     res = RegOpenKeyExW( HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hkey );
302     if (res == ERROR_FILE_NOT_FOUND)
303     {
304         TRACE_(typelib)("%s not found\n", debugstr_w(buffer));
305         return TYPE_E_LIBNOTREGISTERED;
306     }
307     else if (res != ERROR_SUCCESS)
308     {
309         TRACE_(typelib)("failed to open %s for read access\n", debugstr_w(buffer));
310         return TYPE_E_REGISTRYACCESS;
311     }
312 
313     while (hr != S_OK)
314     {
315         LONG dwPathLen = sizeof(Path);
316 
317         get_lcid_subkey( myLCID, SYS_WIN32, buffer );
318 
319         if (RegQueryValueW(hkey, buffer, Path, &dwPathLen))
320         {
321             if (!lcid)
322                 break;
323             else if (myLCID == lcid)
324             {
325                 /* try with sub-langid */
326                 myLCID = SUBLANGID(lcid);
327             }
328             else if ((myLCID == SUBLANGID(lcid)) && myLCID)
329             {
330                 /* try with system langid */
331                 myLCID = 0;
332             }
333             else
334             {
335                 break;
336             }
337         }
338         else
339         {
340             *path = SysAllocString( Path );
341             hr = S_OK;
342         }
343     }
344     RegCloseKey( hkey );
345     TRACE_(typelib)("-- 0x%08x\n", hr);
346     return hr;
347 }
348 
349 /******************************************************************************
350  * CreateTypeLib [OLEAUT32.160]  creates a typelib
351  *
352  * RETURNS
353  *    Success: S_OK
354  *    Failure: Status
355  */
356 HRESULT WINAPI CreateTypeLib(
357         SYSKIND syskind, LPCOLESTR szFile, ICreateTypeLib** ppctlib
358 ) {
359     FIXME("(%d,%s,%p), stub!\n",syskind,debugstr_w(szFile),ppctlib);
360     return E_FAIL;
361 }
362 
363 /******************************************************************************
364  *              LoadTypeLib     [OLEAUT32.161]
365  *
366  * Loads a type library
367  *
368  * PARAMS
369  *  szFile [I] Name of file to load from.
370  *  pptLib [O] Pointer that receives ITypeLib object on success.
371  *
372  * RETURNS
373  *    Success: S_OK
374  *    Failure: Status
375  *
376  * SEE
377  *  LoadTypeLibEx, LoadRegTypeLib, CreateTypeLib.
378  */
379 HRESULT WINAPI LoadTypeLib(const OLECHAR *szFile, ITypeLib * *pptLib)
380 {
381     TRACE("(%s,%p)\n",debugstr_w(szFile), pptLib);
382     return LoadTypeLibEx(szFile, REGKIND_DEFAULT, pptLib);
383 }
384 
385 /******************************************************************************
386  *              LoadTypeLibEx   [OLEAUT32.183]
387  *
388  * Loads and optionally registers a type library
389  *
390  * RETURNS
391  *    Success: S_OK
392  *    Failure: Status
393  */
394 HRESULT WINAPI LoadTypeLibEx(
395     LPCOLESTR szFile,  /* [in] Name of file to load from */
396     REGKIND  regkind,  /* [in] Specify kind of registration */
397     ITypeLib **pptLib) /* [out] Pointer to pointer to loaded type library */
398 {
399     WCHAR szPath[MAX_PATH+1];
400     HRESULT res;
401 
402     TRACE("(%s,%d,%p)\n",debugstr_w(szFile), regkind, pptLib);
403 
404     *pptLib = NULL;
405 
406     res = TLB_ReadTypeLib(szFile, szPath, MAX_PATH + 1, (ITypeLib2**)pptLib);
407 
408     if (SUCCEEDED(res))
409         switch(regkind)
410         {
411             case REGKIND_DEFAULT:
412                 /* don't register typelibs supplied with full path. Experimentation confirms the following */
413                 if (((szFile[0] == '\\') && (szFile[1] == '\\')) ||
414                     (szFile[0] && (szFile[1] == ':'))) break;
415                 /* else fall-through */
416 
417             case REGKIND_REGISTER:
418                 if (FAILED(res = RegisterTypeLib(*pptLib, szPath, NULL)))
419                 {
420                     IUnknown_Release(*pptLib);
421                     *pptLib = 0;
422                 }
423                 break;
424             case REGKIND_NONE:
425                 break;
426         }
427 
428     TRACE(" returns %08x\n",res);
429     return res;
430 }
431 
432 /******************************************************************************
433  *              LoadRegTypeLib  [OLEAUT32.162]
434  *
435  * Loads a registered type library.
436  *
437  * PARAMS
438  *  rguid     [I] GUID of the registered type library.
439  *  wVerMajor [I] major version.
440  *  wVerMinor [I] minor version.
441  *  lcid      [I] locale ID.
442  *  ppTLib    [O] pointer that receives an ITypeLib object on success.
443  *
444  * RETURNS
445  *  Success: S_OK.
446  *  Failure: Any HRESULT code returned from QueryPathOfRegTypeLib or
447  *  LoadTypeLib.
448  */
449 HRESULT WINAPI LoadRegTypeLib(
450         REFGUID rguid,
451         WORD wVerMajor,
452         WORD wVerMinor,
453         LCID lcid,
454         ITypeLib **ppTLib)
455 {
456     BSTR bstr=NULL;
457     HRESULT res;
458 
459     *ppTLib = NULL;
460 
461     res = QueryPathOfRegTypeLib( rguid, wVerMajor, wVerMinor, lcid, &bstr);
462 
463     if(SUCCEEDED(res))
464     {
465         res= LoadTypeLib(bstr, ppTLib);
466         SysFreeString(bstr);
467     }
468 
469     TRACE("(IID: %s) load %s (%p)\n",debugstr_guid(rguid), SUCCEEDED(res)? "SUCCESS":"FAILED", *ppTLib);
470 
471     return res;
472 }
473 
474 
475 /* some string constants shared between RegisterTypeLib and UnRegisterTypeLib */
476 static const WCHAR TypeLibW[] = {'T','y','p','e','L','i','b',0};
477 static const WCHAR FLAGSW[] = {'F','L','A','G','S',0};
478 static const WCHAR HELPDIRW[] = {'H','E','L','P','D','I','R',0};
479 static const WCHAR ProxyStubClsidW[] = {'P','r','o','x','y','S','t','u','b','C','l','s','i','d',0};
480 static const WCHAR ProxyStubClsid32W[] = {'P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
481 
482 /******************************************************************************
483  *              RegisterTypeLib [OLEAUT32.163]
484  * Adds information about a type library to the System Registry
485  * NOTES
486  *    Docs: ITypeLib FAR * ptlib
487  *    Docs: OLECHAR FAR* szFullPath
488  *    Docs: OLECHAR FAR* szHelpDir
489  *
490  * RETURNS
491  *    Success: S_OK
492  *    Failure: Status
493  */
494 HRESULT WINAPI RegisterTypeLib(
495      ITypeLib * ptlib,     /* [in] Pointer to the library*/
496      OLECHAR * szFullPath, /* [in] full Path of the library*/
497      OLECHAR * szHelpDir)  /* [in] dir to the helpfile for the library,
498                                                          may be NULL*/
499 {
500     static const WCHAR PSOA[] = {'{','','','','2','','4','2','4','-',
501                                  '','','','','-','','','','','-','C','','','','-',
502                                  '','','','','','','','','','','4','6','}',0};
503     HRESULT res;
504     TLIBATTR *attr;
505     WCHAR keyName[60];
506     WCHAR tmp[16];
507     HKEY key, subKey;
508     UINT types, tidx;
509     TYPEKIND kind;
510     DWORD disposition;
511 
512     if (ptlib == NULL || szFullPath == NULL)
513         return E_INVALIDARG;
514 
515     if (FAILED(ITypeLib_GetLibAttr(ptlib, &attr)))
516         return E_FAIL;
517 
518     get_typelib_key( &attr->guid, attr->wMajorVerNum, attr->wMinorVerNum, keyName );
519 
520     res = S_OK;
521     if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0,
522         KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS)
523     {
524         LPOLESTR doc;
525 
526         /* Set the human-readable name of the typelib */
527         if (SUCCEEDED(ITypeLib_GetDocumentation(ptlib, -1, NULL, &doc, NULL, NULL)))
528         {
529             if (RegSetValueExW(key, NULL, 0, REG_SZ,
530                 (BYTE *)doc, (lstrlenW(doc)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS)
531                 res = E_FAIL;
532 
533             SysFreeString(doc);
534         }
535         else
536             res = E_FAIL;
537 
538         /* Make up the name of the typelib path subkey */
539         if (!get_lcid_subkey( attr->lcid, attr->syskind, tmp )) res = E_FAIL;
540 
541         /* Create the typelib path subkey */
542         if (res == S_OK && RegCreateKeyExW(key, tmp, 0, NULL, 0,
543             KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
544         {
545             if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
546                 (BYTE *)szFullPath, (lstrlenW(szFullPath)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS)
547                 res = E_FAIL;
548 
549             RegCloseKey(subKey);
550         }
551         else
552             res = E_FAIL;
553 
554         /* Create the flags subkey */
555         if (res == S_OK && RegCreateKeyExW(key, FLAGSW, 0, NULL, 0,
556             KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
557         {
558             /* FIXME: is %u correct? */
559             static const WCHAR formatW[] = {'%','u',0};
560             WCHAR buf[20];
561             sprintfW(buf, formatW, attr->wLibFlags);
562             if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
563                                (BYTE *)buf, (strlenW(buf) + 1)*sizeof(WCHAR) ) != ERROR_SUCCESS)
564                 res = E_FAIL;
565 
566             RegCloseKey(subKey);
567         }
568         else
569             res = E_FAIL;
570 
571         /* create the helpdir subkey */
572         if (res == S_OK && RegCreateKeyExW(key, HELPDIRW, 0, NULL, 0,
573             KEY_WRITE, NULL, &subKey, &disposition) == ERROR_SUCCESS)
574         {
575             BOOL freeHelpDir = FALSE;
576             OLECHAR* pIndexStr;
577 
578             /* if we created a new key, and helpDir was null, set the helpdir
579                to the directory which contains the typelib. However,
580                if we just opened an existing key, we leave the helpdir alone */
581             if ((disposition == REG_CREATED_NEW_KEY) && (szHelpDir == NULL)) {
582                 szHelpDir = SysAllocString(szFullPath);
583                 pIndexStr = strrchrW(szHelpDir, '\\');
584                 if (pIndexStr) {
585                     *pIndexStr = 0;
586                 }
587                 freeHelpDir = TRUE;
588             }
589 
590             /* if we have an szHelpDir, set it! */
591             if (szHelpDir != NULL) {
592                 if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
593                     (BYTE *)szHelpDir, (lstrlenW(szHelpDir)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS) {
594                     res = E_FAIL;
595                 }
596             }
597 
598             /* tidy up */
599             if (freeHelpDir) SysFreeString(szHelpDir);
600             RegCloseKey(subKey);
601 
602         } else {
603             res = E_FAIL;
604         }
605 
606         RegCloseKey(key);
607     }
608     else
609         res = E_FAIL;
610 
611     /* register OLE Automation-compatible interfaces for this typelib */
612     types = ITypeLib_GetTypeInfoCount(ptlib);
613     for (tidx=0; tidx<types; tidx++) {
614         if (SUCCEEDED(ITypeLib_GetTypeInfoType(ptlib, tidx, &kind))) {
615             LPOLESTR name = NULL;
616             ITypeInfo *tinfo = NULL;
617 
618             ITypeLib_GetDocumentation(ptlib, tidx, &name, NULL, NULL, NULL);
619 
620             switch (kind) {
621             case TKIND_INTERFACE:
622                 TRACE_(typelib)("%d: interface %s\n", tidx, debugstr_w(name));
623                 ITypeLib_GetTypeInfo(ptlib, tidx, &tinfo);
624                 break;
625 
626             case TKIND_DISPATCH:
627                 TRACE_(typelib)("%d: dispinterface %s\n", tidx, debugstr_w(name));
628                 ITypeLib_GetTypeInfo(ptlib, tidx, &tinfo);
629                 break;
630 
631             default:
632                 TRACE_(typelib)("%d: %s\n", tidx, debugstr_w(name));
633                 break;
634             }
635 
636             if (tinfo) {
637                 TYPEATTR *tattr = NULL;
638                 ITypeInfo_GetTypeAttr(tinfo, &tattr);
639 
640                 if (tattr) {
641                     TRACE_(typelib)("guid=%s, flags=%04x (",
642                                     debugstr_guid(&tattr->guid),
643                                     tattr->wTypeFlags);
644 
645                     if (TRACE_ON(typelib)) {
646 #define XX(x) if (TYPEFLAG_##x & tattr->wTypeFlags) MESSAGE(#x"|");
647                         XX(FAPPOBJECT);
648                         XX(FCANCREATE);
649                         XX(FLICENSED);
650                         XX(FPREDECLID);
651                         XX(FHIDDEN);
652                         XX(FCONTROL);
653                         XX(FDUAL);
654                         XX(FNONEXTENSIBLE);
655                         XX(FOLEAUTOMATION);
656                         XX(FRESTRICTED);
657                         XX(FAGGREGATABLE);
658                         XX(FREPLACEABLE);
659                         XX(FDISPATCHABLE);
660                         XX(FREVERSEBIND);
661                         XX(FPROXY);
662 #undef XX
663                         MESSAGE("\n");
664                     }
665 
666                     if (tattr->wTypeFlags & (TYPEFLAG_FOLEAUTOMATION|TYPEFLAG_FDUAL|TYPEFLAG_FDISPATCHABLE))
667                     {
668                         /* register interface<->typelib coupling */
669                         get_interface_key( &tattr->guid, keyName );
670                         if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0,
671                                             KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS)
672                         {
673                             if (name)
674                                 RegSetValueExW(key, NULL, 0, REG_SZ,
675                                                (BYTE *)name, (strlenW(name)+1) * sizeof(OLECHAR));
676 
677                             if (RegCreateKeyExW(key, ProxyStubClsidW, 0, NULL, 0,
678                                 KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) {
679                                 RegSetValueExW(subKey, NULL, 0, REG_SZ,
680                                                (const BYTE *)PSOA, sizeof PSOA);
681                                 RegCloseKey(subKey);
682                             }
683 
684                             if (RegCreateKeyExW(key, ProxyStubClsid32W, 0, NULL, 0,
685                                 KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) {
686                                 RegSetValueExW(subKey, NULL, 0, REG_SZ,
687                                                (const BYTE *)PSOA, sizeof PSOA);
688                                 RegCloseKey(subKey);
689                             }
690 
691                             if (RegCreateKeyExW(key, TypeLibW, 0, NULL, 0,
692                                 KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
693                             {
694                                 WCHAR buffer[40];
695                                 static const WCHAR fmtver[] = {'%','x','.','%','x',0 };
696                                 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
697 
698                                 StringFromGUID2(&attr->guid, buffer, 40);
699                                 RegSetValueExW(subKey, NULL, 0, REG_SZ,
700                                                (BYTE *)buffer, (strlenW(buffer)+1) * sizeof(WCHAR));
701                                 sprintfW(buffer, fmtver, attr->wMajorVerNum, attr->wMinorVerNum);
702                                 RegSetValueExW(subKey, VersionW, 0, REG_SZ,
703                                                (BYTE*)buffer, (strlenW(buffer)+1) * sizeof(WCHAR));
704                                 RegCloseKey(subKey);
705                             }
706 
707                             RegCloseKey(key);
708                         }
709                     }
710 
711                     ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
712                 }
713 
714                 ITypeInfo_Release(tinfo);
715             }
716 
717             SysFreeString(name);
718         }
719     }
720 
721     ITypeLib_ReleaseTLibAttr(ptlib, attr);
722 
723     return res;
724 }
725 
726 
727 /******************************************************************************
728  *      UnRegisterTypeLib       [OLEAUT32.186]
729  * Removes information about a type library from the System Registry
730  * NOTES
731  *
732  * RETURNS
733  *    Success: S_OK
734  *    Failure: Status
735  */
736 HRESULT WINAPI UnRegisterTypeLib(
737     REFGUID libid,      /* [in] Guid of the library */
738         WORD wVerMajor, /* [in] major version */
739         WORD wVerMinor, /* [in] minor version */
740         LCID lcid,      /* [in] locale id */
741         SYSKIND syskind)
742 {
743     BSTR tlibPath = NULL;
744     DWORD tmpLength;
745     WCHAR keyName[60];
746     WCHAR subKeyName[50];
747     int result = S_OK;
748     DWORD i = 0;
749     BOOL deleteOtherStuff;
750     HKEY key = NULL;
751     HKEY subKey = NULL;
752     TYPEATTR* typeAttr = NULL;
753     TYPEKIND kind;
754     ITypeInfo* typeInfo = NULL;
755     ITypeLib* typeLib = NULL;
756     int numTypes;
757 
758     TRACE("(IID: %s)\n",debugstr_guid(libid));
759 
760     /* Create the path to the key */
761     get_typelib_key( libid, wVerMajor, wVerMinor, keyName );
762 
763     if (syskind != SYS_WIN16 && syskind != SYS_WIN32)
764     {
765         TRACE("Unsupported syskind %i\n", syskind);
766         result = E_INVALIDARG;
767         goto end;
768     }
769 
770     /* get the path to the typelib on disk */
771     if (QueryPathOfRegTypeLib(libid, wVerMajor, wVerMinor, lcid, &tlibPath) != S_OK) {
772         result = E_INVALIDARG;
773         goto end;
774     }
775 
776     /* Try and open the key to the type library. */
777     if (RegOpenKeyExW(HKEY_CLASSES_ROOT, keyName, 0, KEY_READ | KEY_WRITE, &key) != ERROR_SUCCESS) {
778         result = E_INVALIDARG;
779         goto end;
780     }
781 
782     /* Try and load the type library */
783     if (LoadTypeLibEx(tlibPath, REGKIND_NONE, &typeLib)) {
784         result = TYPE_E_INVALIDSTATE;
785         goto end;
786     }
787 
788     /* remove any types registered with this typelib */
789     numTypes = ITypeLib_GetTypeInfoCount(typeLib);
790     for (i=0; i<numTypes; i++) {
791         /* get the kind of type */
792         if (ITypeLib_GetTypeInfoType(typeLib, i, &kind) != S_OK) {
793             goto enddeleteloop;
794         }
795 
796         /* skip non-interfaces, and get type info for the type */
797         if ((kind != TKIND_INTERFACE) && (kind != TKIND_DISPATCH)) {
798             goto enddeleteloop;
799         }
800         if (ITypeLib_GetTypeInfo(typeLib, i, &typeInfo) != S_OK) {
801             goto enddeleteloop;
802         }
803         if (ITypeInfo_GetTypeAttr(typeInfo, &typeAttr) != S_OK) {
804             goto enddeleteloop;
805         }
806 
807         /* the path to the type */
808         get_interface_key( &typeAttr->guid, subKeyName );
809 
810         /* Delete its bits */
811         if (RegOpenKeyExW(HKEY_CLASSES_ROOT, subKeyName, 0, KEY_WRITE, &subKey) != ERROR_SUCCESS) {
812             goto enddeleteloop;
813         }
814         RegDeleteKeyW(subKey, ProxyStubClsidW);
815         RegDeleteKeyW(subKey, ProxyStubClsid32W);
816         RegDeleteKeyW(subKey, TypeLibW);
817         RegCloseKey(subKey);
818         subKey = NULL;
819         RegDeleteKeyW(HKEY_CLASSES_ROOT, subKeyName);
820 
821 enddeleteloop:
822         if (typeAttr) ITypeInfo_ReleaseTypeAttr(typeInfo, typeAttr);
823         typeAttr = NULL;
824         if (typeInfo) ITypeInfo_Release(typeInfo);
825         typeInfo = NULL;
826     }
827 
828     /* Now, delete the type library path subkey */
829     get_lcid_subkey( lcid, syskind, subKeyName );
830     RegDeleteKeyW(key, subKeyName);
831     *strrchrW( subKeyName, '\\' ) = 0;  /* remove last path component */
832     RegDeleteKeyW(key, subKeyName);
833 
834     /* check if there is anything besides the FLAGS/HELPDIR keys.
835        If there is, we don't delete them */
836     tmpLength = sizeof(subKeyName)/sizeof(WCHAR);
837     deleteOtherStuff = TRUE;
838     i = 0;
839     while(RegEnumKeyExW(key, i++, subKeyName, &tmpLength, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
840         tmpLength = sizeof(subKeyName)/sizeof(WCHAR);
841 
842         /* if its not FLAGS or HELPDIR, then we must keep the rest of the key */
843         if (!strcmpW(subKeyName, FLAGSW)) continue;
844         if (!strcmpW(subKeyName, HELPDIRW)) continue;
845         deleteOtherStuff = FALSE;
846         break;
847     }
848 
849     /* only delete the other parts of the key if we're absolutely sure */
850     if (deleteOtherStuff) {
851         RegDeleteKeyW(key, FLAGSW);
852         RegDeleteKeyW(key, HELPDIRW);
853         RegCloseKey(key);
854         key = NULL;
855 
856         RegDeleteKeyW(HKEY_CLASSES_ROOT, keyName);
857         *strrchrW( keyName, '\\' ) = 0;  /* remove last path component */
858         RegDeleteKeyW(HKEY_CLASSES_ROOT, keyName);
859     }
860 
861 end:
862     SysFreeString(tlibPath);
863     if (typeLib) ITypeLib_Release(typeLib);
864     if (subKey) RegCloseKey(subKey);
865     if (key) RegCloseKey(key);
866     return result;
867 }
868 
869 /*======================= ITypeLib implementation =======================*/
870 
871 typedef struct tagTLBCustData
872 {
873     GUID guid;
874     VARIANT data;
875     struct tagTLBCustData* next;
876 } TLBCustData;
877 
878 /* data structure for import typelibs */
879 typedef struct tagTLBImpLib
880 {
881     int offset;                 /* offset in the file (MSFT)
882                                    offset in nametable (SLTG)
883                                    just used to identify library while reading
884                                    data from file */
885     GUID guid;                  /* libid */
886     BSTR name;                  /* name */
887 
888     LCID lcid;                  /* lcid of imported typelib */
889 
890     WORD wVersionMajor;         /* major version number */
891     WORD wVersionMinor;         /* minor version number */
892 
893     struct tagITypeLibImpl *pImpTypeLib; /* pointer to loaded typelib, or
894                                             NULL if not yet loaded */
895     struct tagTLBImpLib * next;
896 } TLBImpLib;
897 
898 /* internal ITypeLib data */
899 typedef struct tagITypeLibImpl
900 {
901     const ITypeLib2Vtbl *lpVtbl;
902     const ITypeCompVtbl *lpVtblTypeComp;
903     LONG ref;
904     TLIBATTR LibAttr;            /* guid,lcid,syskind,version,flags */
905 
906     /* strings can be stored in tlb as multibyte strings BUT they are *always*
907      * exported to the application as a UNICODE string.
908      */
909     BSTR Name;
910     BSTR DocString;
911     BSTR HelpFile;
912     BSTR HelpStringDll;
913     unsigned long  dwHelpContext;
914     int TypeInfoCount;          /* nr of typeinfo's in librarry */
915     struct tagITypeInfoImpl *pTypeInfo;   /* linked list of type info data */
916     int ctCustData;             /* number of items in cust data list */
917     TLBCustData * pCustData;    /* linked list to cust data */
918     TLBImpLib   * pImpLibs;     /* linked list to all imported typelibs */
919     int ctTypeDesc;             /* number of items in type desc array */
920     TYPEDESC * pTypeDesc;       /* array of TypeDescriptions found in the
921                                    library. Only used while reading MSFT
922                                    typelibs */
923     struct list ref_list;       /* list of ref types in this typelib */
924     HREFTYPE dispatch_href;     /* reference to IDispatch, -1 if unused */
925 
926 
927     /* typelibs are cached, keyed by path and index, so store the linked list info within them */
928     struct tagITypeLibImpl *next, *prev;
929     WCHAR *path;
930     INT index;
931 } ITypeLibImpl;
932 
933 static const ITypeLib2Vtbl tlbvt;
934 static const ITypeCompVtbl tlbtcvt;
935 
936 static inline ITypeLibImpl *impl_from_ITypeComp( ITypeComp *iface )
937 {
938     return (ITypeLibImpl *)((char*)iface - FIELD_OFFSET(ITypeLibImpl, lpVtblTypeComp));
939 }
940 
941 /* ITypeLib methods */
942 static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength);
943 static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength);
944 
945 /*======================= ITypeInfo implementation =======================*/
946 
947 /* data for referenced types */
948 typedef struct tagTLBRefType
949 {
950     INT index;              /* Type index for internal ref or for external ref
951                                it the format is SLTG.  -2 indicates to
952                                use guid */
953 
954     GUID guid;              /* guid of the referenced type */
955                             /* if index == TLB_REF_USE_GUID */
956 
957     HREFTYPE reference;     /* The href of this ref */
958     TLBImpLib *pImpTLInfo;  /* If ref is external ptr to library data
959                                TLB_REF_INTERNAL for internal refs
960                                TLB_REF_NOT_FOUND for broken refs */
961 
962     struct list entry;
963 } TLBRefType;
964 
965 #define TLB_REF_USE_GUID -2
966 
967 #define TLB_REF_INTERNAL (void*)-2
968 #define TLB_REF_NOT_FOUND (void*)-1
969 
970 /* internal Parameter data */
971 typedef struct tagTLBParDesc
972 {
973     BSTR Name;
974     int ctCustData;
975     TLBCustData * pCustData;        /* linked list to cust data */
976 } TLBParDesc;
977 
978 /* internal Function data */
979 typedef struct tagTLBFuncDesc
980 {
981     FUNCDESC funcdesc;      /* lots of info on the function and its attributes. */
982     BSTR Name;             /* the name of this function */
983     TLBParDesc *pParamDesc; /* array with param names and custom data */
984     int helpcontext;
985     int HelpStringContext;
986     BSTR HelpString;
987     BSTR Entry;            /* if its Hiword==0, it numeric; -1 is not present*/
988     int ctCustData;
989     TLBCustData * pCustData;        /* linked list to cust data; */
990     struct tagTLBFuncDesc * next;
991 } TLBFuncDesc;
992 
993 /* internal Variable data */
994 typedef struct tagTLBVarDesc
995 {
996     VARDESC vardesc;        /* lots of info on the variable and its attributes. */
997     BSTR Name;             /* the name of this variable */
998     int HelpContext;
999     int HelpStringContext;  /* FIXME: where? */
1000     BSTR HelpString;
1001     int ctCustData;
1002     TLBCustData * pCustData;/* linked list to cust data; */
1003     struct tagTLBVarDesc * next;
1004 } TLBVarDesc;
1005 
1006 /* internal implemented interface data */
1007 typedef struct tagTLBImplType
1008 {
1009     HREFTYPE hRef;          /* hRef of interface */
1010     int implflags;          /* IMPLFLAG_*s */
1011     int ctCustData;
1012     TLBCustData * pCustData;/* linked list to custom data; */
1013     struct tagTLBImplType *next;
1014 } TLBImplType;
1015 
1016 /* internal TypeInfo data */
1017 typedef struct tagITypeInfoImpl
1018 {
1019     const ITypeInfo2Vtbl *lpVtbl;
1020     const ITypeCompVtbl  *lpVtblTypeComp;
1021     LONG ref;
1022     BOOL no_free_data; /* don't free data structures */
1023     TYPEATTR TypeAttr ;         /* _lots_ of type information. */
1024     ITypeLibImpl * pTypeLib;        /* back pointer to typelib */
1025     int index;                  /* index in this typelib; */
1026     HREFTYPE hreftype;          /* hreftype for app object binding */
1027     /* type libs seem to store the doc strings in ascii
1028      * so why should we do it in unicode?
1029      */
1030     BSTR Name;
1031     BSTR DocString;
1032     BSTR DllName;
1033     unsigned long  dwHelpContext;
1034     unsigned long  dwHelpStringContext;
1035 
1036     /* functions  */
1037     TLBFuncDesc * funclist;     /* linked list with function descriptions */
1038 
1039     /* variables  */
1040     TLBVarDesc * varlist;       /* linked list with variable descriptions */
1041 
1042     /* Implemented Interfaces  */
1043     TLBImplType * impltypelist;
1044 
1045     int ctCustData;
1046     TLBCustData * pCustData;        /* linked list to cust data; */
1047     struct tagITypeInfoImpl * next;
1048 } ITypeInfoImpl;
1049 
1050 static inline ITypeInfoImpl *info_impl_from_ITypeComp( ITypeComp *iface )
1051 {
1052     return (ITypeInfoImpl *)((char*)iface - FIELD_OFFSET(ITypeInfoImpl, lpVtblTypeComp));
1053 }
1054 
1055 static const ITypeInfo2Vtbl tinfvt;
1056 static const ITypeCompVtbl  tcompvt;
1057 
1058 static ITypeInfo2 * ITypeInfo_Constructor(void);
1059 
1060 typedef struct tagTLBContext
1061 {
1062         unsigned int oStart;  /* start of TLB in file */
1063         unsigned int pos;     /* current pos */
1064         unsigned int length;  /* total length */
1065         void *mapping;        /* memory mapping */
1066         MSFT_SegDir * pTblDir;
1067         ITypeLibImpl* pLibInfo;
1068 } TLBContext;
1069 
1070 
1071 static void MSFT_DoRefType(TLBContext *pcx, ITypeLibImpl *pTL, int offset);
1072 
1073 /*
1074  debug
1075 */
1076 static void dump_TypeDesc(const TYPEDESC *pTD,char *szVarType) {
1077     if (pTD->vt & VT_RESERVED)
1078         szVarType += strlen(strcpy(szVarType, "reserved | "));
1079     if (pTD->vt & VT_BYREF)
1080         szVarType += strlen(strcpy(szVarType, "ref to "));
1081     if (pTD->vt & VT_ARRAY)
1082         szVarType += strlen(strcpy(szVarType, "array of "));
1083     if (pTD->vt & VT_VECTOR)
1084         szVarType += strlen(strcpy(szVarType, "vector of "));
1085     switch(pTD->vt & VT_TYPEMASK) {
1086     case VT_UI1: sprintf(szVarType, "VT_UI1"); break;
1087     case VT_I2: sprintf(szVarType, "VT_I2"); break;
1088     case VT_I4: sprintf(szVarType, "VT_I4"); break;
1089     case VT_R4: sprintf(szVarType, "VT_R4"); break;
1090     case VT_R8: sprintf(szVarType, "VT_R8"); break;
1091     case VT_BOOL: sprintf(szVarType, "VT_BOOL"); break;
1092     case VT_ERROR: sprintf(szVarType, "VT_ERROR"); break;
1093     case VT_CY: sprintf(szVarType, "VT_CY"); break;
1094     case VT_DATE: sprintf(szVarType, "VT_DATE"); break;
1095     case VT_BSTR: sprintf(szVarType, "VT_BSTR"); break;
1096     case VT_UNKNOWN: sprintf(szVarType, "VT_UNKNOWN"); break;
1097     case VT_DISPATCH: sprintf(szVarType, "VT_DISPATCH"); break;
1098     case VT_I1: sprintf(szVarType, "VT_I1"); break;
1099     case VT_UI2: sprintf(szVarType, "VT_UI2"); break;
1100     case VT_UI4: sprintf(szVarType, "VT_UI4"); break;
1101     case VT_INT: sprintf(szVarType, "VT_INT"); break;
1102     case VT_UINT: sprintf(szVarType, "VT_UINT"); break;
1103     case VT_VARIANT: sprintf(szVarType, "VT_VARIANT"); break;
1104     case VT_VOID: sprintf(szVarType, "VT_VOID"); break;
1105     case VT_HRESULT: sprintf(szVarType, "VT_HRESULT"); break;
1106     case VT_USERDEFINED: sprintf(szVarType, "VT_USERDEFINED ref = %x",
1107                                  pTD->u.hreftype); break;
1108     case VT_LPSTR: sprintf(szVarType, "VT_LPSTR"); break;
1109     case VT_LPWSTR: sprintf(szVarType, "VT_LPWSTR"); break;
1110     case VT_PTR: sprintf(szVarType, "ptr to ");
1111       dump_TypeDesc(pTD->u.lptdesc, szVarType + 7);
1112       break;
1113     case VT_SAFEARRAY: sprintf(szVarType, "safearray of ");
1114       dump_TypeDesc(pTD->u.lptdesc, szVarType + 13);
1115       break;
1116     case VT_CARRAY: sprintf(szVarType, "%d dim array of ",
1117                             pTD->u.lpadesc->cDims); /* FIXME print out sizes */
1118       dump_TypeDesc(&pTD->u.lpadesc->tdescElem, szVarType + strlen(szVarType));
1119       break;
1120 
1121     default: sprintf(szVarType, "unknown(%d)", pTD->vt & VT_TYPEMASK); break;
1122     }
1123 }
1124 
1125 static void dump_ELEMDESC(const ELEMDESC *edesc) {
1126   char buf[200];
1127   USHORT flags = edesc->u.paramdesc.wParamFlags;
1128   dump_TypeDesc(&edesc->tdesc,buf);
1129   MESSAGE("\t\ttdesc.vartype %d (%s)\n",edesc->tdesc.vt,buf);
1130   MESSAGE("\t\tu.paramdesc.wParamFlags");
1131   if (!flags) MESSAGE(" PARAMFLAGS_NONE");
1132   if (flags & PARAMFLAG_FIN) MESSAGE(" PARAMFLAG_FIN");
1133   if (flags & PARAMFLAG_FOUT) MESSAGE(" PARAMFLAG_FOUT");
1134   if (flags & PARAMFLAG_FLCID) MESSAGE(" PARAMFLAG_FLCID");
1135   if (flags & PARAMFLAG_FRETVAL) MESSAGE(" PARAMFLAG_FRETVAL");
1136   if (flags & PARAMFLAG_FOPT) MESSAGE(" PARAMFLAG_FOPT");
1137   if (flags & PARAMFLAG_FHASDEFAULT) MESSAGE(" PARAMFLAG_FHASDEFAULT");
1138   if (flags & PARAMFLAG_FHASCUSTDATA) MESSAGE(" PARAMFLAG_FHASCUSTDATA");
1139   MESSAGE("\n\t\tu.paramdesc.lpex %p\n",edesc->u.paramdesc.pparamdescex);
1140 }
1141 static void dump_FUNCDESC(const FUNCDESC *funcdesc) {
1142   int i;
1143   MESSAGE("memid is %08x\n",funcdesc->memid);
1144   for (i=0;i<funcdesc->cParams;i++) {
1145       MESSAGE("Param %d:\n",i);
1146       dump_ELEMDESC(funcdesc->lprgelemdescParam+i);
1147   }
1148   MESSAGE("\tfunckind: %d (",funcdesc->funckind);
1149   switch (funcdesc->funckind) {
1150   case FUNC_VIRTUAL: MESSAGE("virtual");break;
1151   case FUNC_PUREVIRTUAL: MESSAGE("pure virtual");break;
1152   case FUNC_NONVIRTUAL: MESSAGE("nonvirtual");break;
1153   case FUNC_STATIC: MESSAGE("static");break;
1154   case FUNC_DISPATCH: MESSAGE("dispatch");break;
1155   default: MESSAGE("unknown");break;
1156   }
1157   MESSAGE(")\n\tinvkind: %d (",funcdesc->invkind);
1158   switch (funcdesc->invkind) {
1159   case INVOKE_FUNC: MESSAGE("func");break;
1160   case INVOKE_PROPERTYGET: MESSAGE("property get");break;
1161   case INVOKE_PROPERTYPUT: MESSAGE("property put");break;
1162   case INVOKE_PROPERTYPUTREF: MESSAGE("property put ref");break;
1163   }
1164   MESSAGE(")\n\tcallconv: %d (",funcdesc->callconv);
1165   switch (funcdesc->callconv) {
1166   case CC_CDECL: MESSAGE("cdecl");break;
1167   case CC_PASCAL: MESSAGE("pascal");break;
1168   case CC_STDCALL: MESSAGE("stdcall");break;
1169   case CC_SYSCALL: MESSAGE("syscall");break;
1170   default:break;
1171   }
1172   MESSAGE(")\n\toVft: %d\n", funcdesc->oVft);
1173   MESSAGE("\tcParamsOpt: %d\n", funcdesc->cParamsOpt);
1174   MESSAGE("\twFlags: %x\n", funcdesc->wFuncFlags);
1175 
1176   MESSAGE("\telemdescFunc (return value type):\n");
1177   dump_ELEMDESC(&funcdesc->elemdescFunc);
1178 }
1179 
1180 static const char * const typekind_desc[] =
1181 {
1182         "TKIND_ENUM",
1183         "TKIND_RECORD",
1184         "TKIND_MODULE",
1185         "TKIND_INTERFACE",
1186         "TKIND_DISPATCH",
1187         "TKIND_COCLASS",
1188         "TKIND_ALIAS",
1189         "TKIND_UNION",
1190         "TKIND_MAX"
1191 };
1192 
1193 static void dump_TLBFuncDescOne(const TLBFuncDesc * pfd)
1194 {
1195   int i;
1196   MESSAGE("%s(%u)\n", debugstr_w(pfd->Name), pfd->funcdesc.cParams);
1197   for (i=0;i<pfd->funcdesc.cParams;i++)
1198       MESSAGE("\tparm%d: %s\n",i,debugstr_w(pfd->pParamDesc[i].Name));
1199 
1200 
1201   dump_FUNCDESC(&(pfd->funcdesc));
1202 
1203   MESSAGE("\thelpstring: %s\n", debugstr_w(pfd->HelpString));
1204   MESSAGE("\tentry: %s\n", (pfd->Entry == (void *)-1) ? "invalid" : debugstr_w(pfd->Entry));
1205 }
1206 static void dump_TLBFuncDesc(const TLBFuncDesc * pfd)
1207 {
1208         while (pfd)
1209         {
1210           dump_TLBFuncDescOne(pfd);
1211           pfd = pfd->next;
1212         };
1213 }
1214 static void dump_TLBVarDesc(const TLBVarDesc * pvd)
1215 {
1216         while (pvd)
1217         {
1218           TRACE_(typelib)("%s\n", debugstr_w(pvd->Name));
1219           pvd = pvd->next;
1220         };
1221 }
1222 
1223 static void dump_TLBImpLib(const TLBImpLib *import)
1224 {
1225     TRACE_(typelib)("%s %s\n", debugstr_guid(&(import->guid)),
1226                     debugstr_w(import->name));
1227     TRACE_(typelib)("v%d.%d lcid=%x offset=%x\n", import->wVersionMajor,
1228                     import->wVersionMinor, import->lcid, import->offset);
1229 }
1230 
1231 static void dump_TLBRefType(const ITypeLibImpl *pTL)
1232 {
1233     TLBRefType *ref;
1234 
1235     LIST_FOR_EACH_ENTRY(ref, &pTL->ref_list, TLBRefType, entry)
1236     {
1237         TRACE_(typelib)("href:0x%08x\n", ref->reference);
1238         if(ref->index == -1)
1239             TRACE_(typelib)("%s\n", debugstr_guid(&(ref->guid)));
1240         else
1241             TRACE_(typelib)("type no: %d\n", ref->index);
1242 
1243         if(ref->pImpTLInfo != TLB_REF_INTERNAL && ref->pImpTLInfo != TLB_REF_NOT_FOUND)
1244         {
1245             TRACE_(typelib)("in lib\n");
1246             dump_TLBImpLib(ref->pImpTLInfo);
1247         }
1248     }
1249 }
1250 
1251 static void dump_TLBImplType(const TLBImplType * impl)
1252 {
1253     while (impl) {
1254         TRACE_(typelib)(
1255                 "implementing/inheriting interface hRef = %x implflags %x\n",
1256                 impl->hRef, impl->implflags);
1257         impl = impl->next;
1258     }
1259 }
1260 
1261 static void dump_Variant(const VARIANT * pvar)
1262 {
1263     SYSTEMTIME st;
1264 
1265     TRACE("%p->{%s%s", pvar, debugstr_VT(pvar), debugstr_VF(pvar));
1266 
1267     if (pvar)
1268     {
1269       if (V_ISBYREF(pvar) || V_TYPE(pvar) == VT_UNKNOWN ||
1270           V_TYPE(pvar) == VT_DISPATCH || V_TYPE(pvar) == VT_RECORD)
1271       {
1272         TRACE(",%p", V_BYREF(pvar));
1273       }
1274       else if (V_ISARRAY(pvar) || V_ISVECTOR(pvar))
1275       {
1276         TRACE(",%p", V_ARRAY(pvar));
1277       }
1278       else switch (V_TYPE(pvar))
1279       {
1280       case VT_I1:   TRACE(",%d", V_I1(pvar)); break;
1281       case VT_UI1:  TRACE(",%d", V_UI1(pvar)); break;
1282       case VT_I2:   TRACE(",%d", V_I2(pvar)); break;
1283       case VT_UI2:  TRACE(",%d", V_UI2(pvar)); break;
1284       case VT_INT:
1285       case VT_I4:   TRACE(",%d", V_I4(pvar)); break;
1286       case VT_UINT:
1287       case VT_UI4:  TRACE(",%d", V_UI4(pvar)); break;
1288       case VT_I8:   TRACE(",0x%08x,0x%08x", (ULONG)(V_I8(pvar) >> 32),
1289                           (ULONG)(V_I8(pvar) & 0xffffffff)); break;
1290       case VT_UI8:  TRACE(",0x%08x,0x%08x", (ULONG)(V_UI8(pvar) >> 32),
1291                           (ULONG)(V_UI8(pvar) & 0xffffffff)); break;
1292       case VT_R4:   TRACE(",%3.3e", V_R4(pvar)); break;
1293       case VT_R8:   TRACE(",%3.3e", V_R8(pvar)); break;
1294       case VT_BOOL: TRACE(",%s", V_BOOL(pvar) ? "TRUE" : "FALSE"); break;
1295       case VT_BSTR: TRACE(",%s", debugstr_w(V_BSTR(pvar))); break;
1296       case VT_CY:   TRACE(",0x%08x,0x%08x", V_CY(pvar).s.Hi,
1297                            V_CY(pvar).s.Lo); break;
1298       case VT_DATE:
1299         if(!VariantTimeToSystemTime(V_DATE(pvar), &st))
1300           TRACE(",<invalid>");
1301         else
1302           TRACE(",%04d/%02d/%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay,
1303                 st.wHour, st.wMinute, st.wSecond);
1304         break;
1305       case VT_ERROR:
1306       case VT_VOID:
1307       case VT_USERDEFINED:
1308       case VT_EMPTY:
1309       case VT_NULL:  break;
1310       default:       TRACE(",?"); break;
1311       }
1312     }
1313     TRACE("}\n");
1314 }
1315 
1316 static void dump_DispParms(const DISPPARAMS * pdp)
1317 {
1318     unsigned int index;
1319 
1320     TRACE("args=%u named args=%u\n", pdp->cArgs, pdp->cNamedArgs);
1321 
1322     if (pdp->cNamedArgs && pdp->rgdispidNamedArgs)
1323     {
1324         TRACE("named args:\n");
1325         for (index = 0; index < pdp->cNamedArgs; index++)
1326             TRACE( "\t0x%x\n", pdp->rgdispidNamedArgs[index] );
1327     }
1328 
1329     if (pdp->cArgs && pdp->rgvarg)
1330     {
1331         TRACE("args:\n");
1332         for (index = 0; index < pdp->cArgs; index++)
1333             dump_Variant( &pdp->rgvarg[index] );
1334     }
1335 }
1336 
1337 static void dump_TypeInfo(const ITypeInfoImpl * pty)
1338 {
1339     TRACE("%p ref=%u\n", pty, pty->ref);
1340     TRACE("%s %s\n", debugstr_w(pty->Name), debugstr_w(pty->DocString));
1341     TRACE("attr:%s\n", debugstr_guid(&(pty->TypeAttr.guid)));
1342     TRACE("kind:%s\n", typekind_desc[pty->TypeAttr.typekind]);
1343     TRACE("fct:%u var:%u impl:%u\n",
1344       pty->TypeAttr.cFuncs, pty->TypeAttr.cVars, pty->TypeAttr.cImplTypes);
1345     TRACE("wTypeFlags: 0x%04x\n", pty->TypeAttr.wTypeFlags);
1346     TRACE("parent tlb:%p index in TLB:%u\n",pty->pTypeLib, pty->index);
1347     if (pty->TypeAttr.typekind == TKIND_MODULE) TRACE("dllname:%s\n", debugstr_w(pty->DllName));
1348     if (TRACE_ON(ole))
1349         dump_TLBFuncDesc(pty->funclist);
1350     dump_TLBVarDesc(pty->varlist);
1351     dump_TLBImplType(pty->impltypelist);
1352 }
1353 
1354 static void dump_VARDESC(const VARDESC *v)
1355 {
1356     MESSAGE("memid %d\n",v->memid);
1357     MESSAGE("lpstrSchema %s\n",debugstr_w(v->lpstrSchema));
1358     MESSAGE("oInst %d\n",v->u.oInst);
1359     dump_ELEMDESC(&(v->elemdescVar));
1360     MESSAGE("wVarFlags %x\n",v->wVarFlags);
1361     MESSAGE("varkind %d\n",v->varkind);
1362 }
1363 
1364 static TYPEDESC stndTypeDesc[VT_LPWSTR+1]=
1365 {
1366     /* VT_LPWSTR is largest type that */
1367     /* may appear in type description*/
1368     {{0}, 0},{{0}, 1},{{0}, 2},{{0}, 3},{{0}, 4},
1369     {{0}, 5},{{0}, 6},{{0}, 7},{{0}, 8},{{0}, 9},
1370     {{0},10},{{0},11},{{0},12},{{0},13},{{0},14},
1371     {{0},15},{{0},16},{{0},17},{{0},18},{{0},19},
1372     {{0},20},{{0},21},{{0},22},{{0},23},{{0},24},
1373     {{0},25},{{0},26},{{0},27},{{0},28},{{0},29},
1374     {{0},30},{{0},31}
1375 };
1376 
1377 static void TLB_abort(void)
1378 {
1379     DebugBreak();
1380 }
1381 
1382 static void * TLB_Alloc(unsigned size) __WINE_ALLOC_SIZE(1);
1383 static void * TLB_Alloc(unsigned size)
1384 {
1385     void * ret;
1386     if((ret=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size))==NULL){
1387         /* FIXME */
1388         ERR("cannot allocate memory\n");
1389     }
1390     return ret;
1391 }
1392 
1393 static void TLB_Free(void * ptr)
1394 {
1395     HeapFree(GetProcessHeap(), 0, ptr);
1396 }
1397 
1398 /* returns the size required for a deep copy of a typedesc into a
1399  * flat buffer */
1400 static SIZE_T TLB_SizeTypeDesc( const TYPEDESC *tdesc, BOOL alloc_initial_space )
1401 {
1402     SIZE_T size = 0;
1403 
1404     if (alloc_initial_space)
1405         size += sizeof(TYPEDESC);
1406 
1407     switch (tdesc->vt)
1408     {
1409     case VT_PTR:
1410     case VT_SAFEARRAY:
1411         size += TLB_SizeTypeDesc(tdesc->u.lptdesc, TRUE);
1412         break;
1413     case VT_CARRAY:
1414         size += FIELD_OFFSET(ARRAYDESC, rgbounds[tdesc->u.lpadesc->cDims]);
1415         size += TLB_SizeTypeDesc(&tdesc->u.lpadesc->tdescElem, FALSE);
1416         break;
1417     }
1418     return size;
1419 }
1420 
1421 /* deep copy a typedesc into a flat buffer */
1422 static void *TLB_CopyTypeDesc( TYPEDESC *dest, const TYPEDESC *src, void *buffer )
1423 {
1424     if (!dest)
1425     {
1426         dest = buffer;
1427         buffer = (char *)buffer + sizeof(TYPEDESC);
1428     }
1429 
1430     *dest = *src;
1431 
1432     switch (src->vt)
1433     {
1434     case VT_PTR:
1435     case VT_SAFEARRAY:
1436         dest->u.lptdesc = buffer;
1437         buffer = TLB_CopyTypeDesc(NULL, src->u.lptdesc, buffer);
1438         break;
1439     case VT_CARRAY:
1440         dest->u.lpadesc = buffer;
1441         memcpy(dest->u.lpadesc, src->u.lpadesc, FIELD_OFFSET(ARRAYDESC, rgbounds[src->u.lpadesc->cDims]));
1442         buffer = (char *)buffer + FIELD_OFFSET(ARRAYDESC, rgbounds[src->u.lpadesc->cDims]);
1443         buffer = TLB_CopyTypeDesc(&dest->u.lpadesc->tdescElem, &src->u.lpadesc->tdescElem, buffer);
1444         break;
1445     }
1446     return buffer;
1447 }
1448 
1449 /* free custom data allocated by MSFT_CustData */
1450 static inline void TLB_FreeCustData(TLBCustData *pCustData)
1451 {
1452     TLBCustData *pCustDataNext;
1453     for (; pCustData; pCustData = pCustDataNext)
1454     {
1455         VariantClear(&pCustData->data);
1456 
1457         pCustDataNext = pCustData->next;
1458         TLB_Free(pCustData);
1459     }
1460 }
1461 
1462 static BSTR TLB_MultiByteToBSTR(const char *ptr)
1463 {
1464     DWORD len;
1465     BSTR ret;
1466 
1467     len = MultiByteToWideChar(CP_ACP, 0, ptr, -1, NULL, 0);
1468     ret = SysAllocStringLen(NULL, len - 1);
1469     if (!ret) return ret;
1470     MultiByteToWideChar(CP_ACP, 0, ptr, -1, ret, len);
1471     return ret;
1472 }
1473 
1474 /**********************************************************************
1475  *
1476  *  Functions for reading MSFT typelibs (those created by CreateTypeLib2)
1477  */
1478 static inline unsigned int MSFT_Tell(const TLBContext *pcx)
1479 {
1480     return pcx->pos;
1481 }
1482 
1483 static inline void MSFT_Seek(TLBContext *pcx, long where)
1484 {
1485     if (where != DO_NOT_SEEK)
1486     {
1487         where += pcx->oStart;
1488         if (where > pcx->length)
1489         {
1490             /* FIXME */
1491             ERR("seek beyond end (%ld/%d)\n", where, pcx->length );
1492             TLB_abort();
1493         }
1494         pcx->pos = where;
1495     }
1496 }
1497 
1498 /* read function */
1499 static DWORD MSFT_Read(void *buffer,  DWORD count, TLBContext *pcx, long where )
1500 {
1501     TRACE_(typelib)("pos=0x%08x len=0x%08x 0x%08x 0x%08x 0x%08lx\n",
1502        pcx->pos, count, pcx->oStart, pcx->length, where);
1503 
1504     MSFT_Seek(pcx, where);
1505     if (pcx->pos + count > pcx->length) count = pcx->length - pcx->pos;
1506     memcpy( buffer, (char *)pcx->mapping + pcx->pos, count );
1507     pcx->pos += count;
1508     return count;
1509 }
1510 
1511 static DWORD MSFT_ReadLEDWords(void *buffer,  DWORD count, TLBContext *pcx,
1512                                long where )
1513 {
1514   DWORD ret;
1515 
1516   ret = MSFT_Read(buffer, count, pcx, where);
1517   FromLEDWords(buffer, ret);
1518 
1519   return ret;
1520 }
1521 
1522 static DWORD MSFT_ReadLEWords(void *buffer,  DWORD count, TLBContext *pcx,
1523                               long where )
1524 {
1525   DWORD ret;
1526 
1527   ret = MSFT_Read(buffer, count, pcx, where);
1528   FromLEWords(buffer, ret);
1529 
1530   return ret;
1531 }
1532 
1533 static void MSFT_ReadGuid( GUID *pGuid, int offset, TLBContext *pcx)
1534 {
1535     if(offset<0 || pcx->pTblDir->pGuidTab.offset <0){
1536         memset(pGuid,0, sizeof(GUID));
1537         return;
1538     }
1539     MSFT_Read(pGuid, sizeof(GUID), pcx, pcx->pTblDir->pGuidTab.offset+offset );
1540     pGuid->Data1 = FromLEDWord(pGuid->Data1);
1541     pGuid->Data2 = FromLEWord(pGuid->Data2);
1542     pGuid->Data3 = FromLEWord(pGuid->Data3);
1543     TRACE_(typelib)("%s\n", debugstr_guid(pGuid));
1544 }
1545 
1546 static HREFTYPE MSFT_ReadHreftype( TLBContext *pcx, int offset )
1547 {
1548     MSFT_NameIntro niName;
1549 
1550     if (offset < 0)
1551     {
1552         ERR_(typelib)("bad offset %d\n", offset);
1553         return -1;
1554     }
1555 
1556     MSFT_ReadLEDWords(&niName, sizeof(niName), pcx,
1557                       pcx->pTblDir->pNametab.offset+offset);
1558 
1559     return niName.hreftype;
1560 }
1561 
1562 static BSTR MSFT_ReadName( TLBContext *pcx, int offset)
1563 {
1564     char * name;
1565     MSFT_NameIntro niName;
1566     int lengthInChars;
1567     BSTR bstrName = NULL;
1568 
1569     if (offset < 0)
1570     {
1571         ERR_(typelib)("bad offset %d\n", offset);
1572         return NULL;
1573     }
1574     MSFT_ReadLEDWords(&niName, sizeof(niName), pcx,
1575                       pcx->pTblDir->pNametab.offset+offset);
1576     niName.namelen &= 0xFF; /* FIXME: correct ? */
1577     name=TLB_Alloc((niName.namelen & 0xff) +1);
1578     MSFT_Read(name, (niName.namelen & 0xff), pcx, DO_NOT_SEEK);
1579     name[niName.namelen & 0xff]='\0';
1580 
1581     lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
1582                                         name, -1, NULL, 0);
1583 
1584     /* no invalid characters in string */
1585     if (lengthInChars)
1586     {
1587         bstrName = SysAllocStringByteLen(NULL, lengthInChars * sizeof(WCHAR));
1588 
1589         /* don't check for invalid character since this has been done previously */
1590         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name, -1, bstrName, lengthInChars);
1591     }
1592     TLB_Free(name);
1593 
1594     TRACE_(typelib)("%s %d\n", debugstr_w(bstrName), lengthInChars);
1595     return bstrName;
1596 }
1597 
1598 static BSTR MSFT_ReadString( TLBContext *pcx, int offset)
1599 {
1600     char * string;
1601     INT16 length;
1602     int lengthInChars;
1603     BSTR bstr = NULL;
1604 
1605     if(offset<0) return NULL;
1606     MSFT_ReadLEWords(&length, sizeof(INT16), pcx, pcx->pTblDir->pStringtab.offset+offset);
1607     if(length <= 0) return 0;
1608     string=TLB_Alloc(length +1);
1609     MSFT_Read(string, length, pcx, DO_NOT_SEEK);
1610     string[length]='\0';
1611 
1612     lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
1613                                         string, -1, NULL, 0);
1614 
1615     /* no invalid characters in string */
1616     if (lengthInChars)
1617     {
1618         bstr = SysAllocStringByteLen(NULL, lengthInChars * sizeof(WCHAR));
1619 
1620         /* don't check for invalid character since this has been done previously */
1621         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, string, -1, bstr, lengthInChars);
1622     }
1623     TLB_Free(string);
1624 
1625     TRACE_(typelib)("%s %d\n", debugstr_w(bstr), lengthInChars);
1626     return bstr;
1627 }
1628 /*
1629  * read a value and fill a VARIANT structure
1630  */
1631 static void MSFT_ReadValue( VARIANT * pVar, int offset, TLBContext *pcx )
1632 {
1633     int size;
1634 
1635     TRACE_(typelib)("\n");
1636 
1637     if(offset <0) { /* data are packed in here */
1638         V_VT(pVar) = (offset & 0x7c000000 )>> 26;
1639         V_I4(pVar) = offset & 0x3ffffff;
1640         return;
1641     }
1642     MSFT_ReadLEWords(&(V_VT(pVar)), sizeof(VARTYPE), pcx,
1643                      pcx->pTblDir->pCustData.offset + offset );
1644     TRACE_(typelib)("Vartype = %x\n", V_VT(pVar));
1645     switch (V_VT(pVar)){
1646         case VT_EMPTY:  /* FIXME: is this right? */
1647         case VT_NULL:   /* FIXME: is this right? */
1648         case VT_I2  :   /* this should not happen */
1649         case VT_I4  :
1650         case VT_R4  :
1651         case VT_ERROR   :
1652         case VT_BOOL    :
1653         case VT_I1  :
1654         case VT_UI1 :
1655         case VT_UI2 :
1656         case VT_UI4 :
1657         case VT_INT :
1658         case VT_UINT    :
1659         case VT_VOID    : /* FIXME: is this right? */
1660         case VT_HRESULT :
1661             size=4; break;
1662         case VT_R8  :
1663         case VT_CY  :
1664         case VT_DATE    :
1665         case VT_I8  :
1666         case VT_UI8 :
1667         case VT_DECIMAL :  /* FIXME: is this right? */
1668         case VT_FILETIME :
1669             size=8;break;
1670             /* pointer types with known behaviour */
1671         case VT_BSTR    :{
1672             char * ptr;
1673             MSFT_ReadLEDWords(&size, sizeof(INT), pcx, DO_NOT_SEEK );
1674             if(size < 0) {
1675                 char next;
1676                 DWORD origPos = MSFT_Tell(pcx), nullPos;
1677 
1678                 do {
1679                     MSFT_Read(&next, 1, pcx, DO_NOT_SEEK);
1680                 } while (next);
1681                 nullPos = MSFT_Tell(pcx);
1682                 size = nullPos - origPos;
1683                 MSFT_Seek(pcx, origPos);
1684             }
1685             ptr=TLB_Alloc(size);/* allocate temp buffer */
1686             MSFT_Read(ptr, size, pcx, DO_NOT_SEEK);/* read string (ANSI) */
1687             V_BSTR(pVar)=SysAllocStringLen(NULL,size);
1688             /* FIXME: do we need a AtoW conversion here? */
1689             V_UNION(pVar, bstrVal[size])='\0';
1690             while(size--) V_UNION(pVar, bstrVal[size])=ptr[size];
1691             TLB_Free(ptr);
1692         }
1693         size=-4; break;
1694     /* FIXME: this will not work AT ALL when the variant contains a pointer */
1695         case VT_DISPATCH :
1696         case VT_VARIANT :
1697         case VT_UNKNOWN :
1698         case VT_PTR :
1699         case VT_SAFEARRAY :
1700         case VT_CARRAY  :
1701         case VT_USERDEFINED :
1702         case VT_LPSTR   :
1703         case VT_LPWSTR  :
1704         case VT_BLOB    :
1705         case VT_STREAM  :
1706         case VT_STORAGE :
1707         case VT_STREAMED_OBJECT :
1708         case VT_STORED_OBJECT   :
1709         case VT_BLOB_OBJECT :
1710         case VT_CF  :
1711         case VT_CLSID   :
1712         default:
1713             size=0;
1714             FIXME("VARTYPE %d is not supported, setting pointer to NULL\n",
1715                 V_VT(pVar));
1716     }
1717 
1718     if(size>0) /* (big|small) endian correct? */
1719         MSFT_Read(&(V_I2(pVar)), size, pcx, DO_NOT_SEEK );
1720     return;
1721 }
1722 /*
1723  * create a linked list with custom data
1724  */
1725 static int MSFT_CustData( TLBContext *pcx, int offset, TLBCustData** ppCustData )
1726 {
1727     MSFT_CDGuid entry;
1728     TLBCustData* pNew;
1729     int count=0;
1730 
1731     TRACE_(typelib)("\n");
1732 
1733     while(offset >=0){
1734         count++;
1735         pNew=TLB_Alloc(sizeof(TLBCustData));
1736         MSFT_ReadLEDWords(&entry, sizeof(entry), pcx, pcx->pTblDir->pCDGuids.offset+offset);
1737         MSFT_ReadGuid(&(pNew->guid), entry.GuidOffset , pcx);
1738         MSFT_ReadValue(&(pNew->data), entry.DataOffset, pcx);
1739         /* add new custom data at head of the list */
1740         pNew->next=*ppCustData;
1741         *ppCustData=pNew;
1742         offset = entry.next;
1743     }
1744     return count;
1745 }
1746 
1747 static void MSFT_GetTdesc(TLBContext *pcx, INT type, TYPEDESC *pTd,
1748                           ITypeInfoImpl *pTI)
1749 {
1750     if(type <0)
1751         pTd->vt=type & VT_TYPEMASK;
1752     else
1753         *pTd=pcx->pLibInfo->pTypeDesc[type/(2*sizeof(INT))];
1754 
1755     if(pTd->vt == VT_USERDEFINED)
1756       MSFT_DoRefType(pcx, pTI->pTypeLib, pTd->u.hreftype);
1757 
1758     TRACE_(typelib)("vt type = %X\n", pTd->vt);
1759 }
1760 
1761 static void MSFT_ResolveReferencedTypes(TLBContext *pcx, ITypeInfoImpl *pTI, TYPEDESC *lpTypeDesc)
1762 {
1763     /* resolve referenced type if any */
1764     while (lpTypeDesc)
1765     {
1766         switch (lpTypeDesc->vt)
1767         {
1768         case VT_PTR:
1769             lpTypeDesc = lpTypeDesc->u.lptdesc;
1770             break;
1771 
1772         case VT_CARRAY:
1773             lpTypeDesc = & (lpTypeDesc->u.lpadesc->tdescElem);
1774             break;
1775 
1776         case VT_USERDEFINED:
1777             MSFT_DoRefType(pcx, pTI->pTypeLib,
1778                            lpTypeDesc->u.hreftype);
1779 
1780             lpTypeDesc = NULL;
1781             break;
1782 
1783         default:
1784             lpTypeDesc = NULL;
1785         }
1786     }
1787 }
1788 
1789 static void
1790 MSFT_DoFuncs(TLBContext*     pcx,
1791             ITypeInfoImpl*  pTI,
1792             int             cFuncs,
1793             int             cVars,
1794             int             offset,
1795             TLBFuncDesc**   pptfd)
1796 {
1797     /*
1798      * member information is stored in a data structure at offset
1799      * indicated by the memoffset field of the typeinfo structure
1800      * There are several distinctive parts.
1801      * The first part starts with a field that holds the total length
1802      * of this (first) part excluding this field. Then follow the records,
1803      * for each member there is one record.
1804      *
1805      * The first entry is always the length of the record (including this
1806      * length word).
1807      * The rest of the record depends on the type of the member. If there is
1808      * a field indicating the member type (function, variable, interface, etc)
1809      * I have not found it yet. At this time we depend on the information
1810      * in the type info and the usual order how things are stored.
1811      *
1812      * Second follows an array sized nrMEM*sizeof(INT) with a member id
1813      * for each member;
1814      *
1815      * Third is an equal sized array with file offsets to the name entry
1816      * of each member.
1817      *
1818      * The fourth and last (?) part is an array with offsets to the records
1819      * in the first part of this file segment.
1820      */
1821 
1822     int infolen, nameoffset, reclength, nrattributes, i;
1823     int recoffset = offset + sizeof(INT);
1824 
1825     char *recbuf = HeapAlloc(GetProcessHeap(), 0, 0xffff);
1826     MSFT_FuncRecord * pFuncRec=(MSFT_FuncRecord *) recbuf;
1827     TLBFuncDesc *ptfd_prev = NULL;
1828 
1829     TRACE_(typelib)("\n");
1830 
1831     MSFT_ReadLEDWords(&infolen, sizeof(INT), pcx, offset);
1832 
1833     for ( i = 0; i < cFuncs ; i++ )
1834     {
1835         *pptfd = TLB_Alloc(sizeof(TLBFuncDesc));
1836 
1837         /* name, eventually add to a hash table */
1838         MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx,
1839                           offset + infolen + (cFuncs + cVars + i + 1) * sizeof(INT));
1840 
1841         /* nameoffset is sometimes -1 on the second half of a propget/propput
1842          * pair of functions */
1843         if ((nameoffset == -1) && (i > 0))
1844             (*pptfd)->Name = SysAllocString(ptfd_prev->Name);
1845         else
1846             (*pptfd)->Name = MSFT_ReadName(pcx, nameoffset);
1847 
1848         /* read the function information record */
1849         MSFT_ReadLEDWords(&reclength, sizeof(INT), pcx, recoffset);
1850 
1851         reclength &= 0xffff;
1852 
1853         MSFT_ReadLEDWords(pFuncRec, reclength - sizeof(INT), pcx, DO_NOT_SEEK);
1854 
1855         /* do the attributes */
1856         nrattributes = (reclength - pFuncRec->nrargs * 3 * sizeof(int) - 0x18)
1857                        / sizeof(int);
1858 
1859         if ( nrattributes > 0 )
1860         {
1861             (*pptfd)->helpcontext = pFuncRec->OptAttr[0] ;
1862 
1863             if ( nrattributes > 1 )
1864             {
1865                 (*pptfd)->HelpString = MSFT_ReadString(pcx,
1866                                                       pFuncRec->OptAttr[1]) ;
1867 
1868                 if ( nrattributes > 2 )
1869                 {
1870                     if ( pFuncRec->FKCCIC & 0x2000 )
1871                     {
1872                        if (HIWORD(pFuncRec->OptAttr[2]) != 0)
1873                            ERR("ordinal 0x%08x invalid, HIWORD != 0\n", pFuncRec->OptAttr[2]);
1874                        (*pptfd)->Entry = (BSTR)pFuncRec->OptAttr[2];
1875                     }
1876                     else
1877                     {
1878                         (*pptfd)->Entry = MSFT_ReadString(pcx,
1879                                                          pFuncRec->OptAttr[2]);
1880                     }
1881                     if( nrattributes > 5 )
1882                     {
1883                         (*pptfd)->HelpStringContext = pFuncRec->OptAttr[5] ;
1884 
1885                         if ( nrattributes > 6 && pFuncRec->FKCCIC & 0x80 )
1886                         {
1887                             MSFT_CustData(pcx,
1888                                           pFuncRec->OptAttr[6],
1889                                           &(*pptfd)->pCustData);
1890                         }
1891                     }
1892                 }
1893                 else
1894                 {
1895                     (*pptfd)->Entry = (BSTR)-1;
1896                 }
1897             }
1898         }
1899 
1900         /* fill the FuncDesc Structure */
1901         MSFT_ReadLEDWords( & (*pptfd)->funcdesc.memid, sizeof(INT), pcx,
1902                            offset + infolen + ( i + 1) * sizeof(INT));
1903 
1904         (*pptfd)->funcdesc.funckind   =  (pFuncRec->FKCCIC)      & 0x7;
1905         (*pptfd)->funcdesc.invkind    =  (pFuncRec->FKCCIC) >> 3 & 0xF;
1906         (*pptfd)->funcdesc.callconv   =  (pFuncRec->FKCCIC) >> 8 & 0xF;
1907         (*pptfd)->funcdesc.cParams    =   pFuncRec->nrargs  ;
1908         (*pptfd)->funcdesc.cParamsOpt =   pFuncRec->nroargs ;
1909         (*pptfd)->funcdesc.oVft       =   (pFuncRec->VtableOffset * sizeof(void *))/4;
1910         (*pptfd)->funcdesc.wFuncFlags =   LOWORD(pFuncRec->Flags) ;
1911 
1912         MSFT_GetTdesc(pcx,
1913                       pFuncRec->DataType,
1914                       &(*pptfd)->funcdesc.elemdescFunc.tdesc,
1915                       pTI);
1916         MSFT_ResolveReferencedTypes(pcx, pTI, &(*pptfd)->funcdesc.elemdescFunc.tdesc);
1917 
1918         /* do the parameters/arguments */
1919         if(pFuncRec->nrargs)
1920         {
1921             int j = 0;
1922             MSFT_ParameterInfo paraminfo;
1923 
1924             (*pptfd)->funcdesc.lprgelemdescParam =
1925                 TLB_Alloc(pFuncRec->nrargs * sizeof(ELEMDESC));
1926 
1927             (*pptfd)->pParamDesc =
1928                 TLB_Alloc(pFuncRec->nrargs * sizeof(TLBParDesc));
1929 
1930             MSFT_ReadLEDWords(&paraminfo, sizeof(paraminfo), pcx,
1931                               recoffset + reclength - pFuncRec->nrargs * sizeof(MSFT_ParameterInfo));
1932 
1933             for ( j = 0 ; j < pFuncRec->nrargs ; j++ )
1934             {
1935                 ELEMDESC *elemdesc = &(*pptfd)->funcdesc.lprgelemdescParam[j];
1936 
1937                 MSFT_GetTdesc(pcx,
1938                               paraminfo.DataType,
1939                               &elemdesc->tdesc,
1940                               pTI);
1941 
1942                 elemdesc->u.paramdesc.wParamFlags = paraminfo.Flags;
1943 
1944                 /* name */
1945                 if (paraminfo.oName == -1)
1946                     /* this occurs for [propput] or [propget] methods, so
1947                      * we should just set the name of the parameter to the
1948                      * name of the method. */
1949                     (*pptfd)->pParamDesc[j].Name = SysAllocString((*pptfd)->Name);
1950                 else
1951                     (*pptfd)->pParamDesc[j].Name =
1952                         MSFT_ReadName( pcx, paraminfo.oName );
1953                 TRACE_(typelib)("param[%d] = %s\n", j, debugstr_w((*pptfd)->pParamDesc[j].Name));
1954 
1955                 MSFT_ResolveReferencedTypes(pcx, pTI, &elemdesc->tdesc);
1956 
1957                 /* default value */
1958                 if ( (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) &&
1959                      (pFuncRec->FKCCIC & 0x1000) )
1960                 {
1961                     INT* pInt = (INT *)((char *)pFuncRec +
1962                                    reclength -
1963                                    (pFuncRec->nrargs * 4 + 1) * sizeof(INT) );
1964 
1965                     PARAMDESC* pParamDesc = &elemdesc->u.paramdesc;
1966 
1967                     pParamDesc->pparamdescex = TLB_Alloc(sizeof(PARAMDESCEX));
1968                     pParamDesc->pparamdescex->cBytes = sizeof(PARAMDESCEX);
1969 
1970                     MSFT_ReadValue(&(pParamDesc->pparamdescex->varDefaultValue),
1971                         pInt[j], pcx);
1972                 }
1973                 else
1974                     elemdesc->u.paramdesc.pparamdescex = NULL;
1975                 /* custom info */
1976                 if ( nrattributes > 7 + j && pFuncRec->FKCCIC & 0x80 )
1977                 {
1978                     MSFT_CustData(pcx,
1979                                   pFuncRec->OptAttr[7+j],
1980                                   &(*pptfd)->pParamDesc[j].pCustData);
1981                 }
1982 
1983                 /* SEEK value = jump to offset,
1984                  * from there jump to the end of record,
1985                  * go back by (j-1) arguments
1986                  */
1987                 MSFT_ReadLEDWords( &paraminfo ,
1988                            sizeof(MSFT_ParameterInfo), pcx,
1989                            recoffset + reclength - ((pFuncRec->nrargs - j - 1)
1990                                                * sizeof(MSFT_ParameterInfo)));
1991             }
1992         }
1993 
1994         /* scode is not used: archaic win16 stuff FIXME: right? */
1995         (*pptfd)->funcdesc.cScodes   = 0 ;
1996         (*pptfd)->funcdesc.lprgscode = NULL ;
1997 
1998         ptfd_prev = *pptfd;
1999         pptfd      = & ((*pptfd)->next);
2000         recoffset += reclength;
2001     }
2002     HeapFree(GetProcessHeap(), 0, recbuf);
2003 }
2004 
2005 static void MSFT_DoVars(TLBContext *pcx, ITypeInfoImpl *pTI, int cFuncs,
2006                        int cVars, int offset, TLBVarDesc ** pptvd)
2007 {
2008     int infolen, nameoffset, reclength;
2009     char recbuf[256];
2010     MSFT_VarRecord * pVarRec=(MSFT_VarRecord *) recbuf;
2011     int i;
2012     int recoffset;
2013 
2014     TRACE_(typelib)("\n");
2015 
2016     MSFT_ReadLEDWords(&infolen,sizeof(INT), pcx, offset);
2017     MSFT_ReadLEDWords(&recoffset,sizeof(INT), pcx, offset + infolen +
2018                       ((cFuncs+cVars)*2+cFuncs + 1)*sizeof(INT));
2019     recoffset += offset+sizeof(INT);
2020     for(i=0;i<cVars;i++){
2021         *pptvd=TLB_Alloc(sizeof(TLBVarDesc));
2022     /* name, eventually add to a hash table */
2023         MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx,
2024                           offset + infolen + (2*cFuncs + cVars + i + 1) * sizeof(INT));
2025         (*pptvd)->Name=MSFT_ReadName(pcx, nameoffset);
2026     /* read the variable information record */
2027         MSFT_ReadLEDWords(&reclength, sizeof(INT), pcx, recoffset);
2028         reclength &=0xff;
2029         MSFT_ReadLEDWords(pVarRec, reclength - sizeof(INT), pcx, DO_NOT_SEEK);
2030     /* Optional data */
2031         if(reclength >(6*sizeof(INT)) )
2032             (*pptvd)->HelpContext=pVarRec->HelpContext;
2033         if(reclength >(7*sizeof(INT)) )
2034             (*pptvd)->HelpString = MSFT_ReadString(pcx, pVarRec->oHelpString) ;
2035         if(reclength >(8*sizeof(INT)) )
2036         if(reclength >(9*sizeof(INT)) )
2037             (*pptvd)->HelpStringContext=pVarRec->HelpStringContext;
2038     /* fill the VarDesc Structure */
2039         MSFT_ReadLEDWords(&(*pptvd)->vardesc.memid, sizeof(INT), pcx,
2040                           offset + infolen + (cFuncs + i + 1) * sizeof(INT));
2041         (*pptvd)->vardesc.varkind = pVarRec->VarKind;
2042         (*pptvd)->vardesc.wVarFlags = pVarRec->Flags;
2043         MSFT_GetTdesc(pcx, pVarRec->DataType,
2044             &(*pptvd)->vardesc.elemdescVar.tdesc, pTI);
2045 /*   (*pptvd)->vardesc.lpstrSchema; is reserved (SDK) FIXME?? */
2046         if(pVarRec->VarKind == VAR_CONST ){
2047             (*pptvd)->vardesc.u.lpvarValue=TLB_Alloc(sizeof(VARIANT));
2048             MSFT_ReadValue((*pptvd)->vardesc.u.lpvarValue,
2049                 pVarRec->OffsValue, pcx);
2050         } else
2051             (*pptvd)->vardesc.u.oInst=pVarRec->OffsValue;
2052         MSFT_ResolveReferencedTypes(pcx, pTI, &(*pptvd)->vardesc.elemdescVar.tdesc);
2053         pptvd=&((*pptvd)->next);
2054         recoffset += reclength;
2055     }
2056 }
2057 /* fill in data for a hreftype (offset). When the referenced type is contained
2058  * in the typelib, it's just an (file) offset in the type info base dir.
2059  * If comes from import, it's an offset+1 in the ImpInfo table
2060  * */
2061 static void MSFT_DoRefType(TLBContext *pcx, ITypeLibImpl *pTL,
2062                           int offset)
2063 {
2064     TLBRefType *ref;
2065 
2066     TRACE_(typelib)("TLB context %p, TLB offset %x\n", pcx, offset);
2067 
2068     LIST_FOR_EACH_ENTRY(ref, &pTL->ref_list, TLBRefType, entry)
2069     {
2070         if(ref->reference == offset) return;
2071     }
2072 
2073     ref = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ref));
2074     list_add_tail(&pTL->ref_list, &ref->entry);
2075 
2076     if(!MSFT_HREFTYPE_INTHISFILE( offset)) {
2077         /* external typelib */
2078         MSFT_ImpInfo impinfo;
2079         TLBImpLib *pImpLib=(pcx->pLibInfo->pImpLibs);
2080 
2081         TRACE_(typelib)("offset %x, masked offset %x\n", offset, offset + (offset & 0xfffffffc));
2082 
2083         MSFT_ReadLEDWords(&impinfo, sizeof(impinfo), pcx,
2084                           pcx->pTblDir->pImpInfo.offset + (offset & 0xfffffffc));
2085         while (pImpLib){   /* search the known offsets of all import libraries */
2086             if(pImpLib->offset==impinfo.oImpFile) break;
2087             pImpLib=pImpLib->next;
2088         }
2089         if(pImpLib){
2090             ref->reference = offset;
2091             ref->pImpTLInfo = pImpLib;
2092             if(impinfo.flags & MSFT_IMPINFO_OFFSET_IS_GUID) {
2093                 MSFT_ReadGuid(&ref->guid, impinfo.oGuid, pcx);
2094                 TRACE("importing by guid %s\n", debugstr_guid(&ref->guid));
2095                 ref->index = TLB_REF_USE_GUID;
2096             } else
2097                 ref->index = impinfo.oGuid;
2098         }else{
2099             ERR("Cannot find a reference\n");
2100             ref->reference = -1;
2101             ref->pImpTLInfo = TLB_REF_NOT_FOUND;
2102         }
2103     }else{
2104         /* in this typelib */
2105         ref->index = MSFT_HREFTYPE_INDEX(offset);
2106         ref->reference = offset;
2107         ref->pImpTLInfo = TLB_REF_INTERNAL;
2108     }
2109 }
2110 
2111 /* process Implemented Interfaces of a com class */
2112 static void MSFT_DoImplTypes(TLBContext *pcx, ITypeInfoImpl *pTI, int count,
2113                             int offset)
2114 {
2115     int i;
2116     MSFT_RefRecord refrec;
2117     TLBImplType **ppImpl = &pTI->impltypelist;
2118 
2119     TRACE_(typelib)("\n");
2120 
2121     for(i=0;i<count;i++){
2122         if(offset<0) break; /* paranoia */
2123         *ppImpl=TLB_Alloc(sizeof(**ppImpl));
2124         MSFT_ReadLEDWords(&refrec,sizeof(refrec),pcx,offset+pcx->pTblDir->pRefTab.offset);
2125         MSFT_DoRefType(pcx, pTI->pTypeLib, refrec.reftype);
2126         (*ppImpl)->hRef = refrec.reftype;
2127         (*ppImpl)->implflags=refrec.flags;
2128         (*ppImpl)->ctCustData=
2129             MSFT_CustData(pcx, refrec.oCustData, &(*ppImpl)->pCustData);
2130         offset=refrec.onext;
2131         ppImpl=&((*ppImpl)->next);
2132     }
2133 }
2134 /*
2135  * process a typeinfo record
2136  */
2137 static ITypeInfoImpl * MSFT_DoTypeInfo(
2138     TLBContext *pcx,
2139     int count,
2140     ITypeLibImpl * pLibInfo)
2141 {
2142     MSFT_TypeInfoBase tiBase;
2143     ITypeInfoImpl *ptiRet;
2144 
2145     TRACE_(typelib)("count=%u\n", count);
2146 
2147     ptiRet = (ITypeInfoImpl*) ITypeInfo_Constructor();
2148     MSFT_ReadLEDWords(&tiBase, sizeof(tiBase) ,pcx ,
2149                       pcx->pTblDir->pTypeInfoTab.offset+count*sizeof(tiBase));
2150 
2151 /* this is where we are coming from */
2152     ptiRet->pTypeLib = pLibInfo;
2153     ptiRet->index=count;
2154 /* fill in the typeattr fields */
2155 
2156     MSFT_ReadGuid(&ptiRet->TypeAttr.guid, tiBase.posguid, pcx);
2157     ptiRet->TypeAttr.lcid=pLibInfo->LibAttr.lcid;   /* FIXME: correct? */
2158     ptiRet->TypeAttr.lpstrSchema=NULL;              /* reserved */
2159     ptiRet->TypeAttr.cbSizeInstance=tiBase.size;
2160     ptiRet->TypeAttr.typekind=tiBase.typekind & 0xF;
2161     ptiRet->TypeAttr.cFuncs=LOWORD(tiBase.cElement);
2162     ptiRet->TypeAttr.cVars=HIWORD(tiBase.cElement);
2163     ptiRet->TypeAttr.cbAlignment=(tiBase.typekind >> 11 )& 0x1F; /* there are more flags there */
2164     ptiRet->TypeAttr.wTypeFlags=tiBase.flags;
2165     ptiRet->TypeAttr.wMajorVerNum=LOWORD(tiBase.version);
2166     ptiRet->TypeAttr.wMinorVerNum=HIWORD(tiBase.version);
2167     ptiRet->TypeAttr.cImplTypes=tiBase.cImplTypes;
2168     ptiRet->TypeAttr.cbSizeVft=(tiBase.cbSizeVft * sizeof(void *))/4; /* FIXME: this is only the non inherited part */
2169     if(ptiRet->TypeAttr.typekind == TKIND_ALIAS)
2170         MSFT_GetTdesc(pcx, tiBase.datatype1,
2171             &ptiRet->TypeAttr.tdescAlias, ptiRet);
2172 
2173 /*  FIXME: */
2174 /*    IDLDESC  idldescType; *//* never saw this one != zero  */
2175 
2176 /* name, eventually add to a hash table */
2177     ptiRet->Name=MSFT_ReadName(pcx, tiBase.NameOffset);
2178     ptiRet->hreftype = MSFT_ReadHreftype(pcx, tiBase.NameOffset);
2179     TRACE_(typelib)("reading %s\n", debugstr_w(ptiRet->Name));
2180     /* help info */
2181     ptiRet->DocString=MSFT_ReadString(pcx, tiBase.docstringoffs);
2182     ptiRet->dwHelpStringContext=tiBase.helpstringcontext;
2183     ptiRet->dwHelpContext=tiBase.helpcontext;
2184 
2185     if (ptiRet->TypeAttr.typekind == TKIND_MODULE)
2186         ptiRet->DllName = MSFT_ReadString(pcx, tiBase.datatype1);
2187 
2188 /* note: InfoType's Help file and HelpStringDll come from the containing
2189  * library. Further HelpString and Docstring appear to be the same thing :(
2190  */
2191     /* functions */
2192     if(ptiRet->TypeAttr.cFuncs >0 )
2193         MSFT_DoFuncs(pcx, ptiRet, ptiRet->TypeAttr.cFuncs,
2194                     ptiRet->TypeAttr.cVars,
2195                     tiBase.memoffset, & ptiRet->funclist);
2196     /* variables */
2197     if(ptiRet->TypeAttr.cVars >0 )
2198         MSFT_DoVars(pcx, ptiRet, ptiRet->TypeAttr.cFuncs,
2199                    ptiRet->TypeAttr.cVars,
2200                    tiBase.memoffset, & ptiRet->varlist);
2201     if(ptiRet->TypeAttr.cImplTypes >0 ) {
2202         switch(ptiRet->TypeAttr.typekind)
2203         {
2204         case TKIND_COCLASS:
2205             MSFT_DoImplTypes(pcx, ptiRet, ptiRet->TypeAttr.cImplTypes ,
2206                 tiBase.datatype1);
2207             break;
2208         case TKIND_DISPATCH:
2209             /* This is not -1 when the interface is a non-base dual interface or
2210                when a dispinterface wraps an interface, i.e., the idl 'dispinterface x {interface y;};'.
2211                Note however that GetRefTypeOfImplType(0) always returns a ref to IDispatch and
2212                not this interface.
2213             */
2214 
2215             if (tiBase.datatype1 != -1)
2216             {
2217                 ptiRet->impltypelist = TLB_Alloc(sizeof(TLBImplType));
2218                 ptiRet->impltypelist->hRef = tiBase.datatype1;
2219                 MSFT_DoRefType(pcx, pLibInfo, tiBase.datatype1);
2220             }
2221           break;
2222         default:
2223             ptiRet->impltypelist=TLB_Alloc(sizeof(TLBImplType));
2224             MSFT_DoRefType(pcx, pLibInfo, tiBase.datatype1);
2225             ptiRet->impltypelist->hRef = tiBase.datatype1;
2226             break;
2227        }
2228     }
2229     ptiRet->ctCustData=
2230         MSFT_CustData(pcx, tiBase.oCustData, &ptiRet->pCustData);
2231 
2232     TRACE_(typelib)("%s guid: %s kind:%s\n",
2233        debugstr_w(ptiRet->Name),
2234        debugstr_guid(&ptiRet->TypeAttr.guid),
2235        typekind_desc[ptiRet->TypeAttr.typekind]);
2236     if (TRACE_ON(typelib))
2237       dump_TypeInfo(ptiRet);
2238 
2239     return ptiRet;
2240 }
2241 
2242 /* Because type library parsing has some degree of overhead, and some apps repeatedly load the same
2243  * typelibs over and over, we cache them here. According to MSDN Microsoft have a similar scheme in
2244  * place. This will cause a deliberate memory leak, but generally losing RAM for cycles is an acceptable
2245  * tradeoff here.
2246  */
2247 static ITypeLibImpl *tlb_cache_first;
2248 static CRITICAL_SECTION cache_section;
2249 static CRITICAL_SECTION_DEBUG cache_section_debug =
2250 {
2251     0, 0, &cache_section,
2252     { &cache_section_debug.ProcessLocksList, &cache_section_debug.ProcessLocksList },
2253       0, 0, { (DWORD_PTR)(__FILE__ ": typelib loader cache") }
2254 };
2255 static CRITICAL_SECTION cache_section = { &cache_section_debug, -1, 0, 0, 0, 0 };
2256 
2257 
2258 typedef struct TLB_PEFile
2259 {
2260     const IUnknownVtbl *lpvtbl;
2261     LONG refs;
2262     HMODULE dll;
2263     HRSRC typelib_resource;
2264     HGLOBAL typelib_global;
2265     LPVOID typelib_base;
2266 } TLB_PEFile;
2267 
2268 static HRESULT WINAPI TLB_PEFile_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2269 {
2270     if (IsEqualIID(riid, &IID_IUnknown))
2271     {
2272         *ppv = iface;
2273         IUnknown_AddRef(iface);
2274         return S_OK;
2275     }
2276     *ppv = NULL;
2277     return E_NOINTERFACE;
2278 }
2279 
2280 static ULONG WINAPI TLB_PEFile_AddRef(IUnknown *iface)
2281 {
2282     TLB_PEFile *This = (TLB_PEFile *)iface;
2283     return InterlockedIncrement(&This->refs);
2284 }
2285 
2286 static ULONG WINAPI TLB_PEFile_Release(IUnknown *iface)
2287 {
2288     TLB_PEFile *This = (TLB_PEFile *)iface;
2289     ULONG refs = InterlockedDecrement(&This->refs);
2290     if (!refs)
2291     {
2292         if (This->typelib_global)
2293             FreeResource(This->typelib_global);
2294         if (This->dll)
2295             FreeLibrary(This->dll);
2296         HeapFree(GetProcessHeap(), 0, This);
2297     }
2298     return refs;
2299 }
2300 
2301 static const IUnknownVtbl TLB_PEFile_Vtable =
2302 {
2303     TLB_PEFile_QueryInterface,
2304     TLB_PEFile_AddRef,
2305     TLB_PEFile_Release
2306 };
2307 
2308 static HRESULT TLB_PEFile_Open(LPCWSTR path, INT index, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile)
2309 {
2310     TLB_PEFile *This;
2311 
2312     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
2313     if (!This)
2314         return E_OUTOFMEMORY;
2315 
2316     This->lpvtbl = &TLB_PEFile_Vtable;
2317     This->refs = 1;
2318     This->dll = NULL;
2319     This->typelib_resource = NULL;
2320     This->typelib_global = NULL;
2321     This->typelib_base = NULL;
2322 
2323     This->dll = LoadLibraryExW(path, 0, DONT_RESOLVE_DLL_REFERENCES |
2324                     LOAD_LIBRARY_AS_DATAFILE | LOAD_WITH_ALTERED_SEARCH_PATH);
2325 
2326     if (This->dll)
2327     {
2328         static const WCHAR TYPELIBW[] = {'T','Y','P','E','L','I','B',0};
2329         This->typelib_resource = FindResourceW(This->dll, MAKEINTRESOURCEW(index), TYPELIBW);
2330         if (This->typelib_resource)
2331         {
2332             This->typelib_global = LoadResource(This->dll, This->typelib_resource);
2333             if (This->typelib_global)
2334             {
2335                 This->typelib_base = LockResource(This->typelib_global);
2336 
2337                 if (This->typelib_base)
2338                 {
2339                     *pdwTLBLength = SizeofResource(This->dll, This->typelib_resource);
2340                     *ppBase = This->typelib_base;
2341                     *ppFile = (IUnknown *)&This->lpvtbl;
2342                     return S_OK;
2343                 }
2344             }
2345         }
2346     }
2347 
2348     TLB_PEFile_Release((IUnknown *)&This->lpvtbl);
2349     return TYPE_E_CANTLOADLIBRARY;
2350 }
2351 
2352 typedef struct TLB_NEFile
2353 {
2354     const IUnknownVtbl *lpvtbl;
2355     LONG refs;
2356     LPVOID typelib_base;
2357 } TLB_NEFile;
2358 
2359 static HRESULT WINAPI TLB_NEFile_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2360 {
2361     if (IsEqualIID(riid, &IID_IUnknown))
2362     {
2363         *ppv = iface;
2364         IUnknown_AddRef(iface);
2365         return S_OK;
2366     }
2367     *ppv = NULL;
2368     return E_NOINTERFACE;
2369 }
2370 
2371 static ULONG WINAPI TLB_NEFile_AddRef(IUnknown *iface)
2372 {
2373     TLB_NEFile *This = (TLB_NEFile *)iface;
2374     return InterlockedIncrement(&This->refs);
2375 }
2376 
2377 static ULONG WINAPI TLB_NEFile_Release(IUnknown *iface)
2378 {
2379     TLB_NEFile *This = (TLB_NEFile *)iface;
2380     ULONG refs = InterlockedDecrement(&This->refs);
2381     if (!refs)
2382     {
2383         HeapFree(GetProcessHeap(), 0, This->typelib_base);
2384         HeapFree(GetProcessHeap(), 0, This);
2385     }
2386     return refs;
2387 }
2388 
2389 static const IUnknownVtbl TLB_NEFile_Vtable =
2390 {
2391     TLB_NEFile_QueryInterface,
2392     TLB_NEFile_AddRef,
2393     TLB_NEFile_Release
2394 };
2395 
2396 /***********************************************************************
2397  *           read_xx_header         [internal]
2398  */
2399 static int read_xx_header( HFILE lzfd )
2400 {
2401     IMAGE_DOS_HEADER mzh;
2402     char magic[3];
2403 
2404     LZSeek( lzfd, 0, SEEK_SET );
2405     if ( sizeof(mzh) != LZRead( lzfd, (LPSTR)&mzh, sizeof(mzh) ) )
2406         return 0;
2407     if ( mzh.e_magic != IMAGE_DOS_SIGNATURE )
2408         return 0;
2409 
2410     LZSeek( lzfd, mzh.e_lfanew, SEEK_SET );
2411     if ( 2 != LZRead( lzfd, magic, 2 ) )
2412         return 0;
2413 
2414     LZSeek( lzfd, mzh.e_lfanew, SEEK_SET );
2415 
2416     if ( magic[0] == 'N' && magic[1] == 'E' )
2417         return IMAGE_OS2_SIGNATURE;
2418     if ( magic[0] == 'P' && magic[1] == 'E' )
2419         return IMAGE_NT_SIGNATURE;
2420 
2421     magic[2] = '\0';
2422     WARN("Can't handle %s files.\n", magic );
2423     return 0;
2424 }
2425 
2426 
2427 /***********************************************************************
2428  *           find_ne_resource         [internal]
2429  */
2430 static BOOL find_ne_resource( HFILE lzfd, LPCSTR typeid, LPCSTR resid,
2431                                 DWORD *resLen, DWORD *resOff )
2432 {
2433     IMAGE_OS2_HEADER nehd;
2434     NE_TYPEINFO *typeInfo;
2435     NE_NAMEINFO *nameInfo;
2436     DWORD nehdoffset;
2437     LPBYTE resTab;
2438     DWORD resTabSize;
2439     int count;
2440 
2441     /* Read in NE header */
2442     nehdoffset = LZSeek( lzfd, 0, SEEK_CUR );
2443     if ( sizeof(nehd) != LZRead( lzfd, (LPSTR)&nehd, sizeof(nehd) ) ) return 0;
2444 
2445     resTabSize = nehd.ne_restab - nehd.ne_rsrctab;
2446     if ( !resTabSize )
2447     {
2448         TRACE("No resources in NE dll\n" );
2449         return FALSE;
2450     }
2451 
2452     /* Read in resource table */
2453     resTab = HeapAlloc( GetProcessHeap(), 0, resTabSize );
2454     if ( !resTab ) return FALSE;
2455 
2456     LZSeek( lzfd, nehd.ne_rsrctab + nehdoffset, SEEK_SET );
2457     if ( resTabSize != LZRead( lzfd, (char*)resTab, resTabSize ) )
2458     {
2459         HeapFree( GetProcessHeap(), 0, resTab );
2460         return FALSE;
2461     }
2462 
2463     /* Find resource */
2464     typeInfo = (NE_TYPEINFO *)(resTab + 2);
2465 
2466     if (HIWORD(typeid) != 0)  /* named type */
2467     {
2468         BYTE len = strlen( typeid );
2469         while (typeInfo->type_id)
2470         {
2471             if (!(typeInfo->type_id & 0x8000))
2472             {
2473                 BYTE *p = resTab + typeInfo->type_id;
2474                 if ((*p == len) && !strncasecmp( (char*)p+1, typeid, len )) goto found_type;
2475             }
2476             typeInfo = (NE_TYPEINFO *)((char *)(typeInfo + 1) +
2477                                        typeInfo->count * sizeof(NE_NAMEINFO));
2478         }
2479     }
2480     else  /* numeric type id */
2481     {
2482         WORD id = LOWORD(typeid) | 0x8000;
2483         while (typeInfo->type_id)
2484         {
2485             if (typeInfo->type_id == id) goto found_type;
2486             typeInfo = (NE_TYPEINFO *)((char *)(typeInfo + 1) +
2487                                        typeInfo->count * sizeof(NE_NAMEINFO));
2488         }
2489     }
2490     TRACE("No typeid entry found for %p\n", typeid );
2491     HeapFree( GetProcessHeap(), 0, resTab );
2492     return FALSE;
2493 
2494  found_type:
2495     nameInfo = (NE_NAMEINFO *)(typeInfo + 1);
2496 
2497     if (HIWORD(resid) != 0)  /* named resource */
2498     {
2499         BYTE len = strlen( resid );
2500         for (count = typeInfo->count; count > 0; count--, nameInfo++)
2501         {
2502             BYTE *p = resTab + nameInfo->id;
2503             if (nameInfo->id & 0x8000) continue;
2504             if ((*p == len) && !strncasecmp( (char*)p+1, resid, len )) goto found_name;
2505         }
2506     }
2507     else  /* numeric resource id */
2508     {
2509         WORD id = LOWORD(resid) | 0x8000;
2510         for (count = typeInfo->count; count > 0; count--, nameInfo++)
2511             if (nameInfo->id == id) goto found_name;
2512     }
2513     TRACE("No resid entry found for %p\n", typeid );
2514     HeapFree( GetProcessHeap(), 0, resTab );
2515     return FALSE;
2516 
2517  found_name:
2518     /* Return resource data */
2519     if ( resLen ) *resLen = nameInfo->length << *(WORD *)resTab;
2520     if ( resOff ) *resOff = nameInfo->offset << *(WORD *)resTab;
2521 
2522     HeapFree( GetProcessHeap(), 0, resTab );
2523     return TRUE;
2524 }
2525 
2526 static HRESULT TLB_NEFile_Open(LPCWSTR path, INT index, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile){
2527 
2528     HFILE lzfd = -1;
2529     OFSTRUCT ofs;
2530     HRESULT hr = TYPE_E_CANTLOADLIBRARY;
2531     TLB_NEFile *This = NULL;
2532 
2533     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
2534     if (!This) return E_OUTOFMEMORY;
2535 
2536     This->lpvtbl = &TLB_NEFile_Vtable;
2537     This->refs = 1;
2538     This->typelib_base = NULL;
2539 
2540     lzfd = LZOpenFileW( (LPWSTR)path, &ofs, OF_READ );
2541     if ( lzfd >= 0 && read_xx_header( lzfd ) == IMAGE_OS2_SIGNATURE )
2542     {
2543         DWORD reslen, offset;
2544         if( find_ne_resource( lzfd, "TYPELIB", MAKEINTRESOURCEA(index), &reslen, &offset ) )
2545         {
2546             This->typelib_base = HeapAlloc(GetProcessHeap(), 0, reslen);
2547             if( !This->typelib_base )
2548                 hr = E_OUTOFMEMORY;
2549             else
2550             {
2551                 LZSeek( lzfd, offset, SEEK_SET );
2552                 reslen = LZRead( lzfd, This->typelib_base, reslen );
2553                 LZClose( lzfd );
2554                 *ppBase = This->typelib_base;
2555                 *pdwTLBLength = reslen;
2556                 *ppFile = (IUnknown *)&This->lpvtbl;
2557                 return S_OK;
2558             }
2559         }
2560     }
2561 
2562     if( lzfd >= 0) LZClose( lzfd );
2563     TLB_NEFile_Release((IUnknown *)&This->lpvtbl);
2564     return hr;
2565 }
2566 
2567 typedef struct TLB_Mapping
2568 {
2569     const IUnknownVtbl *lpvtbl;
2570     LONG refs;
2571     HANDLE file;
2572     HANDLE mapping;
2573     LPVOID typelib_base;
2574 } TLB_Mapping;
2575 
2576 static HRESULT WINAPI TLB_Mapping_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2577 {
2578     if (IsEqualIID(riid, &IID_IUnknown))
2579     {
2580         *ppv = iface;
2581         IUnknown_AddRef(iface);
2582         return S_OK;
2583     }
2584     *ppv = NULL;
2585     return E_NOINTERFACE;
2586 }
2587 
2588 static ULONG WINAPI TLB_Mapping_AddRef(IUnknown *iface)
2589 {
2590     TLB_Mapping *This = (TLB_Mapping *)iface;
2591     return InterlockedIncrement(&This->refs);
2592 }
2593 
2594 static ULONG WINAPI TLB_Mapping_Release(IUnknown *iface)
2595 {
2596     TLB_Mapping *This = (TLB_Mapping *)iface;
2597     ULONG refs = InterlockedDecrement(&This->refs);
2598     if (!refs)
2599     {
2600         if (This->typelib_base)
2601             UnmapViewOfFile(This->typelib_base);
2602         if (This->mapping)
2603             CloseHandle(This->mapping);
2604         if (This->file != INVALID_HANDLE_VALUE)
2605             CloseHandle(This->file);
2606         HeapFree(GetProcessHeap(), 0, This);
2607     }
2608     return refs;
2609 }
2610 
2611 static const IUnknownVtbl TLB_Mapping_Vtable =
2612 {
2613     TLB_Mapping_QueryInterface,
2614     TLB_Mapping_AddRef,
2615     TLB_Mapping_Release
2616 };
2617 
2618 static HRESULT TLB_Mapping_Open(LPCWSTR path, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile)
2619 {
2620     TLB_Mapping *This;
2621 
2622     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
2623     if (!This)
2624         return E_OUTOFMEMORY;
2625 
2626     This->lpvtbl = &TLB_Mapping_Vtable;
2627     This->refs = 1;
2628     This->file = INVALID_HANDLE_VALUE;
2629     This->mapping = NULL;
2630     This->typelib_base = NULL;
2631 
2632     This->file = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
2633     if (INVALID_HANDLE_VALUE != This->file)
2634     {
2635         This->mapping = CreateFileMappingW(This->file, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL);
2636         if (This->mapping)
2637         {
2638             This->typelib_base = MapViewOfFile(This->mapping, FILE_MAP_READ, 0, 0, 0);
2639             if(This->typelib_base)
2640             {
2641                 /* retrieve file size */
2642                 *pdwTLBLength = GetFileSize(This->file, NULL);
2643                 *ppBase = This->typelib_base;
2644                 *ppFile = (IUnknown *)&This->lpvtbl;
2645                 return S_OK;
2646             }
2647         }
2648     }
2649 
2650     IUnknown_Release((IUnknown *)&This->lpvtbl);
2651     return TYPE_E_CANTLOADLIBRARY;
2652 }
2653 
2654 /****************************************************************************
2655  *      TLB_ReadTypeLib
2656  *
2657  * find the type of the typelib file and map the typelib resource into
2658  * the memory
2659  */
2660 #define MSFT_SIGNATURE 0x5446534D /* "MSFT" */
2661 #define SLTG_SIGNATURE 0x47544c53 /* "SLTG" */
2662 static HRESULT TLB_ReadTypeLib(LPCWSTR pszFileName, LPWSTR pszPath, UINT cchPath, ITypeLib2 **ppTypeLib)
2663 {
2664     ITypeLibImpl *entry;
2665     HRESULT ret;
2666     INT index = 1;
2667     LPWSTR index_str, file = (LPWSTR)pszFileName;
2668     LPVOID pBase = NULL;
2669     DWORD dwTLBLength = 0;
2670     IUnknown *pFile = NULL;
2671 
2672     *ppTypeLib = NULL;
2673 
2674     index_str = strrchrW(pszFileName, '\\');
2675     if(index_str && *++index_str != '\0')
2676     {
2677         LPWSTR end_ptr;
2678         long idx = strtolW(index_str, &end_ptr, 10);
2679         if(*end_ptr == '\0')
2680         {
2681             int str_len = index_str - pszFileName - 1;
2682             index = idx;
2683             file = HeapAlloc(GetProcessHeap(), 0, (str_len + 1) * sizeof(WCHAR));
2684             memcpy(file, pszFileName, str_len * sizeof(WCHAR));
2685             file[str_len] = 0;
2686         }
2687     }
2688 
2689     if(!SearchPathW(NULL, file, NULL, cchPath, pszPath, NULL))
2690     {
2691         if(strchrW(file, '\\'))
2692         {
2693             lstrcpyW(pszPath, file);
2694         }
2695         else
2696         {
2697             int len = GetSystemDirectoryW(pszPath, cchPath);
2698             pszPath[len] = '\\';
2699             memcpy(pszPath + len + 1, file, (strlenW(file) + 1) * sizeof(WCHAR));
2700         }
2701     }
2702 
2703     if(file != pszFileName) HeapFree(GetProcessHeap(), 0, file);
2704 
2705     TRACE_(typelib)("File %s index %d\n", debugstr_w(pszPath), index);
2706 
2707     /* We look the path up in the typelib cache. If found, we just addref it, and return the pointer. */
2708     EnterCriticalSection(&cache_section);
2709     for (entry = tlb_cache_first; entry != NULL; entry = entry->next)
2710     {
2711         if (!strcmpiW(entry->path, pszPath) && entry->index == index)
2712         {
2713             TRACE("cache hit\n");
2714             *ppTypeLib = (ITypeLib2*)entry;
2715             ITypeLib_AddRef(*ppTypeLib);
2716             LeaveCriticalSection(&cache_section);
2717             return S_OK;
2718         }
2719     }
2720     LeaveCriticalSection(&cache_section);
2721 
2722     /* now actually load and parse the typelib */
2723 
2724     ret = TLB_PEFile_Open(pszPath, index, &pBase, &dwTLBLength, &pFile);
2725     if (ret == TYPE_E_CANTLOADLIBRARY)
2726         ret = TLB_NEFile_Open(pszPath, index, &pBase, &dwTLBLength, &pFile);
2727     if (ret == TYPE_E_CANTLOADLIBRARY)
2728         ret = TLB_Mapping_Open(pszPath, &pBase, &dwTLBLength, &pFile);
2729     if (SUCCEEDED(ret))
2730     {
2731         if (dwTLBLength >= 4)
2732         {
2733             DWORD dwSignature = FromLEDWord(*((DWORD*) pBase));
2734             if (dwSignature == MSFT_SIGNATURE)
2735                 *ppTypeLib = ITypeLib2_Constructor_MSFT(pBase, dwTLBLength);
2736             else if (dwSignature == SLTG_SIGNATURE)
2737                 *ppTypeLib = ITypeLib2_Constructor_SLTG(pBase, dwTLBLength);
2738             else
2739             {
2740                 FIXME("Header type magic 0x%08x not supported.\n",dwSignature);
2741                 ret = TYPE_E_CANTLOADLIBRARY;
2742             }
2743         }
2744         else
2745             ret = TYPE_E_CANTLOADLIBRARY;
2746         IUnknown_Release(pFile);
2747     }
2748 
2749     if(*ppTypeLib) {
2750         ITypeLibImpl *impl = (ITypeLibImpl*)*ppTypeLib;
2751 
2752         TRACE("adding to cache\n");
2753         impl->path = HeapAlloc(GetProcessHeap(), 0, (strlenW(pszPath)+1) * sizeof(WCHAR));
2754         lstrcpyW(impl->path, pszPath);
2755         /* We should really canonicalise the path here. */
2756         impl->index = index;
2757 
2758         /* FIXME: check if it has added already in the meantime */
2759         EnterCriticalSection(&cache_section);
2760         if ((impl->next = tlb_cache_first) != NULL) impl->next->prev = impl;
2761         impl->prev = NULL;
2762         tlb_cache_first = impl;
2763         LeaveCriticalSection(&cache_section);
2764         ret = S_OK;
2765     } else
2766         ERR("Loading of typelib %s failed with error %d\n", debugstr_w(pszFileName), GetLastError());
2767 
2768     return ret;
2769 }
2770 
2771 /*================== ITypeLib(2) Methods ===================================*/
2772 
2773 static ITypeLibImpl* TypeLibImpl_Constructor(void)
2774 {
2775     ITypeLibImpl* pTypeLibImpl;
2776 
2777     pTypeLibImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeLibImpl));
2778     if (!pTypeLibImpl) return NULL;
2779 
2780     pTypeLibImpl->lpVtbl = &tlbvt;
2781     pTypeLibImpl->lpVtblTypeComp = &tlbtcvt;
2782     pTypeLibImpl->ref = 1;
2783 
2784     list_init(&pTypeLibImpl->ref_list);
2785     pTypeLibImpl->dispatch_href = -1;
2786 
2787     return pTypeLibImpl;
2788 }
2789 
2790 /****************************************************************************
2791  *      ITypeLib2_Constructor_MSFT
2792  *
2793  * loading an MSFT typelib from an in-memory image
2794  */
2795 static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength)
2796 {
2797     TLBContext cx;
2798     long lPSegDir;
2799     MSFT_Header tlbHeader;
2800     MSFT_SegDir tlbSegDir;
2801     ITypeLibImpl * pTypeLibImpl;
2802 
2803     TRACE("%p, TLB length = %d\n", pLib, dwTLBLength);
2804 
2805     pTypeLibImpl = TypeLibImpl_Constructor();
2806     if (!pTypeLibImpl) return NULL;
2807 
2808     /* get pointer to beginning of typelib data */
2809     cx.pos = 0;
2810     cx.oStart=0;
2811     cx.mapping = pLib;
2812     cx.pLibInfo = pTypeLibImpl;
2813     cx.length = dwTLBLength;
2814 
2815     /* read header */
2816     MSFT_ReadLEDWords((void*)&tlbHeader, sizeof(tlbHeader), &cx, 0);
2817     TRACE_(typelib)("header:\n");
2818     TRACE_(typelib)("\tmagic1=0x%08x ,magic2=0x%08x\n",tlbHeader.magic1,tlbHeader.magic2 );
2819     if (tlbHeader.magic1 != MSFT_SIGNATURE) {
2820         FIXME("Header type magic 0x%08x not supported.\n",tlbHeader.magic1);
2821         return NULL;
2822     }
2823     TRACE_(typelib)("\tdispatchpos = 0x%x\n", tlbHeader.dispatchpos);
2824 
2825     /* there is a small amount of information here until the next important
2826      * part:
2827      * the segment directory . Try to calculate the amount of data */
2828     lPSegDir = sizeof(tlbHeader) + (tlbHeader.nrtypeinfos)*4 + ((tlbHeader.varflags & HELPDLLFLAG)? 4 :0);
2829 
2830     /* now read the segment directory */
2831     TRACE("read segment directory (at %ld)\n",lPSegDir);
2832     MSFT_ReadLEDWords(&tlbSegDir, sizeof(tlbSegDir), &cx, lPSegDir);
2833     cx.pTblDir = &tlbSegDir;
2834 
2835     /* just check two entries */
2836     if ( tlbSegDir.pTypeInfoTab.res0c != 0x0F || tlbSegDir.pImpInfo.res0c != 0x0F)
2837     {
2838         ERR("cannot find the table directory, ptr=0x%lx\n",lPSegDir);
2839         HeapFree(GetProcessHeap(),0,pTypeLibImpl);
2840         return NULL;
2841     }
2842 
2843     /* now fill our internal data */
2844     /* TLIBATTR fields */
2845     MSFT_ReadGuid(&pTypeLibImpl->LibAttr.guid, tlbHeader.posguid, &cx);
2846 
2847     /*    pTypeLibImpl->LibAttr.lcid = tlbHeader.lcid;*/
2848     /* Windows seems to have zero here, is this correct? */
2849     if(SUBLANGID(tlbHeader.lcid) == SUBLANG_NEUTRAL)
2850       pTypeLibImpl->LibAttr.lcid = MAKELCID(MAKELANGID(PRIMARYLANGID(tlbHeader.lcid),0),0);
2851     else
2852       pTypeLibImpl->LibAttr.lcid = 0;
2853 
2854     pTypeLibImpl->LibAttr.syskind = tlbHeader.varflags & 0x0f; /* check the mask */
2855     pTypeLibImpl->LibAttr.wMajorVerNum = LOWORD(tlbHeader.version);
2856     pTypeLibImpl->LibAttr.wMinorVerNum = HIWORD(tlbHeader.version);
2857     pTypeLibImpl->LibAttr.wLibFlags = (WORD) tlbHeader.flags & 0xffff;/* check mask */
2858 
2859     /* name, eventually add to a hash table */
2860     pTypeLibImpl->Name = MSFT_ReadName(&cx, tlbHeader.NameOffset);
2861 
2862     /* help info */
2863     pTypeLibImpl->DocString = MSFT_ReadString(&cx, tlbHeader.helpstring);
2864     pTypeLibImpl->HelpFile = MSFT_ReadString(&cx, tlbHeader.helpfile);
2865 
2866     if( tlbHeader.varflags & HELPDLLFLAG)
2867     {
2868             int offset;
2869             MSFT_ReadLEDWords(&offset, sizeof(offset), &cx, sizeof(tlbHeader));
2870             pTypeLibImpl->HelpStringDll = MSFT_ReadString(&cx, offset);
2871     }
2872 
2873     pTypeLibImpl->dwHelpContext = tlbHeader.helpstringcontext;
2874 
2875     /* custom data */
2876     if(tlbHeader.CustomDataOffset >= 0)
2877     {
2878         pTypeLibImpl->ctCustData = MSFT_CustData(&cx, tlbHeader.CustomDataOffset, &pTypeLibImpl->pCustData);
2879     }
2880 
2881     /* fill in type descriptions */
2882     if(tlbSegDir.pTypdescTab.length > 0)
2883     {
2884         int i, j, cTD = tlbSegDir.pTypdescTab.length / (2*sizeof(INT));
2885         INT16 td[4];
2886         pTypeLibImpl->ctTypeDesc = cTD;
2887         pTypeLibImpl->pTypeDesc = TLB_Alloc( cTD * sizeof(TYPEDESC));
2888         MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pTypdescTab.offset);
2889         for(i=0; i<cTD; )
2890         {
2891             /* FIXME: add several sanity checks here */
2892             pTypeLibImpl->pTypeDesc[i].vt = td[0] & VT_TYPEMASK;
2893             if(td[0] == VT_PTR || td[0] == VT_SAFEARRAY)
2894             {
2895                 /* FIXME: check safearray */
2896                 if(td[3] < 0)
2897                     pTypeLibImpl->pTypeDesc[i].u.lptdesc= & stndTypeDesc[td[2]];
2898                 else
2899                     pTypeLibImpl->pTypeDesc[i].u.lptdesc= & pTypeLibImpl->pTypeDesc[td[2]/8];
2900             }
2901             else if(td[0] == VT_CARRAY)
2902             {
2903                 /* array descr table here */
2904                 pTypeLibImpl->pTypeDesc[i].u.lpadesc = (void *)((int) td[2]);  /* temp store offset in*/
2905             }
2906             else if(td[0] == VT_USERDEFINED)
2907             {
2908                 pTypeLibImpl->pTypeDesc[i].u.hreftype = MAKELONG(td[2],td[3]);
2909             }
2910             if(++i<cTD) MSFT_ReadLEWords(td, sizeof(td), &cx, DO_NOT_SEEK);
2911         }
2912 
2913         /* second time around to fill the array subscript info */
2914         for(i=0;i<cTD;i++)
2915         {
2916             if(pTypeLibImpl->pTypeDesc[i].vt != VT_CARRAY) continue;
2917             if(tlbSegDir.pArrayDescriptions.offset>0)
2918             {
2919                 MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pArrayDescriptions.offset + (int) pTypeLibImpl->pTypeDesc[i].u.lpadesc);
2920                 pTypeLibImpl->pTypeDesc[i].u.lpadesc = TLB_Alloc(sizeof(ARRAYDESC)+sizeof(SAFEARRAYBOUND)*(td[3]-1));
2921 
2922                 if(td[1]<0)
2923                     pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem.vt = td[0] & VT_TYPEMASK;
2924                 else
2925                     pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem = stndTypeDesc[td[0]/8];
2926 
2927                 pTypeLibImpl->pTypeDesc[i].u.lpadesc->cDims = td[2];
2928 
2929                 for(j = 0; j<td[2]; j++)
2930                 {
2931                     MSFT_ReadLEDWords(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].cElements,
2932                                       sizeof(INT), &cx, DO_NOT_SEEK);
2933                     MSFT_ReadLEDWords(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].lLbound,
2934                                       sizeof(INT), &cx, DO_NOT_SEEK);
2935                 }
2936             }
2937             else
2938             {
2939                 pTypeLibImpl->pTypeDesc[i].u.lpadesc = NULL;
2940                 ERR("didn't find array description data\n");
2941             }
2942         }
2943     }
2944 
2945     /* imported type libs */
2946     if(tlbSegDir.pImpFiles.offset>0)
2947     {
2948         TLBImpLib **ppImpLib = &(pTypeLibImpl->pImpLibs);
2949         int oGuid, offset = tlbSegDir.pImpFiles.offset;
2950         UINT16 size;
2951 
2952         while(offset < tlbSegDir.pImpFiles.offset +tlbSegDir.pImpFiles.length)
2953         {
2954             char *name;
2955 
2956             *ppImpLib = TLB_Alloc(sizeof(TLBImpLib));
2957             (*ppImpLib)->offset = offset - tlbSegDir.pImpFiles.offset;
2958             MSFT_ReadLEDWords(&oGuid, sizeof(INT), &cx, offset);
2959 
2960             MSFT_ReadLEDWords(&(*ppImpLib)->lcid,         sizeof(LCID),   &cx, DO_NOT_SEEK);
2961             MSFT_ReadLEWords(&(*ppImpLib)->wVersionMajor, sizeof(WORD),   &cx, DO_NOT_SEEK);
2962             MSFT_ReadLEWords(&(*ppImpLib)->wVersionMinor, sizeof(WORD),   &cx, DO_NOT_SEEK);
2963             MSFT_ReadLEWords(& size,                      sizeof(UINT16), &cx, DO_NOT_SEEK);
2964 
2965             size >>= 2;
2966             name = TLB_Alloc(size+1);
2967             MSFT_Read(name, size, &cx, DO_NOT_SEEK);
2968             (*ppImpLib)->name = TLB_MultiByteToBSTR(name);
2969 
2970             MSFT_ReadGuid(&(*ppImpLib)->guid, oGuid, &cx);
2971             offset = (offset + sizeof(INT) + sizeof(DWORD) + sizeof(LCID) + sizeof(UINT16) + size + 3) & ~3;
2972 
2973             ppImpLib = &(*ppImpLib)->next;
2974         }
2975     }
2976 
2977     pTypeLibImpl->dispatch_href = tlbHeader.dispatchpos;
2978     if(pTypeLibImpl->dispatch_href != -1)
2979         MSFT_DoRefType(&cx, pTypeLibImpl, pTypeLibImpl->dispatch_href);
2980 
2981     /* type info's */
2982     if(tlbHeader.nrtypeinfos >= 0 )
2983     {
2984         /*pTypeLibImpl->TypeInfoCount=tlbHeader.nrtypeinfos; */
2985         ITypeInfoImpl **ppTI = &(pTypeLibImpl->pTypeInfo);
2986         int i;
2987 
2988         for(i = 0; i < tlbHeader.nrtypeinfos; i++)
2989         {
2990             *ppTI = MSFT_DoTypeInfo(&cx, i, pTypeLibImpl);
2991 
2992             ppTI = &((*ppTI)->next);
2993             (pTypeLibImpl->TypeInfoCount)++;
2994         }
2995     }
2996 
2997     TRACE("(%p)\n", pTypeLibImpl);
2998     return (ITypeLib2*) pTypeLibImpl;
2999 }
3000 
3001 
3002 static BOOL TLB_GUIDFromString(const char *str, GUID *guid)
3003 {
3004   char b[3];
3005   int i;
3006   short s;
3007 
3008   if(sscanf(str, "%x-%hx-%hx-%hx", &guid->Data1, &guid->Data2, &guid->Data3, &s) != 4) {
3009     FIXME("Can't parse guid %s\n", debugstr_guid(guid));
3010     return FALSE;
3011   }
3012 
3013   guid->Data4[0] = s >> 8;
3014   guid->Data4[1] = s & 0xff;
3015 
3016   b[2] = '\0';
3017   for(i = 0; i < 6; i++) {
3018     memcpy(b, str + 24 + 2 * i, 2);
3019     guid->Data4[i + 2] = strtol(b, NULL, 16);
3020   }
3021   return TRUE;
3022 }
3023 
3024 static WORD SLTG_ReadString(const char *ptr, BSTR *pBstr)
3025 {
3026     WORD bytelen;
3027     DWORD len;
3028 
3029     *pBstr = NULL;
3030     bytelen = *(const WORD*)ptr;
3031     if(bytelen == 0xffff) return 2;
3032     len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, NULL, 0);
3033     *pBstr = SysAllocStringLen(NULL, len - 1);
3034     if (*pBstr)
3035         len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, *pBstr, len);
3036     return bytelen + 2;
3037 }
3038 
3039 static WORD SLTG_ReadStringA(const char *ptr, char **str)
3040 {
3041     WORD bytelen;
3042 
3043     *str = NULL;
3044     bytelen = *(const WORD*)ptr;
3045     if(bytelen == 0xffff) return 2;
3046     *str = HeapAlloc(GetProcessHeap(), 0, bytelen + 1);
3047     memcpy(*str, ptr + 2, bytelen);
3048     (*str)[bytelen] = '\0';
3049     return bytelen + 2;
3050 }
3051 
3052 static DWORD SLTG_ReadLibBlk(LPVOID pLibBlk, ITypeLibImpl *pTypeLibImpl)
3053 {
3054     char *ptr = pLibBlk;
3055     WORD w;
3056 
3057     if((w = *(WORD*)ptr) != SLTG_LIBBLK_MAGIC) {
3058         FIXME("libblk magic = %04x\n", w);
3059         return 0;
3060     }
3061 
3062     ptr += 6;
3063     if((w = *(WORD*)ptr) != 0xffff) {
3064         FIXME("LibBlk.res06 = %04x. Assumung string and skipping\n", w);
3065         ptr += w;
3066     }
3067     ptr += 2;
3068 
3069     ptr += SLTG_ReadString(ptr, &pTypeLibImpl->DocString);
3070 
3071     ptr += SLTG_ReadString(ptr, &pTypeLibImpl->HelpFile);
3072 
3073     pTypeLibImpl->dwHelpContext = *(DWORD*)ptr;
3074     ptr += 4;
3075 
3076     pTypeLibImpl->LibAttr.syskind = *(WORD*)ptr;
3077     ptr += 2;
3078 
3079     if(SUBLANGID(*(WORD*)ptr) == SUBLANG_NEUTRAL)
3080         pTypeLibImpl->LibAttr.lcid = MAKELCID(MAKELANGID(PRIMARYLANGID(*(WORD*)ptr),0),0);
3081     else
3082         pTypeLibImpl->LibAttr.lcid = 0;
3083     ptr += 2;
3084 
3085     ptr += 4; /* skip res12 */
3086 
3087     pTypeLibImpl->LibAttr.wLibFlags = *(WORD*)ptr;
3088     ptr += 2;
3089 
3090     pTypeLibImpl->LibAttr.wMajorVerNum = *(WORD*)ptr;
3091     ptr += 2;
3092 
3093     pTypeLibImpl->LibAttr.wMinorVerNum = *(WORD*)ptr;
3094     ptr += 2;
3095 
3096     memcpy(&pTypeLibImpl->LibAttr.guid, ptr, sizeof(GUID));
3097     ptr += sizeof(GUID);
3098 
3099     return ptr - (char*)pLibBlk;
3100 }
3101 
3102 /* stores a mapping between the sltg typeinfo's references and the typelib's HREFTYPEs */
3103 typedef struct
3104 {
3105     unsigned int num;
3106     HREFTYPE refs[1];
3107 } sltg_ref_lookup_t;
3108 
3109 static HRESULT sltg_get_typelib_ref(const sltg_ref_lookup_t *table, DWORD typeinfo_ref,
3110                                     HREFTYPE *typelib_ref)
3111 {
3112     if(typeinfo_ref < table->num)
3113     {
3114         *typelib_ref = table->refs[typeinfo_ref];
3115         return S_OK;
3116     }
3117 
3118     ERR_(typelib)("Unable to find reference\n");
3119     *typelib_ref = -1;
3120     return E_FAIL;
3121 }
3122 
3123 static WORD *SLTG_DoType(WORD *pType, char *pBlk, TYPEDESC *pTD, const sltg_ref_lookup_t *ref_lookup)
3124 {
3125     BOOL done = FALSE;
3126 
3127     while(!done) {
3128         if((*pType & 0xe00) == 0xe00) {
3129             pTD->vt = VT_PTR;
3130             pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3131                                        sizeof(TYPEDESC));
3132             pTD = pTD->u.lptdesc;
3133         }
3134         switch(*pType & 0x3f) {
3135         case VT_PTR:
3136             pTD->vt = VT_PTR;
3137             pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3138                                        sizeof(TYPEDESC));
3139             pTD = pTD->u.lptdesc;
3140             break;
3141 
3142         case VT_USERDEFINED:
3143             pTD->vt = VT_USERDEFINED;
3144             sltg_get_typelib_ref(ref_lookup, *(++pType) / 4, &pTD->u.hreftype);
3145             done = TRUE;
3146             break;
3147 
3148         case VT_CARRAY:
3149           {
3150             /* *(pType+1) is offset to a SAFEARRAY, *(pType+2) is type of
3151                array */
3152 
3153             SAFEARRAY *pSA = (SAFEARRAY *)(pBlk + *(++pType));
3154 
3155             pTD->vt = VT_CARRAY;
3156             pTD->u.lpadesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3157                                 sizeof(ARRAYDESC) +
3158                                 (pSA->cDims - 1) * sizeof(SAFEARRAYBOUND));
3159             pTD->u.lpadesc->cDims = pSA->cDims;
3160             memcpy(pTD->u.lpadesc->rgbounds, pSA->rgsabound,
3161                    pSA->cDims * sizeof(SAFEARRAYBOUND));
3162 
3163             pTD = &pTD->u.lpadesc->tdescElem;
3164             break;
3165           }
3166 
3167         case VT_SAFEARRAY:
3168           {
3169             /* FIXME: *(pType+1) gives an offset to SAFEARRAY, is this
3170                useful? */
3171 
3172             pType++;
3173             pTD->vt = VT_SAFEARRAY;
3174             pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3175                                        sizeof(TYPEDESC));
3176             pTD = pTD->u.lptdesc;
3177             break;
3178           }
3179         default:
3180             pTD->vt = *pType & 0x3f;
3181             done = TRUE;
3182             break;
3183         }
3184         pType++;
3185     }
3186     return pType;
3187 }
3188 
3189 static WORD *SLTG_DoElem(WORD *pType, char *pBlk,
3190                          ELEMDESC *pElem, const sltg_ref_lookup_t *ref_lookup)
3191 {
3192     /* Handle [in/out] first */
3193     if((*pType & 0xc000) == 0xc000)
3194         pElem->u.paramdesc.wParamFlags = PARAMFLAG_NONE;
3195     else if(*pType & 0x8000)
3196         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN | PARAMFLAG_FOUT;
3197     else if(*pType & 0x4000)
3198         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FOUT;
3199     else
3200         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN;
3201 
3202     if(*pType & 0x2000)
3203         pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FLCID;
3204 
3205     if(*pType & 0x80)
3206         pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FRETVAL;
3207 
3208     return SLTG_DoType(pType, pBlk, &pElem->tdesc, ref_lookup);
3209 }
3210 
3211 
3212 static sltg_ref_lookup_t *SLTG_DoRefs(SLTG_RefInfo *pRef, ITypeLibImpl *pTL,
3213                         char *pNameTable)
3214 {
3215     unsigned int ref;
3216     char *name;
3217     TLBRefType *ref_type;
3218     sltg_ref_lookup_t *table;
3219     HREFTYPE typelib_ref;
3220 
3221     if(pRef->magic != SLTG_REF_MAGIC) {
3222         FIXME("Ref magic = %x\n", pRef->magic);
3223         return NULL;
3224     }
3225     name = ( (char*)pRef->names + pRef->number);
3226 
3227     table = HeapAlloc(GetProcessHeap(), 0, sizeof(*table) + ((pRef->number >> 3) - 1) * sizeof(table->refs[0]));
3228     table->num = pRef->number >> 3;
3229 
3230     /* FIXME should scan the existing list and reuse matching refs added by previous typeinfos */
3231 
3232     /* We don't want the first href to be 0 */
3233     typelib_ref = (list_count(&pTL->ref_list) + 1) << 2;
3234 
3235     for(ref = 0; ref < pRef->number >> 3; ref++) {
3236         char *refname;
3237         unsigned int lib_offs, type_num;
3238 
3239         ref_type = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ref_type));
3240 
3241         name += SLTG_ReadStringA(name, &refname);
3242         if(sscanf(refname, "*\\R%x*#%x", &lib_offs, &type_num) != 2)
3243             FIXME_(typelib)("Can't sscanf ref\n");
3244         if(lib_offs != 0xffff) {
3245             TLBImpLib **import = &pTL->pImpLibs;
3246 
3247             while(*import) {
3248                 if((*import)->offset == lib_offs)
3249                     break;
3250                 import = &(*import)->next;
3251             }
3252             if(!*import) {
3253                 char fname[MAX_PATH+1];
3254                 int len;
3255 
3256                 *import = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3257                                     sizeof(**import));
3258                 (*import)->offset = lib_offs;
3259                 TLB_GUIDFromString( pNameTable + lib_offs + 4,
3260                                     &(*import)->guid);
3261                 if(sscanf(pNameTable + lib_offs + 40, "}#%hd.%hd#%x#%s",
3262                           &(*import)->wVersionMajor,
3263                           &(*import)->wVersionMinor,
3264                           &(*import)->lcid, fname) != 4) {
3265                   FIXME_(typelib)("can't sscanf ref %s\n",
3266                         pNameTable + lib_offs + 40);
3267                 }
3268                 len = strlen(fname);
3269                 if(fname[len-1] != '#')
3270                     FIXME("fname = %s\n", fname);
3271                 fname[len-1] = '\0';
3272                 (*import)->name = TLB_MultiByteToBSTR(fname);
3273             }
3274             ref_type->pImpTLInfo = *import;
3275 
3276             /* Store a reference to IDispatch */
3277             if(pTL->dispatch_href == -1 && IsEqualGUID(&(*import)->guid, &IID_StdOle) && type_num == 4)
3278                 pTL->dispatch_href = typelib_ref;
3279 
3280         } else { /* internal ref */
3281           ref_type->pImpTLInfo = TLB_REF_INTERNAL;
3282         }
3283         ref_type->reference = typelib_ref;
3284         ref_type->index = type_num;
3285 
3286         HeapFree(GetProcessHeap(), 0, refname);
3287         list_add_tail(&pTL->ref_list, &ref_type->entry);
3288 
3289         table->refs[ref] = typelib_ref;
3290         typelib_ref += 4;
3291     }
3292     if((BYTE)*name != SLTG_REF_MAGIC)
3293       FIXME_(typelib)("End of ref block magic = %x\n", *name);
3294     dump_TLBRefType(pTL);
3295     return table;
3296 }
3297 
3298 static char *SLTG_DoImpls(char *pBlk, ITypeInfoImpl *pTI,
3299                           BOOL OneOnly, const sltg_ref_lookup_t *ref_lookup)
3300 {
3301     SLTG_ImplInfo *info;
3302     TLBImplType **ppImplType = &pTI->impltypelist;
3303     /* I don't really get this structure, usually it's 0x16 bytes
3304        long, but iuser.tlb contains some that are 0x18 bytes long.
3305        That's ok because we can use the next ptr to jump to the next
3306        one. But how do we know the length of the last one?  The WORD
3307        at offs 0x8 might be the clue.  For now I'm just assuming that
3308        the last one is the regular 0x16 bytes. */
3309 
3310     info = (SLTG_ImplInfo*)pBlk;
3311     while(1) {
3312         *ppImplType = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3313                                 sizeof(**ppImplType));
3314         sltg_get_typelib_ref(ref_lookup, info->ref, &(*ppImplType)->hRef);
3315         (*ppImplType)->implflags = info->impltypeflags;
3316         pTI->TypeAttr.cImplTypes++;
3317         ppImplType = &(*ppImplType)->next;
3318 
3319         if(info->next == 0xffff)
3320             break;
3321         if(OneOnly)
3322             FIXME_(typelib)("Interface inheriting more than one interface\n");
3323         info = (SLTG_ImplInfo*)(pBlk + info->next);
3324     }
3325     info++; /* see comment at top of function */
3326     return (char*)info;
3327 }
3328 
3329 static void SLTG_DoVars(char *pBlk, char *pFirstItem, ITypeInfoImpl *pTI, unsigned short cVars,
3330                         const char *pNameTable, const sltg_ref_lookup_t *ref_lookup)
3331 {
3332   TLBVarDesc **ppVarDesc = &pTI->varlist;
3333   BSTR bstrPrevName = NULL;
3334   SLTG_Variable *pItem;
3335   unsigned short i;
3336   WORD *pType;
3337 
3338   for(pItem = (SLTG_Variable *)pFirstItem, i = 0; i < cVars;
3339       pItem = (SLTG_Variable *)(pBlk + pItem->next), i++) {
3340 
3341       *ppVarDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3342                              sizeof(**ppVarDesc));
3343       (*ppVarDesc)->vardesc.memid = pItem->memid;
3344 
3345       if (pItem->magic != SLTG_VAR_MAGIC &&
3346           pItem->magic != SLTG_VAR_WITH_FLAGS_MAGIC) {
3347           FIXME_(typelib)("var magic = %02x\n", pItem->magic);
3348           return;
3349       }
3350 
3351       if (pItem->name == 0xfffe)
3352         (*ppVarDesc)->Name = SysAllocString(bstrPrevName);
3353       else
3354         (*ppVarDesc)->Name = TLB_MultiByteToBSTR(pItem->name + pNameTable);
3355 
3356       TRACE_(typelib)("name: %s\n", debugstr_w((*ppVarDesc)->Name));
3357       TRACE_(typelib)("byte_offs = 0x%x\n", pItem->byte_offs);
3358       TRACE_(typelib)("memid = 0x%x\n", pItem->memid);
3359 
3360       if(pItem->flags & 0x02)
3361           pType = &pItem->type;
3362       else
3363           pType = (WORD*)(pBlk + pItem->type);
3364 
3365       if (pItem->flags & ~0xda)
3366         FIXME_(typelib)("unhandled flags = %02x\n", pItem->flags & ~0xda);
3367 
3368       SLTG_DoElem(pType, pBlk,
3369                   &(*ppVarDesc)->vardesc.elemdescVar, ref_lookup);
3370 
3371       if (TRACE_ON(typelib)) {
3372           char buf[300];