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