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