~ [ 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     LCID lcid;
934 
935     /* strings can be stored in tlb as multibyte strings BUT they are *always*
936      * exported to the application as a UNICODE string.
937      */
938     BSTR Name;
939     BSTR DocString;
940     BSTR HelpFile;
941     BSTR HelpStringDll;
942     DWORD dwHelpContext;
943     int TypeInfoCount;          /* nr of typeinfo's in librarry */
944     struct tagITypeInfoImpl *pTypeInfo;   /* linked list of type info data */
945     int ctCustData;             /* number of items in cust data list */
946     TLBCustData * pCustData;    /* linked list to cust data */
947     TLBImpLib   * pImpLibs;     /* linked list to all imported typelibs */
948     int ctTypeDesc;             /* number of items in type desc array */
949     TYPEDESC * pTypeDesc;       /* array of TypeDescriptions found in the
950                                    library. Only used while reading MSFT
951                                    typelibs */
952     struct list ref_list;       /* list of ref types in this typelib */
953     HREFTYPE dispatch_href;     /* reference to IDispatch, -1 if unused */
954 
955 
956     /* typelibs are cached, keyed by path and index, so store the linked list info within them */
957     struct tagITypeLibImpl *next, *prev;
958     WCHAR *path;
959     INT index;
960 } ITypeLibImpl;
961 
962 static const ITypeLib2Vtbl tlbvt;
963 static const ITypeCompVtbl tlbtcvt;
964 
965 static inline ITypeLibImpl *impl_from_ITypeComp( ITypeComp *iface )
966 {
967     return (ITypeLibImpl *)((char*)iface - FIELD_OFFSET(ITypeLibImpl, lpVtblTypeComp));
968 }
969 
970 /* ITypeLib methods */
971 static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength);
972 static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength);
973 
974 /*======================= ITypeInfo implementation =======================*/
975 
976 /* data for referenced types */
977 typedef struct tagTLBRefType
978 {
979     INT index;              /* Type index for internal ref or for external ref
980                                it the format is SLTG.  -2 indicates to
981                                use guid */
982 
983     GUID guid;              /* guid of the referenced type */
984                             /* if index == TLB_REF_USE_GUID */
985 
986     HREFTYPE reference;     /* The href of this ref */
987     TLBImpLib *pImpTLInfo;  /* If ref is external ptr to library data
988                                TLB_REF_INTERNAL for internal refs
989                                TLB_REF_NOT_FOUND for broken refs */
990 
991     struct list entry;
992 } TLBRefType;
993 
994 #define TLB_REF_USE_GUID -2
995 
996 #define TLB_REF_INTERNAL (void*)-2
997 #define TLB_REF_NOT_FOUND (void*)-1
998 
999 /* internal Parameter data */
1000 typedef struct tagTLBParDesc
1001 {
1002     BSTR Name;
1003     int ctCustData;
1004     TLBCustData * pCustData;        /* linked list to cust data */
1005 } TLBParDesc;
1006 
1007 /* internal Function data */
1008 typedef struct tagTLBFuncDesc
1009 {
1010     FUNCDESC funcdesc;      /* lots of info on the function and its attributes. */
1011     BSTR Name;             /* the name of this function */
1012     TLBParDesc *pParamDesc; /* array with param names and custom data */
1013     int helpcontext;
1014     int HelpStringContext;
1015     BSTR HelpString;
1016     BSTR Entry;            /* if its Hiword==0, it numeric; -1 is not present*/
1017     int ctCustData;
1018     TLBCustData * pCustData;        /* linked list to cust data; */
1019     struct tagTLBFuncDesc * next;
1020 } TLBFuncDesc;
1021 
1022 /* internal Variable data */
1023 typedef struct tagTLBVarDesc
1024 {
1025     VARDESC vardesc;        /* lots of info on the variable and its attributes. */
1026     BSTR Name;             /* the name of this variable */
1027     int HelpContext;
1028     int HelpStringContext;  /* FIXME: where? */
1029     BSTR HelpString;
1030     int ctCustData;
1031     TLBCustData * pCustData;/* linked list to cust data; */
1032     struct tagTLBVarDesc * next;
1033 } TLBVarDesc;
1034 
1035 /* internal implemented interface data */
1036 typedef struct tagTLBImplType
1037 {
1038     HREFTYPE hRef;          /* hRef of interface */
1039     int implflags;          /* IMPLFLAG_*s */
1040     int ctCustData;
1041     TLBCustData * pCustData;/* linked list to custom data; */
1042     struct tagTLBImplType *next;
1043 } TLBImplType;
1044 
1045 /* internal TypeInfo data */
1046 typedef struct tagITypeInfoImpl
1047 {
1048     const ITypeInfo2Vtbl *lpVtbl;
1049     const ITypeCompVtbl  *lpVtblTypeComp;
1050     LONG ref;
1051     BOOL no_free_data; /* don't free data structures */
1052     TYPEATTR TypeAttr ;         /* _lots_ of type information. */
1053     ITypeLibImpl * pTypeLib;        /* back pointer to typelib */
1054     int index;                  /* index in this typelib; */
1055     HREFTYPE hreftype;          /* hreftype for app object binding */
1056     /* type libs seem to store the doc strings in ascii
1057      * so why should we do it in unicode?
1058      */
1059     BSTR Name;
1060     BSTR DocString;
1061     BSTR DllName;
1062     DWORD dwHelpContext;
1063     DWORD dwHelpStringContext;
1064 
1065     /* functions  */
1066     TLBFuncDesc * funclist;     /* linked list with function descriptions */
1067 
1068     /* variables  */
1069     TLBVarDesc * varlist;       /* linked list with variable descriptions */
1070 
1071     /* Implemented Interfaces  */
1072     TLBImplType * impltypelist;
1073 
1074     int ctCustData;
1075     TLBCustData * pCustData;        /* linked list to cust data; */
1076     struct tagITypeInfoImpl * next;
1077 } ITypeInfoImpl;
1078 
1079 static inline ITypeInfoImpl *info_impl_from_ITypeComp( ITypeComp *iface )
1080 {
1081     return (ITypeInfoImpl *)((char*)iface - FIELD_OFFSET(ITypeInfoImpl, lpVtblTypeComp));
1082 }
1083 
1084 static const ITypeInfo2Vtbl tinfvt;
1085 static const ITypeCompVtbl  tcompvt;
1086 
1087 static ITypeInfo2 * ITypeInfo_Constructor(void);
1088 
1089 typedef struct tagTLBContext
1090 {
1091         unsigned int oStart;  /* start of TLB in file */
1092         unsigned int pos;     /* current pos */
1093         unsigned int length;  /* total length */
1094         void *mapping;        /* memory mapping */
1095         MSFT_SegDir * pTblDir;
1096         ITypeLibImpl* pLibInfo;
1097 } TLBContext;
1098 
1099 
1100 static void MSFT_DoRefType(TLBContext *pcx, ITypeLibImpl *pTL, int offset);
1101 
1102 /*
1103  debug
1104 */
1105 static void dump_TypeDesc(const TYPEDESC *pTD,char *szVarType) {
1106     if (pTD->vt & VT_RESERVED)
1107         szVarType += strlen(strcpy(szVarType, "reserved | "));
1108     if (pTD->vt & VT_BYREF)
1109         szVarType += strlen(strcpy(szVarType, "ref to "));
1110     if (pTD->vt & VT_ARRAY)
1111         szVarType += strlen(strcpy(szVarType, "array of "));
1112     if (pTD->vt & VT_VECTOR)
1113         szVarType += strlen(strcpy(szVarType, "vector of "));
1114     switch(pTD->vt & VT_TYPEMASK) {
1115     case VT_UI1: sprintf(szVarType, "VT_UI1"); break;
1116     case VT_I2: sprintf(szVarType, "VT_I2"); break;
1117     case VT_I4: sprintf(szVarType, "VT_I4"); break;
1118     case VT_R4: sprintf(szVarType, "VT_R4"); break;
1119     case VT_R8: sprintf(szVarType, "VT_R8"); break;
1120     case VT_BOOL: sprintf(szVarType, "VT_BOOL"); break;
1121     case VT_ERROR: sprintf(szVarType, "VT_ERROR"); break;
1122     case VT_CY: sprintf(szVarType, "VT_CY"); break;
1123     case VT_DATE: sprintf(szVarType, "VT_DATE"); break;
1124     case VT_BSTR: sprintf(szVarType, "VT_BSTR"); break;
1125     case VT_UNKNOWN: sprintf(szVarType, "VT_UNKNOWN"); break;
1126     case VT_DISPATCH: sprintf(szVarType, "VT_DISPATCH"); break;
1127     case VT_I1: sprintf(szVarType, "VT_I1"); break;
1128     case VT_UI2: sprintf(szVarType, "VT_UI2"); break;
1129     case VT_UI4: sprintf(szVarType, "VT_UI4"); break;
1130     case VT_INT: sprintf(szVarType, "VT_INT"); break;
1131     case VT_UINT: sprintf(szVarType, "VT_UINT"); break;
1132     case VT_VARIANT: sprintf(szVarType, "VT_VARIANT"); break;
1133     case VT_VOID: sprintf(szVarType, "VT_VOID"); break;
1134     case VT_HRESULT: sprintf(szVarType, "VT_HRESULT"); break;
1135     case VT_USERDEFINED: sprintf(szVarType, "VT_USERDEFINED ref = %x",
1136                                  pTD->u.hreftype); break;
1137     case VT_LPSTR: sprintf(szVarType, "VT_LPSTR"); break;
1138     case VT_LPWSTR: sprintf(szVarType, "VT_LPWSTR"); break;
1139     case VT_PTR: sprintf(szVarType, "ptr to ");
1140       dump_TypeDesc(pTD->u.lptdesc, szVarType + 7);
1141       break;
1142     case VT_SAFEARRAY: sprintf(szVarType, "safearray of ");
1143       dump_TypeDesc(pTD->u.lptdesc, szVarType + 13);
1144       break;
1145     case VT_CARRAY: sprintf(szVarType, "%d dim array of ",
1146                             pTD->u.lpadesc->cDims); /* FIXME print out sizes */
1147       dump_TypeDesc(&pTD->u.lpadesc->tdescElem, szVarType + strlen(szVarType));
1148       break;
1149 
1150     default: sprintf(szVarType, "unknown(%d)", pTD->vt & VT_TYPEMASK); break;
1151     }
1152 }
1153 
1154 static void dump_ELEMDESC(const ELEMDESC *edesc) {
1155   char buf[200];
1156   USHORT flags = edesc->u.paramdesc.wParamFlags;
1157   dump_TypeDesc(&edesc->tdesc,buf);
1158   MESSAGE("\t\ttdesc.vartype %d (%s)\n",edesc->tdesc.vt,buf);
1159   MESSAGE("\t\tu.paramdesc.wParamFlags");
1160   if (!flags) MESSAGE(" PARAMFLAGS_NONE");
1161   if (flags & PARAMFLAG_FIN) MESSAGE(" PARAMFLAG_FIN");
1162   if (flags & PARAMFLAG_FOUT) MESSAGE(" PARAMFLAG_FOUT");
1163   if (flags & PARAMFLAG_FLCID) MESSAGE(" PARAMFLAG_FLCID");
1164   if (flags & PARAMFLAG_FRETVAL) MESSAGE(" PARAMFLAG_FRETVAL");
1165   if (flags & PARAMFLAG_FOPT) MESSAGE(" PARAMFLAG_FOPT");
1166   if (flags & PARAMFLAG_FHASDEFAULT) MESSAGE(" PARAMFLAG_FHASDEFAULT");
1167   if (flags & PARAMFLAG_FHASCUSTDATA) MESSAGE(" PARAMFLAG_FHASCUSTDATA");
1168   MESSAGE("\n\t\tu.paramdesc.lpex %p\n",edesc->u.paramdesc.pparamdescex);
1169 }
1170 static void dump_FUNCDESC(const FUNCDESC *funcdesc) {
1171   int i;
1172   MESSAGE("memid is %08x\n",funcdesc->memid);
1173   for (i=0;i<funcdesc->cParams;i++) {
1174       MESSAGE("Param %d:\n",i);
1175       dump_ELEMDESC(funcdesc->lprgelemdescParam+i);
1176   }
1177   MESSAGE("\tfunckind: %d (",funcdesc->funckind);
1178   switch (funcdesc->funckind) {
1179   case FUNC_VIRTUAL: MESSAGE("virtual");break;
1180   case FUNC_PUREVIRTUAL: MESSAGE("pure virtual");break;
1181   case FUNC_NONVIRTUAL: MESSAGE("nonvirtual");break;
1182   case FUNC_STATIC: MESSAGE("static");break;
1183   case FUNC_DISPATCH: MESSAGE("dispatch");break;
1184   default: MESSAGE("unknown");break;
1185   }
1186   MESSAGE(")\n\tinvkind: %d (",funcdesc->invkind);
1187   switch (funcdesc->invkind) {
1188   case INVOKE_FUNC: MESSAGE("func");break;
1189   case INVOKE_PROPERTYGET: MESSAGE("property get");break;
1190   case INVOKE_PROPERTYPUT: MESSAGE("property put");break;
1191   case INVOKE_PROPERTYPUTREF: MESSAGE("property put ref");break;
1192   }
1193   MESSAGE(")\n\tcallconv: %d (",funcdesc->callconv);
1194   switch (funcdesc->callconv) {
1195   case CC_CDECL: MESSAGE("cdecl");break;
1196   case CC_PASCAL: MESSAGE("pascal");break;
1197   case CC_STDCALL: MESSAGE("stdcall");break;
1198   case CC_SYSCALL: MESSAGE("syscall");break;
1199   default:break;
1200   }
1201   MESSAGE(")\n\toVft: %d\n", funcdesc->oVft);
1202   MESSAGE("\tcParamsOpt: %d\n", funcdesc->cParamsOpt);
1203   MESSAGE("\twFlags: %x\n", funcdesc->wFuncFlags);
1204 
1205   MESSAGE("\telemdescFunc (return value type):\n");
1206   dump_ELEMDESC(&funcdesc->elemdescFunc);
1207 }
1208 
1209 static const char * const typekind_desc[] =
1210 {
1211         "TKIND_ENUM",
1212         "TKIND_RECORD",
1213         "TKIND_MODULE",
1214         "TKIND_INTERFACE",
1215         "TKIND_DISPATCH",
1216         "TKIND_COCLASS",
1217         "TKIND_ALIAS",
1218         "TKIND_UNION",
1219         "TKIND_MAX"
1220 };
1221 
1222 static void dump_TLBFuncDescOne(const TLBFuncDesc * pfd)
1223 {
1224   int i;
1225   MESSAGE("%s(%u)\n", debugstr_w(pfd->Name), pfd->funcdesc.cParams);
1226   for (i=0;i<pfd->funcdesc.cParams;i++)
1227       MESSAGE("\tparm%d: %s\n",i,debugstr_w(pfd->pParamDesc[i].Name));
1228 
1229 
1230   dump_FUNCDESC(&(pfd->funcdesc));
1231 
1232   MESSAGE("\thelpstring: %s\n", debugstr_w(pfd->HelpString));
1233   MESSAGE("\tentry: %s\n", (pfd->Entry == (void *)-1) ? "invalid" : debugstr_w(pfd->Entry));
1234 }
1235 static void dump_TLBFuncDesc(const TLBFuncDesc * pfd)
1236 {
1237         while (pfd)
1238         {
1239           dump_TLBFuncDescOne(pfd);
1240           pfd = pfd->next;
1241         };
1242 }
1243 static void dump_TLBVarDesc(const TLBVarDesc * pvd)
1244 {
1245         while (pvd)
1246         {
1247           TRACE_(typelib)("%s\n", debugstr_w(pvd->Name));
1248           pvd = pvd->next;
1249         };
1250 }
1251 
1252 static void dump_TLBImpLib(const TLBImpLib *import)
1253 {
1254     TRACE_(typelib)("%s %s\n", debugstr_guid(&(import->guid)),
1255                     debugstr_w(import->name));
1256     TRACE_(typelib)("v%d.%d lcid=%x offset=%x\n", import->wVersionMajor,
1257                     import->wVersionMinor, import->lcid, import->offset);
1258 }
1259 
1260 static void dump_TLBRefType(const ITypeLibImpl *pTL)
1261 {
1262     TLBRefType *ref;
1263 
1264     LIST_FOR_EACH_ENTRY(ref, &pTL->ref_list, TLBRefType, entry)
1265     {
1266         TRACE_(typelib)("href:0x%08x\n", ref->reference);
1267         if(ref->index == -1)
1268             TRACE_(typelib)("%s\n", debugstr_guid(&(ref->guid)));
1269         else
1270             TRACE_(typelib)("type no: %d\n", ref->index);
1271 
1272         if(ref->pImpTLInfo != TLB_REF_INTERNAL && ref->pImpTLInfo != TLB_REF_NOT_FOUND)
1273         {
1274             TRACE_(typelib)("in lib\n");
1275             dump_TLBImpLib(ref->pImpTLInfo);
1276         }
1277     }
1278 }
1279 
1280 static void dump_TLBImplType(const TLBImplType * impl)
1281 {
1282     while (impl) {
1283         TRACE_(typelib)(
1284                 "implementing/inheriting interface hRef = %x implflags %x\n",
1285                 impl->hRef, impl->implflags);
1286         impl = impl->next;
1287     }
1288 }
1289 
1290 static void dump_Variant(const VARIANT * pvar)
1291 {
1292     SYSTEMTIME st;
1293 
1294     TRACE("%p->{%s%s", pvar, debugstr_VT(pvar), debugstr_VF(pvar));
1295 
1296     if (pvar)
1297     {
1298       if (V_ISBYREF(pvar) || V_TYPE(pvar) == VT_UNKNOWN ||
1299           V_TYPE(pvar) == VT_DISPATCH || V_TYPE(pvar) == VT_RECORD)
1300       {
1301         TRACE(",%p", V_BYREF(pvar));
1302       }
1303       else if (V_ISARRAY(pvar) || V_ISVECTOR(pvar))
1304       {
1305         TRACE(",%p", V_ARRAY(pvar));
1306       }
1307       else switch (V_TYPE(pvar))
1308       {
1309       case VT_I1:   TRACE(",%d", V_I1(pvar)); break;
1310       case VT_UI1:  TRACE(",%d", V_UI1(pvar)); break;
1311       case VT_I2:   TRACE(",%d", V_I2(pvar)); break;
1312       case VT_UI2:  TRACE(",%d", V_UI2(pvar)); break;
1313       case VT_INT:
1314       case VT_I4:   TRACE(",%d", V_I4(pvar)); break;
1315       case VT_UINT:
1316       case VT_UI4:  TRACE(",%d", V_UI4(pvar)); break;
1317       case VT_I8:   TRACE(",0x%08x,0x%08x", (ULONG)(V_I8(pvar) >> 32),
1318                           (ULONG)(V_I8(pvar) & 0xffffffff)); break;
1319       case VT_UI8:  TRACE(",0x%08x,0x%08x", (ULONG)(V_UI8(pvar) >> 32),
1320                           (ULONG)(V_UI8(pvar) & 0xffffffff)); break;
1321       case VT_R4:   TRACE(",%3.3e", V_R4(pvar)); break;
1322       case VT_R8:   TRACE(",%3.3e", V_R8(pvar)); break;
1323       case VT_BOOL: TRACE(",%s", V_BOOL(pvar) ? "TRUE" : "FALSE"); break;
1324       case VT_BSTR: TRACE(",%s", debugstr_w(V_BSTR(pvar))); break;
1325       case VT_CY:   TRACE(",0x%08x,0x%08x", V_CY(pvar).s.Hi,
1326                            V_CY(pvar).s.Lo); break;
1327       case VT_DATE:
1328         if(!VariantTimeToSystemTime(V_DATE(pvar), &st))
1329           TRACE(",<invalid>");
1330         else
1331           TRACE(",%04d/%02d/%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay,
1332                 st.wHour, st.wMinute, st.wSecond);
1333         break;
1334       case VT_ERROR:
1335       case VT_VOID:
1336       case VT_USERDEFINED:
1337       case VT_EMPTY:
1338       case VT_NULL:  break;
1339       default:       TRACE(",?"); break;
1340       }
1341     }
1342     TRACE("}\n");
1343 }
1344 
1345 static void dump_DispParms(const DISPPARAMS * pdp)
1346 {
1347     unsigned int index;
1348 
1349     TRACE("args=%u named args=%u\n", pdp->cArgs, pdp->cNamedArgs);
1350 
1351     if (pdp->cNamedArgs && pdp->rgdispidNamedArgs)
1352     {
1353         TRACE("named args:\n");
1354         for (index = 0; index < pdp->cNamedArgs; index++)
1355             TRACE( "\t0x%x\n", pdp->rgdispidNamedArgs[index] );
1356     }
1357 
1358     if (pdp->cArgs && pdp->rgvarg)
1359     {
1360         TRACE("args:\n");
1361         for (index = 0; index < pdp->cArgs; index++)
1362             dump_Variant( &pdp->rgvarg[index] );
1363     }
1364 }
1365 
1366 static void dump_TypeInfo(const ITypeInfoImpl * pty)
1367 {
1368     TRACE("%p ref=%u\n", pty, pty->ref);
1369     TRACE("%s %s\n", debugstr_w(pty->Name), debugstr_w(pty->DocString));
1370     TRACE("attr:%s\n", debugstr_guid(&(pty->TypeAttr.guid)));
1371     TRACE("kind:%s\n", typekind_desc[pty->TypeAttr.typekind]);
1372     TRACE("fct:%u var:%u impl:%u\n",
1373       pty->TypeAttr.cFuncs, pty->TypeAttr.cVars, pty->TypeAttr.cImplTypes);
1374     TRACE("wTypeFlags: 0x%04x\n", pty->TypeAttr.wTypeFlags);
1375     TRACE("parent tlb:%p index in TLB:%u\n",pty->pTypeLib, pty->index);
1376     if (pty->TypeAttr.typekind == TKIND_MODULE) TRACE("dllname:%s\n", debugstr_w(pty->DllName));
1377     if (TRACE_ON(ole))
1378         dump_TLBFuncDesc(pty->funclist);
1379     dump_TLBVarDesc(pty->varlist);
1380     dump_TLBImplType(pty->impltypelist);
1381 }
1382 
1383 static void dump_VARDESC(const VARDESC *v)
1384 {
1385     MESSAGE("memid %d\n",v->memid);
1386     MESSAGE("lpstrSchema %s\n",debugstr_w(v->lpstrSchema));
1387     MESSAGE("oInst %d\n",v->u.oInst);
1388     dump_ELEMDESC(&(v->elemdescVar));
1389     MESSAGE("wVarFlags %x\n",v->wVarFlags);
1390     MESSAGE("varkind %d\n",v->varkind);
1391 }
1392 
1393 static TYPEDESC stndTypeDesc[VT_LPWSTR+1]=
1394 {
1395     /* VT_LPWSTR is largest type that */
1396     /* may appear in type description*/
1397     {{0}, 0},{{0}, 1},{{0}, 2},{{0}, 3},{{0}, 4},
1398     {{0}, 5},{{0}, 6},{{0}, 7},{{0}, 8},{{0}, 9},
1399     {{0},10},{{0},11},{{0},12},{{0},13},{{0},14},
1400     {{0},15},{{0},16},{{0},17},{{0},18},{{0},19},
1401     {{0},20},{{0},21},{{0},22},{{0},23},{{0},24},
1402     {{0},25},{{0},26},{{0},27},{{0},28},{{0},29},
1403     {{0},30},{{0},31}
1404 };
1405 
1406 static void TLB_abort(void)
1407 {
1408     DebugBreak();
1409 }
1410 
1411 static void * TLB_Alloc(unsigned size) __WINE_ALLOC_SIZE(1);
1412 static void * TLB_Alloc(unsigned size)
1413 {
1414     void * ret;
1415     if((ret=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size))==NULL){
1416         /* FIXME */
1417         ERR("cannot allocate memory\n");
1418     }
1419     return ret;
1420 }
1421 
1422 static void TLB_Free(void * ptr)
1423 {
1424     HeapFree(GetProcessHeap(), 0, ptr);
1425 }
1426 
1427 /* returns the size required for a deep copy of a typedesc into a
1428  * flat buffer */
1429 static SIZE_T TLB_SizeTypeDesc( const TYPEDESC *tdesc, BOOL alloc_initial_space )
1430 {
1431     SIZE_T size = 0;
1432 
1433     if (alloc_initial_space)
1434         size += sizeof(TYPEDESC);
1435 
1436     switch (tdesc->vt)
1437     {
1438     case VT_PTR:
1439     case VT_SAFEARRAY:
1440         size += TLB_SizeTypeDesc(tdesc->u.lptdesc, TRUE);
1441         break;
1442     case VT_CARRAY:
1443         size += FIELD_OFFSET(ARRAYDESC, rgbounds[tdesc->u.lpadesc->cDims]);
1444         size += TLB_SizeTypeDesc(&tdesc->u.lpadesc->tdescElem, FALSE);
1445         break;
1446     }
1447     return size;
1448 }
1449 
1450 /* deep copy a typedesc into a flat buffer */
1451 static void *TLB_CopyTypeDesc( TYPEDESC *dest, const TYPEDESC *src, void *buffer )
1452 {
1453     if (!dest)
1454     {
1455         dest = buffer;
1456         buffer = (char *)buffer + sizeof(TYPEDESC);
1457     }
1458 
1459     *dest = *src;
1460 
1461     switch (src->vt)
1462     {
1463     case VT_PTR:
1464     case VT_SAFEARRAY:
1465         dest->u.lptdesc = buffer;
1466         buffer = TLB_CopyTypeDesc(NULL, src->u.lptdesc, buffer);
1467         break;
1468     case VT_CARRAY:
1469         dest->u.lpadesc = buffer;
1470         memcpy(dest->u.lpadesc, src->u.lpadesc, FIELD_OFFSET(ARRAYDESC, rgbounds[src->u.lpadesc->cDims]));
1471         buffer = (char *)buffer + FIELD_OFFSET(ARRAYDESC, rgbounds[src->u.lpadesc->cDims]);
1472         buffer = TLB_CopyTypeDesc(&dest->u.lpadesc->tdescElem, &src->u.lpadesc->tdescElem, buffer);
1473         break;
1474     }
1475     return buffer;
1476 }
1477 
1478 /* free custom data allocated by MSFT_CustData */
1479 static inline void TLB_FreeCustData(TLBCustData *pCustData)
1480 {
1481     TLBCustData *pCustDataNext;
1482     for (; pCustData; pCustData = pCustDataNext)
1483     {
1484         VariantClear(&pCustData->data);
1485 
1486         pCustDataNext = pCustData->next;
1487         TLB_Free(pCustData);
1488     }
1489 }
1490 
1491 static BSTR TLB_MultiByteToBSTR(const char *ptr)
1492 {
1493     DWORD len;
1494     BSTR ret;
1495 
1496     len = MultiByteToWideChar(CP_ACP, 0, ptr, -1, NULL, 0);
1497     ret = SysAllocStringLen(NULL, len - 1);
1498     if (!ret) return ret;
1499     MultiByteToWideChar(CP_ACP, 0, ptr, -1, ret, len);
1500     return ret;
1501 }
1502 
1503 /**********************************************************************
1504  *
1505  *  Functions for reading MSFT typelibs (those created by CreateTypeLib2)
1506  */
1507 static inline unsigned int MSFT_Tell(const TLBContext *pcx)
1508 {
1509     return pcx->pos;
1510 }
1511 
1512 static inline void MSFT_Seek(TLBContext *pcx, long where)
1513 {
1514     if (where != DO_NOT_SEEK)
1515     {
1516         where += pcx->oStart;
1517         if (where > pcx->length)
1518         {
1519             /* FIXME */
1520             ERR("seek beyond end (%ld/%d)\n", where, pcx->length );
1521             TLB_abort();
1522         }
1523         pcx->pos = where;
1524     }
1525 }
1526 
1527 /* read function */
1528 static DWORD MSFT_Read(void *buffer,  DWORD count, TLBContext *pcx, long where )
1529 {
1530     TRACE_(typelib)("pos=0x%08x len=0x%08x 0x%08x 0x%08x 0x%08lx\n",
1531        pcx->pos, count, pcx->oStart, pcx->length, where);
1532 
1533     MSFT_Seek(pcx, where);
1534     if (pcx->pos + count > pcx->length) count = pcx->length - pcx->pos;
1535     memcpy( buffer, (char *)pcx->mapping + pcx->pos, count );
1536     pcx->pos += count;
1537     return count;
1538 }
1539 
1540 static DWORD MSFT_ReadLEDWords(void *buffer,  DWORD count, TLBContext *pcx,
1541                                long where )
1542 {
1543   DWORD ret;
1544 
1545   ret = MSFT_Read(buffer, count, pcx, where);
1546   FromLEDWords(buffer, ret);
1547 
1548   return ret;
1549 }
1550 
1551 static DWORD MSFT_ReadLEWords(void *buffer,  DWORD count, TLBContext *pcx,
1552                               long where )
1553 {
1554   DWORD ret;
1555 
1556   ret = MSFT_Read(buffer, count, pcx, where);
1557   FromLEWords(buffer, ret);
1558 
1559   return ret;
1560 }
1561 
1562 static void MSFT_ReadGuid( GUID *pGuid, int offset, TLBContext *pcx)
1563 {
1564     if(offset<0 || pcx->pTblDir->pGuidTab.offset <0){
1565         memset(pGuid,0, sizeof(GUID));
1566         return;
1567     }
1568     MSFT_Read(pGuid, sizeof(GUID), pcx, pcx->pTblDir->pGuidTab.offset+offset );
1569     pGuid->Data1 = FromLEDWord(pGuid->Data1);
1570     pGuid->Data2 = FromLEWord(pGuid->Data2);
1571     pGuid->Data3 = FromLEWord(pGuid->Data3);
1572     TRACE_(typelib)("%s\n", debugstr_guid(pGuid));
1573 }
1574 
1575 static HREFTYPE MSFT_ReadHreftype( TLBContext *pcx, int offset )
1576 {
1577     MSFT_NameIntro niName;
1578 
1579     if (offset < 0)
1580     {
1581         ERR_(typelib)("bad offset %d\n", offset);
1582         return -1;
1583     }
1584 
1585     MSFT_ReadLEDWords(&niName, sizeof(niName), pcx,
1586                       pcx->pTblDir->pNametab.offset+offset);
1587 
1588     return niName.hreftype;
1589 }
1590 
1591 static BSTR MSFT_ReadName( TLBContext *pcx, int offset)
1592 {
1593     char * name;
1594     MSFT_NameIntro niName;
1595     int lengthInChars;
1596     BSTR bstrName = NULL;
1597 
1598     if (offset < 0)
1599     {
1600         ERR_(typelib)("bad offset %d\n", offset);
1601         return NULL;
1602     }
1603     MSFT_ReadLEDWords(&niName, sizeof(niName), pcx,
1604                       pcx->pTblDir->pNametab.offset+offset);
1605     niName.namelen &= 0xFF; /* FIXME: correct ? */
1606     name=TLB_Alloc((niName.namelen & 0xff) +1);
1607     MSFT_Read(name, (niName.namelen & 0xff), pcx, DO_NOT_SEEK);
1608     name[niName.namelen & 0xff]='\0';
1609 
1610     lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
1611                                         name, -1, NULL, 0);
1612 
1613     /* no invalid characters in string */
1614     if (lengthInChars)
1615     {
1616         bstrName = SysAllocStringByteLen(NULL, lengthInChars * sizeof(WCHAR));
1617 
1618         /* don't check for invalid character since this has been done previously */
1619         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name, -1, bstrName, lengthInChars);
1620     }
1621     TLB_Free(name);
1622 
1623     TRACE_(typelib)("%s %d\n", debugstr_w(bstrName), lengthInChars);
1624     return bstrName;
1625 }
1626 
1627 static BSTR MSFT_ReadString( TLBContext *pcx, int offset)
1628 {
1629     char * string;
1630     INT16 length;
1631     int lengthInChars;
1632     BSTR bstr = NULL;
1633 
1634     if(offset<0) return NULL;
1635     MSFT_ReadLEWords(&length, sizeof(INT16), pcx, pcx->pTblDir->pStringtab.offset+offset);
1636     if(length <= 0) return 0;
1637     string=TLB_Alloc(length +1);
1638     MSFT_Read(string, length, pcx, DO_NOT_SEEK);
1639     string[length]='\0';
1640 
1641     lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
1642                                         string, -1, NULL, 0);
1643 
1644     /* no invalid characters in string */
1645     if (lengthInChars)
1646     {
1647         bstr = SysAllocStringByteLen(NULL, lengthInChars * sizeof(WCHAR));
1648 
1649         /* don't check for invalid character since this has been done previously */
1650         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, string, -1, bstr, lengthInChars);
1651     }
1652     TLB_Free(string);
1653 
1654     TRACE_(typelib)("%s %d\n", debugstr_w(bstr), lengthInChars);
1655     return bstr;
1656 }
1657 /*
1658  * read a value and fill a VARIANT structure
1659  */
1660 static void MSFT_ReadValue( VARIANT * pVar, int offset, TLBContext *pcx )
1661 {
1662     int size;
1663 
1664     TRACE_(typelib)("\n");
1665 
1666     if(offset <0) { /* data are packed in here */
1667         V_VT(pVar) = (offset & 0x7c000000 )>> 26;
1668         V_I4(pVar) = offset & 0x3ffffff;
1669         return;
1670     }
1671     MSFT_ReadLEWords(&(V_VT(pVar)), sizeof(VARTYPE), pcx,
1672                      pcx->pTblDir->pCustData.offset + offset );
1673     TRACE_(typelib)("Vartype = %x\n", V_VT(pVar));
1674     switch (V_VT(pVar)){
1675         case VT_EMPTY:  /* FIXME: is this right? */
1676         case VT_NULL:   /* FIXME: is this right? */
1677         case VT_I2  :   /* this should not happen */
1678         case VT_I4  :
1679         case VT_R4  :
1680         case VT_ERROR   :
1681         case VT_BOOL    :
1682         case VT_I1  :
1683         case VT_UI1 :
1684         case VT_UI2 :
1685         case VT_UI4 :
1686         case VT_INT :
1687         case VT_UINT    :
1688         case VT_VOID    : /* FIXME: is this right? */
1689         case VT_HRESULT :
1690             size=4; break;
1691         case VT_R8  :
1692         case VT_CY  :
1693         case VT_DATE    :
1694         case VT_I8  :
1695         case VT_UI8 :
1696         case VT_DECIMAL :  /* FIXME: is this right? */
1697         case VT_FILETIME :
1698             size=8;break;
1699             /* pointer types with known behaviour */
1700         case VT_BSTR    :{
1701             char * ptr;
1702             MSFT_ReadLEDWords(&size, sizeof(INT), pcx, DO_NOT_SEEK );
1703             if(size < 0) {
1704                 char next;
1705                 DWORD origPos = MSFT_Tell(pcx), nullPos;
1706 
1707                 do {
1708                     MSFT_Read(&next, 1, pcx, DO_NOT_SEEK);
1709                 } while (next);
1710                 nullPos = MSFT_Tell(pcx);
1711                 size = nullPos - origPos;
1712                 MSFT_Seek(pcx, origPos);
1713             }
1714             ptr=TLB_Alloc(size);/* allocate temp buffer */
1715             MSFT_Read(ptr, size, pcx, DO_NOT_SEEK);/* read string (ANSI) */
1716             V_BSTR(pVar)=SysAllocStringLen(NULL,size);
1717             /* FIXME: do we need a AtoW conversion here? */
1718             V_UNION(pVar, bstrVal[size])='\0';
1719             while(size--) V_UNION(pVar, bstrVal[size])=ptr[size];
1720             TLB_Free(ptr);
1721         }
1722         size=-4; break;
1723     /* FIXME: this will not work AT ALL when the variant contains a pointer */
1724         case VT_DISPATCH :
1725         case VT_VARIANT :
1726         case VT_UNKNOWN :
1727         case VT_PTR :
1728         case VT_SAFEARRAY :
1729         case VT_CARRAY  :
1730         case VT_USERDEFINED :
1731         case VT_LPSTR   :
1732         case VT_LPWSTR  :
1733         case VT_BLOB    :
1734         case VT_STREAM  :
1735         case VT_STORAGE :
1736         case VT_STREAMED_OBJECT :
1737         case VT_STORED_OBJECT   :
1738         case VT_BLOB_OBJECT :
1739         case VT_CF  :
1740         case VT_CLSID   :
1741         default:
1742             size=0;
1743             FIXME("VARTYPE %d is not supported, setting pointer to NULL\n",
1744                 V_VT(pVar));
1745     }
1746 
1747     if(size>0) /* (big|small) endian correct? */
1748         MSFT_Read(&(V_I2(pVar)), size, pcx, DO_NOT_SEEK );
1749     return;
1750 }
1751 /*
1752  * create a linked list with custom data
1753  */
1754 static int MSFT_CustData( TLBContext *pcx, int offset, TLBCustData** ppCustData )
1755 {
1756     MSFT_CDGuid entry;
1757     TLBCustData* pNew;
1758     int count=0;
1759 
1760     TRACE_(typelib)("\n");
1761 
1762     while(offset >=0){
1763         count++;
1764         pNew=TLB_Alloc(sizeof(TLBCustData));
1765         MSFT_ReadLEDWords(&entry, sizeof(entry), pcx, pcx->pTblDir->pCDGuids.offset+offset);
1766         MSFT_ReadGuid(&(pNew->guid), entry.GuidOffset , pcx);
1767         MSFT_ReadValue(&(pNew->data), entry.DataOffset, pcx);
1768         /* add new custom data at head of the list */
1769         pNew->next=*ppCustData;
1770         *ppCustData=pNew;
1771         offset = entry.next;
1772     }
1773     return count;
1774 }
1775 
1776 static void MSFT_GetTdesc(TLBContext *pcx, INT type, TYPEDESC *pTd,
1777                           ITypeInfoImpl *pTI)
1778 {
1779     if(type <0)
1780         pTd->vt=type & VT_TYPEMASK;
1781     else
1782         *pTd=pcx->pLibInfo->pTypeDesc[type/(2*sizeof(INT))];
1783 
1784     if(pTd->vt == VT_USERDEFINED)
1785       MSFT_DoRefType(pcx, pTI->pTypeLib, pTd->u.hreftype);
1786 
1787     TRACE_(typelib)("vt type = %X\n", pTd->vt);
1788 }
1789 
1790 static void MSFT_ResolveReferencedTypes(TLBContext *pcx, ITypeInfoImpl *pTI, TYPEDESC *lpTypeDesc)
1791 {
1792     /* resolve referenced type if any */
1793     while (lpTypeDesc)
1794     {
1795         switch (lpTypeDesc->vt)
1796         {
1797         case VT_PTR:
1798             lpTypeDesc = lpTypeDesc->u.lptdesc;
1799             break;
1800 
1801         case VT_CARRAY:
1802             lpTypeDesc = & (lpTypeDesc->u.lpadesc->tdescElem);
1803             break;
1804 
1805         case VT_USERDEFINED:
1806             MSFT_DoRefType(pcx, pTI->pTypeLib,
1807                            lpTypeDesc->u.hreftype);
1808 
1809             lpTypeDesc = NULL;
1810             break;
1811 
1812         default:
1813             lpTypeDesc = NULL;
1814         }
1815     }
1816 }
1817 
1818 static void
1819 MSFT_DoFuncs(TLBContext*     pcx,
1820             ITypeInfoImpl*  pTI,
1821             int             cFuncs,
1822             int             cVars,
1823             int             offset,
1824             TLBFuncDesc**   pptfd)
1825 {
1826     /*
1827      * member information is stored in a data structure at offset
1828      * indicated by the memoffset field of the typeinfo structure
1829      * There are several distinctive parts.
1830      * The first part starts with a field that holds the total length
1831      * of this (first) part excluding this field. Then follow the records,
1832      * for each member there is one record.
1833      *
1834      * The first entry is always the length of the record (including this
1835      * length word).
1836      * The rest of the record depends on the type of the member. If there is
1837      * a field indicating the member type (function, variable, interface, etc)
1838      * I have not found it yet. At this time we depend on the information
1839      * in the type info and the usual order how things are stored.
1840      *
1841      * Second follows an array sized nrMEM*sizeof(INT) with a member id
1842      * for each member;
1843      *
1844      * Third is an equal sized array with file offsets to the name entry
1845      * of each member.
1846      *
1847      * The fourth and last (?) part is an array with offsets to the records
1848      * in the first part of this file segment.
1849      */
1850 
1851     int infolen, nameoffset, reclength, nrattributes, i;
1852     int recoffset = offset + sizeof(INT);
1853 
1854     char *recbuf = HeapAlloc(GetProcessHeap(), 0, 0xffff);
1855     MSFT_FuncRecord * pFuncRec=(MSFT_FuncRecord *) recbuf;
1856     TLBFuncDesc *ptfd_prev = NULL;
1857 
1858     TRACE_(typelib)("\n");
1859 
1860     MSFT_ReadLEDWords(&infolen, sizeof(INT), pcx, offset);
1861 
1862     for ( i = 0; i < cFuncs ; i++ )
1863     {
1864         *pptfd = TLB_Alloc(sizeof(TLBFuncDesc));
1865 
1866         /* name, eventually add to a hash table */
1867         MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx,
1868                           offset + infolen + (cFuncs + cVars + i + 1) * sizeof(INT));
1869 
1870         /* nameoffset is sometimes -1 on the second half of a propget/propput
1871          * pair of functions */
1872         if ((nameoffset == -1) && (i > 0))
1873             (*pptfd)->Name = SysAllocString(ptfd_prev->Name);
1874         else
1875             (*pptfd)->Name = MSFT_ReadName(pcx, nameoffset);
1876 
1877         /* read the function information record */
1878         MSFT_ReadLEDWords(&reclength, sizeof(INT), pcx, recoffset);
1879 
1880         reclength &= 0xffff;
1881 
1882         MSFT_ReadLEDWords(pFuncRec, reclength - sizeof(INT), pcx, DO_NOT_SEEK);
1883 
1884         /* do the attributes */
1885         nrattributes = (reclength - pFuncRec->nrargs * 3 * sizeof(int) - 0x18)
1886                        / sizeof(int);
1887 
1888         if ( nrattributes > 0 )
1889         {
1890             (*pptfd)->helpcontext = pFuncRec->OptAttr[0] ;
1891 
1892             if ( nrattributes > 1 )
1893             {
1894                 (*pptfd)->HelpString = MSFT_ReadString(pcx,
1895                                                       pFuncRec->OptAttr[1]) ;
1896 
1897                 if ( nrattributes > 2 )
1898                 {
1899                     if ( pFuncRec->FKCCIC & 0x2000 )
1900                     {
1901                        if (HIWORD(pFuncRec->OptAttr[2]) != 0)
1902                            ERR("ordinal 0x%08x invalid, HIWORD != 0\n", pFuncRec->OptAttr[2]);
1903                        (*pptfd)->Entry = (BSTR)pFuncRec->OptAttr[2];
1904                     }
1905                     else
1906                     {
1907                         (*pptfd)->Entry = MSFT_ReadString(pcx,
1908                                                          pFuncRec->OptAttr[2]);
1909                     }
1910                     if( nrattributes > 5 )
1911                     {
1912                         (*pptfd)->HelpStringContext = pFuncRec->OptAttr[5] ;
1913 
1914                         if ( nrattributes > 6 && pFuncRec->FKCCIC & 0x80 )
1915                         {
1916                             MSFT_CustData(pcx,
1917                                           pFuncRec->OptAttr[6],
1918                                           &(*pptfd)->pCustData);
1919                         }
1920                     }
1921                 }
1922                 else
1923                 {
1924                     (*pptfd)->Entry = (BSTR)-1;
1925                 }
1926             }
1927         }
1928 
1929         /* fill the FuncDesc Structure */
1930         MSFT_ReadLEDWords( & (*pptfd)->funcdesc.memid, sizeof(INT), pcx,
1931                            offset + infolen + ( i + 1) * sizeof(INT));
1932 
1933         (*pptfd)->funcdesc.funckind   =  (pFuncRec->FKCCIC)      & 0x7;
1934         (*pptfd)->funcdesc.invkind    =  (pFuncRec->FKCCIC) >> 3 & 0xF;
1935         (*pptfd)->funcdesc.callconv   =  (pFuncRec->FKCCIC) >> 8 & 0xF;
1936         (*pptfd)->funcdesc.cParams    =   pFuncRec->nrargs  ;
1937         (*pptfd)->funcdesc.cParamsOpt =   pFuncRec->nroargs ;
1938         (*pptfd)->funcdesc.oVft       =   pFuncRec->VtableOffset;
1939         (*pptfd)->funcdesc.wFuncFlags =   LOWORD(pFuncRec->Flags) ;
1940 
1941         MSFT_GetTdesc(pcx,
1942                       pFuncRec->DataType,
1943                       &(*pptfd)->funcdesc.elemdescFunc.tdesc,
1944                       pTI);
1945         MSFT_ResolveReferencedTypes(pcx, pTI, &(*pptfd)->funcdesc.elemdescFunc.tdesc);
1946 
1947         /* do the parameters/arguments */
1948         if(pFuncRec->nrargs)
1949         {
1950             int j = 0;
1951             MSFT_ParameterInfo paraminfo;
1952 
1953             (*pptfd)->funcdesc.lprgelemdescParam =
1954                 TLB_Alloc(pFuncRec->nrargs * sizeof(ELEMDESC));
1955 
1956             (*pptfd)->pParamDesc =
1957                 TLB_Alloc(pFuncRec->nrargs * sizeof(TLBParDesc));
1958 
1959             MSFT_ReadLEDWords(&paraminfo, sizeof(paraminfo), pcx,
1960                               recoffset + reclength - pFuncRec->nrargs * sizeof(MSFT_ParameterInfo));
1961 
1962             for ( j = 0 ; j < pFuncRec->nrargs ; j++ )
1963             {
1964                 ELEMDESC *elemdesc = &(*pptfd)->funcdesc.lprgelemdescParam[j];
1965 
1966                 MSFT_GetTdesc(pcx,
1967                               paraminfo.DataType,
1968                               &elemdesc->tdesc,
1969                               pTI);
1970 
1971                 elemdesc->u.paramdesc.wParamFlags = paraminfo.Flags;
1972 
1973                 /* name */
1974                 if (paraminfo.oName == -1)
1975                     /* this occurs for [propput] or [propget] methods, so
1976                      * we should just set the name of the parameter to the
1977                      * name of the method. */
1978                     (*pptfd)->pParamDesc[j].Name = SysAllocString((*pptfd)->Name);
1979                 else
1980                     (*pptfd)->pParamDesc[j].Name =
1981                         MSFT_ReadName( pcx, paraminfo.oName );
1982                 TRACE_(typelib)("param[%d] = %s\n", j, debugstr_w((*pptfd)->pParamDesc[j].Name));
1983 
1984                 MSFT_ResolveReferencedTypes(pcx, pTI, &elemdesc->tdesc);
1985 
1986                 /* default value */
1987                 if ( (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) &&
1988                      (pFuncRec->FKCCIC & 0x1000) )
1989                 {
1990                     INT* pInt = (INT *)((char *)pFuncRec +
1991                                    reclength -
1992                                    (pFuncRec->nrargs * 4 + 1) * sizeof(INT) );
1993 
1994                     PARAMDESC* pParamDesc = &elemdesc->u.paramdesc;
1995 
1996                     pParamDesc->pparamdescex = TLB_Alloc(sizeof(PARAMDESCEX));
1997                     pParamDesc->pparamdescex->cBytes = sizeof(PARAMDESCEX);
1998 
1999                     MSFT_ReadValue(&(pParamDesc->pparamdescex->varDefaultValue),
2000                         pInt[j], pcx);
2001                 }
2002                 else
2003                     elemdesc->u.paramdesc.pparamdescex = NULL;
2004                 /* custom info */
2005                 if ( nrattributes > 7 + j && pFuncRec->FKCCIC & 0x80 )
2006                 {
2007                     MSFT_CustData(pcx,
2008                                   pFuncRec->OptAttr[7+j],
2009                                   &(*pptfd)->pParamDesc[j].pCustData);
2010                 }
2011 
2012                 /* SEEK value = jump to offset,
2013                  * from there jump to the end of record,
2014                  * go back by (j-1) arguments
2015                  */
2016                 MSFT_ReadLEDWords( &paraminfo ,
2017                            sizeof(MSFT_ParameterInfo), pcx,
2018                            recoffset + reclength - ((pFuncRec->nrargs - j - 1)
2019                                                * sizeof(MSFT_ParameterInfo)));
2020             }
2021         }
2022 
2023         /* scode is not used: archaic win16 stuff FIXME: right? */
2024         (*pptfd)->funcdesc.cScodes   = 0 ;
2025         (*pptfd)->funcdesc.lprgscode = NULL ;
2026 
2027         ptfd_prev = *pptfd;
2028         pptfd      = & ((*pptfd)->next);
2029         recoffset += reclength;
2030     }
2031     HeapFree(GetProcessHeap(), 0, recbuf);
2032 }
2033 
2034 static void MSFT_DoVars(TLBContext *pcx, ITypeInfoImpl *pTI, int cFuncs,
2035                        int cVars, int offset, TLBVarDesc ** pptvd)
2036 {
2037     int infolen, nameoffset, reclength;
2038     char recbuf[256];
2039     MSFT_VarRecord * pVarRec=(MSFT_VarRecord *) recbuf;
2040     int i;
2041     int recoffset;
2042 
2043     TRACE_(typelib)("\n");
2044 
2045     MSFT_ReadLEDWords(&infolen,sizeof(INT), pcx, offset);
2046     MSFT_ReadLEDWords(&recoffset,sizeof(INT), pcx, offset + infolen +
2047                       ((cFuncs+cVars)*2+cFuncs + 1)*sizeof(INT));
2048     recoffset += offset+sizeof(INT);
2049     for(i=0;i<cVars;i++){
2050         *pptvd=TLB_Alloc(sizeof(TLBVarDesc));
2051     /* name, eventually add to a hash table */
2052         MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx,
2053                           offset + infolen + (2*cFuncs + cVars + i + 1) * sizeof(INT));
2054         (*pptvd)->Name=MSFT_ReadName(pcx, nameoffset);
2055     /* read the variable information record */
2056         MSFT_ReadLEDWords(&reclength, sizeof(INT), pcx, recoffset);
2057         reclength &=0xff;
2058         MSFT_ReadLEDWords(pVarRec, reclength - sizeof(INT), pcx, DO_NOT_SEEK);
2059     /* Optional data */
2060         if(reclength >(6*sizeof(INT)) )
2061             (*pptvd)->HelpContext=pVarRec->HelpContext;
2062         if(reclength >(7*sizeof(INT)) )
2063             (*pptvd)->HelpString = MSFT_ReadString(pcx, pVarRec->oHelpString) ;
2064         if(reclength >(8*sizeof(INT)) )
2065         if(reclength >(9*sizeof(INT)) )
2066             (*pptvd)->HelpStringContext=pVarRec->HelpStringContext;
2067     /* fill the VarDesc Structure */
2068         MSFT_ReadLEDWords(&(*pptvd)->vardesc.memid, sizeof(INT), pcx,
2069                           offset + infolen + (cFuncs + i + 1) * sizeof(INT));
2070         (*pptvd)->vardesc.varkind = pVarRec->VarKind;
2071         (*pptvd)->vardesc.wVarFlags = pVarRec->Flags;
2072         MSFT_GetTdesc(pcx, pVarRec->DataType,
2073             &(*pptvd)->vardesc.elemdescVar.tdesc, pTI);
2074 /*   (*pptvd)->vardesc.lpstrSchema; is reserved (SDK) FIXME?? */
2075         if(pVarRec->VarKind == VAR_CONST ){
2076             (*pptvd)->vardesc.u.lpvarValue=TLB_Alloc(sizeof(VARIANT));
2077             MSFT_ReadValue((*pptvd)->vardesc.u.lpvarValue,
2078                 pVarRec->OffsValue, pcx);
2079         } else
2080             (*pptvd)->vardesc.u.oInst=pVarRec->OffsValue;
2081         MSFT_ResolveReferencedTypes(pcx, pTI, &(*pptvd)->vardesc.elemdescVar.tdesc);
2082         pptvd=&((*pptvd)->next);
2083         recoffset += reclength;
2084     }
2085 }
2086 /* fill in data for a hreftype (offset). When the referenced type is contained
2087  * in the typelib, it's just an (file) offset in the type info base dir.
2088  * If comes from import, it's an offset+1 in the ImpInfo table
2089  * */
2090 static void MSFT_DoRefType(TLBContext *pcx, ITypeLibImpl *pTL,
2091                           int offset)
2092 {
2093     TLBRefType *ref;
2094 
2095     TRACE_(typelib)("TLB context %p, TLB offset %x\n", pcx, offset);
2096 
2097     LIST_FOR_EACH_ENTRY(ref, &pTL->ref_list, TLBRefType, entry)
2098     {
2099         if(ref->reference == offset) return;
2100     }
2101 
2102     ref = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ref));
2103     list_add_tail(&pTL->ref_list, &ref->entry);
2104 
2105     if(!MSFT_HREFTYPE_INTHISFILE( offset)) {
2106         /* external typelib */
2107         MSFT_ImpInfo impinfo;
2108         TLBImpLib *pImpLib=(pcx->pLibInfo->pImpLibs);
2109 
2110         TRACE_(typelib)("offset %x, masked offset %x\n", offset, offset + (offset & 0xfffffffc));
2111 
2112         MSFT_ReadLEDWords(&impinfo, sizeof(impinfo), pcx,
2113                           pcx->pTblDir->pImpInfo.offset + (offset & 0xfffffffc));
2114         while (pImpLib){   /* search the known offsets of all import libraries */
2115             if(pImpLib->offset==impinfo.oImpFile) break;
2116             pImpLib=pImpLib->next;
2117         }
2118         if(pImpLib){
2119             ref->reference = offset;
2120             ref->pImpTLInfo = pImpLib;
2121             if(impinfo.flags & MSFT_IMPINFO_OFFSET_IS_GUID) {
2122                 MSFT_ReadGuid(&ref->guid, impinfo.oGuid, pcx);
2123                 TRACE("importing by guid %s\n", debugstr_guid(&ref->guid));
2124                 ref->index = TLB_REF_USE_GUID;
2125             } else
2126                 ref->index = impinfo.oGuid;
2127         }else{
2128             ERR("Cannot find a reference\n");
2129             ref->reference = -1;
2130             ref->pImpTLInfo = TLB_REF_NOT_FOUND;
2131         }
2132     }else{
2133         /* in this typelib */
2134         ref->index = MSFT_HREFTYPE_INDEX(offset);
2135         ref->reference = offset;
2136         ref->pImpTLInfo = TLB_REF_INTERNAL;
2137     }
2138 }
2139 
2140 /* process Implemented Interfaces of a com class */
2141 static void MSFT_DoImplTypes(TLBContext *pcx, ITypeInfoImpl *pTI, int count,
2142                             int offset)
2143 {
2144     int i;
2145     MSFT_RefRecord refrec;
2146     TLBImplType **ppImpl = &pTI->impltypelist;
2147 
2148     TRACE_(typelib)("\n");
2149 
2150     for(i=0;i<count;i++){
2151         if(offset<0) break; /* paranoia */
2152         *ppImpl=TLB_Alloc(sizeof(**ppImpl));
2153         MSFT_ReadLEDWords(&refrec,sizeof(refrec),pcx,offset+pcx->pTblDir->pRefTab.offset);
2154         MSFT_DoRefType(pcx, pTI->pTypeLib, refrec.reftype);
2155         (*ppImpl)->hRef = refrec.reftype;
2156         (*ppImpl)->implflags=refrec.flags;
2157         (*ppImpl)->ctCustData=
2158             MSFT_CustData(pcx, refrec.oCustData, &(*ppImpl)->pCustData);
2159         offset=refrec.onext;
2160         ppImpl=&((*ppImpl)->next);
2161     }
2162 }
2163 /*
2164  * process a typeinfo record
2165  */
2166 static ITypeInfoImpl * MSFT_DoTypeInfo(
2167     TLBContext *pcx,
2168     int count,
2169     ITypeLibImpl * pLibInfo)
2170 {
2171     MSFT_TypeInfoBase tiBase;
2172     ITypeInfoImpl *ptiRet;
2173 
2174     TRACE_(typelib)("count=%u\n", count);
2175 
2176     ptiRet = (ITypeInfoImpl*) ITypeInfo_Constructor();
2177     MSFT_ReadLEDWords(&tiBase, sizeof(tiBase) ,pcx ,
2178                       pcx->pTblDir->pTypeInfoTab.offset+count*sizeof(tiBase));
2179 
2180 /* this is where we are coming from */
2181     ptiRet->pTypeLib = pLibInfo;
2182     ptiRet->index=count;
2183 /* fill in the typeattr fields */
2184 
2185     MSFT_ReadGuid(&ptiRet->TypeAttr.guid, tiBase.posguid, pcx);
2186     ptiRet->TypeAttr.lcid=pLibInfo->LibAttr.lcid;   /* FIXME: correct? */
2187     ptiRet->TypeAttr.lpstrSchema=NULL;              /* reserved */
2188     ptiRet->TypeAttr.cbSizeInstance=tiBase.size;
2189     ptiRet->TypeAttr.typekind=tiBase.typekind & 0xF;
2190     ptiRet->TypeAttr.cFuncs=LOWORD(tiBase.cElement);
2191     ptiRet->TypeAttr.cVars=HIWORD(tiBase.cElement);
2192     ptiRet->TypeAttr.cbAlignment=(tiBase.typekind >> 11 )& 0x1F; /* there are more flags there */
2193     ptiRet->TypeAttr.wTypeFlags=tiBase.flags;
2194     ptiRet->TypeAttr.wMajorVerNum=LOWORD(tiBase.version);
2195     ptiRet->TypeAttr.wMinorVerNum=HIWORD(tiBase.version);
2196     ptiRet->TypeAttr.cImplTypes=tiBase.cImplTypes;
2197     ptiRet->TypeAttr.cbSizeVft=tiBase.cbSizeVft; /* FIXME: this is only the non inherited part */
2198     if(ptiRet->TypeAttr.typekind == TKIND_ALIAS)
2199         MSFT_GetTdesc(pcx, tiBase.datatype1,
2200             &ptiRet->TypeAttr.tdescAlias, ptiRet);
2201 
2202 /*  FIXME: */
2203 /*    IDLDESC  idldescType; *//* never saw this one != zero  */
2204 
2205 /* name, eventually add to a hash table */
2206     ptiRet->Name=MSFT_ReadName(pcx, tiBase.NameOffset);
2207     ptiRet->hreftype = MSFT_ReadHreftype(pcx, tiBase.NameOffset);
2208     TRACE_(typelib)("reading %s\n", debugstr_w(ptiRet->Name));
2209     /* help info */
2210     ptiRet->DocString=MSFT_ReadString(pcx, tiBase.docstringoffs);
2211     ptiRet->dwHelpStringContext=tiBase.helpstringcontext;
2212     ptiRet->dwHelpContext=tiBase.helpcontext;
2213 
2214     if (ptiRet->TypeAttr.typekind == TKIND_MODULE)
2215         ptiRet->DllName = MSFT_ReadString(pcx, tiBase.datatype1);
2216 
2217 /* note: InfoType's Help file and HelpStringDll come from the containing
2218  * library. Further HelpString and Docstring appear to be the same thing :(
2219  */
2220     /* functions */
2221     if(ptiRet->TypeAttr.cFuncs >0 )
2222         MSFT_DoFuncs(pcx, ptiRet, ptiRet->TypeAttr.cFuncs,
2223                     ptiRet->TypeAttr.cVars,
2224                     tiBase.memoffset, & ptiRet->funclist);
2225     /* variables */
2226     if(ptiRet->TypeAttr.cVars >0 )
2227         MSFT_DoVars(pcx, ptiRet, ptiRet->TypeAttr.cFuncs,
2228                    ptiRet->TypeAttr.cVars,
2229                    tiBase.memoffset, & ptiRet->varlist);
2230     if(ptiRet->TypeAttr.cImplTypes >0 ) {
2231         switch(ptiRet->TypeAttr.typekind)
2232         {
2233         case TKIND_COCLASS:
2234             MSFT_DoImplTypes(pcx, ptiRet, ptiRet->TypeAttr.cImplTypes ,
2235                 tiBase.datatype1);
2236             break;
2237         case TKIND_DISPATCH:
2238             /* This is not -1 when the interface is a non-base dual interface or
2239                when a dispinterface wraps an interface, i.e., the idl 'dispinterface x {interface y;};'.
2240                Note however that GetRefTypeOfImplType(0) always returns a ref to IDispatch and
2241                not this interface.
2242             */
2243 
2244             if (tiBase.datatype1 != -1)
2245             {
2246                 ptiRet->impltypelist = TLB_Alloc(sizeof(TLBImplType));
2247                 ptiRet->impltypelist->hRef = tiBase.datatype1;
2248                 MSFT_DoRefType(pcx, pLibInfo, tiBase.datatype1);
2249             }
2250           break;
2251         default:
2252             ptiRet->impltypelist=TLB_Alloc(sizeof(TLBImplType));
2253             MSFT_DoRefType(pcx, pLibInfo, tiBase.datatype1);
2254             ptiRet->impltypelist->hRef = tiBase.datatype1;
2255             break;
2256        }
2257     }
2258     ptiRet->ctCustData=
2259         MSFT_CustData(pcx, tiBase.oCustData, &ptiRet->pCustData);
2260 
2261     TRACE_(typelib)("%s guid: %s kind:%s\n",
2262        debugstr_w(ptiRet->Name),
2263        debugstr_guid(&ptiRet->TypeAttr.guid),
2264        typekind_desc[ptiRet->TypeAttr.typekind]);
2265     if (TRACE_ON(typelib))
2266       dump_TypeInfo(ptiRet);
2267 
2268     return ptiRet;
2269 }
2270 
2271 /* Because type library parsing has some degree of overhead, and some apps repeatedly load the same
2272  * typelibs over and over, we cache them here. According to MSDN Microsoft have a similar scheme in
2273  * place. This will cause a deliberate memory leak, but generally losing RAM for cycles is an acceptable
2274  * tradeoff here.
2275  */
2276 static ITypeLibImpl *tlb_cache_first;
2277 static CRITICAL_SECTION cache_section;
2278 static CRITICAL_SECTION_DEBUG cache_section_debug =
2279 {
2280     0, 0, &cache_section,
2281     { &cache_section_debug.ProcessLocksList, &cache_section_debug.ProcessLocksList },
2282       0, 0, { (DWORD_PTR)(__FILE__ ": typelib loader cache") }
2283 };
2284 static CRITICAL_SECTION cache_section = { &cache_section_debug, -1, 0, 0, 0, 0 };
2285 
2286 
2287 typedef struct TLB_PEFile
2288 {
2289     const IUnknownVtbl *lpvtbl;
2290     LONG refs;
2291     HMODULE dll;
2292     HRSRC typelib_resource;
2293     HGLOBAL typelib_global;
2294     LPVOID typelib_base;
2295 } TLB_PEFile;
2296 
2297 static HRESULT WINAPI TLB_PEFile_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2298 {
2299     if (IsEqualIID(riid, &IID_IUnknown))
2300     {
2301         *ppv = iface;
2302         IUnknown_AddRef(iface);
2303         return S_OK;
2304     }
2305     *ppv = NULL;
2306     return E_NOINTERFACE;
2307 }
2308 
2309 static ULONG WINAPI TLB_PEFile_AddRef(IUnknown *iface)
2310 {
2311     TLB_PEFile *This = (TLB_PEFile *)iface;
2312     return InterlockedIncrement(&This->refs);
2313 }
2314 
2315 static ULONG WINAPI TLB_PEFile_Release(IUnknown *iface)
2316 {
2317     TLB_PEFile *This = (TLB_PEFile *)iface;
2318     ULONG refs = InterlockedDecrement(&This->refs);
2319     if (!refs)
2320     {
2321         if (This->typelib_global)
2322             FreeResource(This->typelib_global);
2323         if (This->dll)
2324             FreeLibrary(This->dll);
2325         HeapFree(GetProcessHeap(), 0, This);
2326     }
2327     return refs;
2328 }
2329 
2330 static const IUnknownVtbl TLB_PEFile_Vtable =
2331 {
2332     TLB_PEFile_QueryInterface,
2333     TLB_PEFile_AddRef,
2334     TLB_PEFile_Release
2335 };
2336 
2337 static HRESULT TLB_PEFile_Open(LPCWSTR path, INT index, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile)
2338 {
2339     TLB_PEFile *This;
2340 
2341     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
2342     if (!This)
2343         return E_OUTOFMEMORY;
2344 
2345     This->lpvtbl = &TLB_PEFile_Vtable;
2346     This->refs = 1;
2347     This->dll = NULL;
2348     This->typelib_resource = NULL;
2349     This->typelib_global = NULL;
2350     This->typelib_base = NULL;
2351 
2352     This->dll = LoadLibraryExW(path, 0, DONT_RESOLVE_DLL_REFERENCES |
2353                     LOAD_LIBRARY_AS_DATAFILE | LOAD_WITH_ALTERED_SEARCH_PATH);
2354 
2355     if (This->dll)
2356     {
2357         static const WCHAR TYPELIBW[] = {'T','Y','P','E','L','I','B',0};
2358         This->typelib_resource = FindResourceW(This->dll, MAKEINTRESOURCEW(index), TYPELIBW);
2359         if (This->typelib_resource)
2360         {
2361             This->typelib_global = LoadResource(This->dll, This->typelib_resource);
2362             if (This->typelib_global)
2363             {
2364                 This->typelib_base = LockResource(This->typelib_global);
2365 
2366                 if (This->typelib_base)
2367                 {
2368                     *pdwTLBLength = SizeofResource(This->dll, This->typelib_resource);
2369                     *ppBase = This->typelib_base;
2370                     *ppFile = (IUnknown *)&This->lpvtbl;
2371                     return S_OK;
2372                 }
2373             }
2374         }
2375     }
2376 
2377     TLB_PEFile_Release((IUnknown *)&This->lpvtbl);
2378     return TYPE_E_CANTLOADLIBRARY;
2379 }
2380 
2381 typedef struct TLB_NEFile
2382 {
2383     const IUnknownVtbl *lpvtbl;
2384     LONG refs;
2385     LPVOID typelib_base;
2386 } TLB_NEFile;
2387 
2388 static HRESULT WINAPI TLB_NEFile_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2389 {
2390     if (IsEqualIID(riid, &IID_IUnknown))
2391     {
2392         *ppv = iface;
2393         IUnknown_AddRef(iface);
2394         return S_OK;
2395     }
2396     *ppv = NULL;
2397     return E_NOINTERFACE;
2398 }
2399 
2400 static ULONG WINAPI TLB_NEFile_AddRef(IUnknown *iface)
2401 {
2402     TLB_NEFile *This = (TLB_NEFile *)iface;
2403     return InterlockedIncrement(&This->refs);
2404 }
2405 
2406 static ULONG WINAPI TLB_NEFile_Release(IUnknown *iface)
2407 {
2408     TLB_NEFile *This = (TLB_NEFile *)iface;
2409     ULONG refs = InterlockedDecrement(&This->refs);
2410     if (!refs)
2411     {
2412         HeapFree(GetProcessHeap(), 0, This->typelib_base);
2413         HeapFree(GetProcessHeap(), 0, This);
2414     }
2415     return refs;
2416 }
2417 
2418 static const IUnknownVtbl TLB_NEFile_Vtable =
2419 {
2420     TLB_NEFile_QueryInterface,
2421     TLB_NEFile_AddRef,
2422     TLB_NEFile_Release
2423 };
2424 
2425 /***********************************************************************
2426  *           read_xx_header         [internal]
2427  */
2428 static int read_xx_header( HFILE lzfd )
2429 {
2430     IMAGE_DOS_HEADER mzh;
2431     char magic[3];
2432 
2433     LZSeek( lzfd, 0, SEEK_SET );
2434     if ( sizeof(mzh) != LZRead( lzfd, (LPSTR)&mzh, sizeof(mzh) ) )
2435         return 0;
2436     if ( mzh.e_magic != IMAGE_DOS_SIGNATURE )
2437         return 0;
2438 
2439     LZSeek( lzfd, mzh.e_lfanew, SEEK_SET );
2440     if ( 2 != LZRead( lzfd, magic, 2 ) )
2441         return 0;
2442 
2443     LZSeek( lzfd, mzh.e_lfanew, SEEK_SET );
2444 
2445     if ( magic[0] == 'N' && magic[1] == 'E' )
2446         return IMAGE_OS2_SIGNATURE;
2447     if ( magic[0] == 'P' && magic[1] == 'E' )
2448         return IMAGE_NT_SIGNATURE;
2449 
2450     magic[2] = '\0';
2451     WARN("Can't handle %s files.\n", magic );
2452     return 0;
2453 }
2454 
2455 
2456 /***********************************************************************
2457  *           find_ne_resource         [internal]
2458  */
2459 static BOOL find_ne_resource( HFILE lzfd, LPCSTR typeid, LPCSTR resid,
2460                                 DWORD *resLen, DWORD *resOff )
2461 {
2462     IMAGE_OS2_HEADER nehd;
2463     NE_TYPEINFO *typeInfo;
2464     NE_NAMEINFO *nameInfo;
2465     DWORD nehdoffset;
2466     LPBYTE resTab;
2467     DWORD resTabSize;
2468     int count;
2469 
2470     /* Read in NE header */
2471     nehdoffset = LZSeek( lzfd, 0, SEEK_CUR );
2472     if ( sizeof(nehd) != LZRead( lzfd, (LPSTR)&nehd, sizeof(nehd) ) ) return 0;
2473 
2474     resTabSize = nehd.ne_restab - nehd.ne_rsrctab;
2475     if ( !resTabSize )
2476     {
2477         TRACE("No resources in NE dll\n" );
2478         return FALSE;
2479     }
2480 
2481     /* Read in resource table */
2482     resTab = HeapAlloc( GetProcessHeap(), 0, resTabSize );
2483     if ( !resTab ) return FALSE;
2484 
2485     LZSeek( lzfd, nehd.ne_rsrctab + nehdoffset, SEEK_SET );
2486     if ( resTabSize != LZRead( lzfd, (char*)resTab, resTabSize ) )
2487     {
2488         HeapFree( GetProcessHeap(), 0, resTab );
2489         return FALSE;
2490     }
2491 
2492     /* Find resource */
2493     typeInfo = (NE_TYPEINFO *)(resTab + 2);
2494 
2495     if (HIWORD(typeid) != 0)  /* named type */
2496     {
2497         BYTE len = strlen( typeid );
2498         while (typeInfo->type_id)
2499         {
2500             if (!(typeInfo->type_id & 0x8000))
2501             {
2502                 BYTE *p = resTab + typeInfo->type_id;
2503                 if ((*p == len) && !strncasecmp( (char*)p+1, typeid, len )) goto found_type;
2504             }
2505             typeInfo = (NE_TYPEINFO *)((char *)(typeInfo + 1) +
2506                                        typeInfo->count * sizeof(NE_NAMEINFO));
2507         }
2508     }
2509     else  /* numeric type id */
2510     {
2511         WORD id = LOWORD(typeid) | 0x8000;
2512         while (typeInfo->type_id)
2513         {
2514             if (typeInfo->type_id == id) goto found_type;
2515             typeInfo = (NE_TYPEINFO *)((char *)(typeInfo + 1) +
2516                                        typeInfo->count * sizeof(NE_NAMEINFO));
2517         }
2518     }
2519     TRACE("No typeid entry found for %p\n", typeid );
2520     HeapFree( GetProcessHeap(), 0, resTab );
2521     return FALSE;
2522 
2523  found_type:
2524     nameInfo = (NE_NAMEINFO *)(typeInfo + 1);
2525 
2526     if (HIWORD(resid) != 0)  /* named resource */
2527     {
2528         BYTE len = strlen( resid );
2529         for (count = typeInfo->count; count > 0; count--, nameInfo++)
2530         {
2531             BYTE *p = resTab + nameInfo->id;
2532             if (nameInfo->id & 0x8000) continue;
2533             if ((*p == len) && !strncasecmp( (char*)p+1, resid, len )) goto found_name;
2534         }
2535     }
2536     else  /* numeric resource id */
2537     {
2538         WORD id = LOWORD(resid) | 0x8000;
2539         for (count = typeInfo->count; count > 0; count--, nameInfo++)
2540             if (nameInfo->id == id) goto found_name;
2541     }
2542     TRACE("No resid entry found for %p\n", typeid );
2543     HeapFree( GetProcessHeap(), 0, resTab );
2544     return FALSE;
2545 
2546  found_name:
2547     /* Return resource data */
2548     if ( resLen ) *resLen = nameInfo->length << *(WORD *)resTab;
2549     if ( resOff ) *resOff = nameInfo->offset << *(WORD *)resTab;
2550 
2551     HeapFree( GetProcessHeap(), 0, resTab );
2552     return TRUE;
2553 }
2554 
2555 static HRESULT TLB_NEFile_Open(LPCWSTR path, INT index, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile){
2556 
2557     HFILE lzfd = -1;
2558     OFSTRUCT ofs;
2559     HRESULT hr = TYPE_E_CANTLOADLIBRARY;
2560     TLB_NEFile *This = NULL;
2561 
2562     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
2563     if (!This) return E_OUTOFMEMORY;
2564 
2565     This->lpvtbl = &TLB_NEFile_Vtable;
2566     This->refs = 1;
2567     This->typelib_base = NULL;
2568 
2569     lzfd = LZOpenFileW( (LPWSTR)path, &ofs, OF_READ );
2570     if ( lzfd >= 0 && read_xx_header( lzfd ) == IMAGE_OS2_SIGNATURE )
2571     {
2572         DWORD reslen, offset;
2573         if( find_ne_resource( lzfd, "TYPELIB", MAKEINTRESOURCEA(index), &reslen, &offset ) )
2574         {
2575             This->typelib_base = HeapAlloc(GetProcessHeap(), 0, reslen);
2576             if( !This->typelib_base )
2577                 hr = E_OUTOFMEMORY;
2578             else
2579             {
2580                 LZSeek( lzfd, offset, SEEK_SET );
2581                 reslen = LZRead( lzfd, This->typelib_base, reslen );
2582                 LZClose( lzfd );
2583                 *ppBase = This->typelib_base;
2584                 *pdwTLBLength = reslen;
2585                 *ppFile = (IUnknown *)&This->lpvtbl;
2586                 return S_OK;
2587             }
2588         }
2589     }
2590 
2591     if( lzfd >= 0) LZClose( lzfd );
2592     TLB_NEFile_Release((IUnknown *)&This->lpvtbl);
2593     return hr;
2594 }
2595 
2596 typedef struct TLB_Mapping
2597 {
2598     const IUnknownVtbl *lpvtbl;
2599     LONG refs;
2600     HANDLE file;
2601     HANDLE mapping;
2602     LPVOID typelib_base;
2603 } TLB_Mapping;
2604 
2605 static HRESULT WINAPI TLB_Mapping_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2606 {
2607     if (IsEqualIID(riid, &IID_IUnknown))
2608     {
2609         *ppv = iface;
2610         IUnknown_AddRef(iface);
2611         return S_OK;
2612     }
2613     *ppv = NULL;
2614     return E_NOINTERFACE;
2615 }
2616 
2617 static ULONG WINAPI TLB_Mapping_AddRef(IUnknown *iface)
2618 {
2619     TLB_Mapping *This = (TLB_Mapping *)iface;
2620     return InterlockedIncrement(&This->refs);
2621 }
2622 
2623 static ULONG WINAPI TLB_Mapping_Release(IUnknown *iface)
2624 {
2625     TLB_Mapping *This = (TLB_Mapping *)iface;
2626     ULONG refs = InterlockedDecrement(&This->refs);
2627     if (!refs)
2628     {
2629         if (This->typelib_base)
2630             UnmapViewOfFile(This->typelib_base);
2631         if (This->mapping)
2632             CloseHandle(This->mapping);
2633         if (This->file != INVALID_HANDLE_VALUE)
2634             CloseHandle(This->file);
2635         HeapFree(GetProcessHeap(), 0, This);
2636     }
2637     return refs;
2638 }
2639 
2640 static const IUnknownVtbl TLB_Mapping_Vtable =
2641 {
2642     TLB_Mapping_QueryInterface,
2643     TLB_Mapping_AddRef,
2644     TLB_Mapping_Release
2645 };
2646 
2647 static HRESULT TLB_Mapping_Open(LPCWSTR path, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile)
2648 {
2649     TLB_Mapping *This;
2650 
2651     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
2652     if (!This)
2653         return E_OUTOFMEMORY;
2654 
2655     This->lpvtbl = &TLB_Mapping_Vtable;
2656     This->refs = 1;
2657     This->file = INVALID_HANDLE_VALUE;
2658     This->mapping = NULL;
2659     This->typelib_base = NULL;
2660 
2661     This->file = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
2662     if (INVALID_HANDLE_VALUE != This->file)
2663     {
2664         This->mapping = CreateFileMappingW(This->file, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL);
2665         if (This->mapping)
2666         {
2667             This->typelib_base = MapViewOfFile(This->mapping, FILE_MAP_READ, 0, 0, 0);
2668             if(This->typelib_base)
2669             {
2670                 /* retrieve file size */
2671                 *pdwTLBLength = GetFileSize(This->file, NULL);
2672                 *ppBase = This->typelib_base;
2673                 *ppFile = (IUnknown *)&This->lpvtbl;
2674                 return S_OK;
2675             }
2676         }
2677     }
2678 
2679     IUnknown_Release((IUnknown *)&This->lpvtbl);
2680     return TYPE_E_CANTLOADLIBRARY;
2681 }
2682 
2683 /****************************************************************************
2684  *      TLB_ReadTypeLib
2685  *
2686  * find the type of the typelib file and map the typelib resource into
2687  * the memory
2688  */
2689 #define MSFT_SIGNATURE 0x5446534D /* "MSFT" */
2690 #define SLTG_SIGNATURE 0x47544c53 /* "SLTG" */
2691 static HRESULT TLB_ReadTypeLib(LPCWSTR pszFileName, LPWSTR pszPath, UINT cchPath, ITypeLib2 **ppTypeLib)
2692 {
2693     ITypeLibImpl *entry;
2694     HRESULT ret;
2695     INT index = 1;
2696     LPWSTR index_str, file = (LPWSTR)pszFileName;
2697     LPVOID pBase = NULL;
2698     DWORD dwTLBLength = 0;
2699     IUnknown *pFile = NULL;
2700 
2701     *ppTypeLib = NULL;
2702 
2703     index_str = strrchrW(pszFileName, '\\');
2704     if(index_str && *++index_str != '\0')
2705     {
2706         LPWSTR end_ptr;
2707         long idx = strtolW(index_str, &end_ptr, 10);
2708         if(*end_ptr == '\0')
2709         {
2710             int str_len = index_str - pszFileName - 1;
2711             index = idx;
2712             file = HeapAlloc(GetProcessHeap(), 0, (str_len + 1) * sizeof(WCHAR));
2713             memcpy(file, pszFileName, str_len * sizeof(WCHAR));
2714             file[str_len] = 0;
2715         }
2716     }
2717 
2718     if(!SearchPathW(NULL, file, NULL, cchPath, pszPath, NULL))
2719     {
2720         if(strchrW(file, '\\'))
2721         {
2722             lstrcpyW(pszPath, file);
2723         }
2724         else
2725         {
2726             int len = GetSystemDirectoryW(pszPath, cchPath);
2727             pszPath[len] = '\\';
2728             memcpy(pszPath + len + 1, file, (strlenW(file) + 1) * sizeof(WCHAR));
2729         }
2730     }
2731 
2732     if(file != pszFileName) HeapFree(GetProcessHeap(), 0, file);
2733 
2734     TRACE_(typelib)("File %s index %d\n", debugstr_w(pszPath), index);
2735 
2736     /* We look the path up in the typelib cache. If found, we just addref it, and return the pointer. */
2737     EnterCriticalSection(&cache_section);
2738     for (entry = tlb_cache_first; entry != NULL; entry = entry->next)
2739     {
2740         if (!strcmpiW(entry->path, pszPath) && entry->index == index)
2741         {
2742             TRACE("cache hit\n");
2743             *ppTypeLib = (ITypeLib2*)entry;
2744             ITypeLib_AddRef(*ppTypeLib);
2745             LeaveCriticalSection(&cache_section);
2746             return S_OK;
2747         }
2748     }
2749     LeaveCriticalSection(&cache_section);
2750 
2751     /* now actually load and parse the typelib */
2752 
2753     ret = TLB_PEFile_Open(pszPath, index, &pBase, &dwTLBLength, &pFile);
2754     if (ret == TYPE_E_CANTLOADLIBRARY)
2755         ret = TLB_NEFile_Open(pszPath, index, &pBase, &dwTLBLength, &pFile);
2756     if (ret == TYPE_E_CANTLOADLIBRARY)
2757         ret = TLB_Mapping_Open(pszPath, &pBase, &dwTLBLength, &pFile);
2758     if (SUCCEEDED(ret))
2759     {
2760         if (dwTLBLength >= 4)
2761         {
2762             DWORD dwSignature = FromLEDWord(*((DWORD*) pBase));
2763             if (dwSignature == MSFT_SIGNATURE)
2764                 *ppTypeLib = ITypeLib2_Constructor_MSFT(pBase, dwTLBLength);
2765             else if (dwSignature == SLTG_SIGNATURE)
2766                 *ppTypeLib = ITypeLib2_Constructor_SLTG(pBase, dwTLBLength);
2767             else
2768             {
2769                 FIXME("Header type magic 0x%08x not supported.\n",dwSignature);
2770                 ret = TYPE_E_CANTLOADLIBRARY;
2771             }
2772         }
2773         else
2774             ret = TYPE_E_CANTLOADLIBRARY;
2775         IUnknown_Release(pFile);
2776     }
2777 
2778     if(*ppTypeLib) {
2779         ITypeLibImpl *impl = (ITypeLibImpl*)*ppTypeLib;
2780 
2781         TRACE("adding to cache\n");
2782         impl->path = HeapAlloc(GetProcessHeap(), 0, (strlenW(pszPath)+1) * sizeof(WCHAR));
2783         lstrcpyW(impl->path, pszPath);
2784         /* We should really canonicalise the path here. */
2785         impl->index = index;
2786 
2787         /* FIXME: check if it has added already in the meantime */
2788         EnterCriticalSection(&cache_section);
2789         if ((impl->next = tlb_cache_first) != NULL) impl->next->prev = impl;
2790         impl->prev = NULL;
2791         tlb_cache_first = impl;
2792         LeaveCriticalSection(&cache_section);
2793         ret = S_OK;
2794     } else
2795         ERR("Loading of typelib %s failed with error %d\n", debugstr_w(pszFileName), GetLastError());
2796 
2797     return ret;
2798 }
2799 
2800 /*================== ITypeLib(2) Methods ===================================*/
2801 
2802 static ITypeLibImpl* TypeLibImpl_Constructor(void)
2803 {
2804     ITypeLibImpl* pTypeLibImpl;
2805 
2806     pTypeLibImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeLibImpl));
2807     if (!pTypeLibImpl) return NULL;
2808 
2809     pTypeLibImpl->lpVtbl = &tlbvt;
2810     pTypeLibImpl->lpVtblTypeComp = &tlbtcvt;
2811     pTypeLibImpl->ref = 1;
2812 
2813     list_init(&pTypeLibImpl->ref_list);
2814     pTypeLibImpl->dispatch_href = -1;
2815 
2816     return pTypeLibImpl;
2817 }
2818 
2819 /****************************************************************************
2820  *      ITypeLib2_Constructor_MSFT
2821  *
2822  * loading an MSFT typelib from an in-memory image
2823  */
2824 static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength)
2825 {
2826     TLBContext cx;
2827     long lPSegDir;
2828     MSFT_Header tlbHeader;
2829     MSFT_SegDir tlbSegDir;
2830     ITypeLibImpl * pTypeLibImpl;
2831 
2832     TRACE("%p, TLB length = %d\n", pLib, dwTLBLength);
2833 
2834     pTypeLibImpl = TypeLibImpl_Constructor();
2835     if (!pTypeLibImpl) return NULL;
2836 
2837     /* get pointer to beginning of typelib data */
2838     cx.pos = 0;
2839     cx.oStart=0;
2840     cx.mapping = pLib;
2841     cx.pLibInfo = pTypeLibImpl;
2842     cx.length = dwTLBLength;
2843 
2844     /* read header */
2845     MSFT_ReadLEDWords((void*)&tlbHeader, sizeof(tlbHeader), &cx, 0);
2846     TRACE_(typelib)("header:\n");
2847     TRACE_(typelib)("\tmagic1=0x%08x ,magic2=0x%08x\n",tlbHeader.magic1,tlbHeader.magic2 );
2848     if (tlbHeader.magic1 != MSFT_SIGNATURE) {
2849         FIXME("Header type magic 0x%08x not supported.\n",tlbHeader.magic1);
2850         return NULL;
2851     }
2852     TRACE_(typelib)("\tdispatchpos = 0x%x\n", tlbHeader.dispatchpos);
2853 
2854     /* there is a small amount of information here until the next important
2855      * part:
2856      * the segment directory . Try to calculate the amount of data */
2857     lPSegDir = sizeof(tlbHeader) + (tlbHeader.nrtypeinfos)*4 + ((tlbHeader.varflags & HELPDLLFLAG)? 4 :0);
2858 
2859     /* now read the segment directory */
2860     TRACE("read segment directory (at %ld)\n",lPSegDir);
2861     MSFT_ReadLEDWords(&tlbSegDir, sizeof(tlbSegDir), &cx, lPSegDir);
2862     cx.pTblDir = &tlbSegDir;
2863 
2864     /* just check two entries */
2865     if ( tlbSegDir.pTypeInfoTab.res0c != 0x0F || tlbSegDir.pImpInfo.res0c != 0x0F)
2866     {
2867         ERR("cannot find the table directory, ptr=0x%lx\n",lPSegDir);
2868         HeapFree(GetProcessHeap(),0,pTypeLibImpl);
2869         return NULL;
2870     }
2871 
2872     /* now fill our internal data */
2873     /* TLIBATTR fields */
2874     MSFT_ReadGuid(&pTypeLibImpl->LibAttr.guid, tlbHeader.posguid, &cx);
2875 
2876     pTypeLibImpl->LibAttr.lcid = tlbHeader.lcid2;
2877     pTypeLibImpl->LibAttr.syskind = tlbHeader.varflags & 0x0f; /* check the mask */
2878     pTypeLibImpl->LibAttr.wMajorVerNum = LOWORD(tlbHeader.version);
2879     pTypeLibImpl->LibAttr.wMinorVerNum = HIWORD(tlbHeader.version);
2880     pTypeLibImpl->LibAttr.wLibFlags = (WORD) tlbHeader.flags & 0xffff;/* check mask */
2881 
2882     pTypeLibImpl->lcid = tlbHeader.lcid;
2883 
2884     /* name, eventually add to a hash table */
2885     pTypeLibImpl->Name = MSFT_ReadName(&cx, tlbHeader.NameOffset);
2886 
2887     /* help info */
2888     pTypeLibImpl->DocString = MSFT_ReadString(&cx, tlbHeader.helpstring);
2889     pTypeLibImpl->HelpFile = MSFT_ReadString(&cx, tlbHeader.helpfile);
2890 
2891     if( tlbHeader.varflags & HELPDLLFLAG)
2892     {
2893             int offset;
2894             MSFT_ReadLEDWords(&offset, sizeof(offset), &cx, sizeof(tlbHeader));
2895             pTypeLibImpl->HelpStringDll = MSFT_ReadString(&cx, offset);
2896     }
2897 
2898     pTypeLibImpl->dwHelpContext = tlbHeader.helpstringcontext;
2899 
2900     /* custom data */
2901     if(tlbHeader.CustomDataOffset >= 0)
2902     {
2903         pTypeLibImpl->ctCustData = MSFT_CustData(&cx, tlbHeader.CustomDataOffset, &pTypeLibImpl->pCustData);
2904     }
2905 
2906     /* fill in type descriptions */
2907     if(tlbSegDir.pTypdescTab.length > 0)
2908     {
2909         int i, j, cTD = tlbSegDir.pTypdescTab.length / (2*sizeof(INT));
2910         INT16 td[4];
2911         pTypeLibImpl->ctTypeDesc = cTD;
2912         pTypeLibImpl->pTypeDesc = TLB_Alloc( cTD * sizeof(TYPEDESC));
2913         MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pTypdescTab.offset);
2914         for(i=0; i<cTD; )
2915         {
2916             /* FIXME: add several sanity checks here */
2917             pTypeLibImpl->pTypeDesc[i].vt = td[0] & VT_TYPEMASK;
2918             if(td[0] == VT_PTR || td[0] == VT_SAFEARRAY)
2919             {
2920                 /* FIXME: check safearray */
2921                 if(td[3] < 0)
2922                     pTypeLibImpl->pTypeDesc[i].u.lptdesc= & stndTypeDesc[td[2]];
2923                 else
2924                     pTypeLibImpl->pTypeDesc[i].u.lptdesc= & pTypeLibImpl->pTypeDesc[td[2]/8];
2925             }
2926             else if(td[0] == VT_CARRAY)
2927             {
2928                 /* array descr table here */
2929                 pTypeLibImpl->pTypeDesc[i].u.lpadesc = (void *)((int) td[2]);  /* temp store offset in*/
2930             }
2931             else if(td[0] == VT_USERDEFINED)
2932             {
2933                 pTypeLibImpl->pTypeDesc[i].u.hreftype = MAKELONG(td[2],td[3]);
2934             }
2935             if(++i<cTD) MSFT_ReadLEWords(td, sizeof(td), &cx, DO_NOT_SEEK);
2936         }
2937 
2938         /* second time around to fill the array subscript info */
2939         for(i=0;i<cTD;i++)
2940         {
2941             if(pTypeLibImpl->pTypeDesc[i].vt != VT_CARRAY) continue;
2942             if(tlbSegDir.pArrayDescriptions.offset>0)
2943             {
2944                 MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pArrayDescriptions.offset + (int) pTypeLibImpl->pTypeDesc[i].u.lpadesc);
2945                 pTypeLibImpl->pTypeDesc[i].u.lpadesc = TLB_Alloc(sizeof(ARRAYDESC)+sizeof(SAFEARRAYBOUND)*(td[3]-1));
2946 
2947                 if(td[1]<0)
2948                     pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem.vt = td[0] & VT_TYPEMASK;
2949                 else
2950                     pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem = cx.pLibInfo->pTypeDesc[td[0]/(2*sizeof(INT))];
2951 
2952                 pTypeLibImpl->pTypeDesc[i].u.lpadesc->cDims = td[2];
2953 
2954                 for(j = 0; j<td[2]; j++)
2955                 {
2956                     MSFT_ReadLEDWords(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].cElements,
2957                                       sizeof(INT), &cx, DO_NOT_SEEK);
2958                     MSFT_ReadLEDWords(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].lLbound,
2959                                       sizeof(INT), &cx, DO_NOT_SEEK);
2960                 }
2961             }
2962             else
2963             {
2964                 pTypeLibImpl->pTypeDesc[i].u.lpadesc = NULL;
2965                 ERR("didn't find array description data\n");
2966             }
2967         }
2968     }
2969 
2970     /* imported type libs */
2971     if(tlbSegDir.pImpFiles.offset>0)
2972     {
2973         TLBImpLib **ppImpLib = &(pTypeLibImpl->pImpLibs);
2974         int oGuid, offset = tlbSegDir.pImpFiles.offset;
2975         UINT16 size;
2976 
2977         while(offset < tlbSegDir.pImpFiles.offset +tlbSegDir.pImpFiles.length)
2978         {
2979             char *name;
2980 
2981             *ppImpLib = TLB_Alloc(sizeof(TLBImpLib));
2982             (*ppImpLib)->offset = offset - tlbSegDir.pImpFiles.offset;
2983             MSFT_ReadLEDWords(&oGuid, sizeof(INT), &cx, offset);
2984 
2985             MSFT_ReadLEDWords(&(*ppImpLib)->lcid,         sizeof(LCID),   &cx, DO_NOT_SEEK);
2986             MSFT_ReadLEWords(&(*ppImpLib)->wVersionMajor, sizeof(WORD),   &cx, DO_NOT_SEEK);
2987             MSFT_ReadLEWords(&(*ppImpLib)->wVersionMinor, sizeof(WORD),   &cx, DO_NOT_SEEK);
2988             MSFT_ReadLEWords(& size,                      sizeof(UINT16), &cx, DO_NOT_SEEK);
2989 
2990             size >>= 2;
2991             name = TLB_Alloc(size+1);
2992             MSFT_Read(name, size, &cx, DO_NOT_SEEK);
2993             (*ppImpLib)->name = TLB_MultiByteToBSTR(name);
2994 
2995             MSFT_ReadGuid(&(*ppImpLib)->guid, oGuid, &cx);
2996             offset = (offset + sizeof(INT) + sizeof(DWORD) + sizeof(LCID) + sizeof(UINT16) + size + 3) & ~3;
2997 
2998             ppImpLib = &(*ppImpLib)->next;
2999         }
3000     }
3001 
3002     pTypeLibImpl->dispatch_href = tlbHeader.dispatchpos;
3003     if(pTypeLibImpl->dispatch_href != -1)
3004         MSFT_DoRefType(&cx, pTypeLibImpl, pTypeLibImpl->dispatch_href);
3005 
3006     /* type info's */
3007     if(tlbHeader.nrtypeinfos >= 0 )
3008     {
3009         /*pTypeLibImpl->TypeInfoCount=tlbHeader.nrtypeinfos; */
3010         ITypeInfoImpl **ppTI = &(pTypeLibImpl->pTypeInfo);
3011         int i;
3012 
3013         for(i = 0; i < tlbHeader.nrtypeinfos; i++)
3014         {
3015             *ppTI = MSFT_DoTypeInfo(&cx, i, pTypeLibImpl);
3016 
3017             ppTI = &((*ppTI)->next);
3018             (pTypeLibImpl->TypeInfoCount)++;
3019         }
3020     }
3021 
3022     TRACE("(%p)\n", pTypeLibImpl);
3023     return (ITypeLib2*) pTypeLibImpl;
3024 }
3025 
3026 
3027 static BOOL TLB_GUIDFromString(const char *str, GUID *guid)
3028 {
3029   char b[3];
3030   int i;
3031   short s;
3032 
3033   if(sscanf(str, "%x-%hx-%hx-%hx", &guid->Data1, &guid->Data2, &guid->Data3, &s) != 4) {
3034     FIXME("Can't parse guid %s\n", debugstr_guid(guid));
3035     return FALSE;
3036   }
3037 
3038   guid->Data4[0] = s >> 8;
3039   guid->Data4[1] = s & 0xff;
3040 
3041   b[2] = '\0';
3042   for(i = 0; i < 6; i++) {
3043     memcpy(b, str + 24 + 2 * i, 2);
3044     guid->Data4[i + 2] = strtol(b, NULL, 16);
3045   }
3046   return TRUE;
3047 }
3048 
3049 static WORD SLTG_ReadString(const char *ptr, BSTR *pBstr)
3050 {
3051     WORD bytelen;
3052     DWORD len;
3053 
3054     *pBstr = NULL;
3055     bytelen = *(const WORD*)ptr;
3056     if(bytelen == 0xffff) return 2;
3057     len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, NULL, 0);
3058     *pBstr = SysAllocStringLen(NULL, len);
3059     if (*pBstr)
3060         len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, *pBstr, len);
3061     return bytelen + 2;
3062 }
3063 
3064 static WORD SLTG_ReadStringA(const char *ptr, char **str)
3065 {
3066     WORD bytelen;
3067 
3068     *str = NULL;
3069     bytelen = *(const WORD*)ptr;
3070     if(bytelen == 0xffff) return 2;
3071     *str = HeapAlloc(GetProcessHeap(), 0, bytelen + 1);
3072     memcpy(*str, ptr + 2, bytelen);
3073     (*str)[bytelen] = '\0';
3074     return bytelen + 2;
3075 }
3076 
3077 static DWORD SLTG_ReadLibBlk(LPVOID pLibBlk, ITypeLibImpl *pTypeLibImpl)
3078 {
3079     char *ptr = pLibBlk;
3080     WORD w;
3081 
3082     if((w = *(WORD*)ptr) != SLTG_LIBBLK_MAGIC) {
3083         FIXME("libblk magic = %04x\n", w);
3084         return 0;
3085     }
3086 
3087     ptr += 6;
3088     if((w = *(WORD*)ptr) != 0xffff) {
3089         FIXME("LibBlk.res06 = %04x. Assumung string and skipping\n", w);
3090         ptr += w;
3091     }
3092     ptr += 2;
3093 
3094     ptr += SLTG_ReadString(ptr, &pTypeLibImpl->DocString);
3095 
3096     ptr += SLTG_ReadString(ptr, &pTypeLibImpl->HelpFile);
3097 
3098     pTypeLibImpl->dwHelpContext = *(DWORD*)ptr;
3099     ptr += 4;
3100 
3101     pTypeLibImpl->LibAttr.syskind = *(WORD*)ptr;
3102     ptr += 2;
3103 
3104     if(SUBLANGID(*(WORD*)ptr) == SUBLANG_NEUTRAL)
3105         pTypeLibImpl->lcid = pTypeLibImpl->LibAttr.lcid = MAKELCID(MAKELANGID(PRIMARYLANGID(*(WORD*)ptr),0),0);
3106     else
3107         pTypeLibImpl->lcid = pTypeLibImpl->LibAttr.lcid = 0;
3108     ptr += 2;
3109 
3110     ptr += 4; /* skip res12 */
3111 
3112     pTypeLibImpl->LibAttr.wLibFlags = *(WORD*)ptr;
3113     ptr += 2;
3114 
3115     pTypeLibImpl->LibAttr.wMajorVerNum = *(WORD*)ptr;
3116     ptr += 2;
3117 
3118     pTypeLibImpl->LibAttr.wMinorVerNum = *(WORD*)ptr;
3119     ptr += 2;
3120 
3121     memcpy(&pTypeLibImpl->LibAttr.guid, ptr, sizeof(GUID));
3122     ptr += sizeof(GUID);
3123 
3124     return ptr - (char*)pLibBlk;
3125 }
3126 
3127 /* stores a mapping between the sltg typeinfo's references and the typelib's HREFTYPEs */
3128 typedef struct
3129 {
3130     unsigned int num;
3131     HREFTYPE refs[1];
3132 } sltg_ref_lookup_t;
3133 
3134 static HRESULT sltg_get_typelib_ref(const sltg_ref_lookup_t *table, DWORD typeinfo_ref,
3135                                     HREFTYPE *typelib_ref)
3136 {
3137     if(table && typeinfo_ref < table->num)
3138     {
3139         *typelib_ref = table->refs[typeinfo_ref];
3140         return S_OK;
3141     }
3142 
3143     ERR_(typelib)("Unable to find reference\n");
3144     *typelib_ref = -1;
3145     return E_FAIL;
3146 }
3147 
3148 static WORD *SLTG_DoType(WORD *pType, char *pBlk, TYPEDESC *pTD, const sltg_ref_lookup_t *ref_lookup)
3149 {
3150     BOOL done = FALSE;
3151 
3152     while(!done) {
3153         if((*pType & 0xe00) == 0xe00) {
3154             pTD->vt = VT_PTR;
3155             pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3156                                        sizeof(TYPEDESC));
3157             pTD = pTD->u.lptdesc;
3158         }
3159         switch(*pType & 0x3f) {
3160         case VT_PTR:
3161             pTD->vt = VT_PTR;
3162             pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3163                                        sizeof(TYPEDESC));
3164             pTD = pTD->u.lptdesc;
3165             break;
3166 
3167         case VT_USERDEFINED:
3168             pTD->vt = VT_USERDEFINED;
3169             sltg_get_typelib_ref(ref_lookup, *(++pType) / 4, &pTD->u.hreftype);
3170             done = TRUE;
3171             break;
3172 
3173         case VT_CARRAY:
3174           {
3175             /* *(pType+1) is offset to a SAFEARRAY, *(pType+2) is type of
3176                array */
3177 
3178             SAFEARRAY *pSA = (SAFEARRAY *)(pBlk + *(++pType));
3179 
3180             pTD->vt = VT_CARRAY;
3181             pTD->u.lpadesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3182                                 sizeof(ARRAYDESC) +
3183                                 (pSA->cDims - 1) * sizeof(SAFEARRAYBOUND));
3184             pTD->u.lpadesc->cDims = pSA->cDims;
3185             memcpy(pTD->u.lpadesc->rgbounds, pSA->rgsabound,
3186                    pSA->cDims * sizeof(SAFEARRAYBOUND));
3187 
3188             pTD = &pTD->u.lpadesc->tdescElem;
3189             break;
3190           }
3191 
3192         case VT_SAFEARRAY:
3193           {
3194             /* FIXME: *(pType+1) gives an offset to SAFEARRAY, is this
3195                useful? */
3196 
3197             pType++;
3198             pTD->vt = VT_SAFEARRAY;
3199             pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3200                                        sizeof(TYPEDESC));
3201             pTD = pTD->u.lptdesc;
3202             break;
3203           }
3204         default:
3205             pTD->vt = *pType & 0x3f;
3206             done = TRUE;
3207             break;
3208         }
3209         pType++;
3210     }
3211     return pType;
3212 }
3213 
3214 static WORD *SLTG_DoElem(WORD *pType, char *pBlk,
3215                          ELEMDESC *pElem, const sltg_ref_lookup_t *ref_lookup)
3216 {
3217     /* Handle [in/out] first */
3218     if((*pType & 0xc000) == 0xc000)
3219         pElem->u.paramdesc.wParamFlags = PARAMFLAG_NONE;
3220     else if(*pType & 0x8000)
3221         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN | PARAMFLAG_FOUT;
3222     else if(*pType & 0x4000)
3223         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FOUT;
3224     else
3225         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN;
3226 
3227     if(*pType & 0x2000)
3228         pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FLCID;
3229 
3230     if(*pType & 0x80)
3231         pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FRETVAL;
3232 
3233     return SLTG_DoType(pType, pBlk, &pElem->tdesc, ref_lookup);
3234 }
3235 
3236 
3237 static sltg_ref_lookup_t *SLTG_DoRefs(SLTG_RefInfo *pRef, ITypeLibImpl *pTL,
3238                         char *pNameTable)
3239 {
3240     unsigned int ref;
3241     char *name;
3242     TLBRefType *ref_type;
3243     sltg_ref_lookup_t *table;
3244     HREFTYPE typelib_ref;
3245 
3246     if(pRef->magic != SLTG_REF_MAGIC) {
3247         FIXME("Ref magic = %x\n", pRef->magic);
3248         return NULL;
3249     }
3250     name = ( (char*)pRef->names + pRef->number);
3251 
3252     table = HeapAlloc(GetProcessHeap(), 0, sizeof(*table) + ((pRef->number >> 3) - 1) * sizeof(table->refs[0]));
3253     table->num = pRef->number >> 3;
3254 
3255     /* FIXME should scan the existing list and reuse matching refs added by previous typeinfos */
3256 
3257     /* We don't want the first href to be 0 */
3258     typelib_ref = (list_count(&pTL->ref_list) + 1) << 2;
3259 
3260     for(ref = 0; ref < pRef->number >> 3; ref++) {
3261         char *refname;
3262         unsigned int lib_offs, type_num;
3263 
3264         ref_type = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ref_type));
3265 
3266         name += SLTG_ReadStringA(name, &refname);
3267         if(sscanf(refname, "*\\R%x*#%x", &lib_offs, &type_num) != 2)
3268             FIXME_(typelib)("Can't sscanf ref\n");
3269         if(lib_offs != 0xffff) {
3270             TLBImpLib **import = &pTL->pImpLibs;
3271 
3272             while(*import) {
3273                 if((*import)->offset == lib_offs)
3274                     break;
3275                 import = &(*import)->next;
3276             }
3277             if(!*import) {
3278                 char fname[MAX_PATH+1];
3279                 int len;
3280 
3281                 *import = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3282                                     sizeof(**import));
3283                 (*import)->offset = lib_offs;
3284                 TLB_GUIDFromString( pNameTable + lib_offs + 4,
3285                                     &(*import)->guid);
3286                 if(sscanf(pNameTable + lib_offs + 40, "}#%hd.%hd#%x#%s",
3287                           &(*import)->wVersionMajor,
3288                           &(*import)->wVersionMinor,
3289                           &(*import)->lcid, fname) != 4) {
3290                   FIXME_(typelib)("can't sscanf ref %s\n",
3291                         pNameTable + lib_offs + 40);
3292                 }
3293                 len = strlen(fname);
3294                 if(fname[len-1] != '#')
3295                     FIXME("fname = %s\n", fname);
3296                 fname[len-1] = '\0';
3297                 (*import)->name = TLB_MultiByteToBSTR(fname);
3298             }
3299             ref_type->pImpTLInfo = *import;
3300 
3301             /* Store a reference to IDispatch */
3302             if(pTL->dispatch_href == -1 && IsEqualGUID(&(*import)->guid, &IID_StdOle) && type_num == 4)
3303                 pTL->dispatch_href = typelib_ref;
3304 
3305         } else { /* internal ref */
3306           ref_type->pImpTLInfo = TLB_REF_INTERNAL;
3307         }
3308         ref_type->reference = typelib_ref;
3309         ref_type->index = type_num;
3310 
3311         HeapFree(GetProcessHeap(), 0, refname);
3312         list_add_tail(&pTL->ref_list, &ref_type->entry);
3313 
3314         table->refs[ref] = typelib_ref;
3315         typelib_ref += 4;
3316     }
3317     if((BYTE)*name != SLTG_REF_MAGIC)
3318       FIXME_(typelib)("End of ref block magic = %x\n", *name);
3319     dump_TLBRefType(pTL);
3320     return table;
3321 }
3322 
3323 static char *SLTG_DoImpls(char *pBlk, ITypeInfoImpl *pTI,
3324                           BOOL OneOnly, const sltg_ref_lookup_t *ref_lookup)
3325 {
3326     SLTG_ImplInfo *info;
3327     TLBImplType **ppImplType = &pTI->impltypelist;
3328     /* I don't really get this structure, usually it's 0x16 bytes
3329        long, but iuser.tlb contains some that are 0x18 bytes long.
3330        That's ok because we can use the next ptr to jump to the next
3331        one. But how do we know the length of the last one?  The WORD
3332        at offs 0x8 might be the clue.  For now I'm just assuming that
3333        the last one is the regular 0x16 bytes. */
3334 
3335     info = (SLTG_ImplInfo*)pBlk;
3336     while(1) {
3337         *ppImplType = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3338                                 sizeof(**ppImplType));
3339         sltg_get_typelib_ref(ref_lookup, info->ref, &(*ppImplType)->hRef);
3340         (*ppImplType)->implflags = info->impltypeflags;
3341         pTI->TypeAttr.cImplTypes++;
3342         ppImplType = &(*ppImplType)->next;
3343 
3344         if(info->next == 0xffff)
3345             break;
3346         if(OneOnly)
3347             FIXME_(typelib)("Interface inheriting more than one interface\n");
3348         info = (SLTG_ImplInfo*)(pBlk + info->next);
3349     }
3350     info++; /* see comment at top of function */
3351     return (char*)info;
3352 }
3353 
3354 static void SLTG_DoVars(char *pBlk, char *pFirstItem, ITypeInfoImpl *pTI, unsigned short cVars,
3355                         const char *pNameTable, const sltg_ref_lookup_t *ref_lookup)
3356 {
3357   TLBVarDesc **ppVarDesc = &pTI->varlist;
3358   BSTR bstrPrevName = NULL;
3359   SLTG_Variable *pItem;
3360   unsigned short i;
3361   WORD *pType;
3362 
3363   for(pItem = (SLTG_Variable *)pFirstItem, i = 0; i < cVars;
3364       pItem = (SLTG_Variable *)(pBlk + pItem->next), i++) {
3365 
3366       *ppVarDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3367                              sizeof(**ppVarDesc));
3368       (*ppVarDesc)->vardesc.memid = pItem->memid;
3369 
3370       if (pItem->magic != SLTG_VAR_MAGIC &&
3371           pItem->magic != SLTG_VAR_WITH_FLAGS_MAGIC) {
3372           FIXME_(typelib)("var magic = %02x\n", pItem->magic);
3373           return;
3374       }
3375 
3376       if (pItem->name == 0xfffe)
3377         (*ppVarDesc)->Name = SysAllocString(bstrPrevName);
3378       else
3379         (*ppVarDesc)->Name = TLB_MultiByteToBSTR(pItem->name + pNameTable);
3380 
3381       TRACE_(typelib)("name: %s\n", debugstr_w((*ppVarDesc)->Name));
3382       TRACE_(typelib)("byte_offs = 0x%x\n", pItem->byte_offs);
3383       TRACE_(typelib)("memid = 0x%x\n", pItem->memid);
3384 
3385       if(pItem->flags & 0x02)
3386           pType = &pItem->type;
3387       else
3388           pType = (WORD*)(pBlk + pItem->type);
3389 
3390       if (pItem->flags & ~0xda)
3391         FIXME_(typelib)("unhandled flags = %02x\n", pItem->flags & ~0xda);
3392 
3393       SLTG_DoElem(pType, pBlk,
3394                   &(*ppVarDesc)->vardesc.elemdescVar, ref_lookup);
3395 
3396       if (TRACE_ON(typelib)) {
3397           char buf[300];
3398           dump_TypeDesc(&(*ppVarDesc)->vardesc.elemdescVar.tdesc, buf);
3399           TRACE_(typelib)("elemdescVar: %s\n", buf);
3400       }
3401 
3402       if (pItem->flags & 0x40) {
3403         TRACE_(typelib)("VAR_DISPATCH\n");
3404         (*ppVarDesc)->vardesc.varkind = VAR_DISPATCH;
3405       }
3406       else if (pItem->flags & 0x10) {
3407         TRACE_(typelib)("VAR_CONST\n");
3408         (*ppVarDesc)->vardesc.varkind = VAR_CONST;
3409         (*ppVarDesc)->vardesc.u.lpvarValue = HeapAlloc(GetProcessHeap(), 0,
3410                                                        sizeof(VARIANT));
3411         V_VT((*ppVarDesc)->vardesc.u.lpvarValue) = VT_INT;
3412         if (pItem->flags & 0x08)
3413           V_INT((*ppVarDesc)->vardesc.u.lpvarValue) = pItem->byte_offs;
3414         else {
3415           switch ((*ppVarDesc)->vardesc.elemdescVar.tdesc.vt)
3416           {
3417             case VT_LPSTR:
3418             case VT_LPWSTR:
3419             case VT_BSTR:
3420             {
3421               WORD len = *(WORD *)(pBlk + pItem->byte_offs);
3422               BSTR str;
3423               TRACE_(typelib)("len = %u\n", len);
3424               if (len == 0xffff) {
3425                 str = NULL;
3426               } else {
3427                 INT alloc_len = MultiByteToWideChar(CP_ACP, 0, pBlk + pItem->byte_offs + 2, len, NULL, 0);
3428                 str = SysAllocStringLen(NULL, alloc_len);
3429                 MultiByteToWideChar(CP_ACP, 0, pBlk + pItem->byte_offs + 2, len, str, alloc_len);
3430               }
3431               V_VT((*ppVarDesc)->vardesc.u.lpvarValue) = VT_BSTR;
3432               V_BSTR((*ppVarDesc)->vardesc.u.lpvarValue) = str;
3433               break;
3434             }
3435             case VT_I2:
3436             case VT_UI2:
3437             case VT_I4:
3438             case VT_UI4:
3439             case VT_INT:
3440             case VT_UINT:
3441               V_INT((*ppVarDesc)->vardesc.u.lpvarValue) =
3442                 *(INT*)(pBlk + pItem->byte_offs);
3443               break;
3444             default:
3445               FIXME_(typelib)("VAR_CONST unimplemented for type %d\n", (*ppVarDesc)->vardesc.elemdescVar.tdesc.vt);
3446           }
3447         }
3448       }
3449       else {
3450         TRACE_(typelib)("VAR_PERINSTANCE\n");
3451         (*ppVarDesc)->vardesc.u.oInst = pItem->byte_offs;
3452         (*ppVarDesc)->vardesc.varkind = VAR_PERINSTANCE;
3453       }
3454 
3455       if (pItem->magic == SLTG_VAR_WITH_FLAGS_MAGIC)
3456         (*ppVarDesc)->vardesc.wVarFlags = pItem->varflags;
3457 
3458       if (pItem->flags & 0x80)
3459         (*ppVarDesc)->vardesc.wVarFlags |= VARFLAG_FREADONLY;
3460 
3461       bstrPrevName = (*ppVarDesc)->Name;
3462       ppVarDesc = &((*ppVarDesc)->next);
3463   }
3464   pTI->TypeAttr.cVars = cVars;
3465 }
3466 
3467 static void SLTG_DoFuncs(char *pBlk, char *pFirstItem, ITypeInfoImpl *pTI,
3468                          unsigned short cFuncs, char *pNameTable, const sltg_ref_lookup_t *ref_lookup)
3469 {
3470     SLTG_Function *pFunc;
3471     unsigned short i;
3472     TLBFuncDesc **ppFuncDesc = &pTI->funclist;
3473 
3474     for(pFunc = (SLTG_Function*)pFirstItem, i = 0; i < cFuncs;
3475         pFunc = (SLTG_Function*)(pBlk + pFunc->next), i++) {
3476 
3477         int param;
3478         WORD *pType, *pArg;
3479 
3480         *ppFuncDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3481                                 sizeof(**ppFuncDesc));
3482 
3483         switch (pFunc->magic & ~SLTG_FUNCTION_FLAGS_PRESENT) {
3484         case SLTG_FUNCTION_MAGIC:
3485             (*ppFuncDesc)->funcdesc.funckind = FUNC_PUREVIRTUAL;
3486             break;
3487         case SLTG_DISPATCH_FUNCTION_MAGIC:
3488             (*ppFuncDesc)->funcdesc.funckind = FUNC_DISPATCH;
3489             break;
3490         case SLTG_STATIC_FUNCTION_MAGIC:
3491             (*ppFuncDesc)->funcdesc.funckind = FUNC_STATIC;
3492             break;
3493         default:
3494             FIXME("unimplemented func magic = %02x\n", pFunc->magic & ~SLTG_FUNCTION_FLAGS_PRESENT);
3495             HeapFree(GetProcessHeap(), 0, *ppFuncDesc);
3496             *ppFuncDesc = NULL;
3497             return;
3498         }
3499         (*ppFuncDesc)->Name = TLB_MultiByteToBSTR(pFunc->name + pNameTable);
3500 
3501         (*ppFuncDesc)->funcdesc.memid = pFunc->dispid;
3502         (*ppFuncDesc)->funcdesc.invkind = pFunc->inv >> 4;
3503         (*ppFuncDesc)->funcdesc.callconv = pFunc->nacc & 0x7;
3504         (*ppFuncDesc)->funcdesc.cParams = pFunc->nacc >> 3;
3505         (*ppFuncDesc)->funcdesc.cParamsOpt = (pFunc->retnextopt & 0x7e) >> 1;
3506         (*ppFuncDesc)->funcdesc.oVft = pFunc->vtblpos;
3507 
3508         if(pFunc->magic & SLTG_FUNCTION_FLAGS_PRESENT)
3509             (*ppFuncDesc)->funcdesc.wFuncFlags = pFunc->funcflags;
3510 
3511         if(pFunc->retnextopt & 0x80)
3512             pType = &pFunc->rettype;
3513         else
3514             pType = (WORD*)(pBlk + pFunc->rettype);
3515 
3516         SLTG_DoElem(pType, pBlk, &(*ppFuncDesc)->funcdesc.elemdescFunc, ref_lookup);
3517 
3518         (*ppFuncDesc)->funcdesc.lprgelemdescParam =
3519           HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3520                     (*ppFuncDesc)->funcdesc.cParams * sizeof(ELEMDESC));
3521         (*ppFuncDesc)->pParamDesc =
3522           HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3523                     (*ppFuncDesc)->funcdesc.cParams * sizeof(TLBParDesc));
3524 
3525         pArg = (WORD*)(pBlk + pFunc->arg_off);
3526 
3527         for(param = 0; param < (*ppFuncDesc)->funcdesc.cParams; param++) {
3528             char *paramName = pNameTable + *pArg;
3529             BOOL HaveOffs;
3530             /* If arg type follows then paramName points to the 2nd
3531                letter of the name, else the next WORD is an offset to
3532                the arg type and paramName points to the first letter.
3533                So let's take one char off paramName and see if we're
3534                pointing at an alpha-numeric char.  However if *pArg is
3535                0xffff or 0xfffe then the param has no name, the former
3536                meaning that the next WORD is the type, the latter
3537                meaning that the next WORD is an offset to the type. */
3538 
3539             HaveOffs = FALSE;
3540             if(*pArg == 0xffff)
3541                 paramName = NULL;
3542             else if(*pArg == 0xfffe) {
3543                 paramName = NULL;
3544                 HaveOffs = TRUE;
3545             }
3546             else if(paramName[-1] && !isalnum(paramName[-1]))
3547                 HaveOffs = TRUE;
3548 
3549             pArg++;
3550 
3551             if(HaveOffs) { /* the next word is an offset to type */
3552                 pType = (WORD*)(pBlk + *pArg);
3553                 SLTG_DoElem(pType, pBlk,
3554                             &(*ppFuncDesc)->funcdesc.lprgelemdescParam[param], ref_lookup);
3555                 pArg++;
3556             } else {
3557                 if(paramName)
3558                   paramName--;
3559                 pArg = SLTG_DoElem(pArg, pBlk,
3560                                    &(*ppFuncDesc)->funcdesc.lprgelemdescParam[param], ref_lookup);
3561             }
3562 
3563             /* Are we an optional param ? */
3564             if((*ppFuncDesc)->funcdesc.cParams - param <=
3565                (*ppFuncDesc)->funcdesc.cParamsOpt)
3566               (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].u.paramdesc.wParamFlags |= PARAMFLAG_FOPT;
3567 
3568             if(paramName) {
3569                 (*ppFuncDesc)->pParamDesc[param].Name =
3570                   TLB_MultiByteToBSTR(paramName);
3571             } else {
3572                 (*ppFuncDesc)->pParamDesc[param].Name =
3573                   SysAllocString((*ppFuncDesc)->Name);
3574             }
3575         }
3576 
3577         ppFuncDesc = &((*ppFuncDesc)->next);
3578         if(pFunc->next == 0xffff) break;
3579     }
3580     pTI->TypeAttr.cFuncs = cFuncs;
3581 }
3582 
3583 static void SLTG_ProcessCoClass(char *pBlk, ITypeInfoImpl *pTI,
3584                                 char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3585                                 SLTG_TypeInfoTail *pTITail)
3586 {
3587     char *pFirstItem;
3588     sltg_ref_lookup_t *ref_lookup = NULL;
3589 
3590     if(pTIHeader->href_table != 0xffffffff) {
3591         ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3592                     pNameTable);
3593     }
3594 
3595     pFirstItem = pBlk;
3596 
3597     if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
3598         SLTG_DoImpls(pFirstItem, pTI, FALSE, ref_lookup);
3599     }
3600     HeapFree(GetProcessHeap(), 0, ref_lookup);
3601 }
3602 
3603 
3604 static void SLTG_ProcessInterface(char *pBlk, ITypeInfoImpl *pTI,
3605                                   char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3606                                   const SLTG_TypeInfoTail *pTITail)
3607 {
3608     char *pFirstItem;
3609     sltg_ref_lookup_t *ref_lookup = NULL;
3610 
3611     if(pTIHeader->href_table != 0xffffffff) {
3612         ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3613                     pNameTable);
3614     }
3615 
3616     pFirstItem = pBlk;
3617 
3618     if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
3619         SLTG_DoImpls(pFirstItem, pTI, TRUE, ref_lookup);
3620     }
3621 
3622     if (pTITail->funcs_off != 0xffff)
3623         SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup);
3624 
3625     HeapFree(GetProcessHeap(), 0, ref_lookup);
3626 
3627     if (TRACE_ON(typelib))
3628         dump_TLBFuncDesc(pTI->funclist);
3629 }
3630 
3631 static void SLTG_ProcessRecord(char *pBlk, ITypeInfoImpl *pTI,
3632                                const char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3633                                const SLTG_TypeInfoTail *pTITail)
3634 {
3635   SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, NULL);
3636 }
3637 
3638 static void SLTG_ProcessAlias(char *pBlk, ITypeInfoImpl *pTI,
3639                               char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3640                               const SLTG_TypeInfoTail *pTITail)
3641 {
3642   WORD *pType;
3643   sltg_ref_lookup_t *ref_lookup = NULL;
3644 
3645   if (pTITail->simple_alias) {
3646     /* if simple alias, no more processing required */
3647     pTI->TypeAttr.tdescAlias.vt = pTITail->tdescalias_vt;
3648     return;
3649   }
3650 
3651   if(pTIHeader->href_table != 0xffffffff) {
3652       ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3653                   pNameTable);
3654   }
3655 
3656   /* otherwise it is an offset to a type */
3657   pType = (WORD *)(pBlk + pTITail->tdescalias_vt);
3658 
3659   SLTG_DoType(pType, pBlk, &pTI->TypeAttr.tdescAlias, ref_lookup);
3660 
3661   HeapFree(GetProcessHeap(), 0, ref_lookup);
3662 }
3663 
3664 static void SLTG_ProcessDispatch(char *pBlk, ITypeInfoImpl *pTI,
3665                                  char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3666                                  const SLTG_TypeInfoTail *pTITail)
3667 {
3668   sltg_ref_lookup_t *ref_lookup = NULL;
3669   if (pTIHeader->href_table != 0xffffffff)
3670       ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3671                                   pNameTable);
3672 
3673   if (pTITail->vars_off != 0xffff)
3674     SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, ref_lookup);
3675 
3676   if (pTITail->funcs_off != 0xffff)
3677     SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup);
3678 
3679   if (pTITail->impls_off != 0xffff)
3680     SLTG_DoImpls(pBlk + pTITail->impls_off, pTI, FALSE, ref_lookup);
3681 
3682   /* this is necessary to cope with MSFT typelibs that set cFuncs to the number
3683    * of dispinterface functions including the IDispatch ones, so
3684    * ITypeInfo::GetFuncDesc takes the real value for cFuncs from cbSizeVft */
3685   pTI->TypeAttr.cbSizeVft = pTI->TypeAttr.cFuncs * sizeof(void *);
3686 
3687   HeapFree(GetProcessHeap(), 0, ref_lookup);
3688   if (TRACE_ON(typelib))
3689       dump_TLBFuncDesc(pTI->funclist);
3690 }
3691 
3692 static void SLTG_ProcessEnum(char *pBlk, ITypeInfoImpl *pTI,
3693                              const char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3694                              const SLTG_TypeInfoTail *pTITail)
3695 {
3696   SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, NULL);
3697 }
3698 
3699 static void SLTG_ProcessModule(char *pBlk, ITypeInfoImpl *pTI,
3700                                char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3701                                const SLTG_TypeInfoTail *pTITail)
3702 {
3703   sltg_ref_lookup_t *ref_lookup = NULL;
3704   if (pTIHeader->href_table != 0xffffffff)
3705       ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3706                                   pNameTable);
3707 
3708   if (pTITail->vars_off != 0xffff)
3709     SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, ref_lookup);
3710 
3711   if (pTITail->funcs_off != 0xffff)
3712     SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup);
3713   HeapFree(GetProcessHeap(), 0, ref_lookup);
3714   if (TRACE_ON(typelib))
3715     dump_TypeInfo(pTI);
3716 }
3717 
3718 /* Because SLTG_OtherTypeInfo is such a painful struct, we make a more
3719    managable copy of it into this */
3720 typedef struct {
3721   WORD small_no;
3722   char *index_name;
3723   char *other_name;
3724   WORD res1a;
3725   WORD name_offs;
3726   WORD more_bytes;
3727   char *extra;
3728   WORD res20;
3729   DWORD helpcontext;
3730   WORD res26;
3731   GUID uuid;
3732 } SLTG_InternalOtherTypeInfo;
3733 
3734 /****************************************************************************
3735  *      ITypeLib2_Constructor_SLTG
3736  *
3737  * loading a SLTG typelib from an in-memory image
3738  */
3739 static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength)
3740 {
3741     ITypeLibImpl *pTypeLibImpl;
3742     SLTG_Header *pHeader;
3743     SLTG_BlkEntry *pBlkEntry;
3744     SLTG_Magic *pMagic;
3745     SLTG_Index *pIndex;
3746     SLTG_Pad9 *pPad9;
3747     LPVOID pBlk, pFirstBlk;
3748     SLTG_LibBlk *pLibBlk;
3749     SLTG_InternalOtherTypeInfo *pOtherTypeInfoBlks;
3750     char *pAfterOTIBlks = NULL;
3751     char *pNameTable, *ptr;
3752     int i;
3753     DWORD len, order;
3754     ITypeInfoImpl **ppTypeInfoImpl;
3755 
3756     TRACE_(typelib)("%p, TLB length = %d\n", pLib, dwTLBLength);
3757 
3758 
3759     pTypeLibImpl = TypeLibImpl_Constructor();
3760     if (!pTypeLibImpl) return NULL;
3761 
3762     pHeader = pLib;
3763 
3764     TRACE_(typelib)("header:\n");
3765     TRACE_(typelib)("\tmagic=0x%08x, file blocks = %d\n", pHeader->SLTG_magic,
3766           pHeader->nrOfFileBlks );
3767     if (pHeader->SLTG_magic != SLTG_SIGNATURE) {
3768         FIXME_(typelib)("Header type magic 0x%08x not supported.\n",
3769               pHeader->SLTG_magic);
3770         return NULL;
3771     }
3772 
3773     /* There are pHeader->nrOfFileBlks - 2 TypeInfo records in this typelib */
3774     pTypeLibImpl->TypeInfoCount = pHeader->nrOfFileBlks - 2;
3775 
3776     /* This points to pHeader->nrOfFileBlks - 1 of SLTG_BlkEntry */
3777     pBlkEntry = (SLTG_BlkEntry*)(pHeader + 1);
3778 
3779     /* Next we have a magic block */
3780     pMagic = (SLTG_Magic*)(pBlkEntry + pHeader->nrOfFileBlks - 1);
3781 
3782     /* Let's see if we're still in sync */
3783     if(memcmp(pMagic->CompObj_magic, SLTG_COMPOBJ_MAGIC,
3784               sizeof(SLTG_COMPOBJ_MAGIC))) {
3785         FIXME_(typelib)("CompObj magic = %s\n", pMagic->CompObj_magic);
3786         return NULL;
3787     }
3788     if(memcmp(pMagic->dir_magic, SLTG_DIR_MAGIC,
3789               sizeof(SLTG_DIR_MAGIC))) {
3790         FIXME_(typelib)("dir magic = %s\n", pMagic->dir_magic);
3791         return NULL;
3792     }
3793 
3794     pIndex = (SLTG_Index*)(pMagic+1);
3795 
3796     pPad9 = (SLTG_Pad9*)(pIndex + pTypeLibImpl->TypeInfoCount);
3797 
3798     pFirstBlk = pPad9 + 1;
3799 
3800     /* We'll set up a ptr to the main library block, which is the last one. */
3801 
3802     for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0;
3803           pBlkEntry[order].next != 0;
3804           order = pBlkEntry[order].next - 1, i++) {
3805        pBlk = (char*)pBlk + pBlkEntry[order].len;
3806     }
3807     pLibBlk = pBlk;
3808 
3809     len = SLTG_ReadLibBlk(pLibBlk, pTypeLibImpl);
3810 
3811     /* Now there's 0x40 bytes of 0xffff with the numbers 0 to TypeInfoCount
3812        interspersed */
3813 
3814     len += 0x40;
3815 
3816     /* And now TypeInfoCount of SLTG_OtherTypeInfo */
3817 
3818     pOtherTypeInfoBlks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3819                                    sizeof(*pOtherTypeInfoBlks) *
3820                                    pTypeLibImpl->TypeInfoCount);
3821 
3822 
3823     ptr = (char*)pLibBlk + len;
3824 
3825     for(i = 0; i < pTypeLibImpl->TypeInfoCount; i++) {
3826         WORD w, extra;
3827         len = 0;
3828 
3829         pOtherTypeInfoBlks[i].small_no = *(WORD*)ptr;
3830 
3831         w = *(WORD*)(ptr + 2);
3832         if(w != 0xffff) {
3833             len += w;
3834             pOtherTypeInfoBlks[i].index_name = HeapAlloc(GetProcessHeap(),0,
3835                                                          w+1);
3836             memcpy(pOtherTypeInfoBlks[i].index_name, ptr + 4, w);
3837             pOtherTypeInfoBlks[i].index_name[w] = '\0';
3838         }
3839         w = *(WORD*)(ptr + 4 + len);
3840         if(w != 0xffff) {
3841             TRACE_(typelib)("\twith %s\n", debugstr_an(ptr + 6 + len, w));
3842             len += w;
3843             pOtherTypeInfoBlks[i].other_name = HeapAlloc(GetProcessHeap(),0,
3844                                                          w+1);
3845             memcpy(pOtherTypeInfoBlks[i].other_name, ptr + 6 + len, w);
3846             pOtherTypeInfoBlks[i].other_name[w] = '\0';
3847         }
3848         pOtherTypeInfoBlks[i].res1a = *(WORD*)(ptr + len + 6);
3849         pOtherTypeInfoBlks[i].name_offs = *(WORD*)(ptr + len + 8);
3850         extra = pOtherTypeInfoBlks[i].more_bytes = *(WORD*)(ptr + 10 + len);
3851         if(extra) {
3852             pOtherTypeInfoBlks[i].extra = HeapAlloc(GetProcessHeap(),0,
3853                                                     extra);
3854             memcpy(pOtherTypeInfoBlks[i].extra, ptr + 12, extra);
3855             len += extra;
3856         }
3857         pOtherTypeInfoBlks[i].res20 = *(WORD*)(ptr + 12 + len);
3858         pOtherTypeInfoBlks[i].helpcontext = *(DWORD*)(ptr + 14 + len);
3859         pOtherTypeInfoBlks[i].res26 = *(WORD*)(ptr + 18 + len);
3860         memcpy(&pOtherTypeInfoBlks[i].uuid, ptr + 20 + len, sizeof(GUID));
3861         len += sizeof(SLTG_OtherTypeInfo);
3862         ptr += len;
3863     }
3864 
3865     pAfterOTIBlks = ptr;
3866 
3867     /* Skip this WORD and get the next DWORD */
3868     len = *(DWORD*)(pAfterOTIBlks + 2);
3869 
3870     /* Now add this to pLibBLk look at what we're pointing at and
3871        possibly add 0x20, then add 0x216, sprinkle a bit a magic
3872        dust and we should be pointing at the beginning of the name
3873        table */
3874 
3875     pNameTable = (char*)pLibBlk + len;
3876 
3877    switch(*(WORD*)pNameTable) {
3878    case 0xffff:
3879        break;
3880    case 0x0200:
3881        pNameTable += 0x20;
3882        break;
3883    default:
3884        FIXME_(typelib)("pNameTable jump = %x\n", *(WORD*)pNameTable);
3885        break;
3886    }
3887 
3888     pNameTable += 0x216;
3889 
3890     pNameTable += 2;
3891 
3892     TRACE_(typelib)("Library name is %s\n", pNameTable + pLibBlk->name);
3893 
3894     pTypeLibImpl->Name = TLB_MultiByteToBSTR(pNameTable + pLibBlk->name);
3895 
3896 
3897     /* Hopefully we now have enough ptrs set up to actually read in
3898        some TypeInfos.  It's not clear which order to do them in, so
3899        I'll just follow the links along the BlkEntry chain and read
3900        them in the order in which they are in the file */
3901 
3902     ppTypeInfoImpl = &(pTypeLibImpl->pTypeInfo);
3903 
3904     for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0;
3905         pBlkEntry[order].next != 0;
3906         order = pBlkEntry[order].next - 1, i++) {
3907 
3908       SLTG_TypeInfoHeader *pTIHeader;
3909       SLTG_TypeInfoTail *pTITail;
3910       SLTG_MemberHeader *pMemHeader;
3911 
3912       if(strcmp(pBlkEntry[order].index_string + (char*)pMagic,
3913                 pOtherTypeInfoBlks[i].index_name)) {
3914         FIXME_(typelib)("Index strings don't match\n");
3915         return NULL;
3916       }
3917 
3918       pTIHeader = pBlk;
3919       if(pTIHeader->magic != SLTG_TIHEADER_MAGIC) {
3920         FIXME_(typelib)("TypeInfoHeader magic = %04x\n", pTIHeader->magic);
3921         return NULL;
3922       }
3923       TRACE_(typelib)("pTIHeader->res06 = %x, pTIHeader->res0e = %x, "
3924         "pTIHeader->res16 = %x, pTIHeader->res1e = %x\n",
3925         pTIHeader->res06, pTIHeader->res0e, pTIHeader->res16, pTIHeader->res1e);
3926 
3927       *ppTypeInfoImpl = (ITypeInfoImpl*)ITypeInfo_Constructor();
3928       (*ppTypeInfoImpl)->pTypeLib = pTypeLibImpl;
3929       (*ppTypeInfoImpl)->index = i;
3930       (*ppTypeInfoImpl)->Name = TLB_MultiByteToBSTR(
3931                                              pOtherTypeInfoBlks[i].name_offs +
3932                                              pNameTable);
3933       (*ppTypeInfoImpl)->dwHelpContext = pOtherTypeInfoBlks[i].helpcontext;
3934       (*ppTypeInfoImpl)->TypeAttr.guid = pOtherTypeInfoBlks[i].uuid;
3935       (*ppTypeInfoImpl)->TypeAttr.typekind = pTIHeader->typekind;
3936       (*ppTypeInfoImpl)->TypeAttr.wMajorVerNum = pTIHeader->major_version;
3937       (*ppTypeInfoImpl)->TypeAttr.wMinorVerNum = pTIHeader->minor_version;
3938       (*ppTypeInfoImpl)->TypeAttr.wTypeFlags =
3939         (pTIHeader->typeflags1 >> 3) | (pTIHeader->typeflags2 << 5);
3940 
3941       if((*ppTypeInfoImpl)->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL)
3942         (*ppTypeInfoImpl)->TypeAttr.typekind = TKIND_DISPATCH;
3943 
3944       if((pTIHeader->typeflags1 & 7) != 2)
3945         FIXME_(typelib)("typeflags1 = %02x\n", pTIHeader->typeflags1);
3946       if(pTIHeader->typeflags3 != 2)
3947         FIXME_(typelib)("typeflags3 = %02x\n", pTIHeader->typeflags3);
3948 
3949       TRACE_(typelib)("TypeInfo %s of kind %s guid %s typeflags %04x\n",
3950             debugstr_w((*ppTypeInfoImpl)->Name),
3951             typekind_desc[pTIHeader->typekind],
3952             debugstr_guid(&(*ppTypeInfoImpl)->TypeAttr.guid),
3953             (*ppTypeInfoImpl)->TypeAttr.wTypeFlags);
3954 
3955       pMemHeader = (SLTG_MemberHeader*)((char *)pBlk + pTIHeader->elem_table);
3956 
3957       pTITail = (SLTG_TypeInfoTail*)((char *)(pMemHeader + 1) + pMemHeader->cbExtra);
3958 
3959       (*ppTypeInfoImpl)->TypeAttr.cbAlignment = pTITail->cbAlignment;
3960       (*ppTypeInfoImpl)->TypeAttr.cbSizeInstance = pTITail->cbSizeInstance;
3961       (*ppTypeInfoImpl)->TypeAttr.cbSizeVft = pTITail->cbSizeVft;
3962 
3963       switch(pTIHeader->typekind) {
3964       case TKIND_ENUM:
3965         SLTG_ProcessEnum((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
3966                          pTIHeader, pTITail);
3967         break;
3968 
3969       case TKIND_RECORD:
3970         SLTG_ProcessRecord((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
3971                            pTIHeader, pTITail);
3972         break;
3973 
3974       case TKIND_INTERFACE:
3975         SLTG_ProcessInterface((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
3976                               pTIHeader, pTITail);
3977         break;
3978 
3979       case TKIND_COCLASS:
3980         SLTG_ProcessCoClass((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
3981                             pTIHeader, pTITail);
3982         break;
3983 
3984       case TKIND_ALIAS:
3985         SLTG_ProcessAlias((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
3986                           pTIHeader, pTITail);
3987         break;
3988 
3989       case TKIND_DISPATCH:
3990         SLTG_ProcessDispatch((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
3991                              pTIHeader, pTITail);
3992         break;
3993 
3994       case TKIND_MODULE:
3995         SLTG_ProcessModule((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
3996                            pTIHeader, pTITail);
3997         break;
3998 
3999       default:
4000         FIXME("Not processing typekind %d\n", pTIHeader->typekind);
4001         break;
4002 
4003       }
4004 
4005       /* could get cFuncs, cVars and cImplTypes from here
4006                        but we've already set those */
4007 #define X(x) TRACE_(typelib)("tt "#x": %x\n",pTITail->res##x);
4008       X(06);
4009       X(16);
4010       X(18);
4011       X(1a);
4012       X(1e);
4013       X(24);
4014       X(26);
4015       X(2a);
4016       X(2c);
4017       X(2e);
4018       X(30);
4019       X(32);
4020       X(34);
4021 #undef X
4022       ppTypeInfoImpl = &((*ppTypeInfoImpl)->next);
4023       pBlk = (char*)pBlk + pBlkEntry[order].len;
4024     }
4025 
4026     if(i != pTypeLibImpl->TypeInfoCount) {
4027       FIXME("Somehow processed %d TypeInfos\n", i);
4028       return NULL;
4029     }
4030 
4031     HeapFree(GetProcessHeap(), 0, pOtherTypeInfoBlks);
4032     return (ITypeLib2*)pTypeLibImpl;
4033 }
4034 
4035 /* ITypeLib::QueryInterface
4036  */
4037 static HRESULT WINAPI ITypeLib2_fnQueryInterface