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