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