~ [ 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_LPSTR: sprintf(szVarType, "VT_LPSTR"); break;
1088     case VT_LPWSTR: sprintf(szVarType, "VT_LPWSTR"); break;
1089     case VT_PTR: sprintf(szVarType, "ptr to ");
1090       dump_TypeDesc(pTD->u.lptdesc, szVarType + 7);
1091       break;
1092     case VT_SAFEARRAY: sprintf(szVarType, "safearray of ");
1093       dump_TypeDesc(pTD->u.lptdesc, szVarType + 13);
1094       break;
1095     case VT_CARRAY: sprintf(szVarType, "%d dim array of ",
1096                             pTD->u.lpadesc->cDims); /* FIXME print out sizes */
1097       dump_TypeDesc(&pTD->u.lpadesc->tdescElem, szVarType + strlen(szVarType));
1098       break;
1099 
1100     default: sprintf(szVarType, "unknown(%d)", pTD->vt & VT_TYPEMASK); break;
1101     }
1102 }
1103 
1104 static void dump_ELEMDESC(const ELEMDESC *edesc) {
1105   char buf[200];
1106   USHORT flags = edesc->u.paramdesc.wParamFlags;
1107   dump_TypeDesc(&edesc->tdesc,buf);
1108   MESSAGE("\t\ttdesc.vartype %d (%s)\n",edesc->tdesc.vt,buf);
1109   MESSAGE("\t\tu.paramdesc.wParamFlags");
1110   if (!flags) MESSAGE(" PARAMFLAGS_NONE");
1111   if (flags & PARAMFLAG_FIN) MESSAGE(" PARAMFLAG_FIN");
1112   if (flags & PARAMFLAG_FOUT) MESSAGE(" PARAMFLAG_FOUT");
1113   if (flags & PARAMFLAG_FLCID) MESSAGE(" PARAMFLAG_FLCID");
1114   if (flags & PARAMFLAG_FRETVAL) MESSAGE(" PARAMFLAG_FRETVAL");
1115   if (flags & PARAMFLAG_FOPT) MESSAGE(" PARAMFLAG_FOPT");
1116   if (flags & PARAMFLAG_FHASDEFAULT) MESSAGE(" PARAMFLAG_FHASDEFAULT");
1117   if (flags & PARAMFLAG_FHASCUSTDATA) MESSAGE(" PARAMFLAG_FHASCUSTDATA");
1118   MESSAGE("\n\t\tu.paramdesc.lpex %p\n",edesc->u.paramdesc.pparamdescex);
1119 }
1120 static void dump_FUNCDESC(const FUNCDESC *funcdesc) {
1121   int i;
1122   MESSAGE("memid is %08x\n",funcdesc->memid);
1123   for (i=0;i<funcdesc->cParams;i++) {
1124       MESSAGE("Param %d:\n",i);
1125       dump_ELEMDESC(funcdesc->lprgelemdescParam+i);
1126   }
1127   MESSAGE("\tfunckind: %d (",funcdesc->funckind);
1128   switch (funcdesc->funckind) {
1129   case FUNC_VIRTUAL: MESSAGE("virtual");break;
1130   case FUNC_PUREVIRTUAL: MESSAGE("pure virtual");break;
1131   case FUNC_NONVIRTUAL: MESSAGE("nonvirtual");break;
1132   case FUNC_STATIC: MESSAGE("static");break;
1133   case FUNC_DISPATCH: MESSAGE("dispatch");break;
1134   default: MESSAGE("unknown");break;
1135   }
1136   MESSAGE(")\n\tinvkind: %d (",funcdesc->invkind);
1137   switch (funcdesc->invkind) {
1138   case INVOKE_FUNC: MESSAGE("func");break;
1139   case INVOKE_PROPERTYGET: MESSAGE("property get");break;
1140   case INVOKE_PROPERTYPUT: MESSAGE("property put");break;
1141   case INVOKE_PROPERTYPUTREF: MESSAGE("property put ref");break;
1142   }
1143   MESSAGE(")\n\tcallconv: %d (",funcdesc->callconv);
1144   switch (funcdesc->callconv) {
1145   case CC_CDECL: MESSAGE("cdecl");break;
1146   case CC_PASCAL: MESSAGE("pascal");break;
1147   case CC_STDCALL: MESSAGE("stdcall");break;
1148   case CC_SYSCALL: MESSAGE("syscall");break;
1149   default:break;
1150   }
1151   MESSAGE(")\n\toVft: %d\n", funcdesc->oVft);
1152   MESSAGE("\tcParamsOpt: %d\n", funcdesc->cParamsOpt);
1153   MESSAGE("\twFlags: %x\n", funcdesc->wFuncFlags);
1154 
1155   MESSAGE("\telemdescFunc (return value type):\n");
1156   dump_ELEMDESC(&funcdesc->elemdescFunc);
1157 }
1158 
1159 static const char * const typekind_desc[] =
1160 {
1161         "TKIND_ENUM",
1162         "TKIND_RECORD",
1163         "TKIND_MODULE",
1164         "TKIND_INTERFACE",
1165         "TKIND_DISPATCH",
1166         "TKIND_COCLASS",
1167         "TKIND_ALIAS",
1168         "TKIND_UNION",
1169         "TKIND_MAX"
1170 };
1171 
1172 static void dump_TLBFuncDescOne(const TLBFuncDesc * pfd)
1173 {
1174   int i;
1175   MESSAGE("%s(%u)\n", debugstr_w(pfd->Name), pfd->funcdesc.cParams);
1176   for (i=0;i<pfd->funcdesc.cParams;i++)
1177       MESSAGE("\tparm%d: %s\n",i,debugstr_w(pfd->pParamDesc[i].Name));
1178 
1179 
1180   dump_FUNCDESC(&(pfd->funcdesc));
1181 
1182   MESSAGE("\thelpstring: %s\n", debugstr_w(pfd->HelpString));
1183   MESSAGE("\tentry: %s\n", (pfd->Entry == (void *)-1) ? "invalid" : debugstr_w(pfd->Entry));
1184 }
1185 static void dump_TLBFuncDesc(const TLBFuncDesc * pfd)
1186 {
1187         while (pfd)
1188         {
1189           dump_TLBFuncDescOne(pfd);
1190           pfd = pfd->next;
1191         };
1192 }
1193 static void dump_TLBVarDesc(const TLBVarDesc * pvd)
1194 {
1195         while (pvd)
1196         {
1197           TRACE_(typelib)("%s\n", debugstr_w(pvd->Name));
1198           pvd = pvd->next;
1199         };
1200 }
1201 
1202 static void dump_TLBImpLib(const TLBImpLib *import)
1203 {
1204     TRACE_(typelib)("%s %s\n", debugstr_guid(&(import->guid)),
1205                     debugstr_w(import->name));
1206     TRACE_(typelib)("v%d.%d lcid=%x offset=%x\n", import->wVersionMajor,
1207                     import->wVersionMinor, import->lcid, import->offset);
1208 }
1209 
1210 static void dump_TLBRefType(const ITypeLibImpl *pTL)
1211 {
1212     TLBRefType *ref;
1213 
1214     LIST_FOR_EACH_ENTRY(ref, &pTL->ref_list, TLBRefType, entry)
1215     {
1216         TRACE_(typelib)("href:0x%08x\n", ref->reference);
1217         if(ref->index == -1)
1218             TRACE_(typelib)("%s\n", debugstr_guid(&(ref->guid)));
1219         else
1220             TRACE_(typelib)("type no: %d\n", ref->index);
1221 
1222         if(ref->pImpTLInfo != TLB_REF_INTERNAL && ref->pImpTLInfo != TLB_REF_NOT_FOUND)
1223         {
1224             TRACE_(typelib)("in lib\n");
1225             dump_TLBImpLib(ref->pImpTLInfo);
1226         }
1227     }
1228 }
1229 
1230 static void dump_TLBImplType(const TLBImplType * impl)
1231 {
1232     while (impl) {
1233         TRACE_(typelib)(
1234                 "implementing/inheriting interface hRef = %x implflags %x\n",
1235                 impl->hRef, impl->implflags);
1236         impl = impl->next;
1237     }
1238 }
1239 
1240 static void dump_Variant(const VARIANT * pvar)
1241 {
1242     SYSTEMTIME st;
1243 
1244     TRACE("%p->{%s%s", pvar, debugstr_VT(pvar), debugstr_VF(pvar));
1245 
1246     if (pvar)
1247     {
1248       if (V_ISBYREF(pvar) || V_TYPE(pvar) == VT_UNKNOWN ||
1249           V_TYPE(pvar) == VT_DISPATCH || V_TYPE(pvar) == VT_RECORD)
1250       {
1251         TRACE(",%p", V_BYREF(pvar));
1252       }
1253       else if (V_ISARRAY(pvar) || V_ISVECTOR(pvar))
1254       {
1255         TRACE(",%p", V_ARRAY(pvar));
1256       }
1257       else switch (V_TYPE(pvar))
1258       {
1259       case VT_I1:   TRACE(",%d", V_I1(pvar)); break;
1260       case VT_UI1:  TRACE(",%d", V_UI1(pvar)); break;
1261       case VT_I2:   TRACE(",%d", V_I2(pvar)); break;
1262       case VT_UI2:  TRACE(",%d", V_UI2(pvar)); break;
1263       case VT_INT:
1264       case VT_I4:   TRACE(",%d", V_I4(pvar)); break;
1265       case VT_UINT:
1266       case VT_UI4:  TRACE(",%d", V_UI4(pvar)); break;
1267       case VT_I8:   TRACE(",0x%08x,0x%08x", (ULONG)(V_I8(pvar) >> 32),
1268                           (ULONG)(V_I8(pvar) & 0xffffffff)); break;
1269       case VT_UI8:  TRACE(",0x%08x,0x%08x", (ULONG)(V_UI8(pvar) >> 32),
1270                           (ULONG)(V_UI8(pvar) & 0xffffffff)); break;
1271       case VT_R4:   TRACE(",%3.3e", V_R4(pvar)); break;
1272       case VT_R8:   TRACE(",%3.3e", V_R8(pvar)); break;
1273       case VT_BOOL: TRACE(",%s", V_BOOL(pvar) ? "TRUE" : "FALSE"); break;
1274       case VT_BSTR: TRACE(",%s", debugstr_w(V_BSTR(pvar))); break;
1275       case VT_CY:   TRACE(",0x%08x,0x%08x", V_CY(pvar).s.Hi,
1276                            V_CY(pvar).s.Lo); break;
1277       case VT_DATE:
1278         if(!VariantTimeToSystemTime(V_DATE(pvar), &st))
1279           TRACE(",<invalid>");
1280         else
1281           TRACE(",%04d/%02d/%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay,
1282                 st.wHour, st.wMinute, st.wSecond);
1283         break;
1284       case VT_ERROR:
1285       case VT_VOID:
1286       case VT_USERDEFINED:
1287       case VT_EMPTY:
1288       case VT_NULL:  break;
1289       default:       TRACE(",?"); break;
1290       }
1291     }
1292     TRACE("}\n");
1293 }
1294 
1295 static void dump_DispParms(const DISPPARAMS * pdp)
1296 {
1297     int index;
1298 
1299     TRACE("args=%u named args=%u\n", pdp->cArgs, pdp->cNamedArgs);
1300 
1301     if (pdp->cNamedArgs && pdp->rgdispidNamedArgs)
1302     {
1303         TRACE("named args:\n");
1304         for (index = 0; index < pdp->cNamedArgs; index++)
1305             TRACE( "\t0x%x\n", pdp->rgdispidNamedArgs[index] );
1306     }
1307 
1308     if (pdp->cArgs && pdp->rgvarg)
1309     {
1310         TRACE("args:\n");
1311         for (index = 0; index < pdp->cArgs; index++)
1312             dump_Variant( &pdp->rgvarg[index] );
1313     }
1314 }
1315 
1316 static void dump_TypeInfo(const ITypeInfoImpl * pty)
1317 {
1318     TRACE("%p ref=%u\n", pty, pty->ref);
1319     TRACE("%s %s\n", debugstr_w(pty->Name), debugstr_w(pty->DocString));
1320     TRACE("attr:%s\n", debugstr_guid(&(pty->TypeAttr.guid)));
1321     TRACE("kind:%s\n", typekind_desc[pty->TypeAttr.typekind]);
1322     TRACE("fct:%u var:%u impl:%u\n",
1323       pty->TypeAttr.cFuncs, pty->TypeAttr.cVars, pty->TypeAttr.cImplTypes);
1324     TRACE("wTypeFlags: 0x%04x\n", pty->TypeAttr.wTypeFlags);
1325     TRACE("parent tlb:%p index in TLB:%u\n",pty->pTypeLib, pty->index);
1326     if (pty->TypeAttr.typekind == TKIND_MODULE) TRACE("dllname:%s\n", debugstr_w(pty->DllName));
1327     if (TRACE_ON(ole))
1328         dump_TLBFuncDesc(pty->funclist);
1329     dump_TLBVarDesc(pty->varlist);
1330     dump_TLBImplType(pty->impltypelist);
1331 }
1332 
1333 static void dump_VARDESC(const VARDESC *v)
1334 {
1335     MESSAGE("memid %d\n",v->memid);
1336     MESSAGE("lpstrSchema %s\n",debugstr_w(v->lpstrSchema));
1337     MESSAGE("oInst %d\n",v->u.oInst);
1338     dump_ELEMDESC(&(v->elemdescVar));
1339     MESSAGE("wVarFlags %x\n",v->wVarFlags);
1340     MESSAGE("varkind %d\n",v->varkind);
1341 }
1342 
1343 static TYPEDESC stndTypeDesc[VT_LPWSTR+1]=
1344 {
1345     /* VT_LPWSTR is largest type that */
1346     /* may appear in type description*/
1347     {{0}, 0},{{0}, 1},{{0}, 2},{{0}, 3},{{0}, 4},
1348     {{0}, 5},{{0}, 6},{{0}, 7},{{0}, 8},{{0}, 9},
1349     {{0},10},{{0},11},{{0},12},{{0},13},{{0},14},
1350     {{0},15},{{0},16},{{0},17},{{0},18},{{0},19},
1351     {{0},20},{{0},21},{{0},22},{{0},23},{{0},24},
1352     {{0},25},{{0},26},{{0},27},{{0},28},{{0},29},
1353     {{0},30},{{0},31}
1354 };
1355 
1356 static void TLB_abort(void)
1357 {
1358     DebugBreak();
1359 }
1360 static void * TLB_Alloc(unsigned size)
1361 {
1362     void * ret;
1363     if((ret=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size))==NULL){
1364         /* FIXME */
1365         ERR("cannot allocate memory\n");
1366     }
1367     return ret;
1368 }
1369 
1370 static void TLB_Free(void * ptr)
1371 {
1372     HeapFree(GetProcessHeap(), 0, ptr);
1373 }
1374 
1375 /* returns the size required for a deep copy of a typedesc into a
1376  * flat buffer */
1377 static SIZE_T TLB_SizeTypeDesc( const TYPEDESC *tdesc, BOOL alloc_initial_space )
1378 {
1379     SIZE_T size = 0;
1380 
1381     if (alloc_initial_space)
1382         size += sizeof(TYPEDESC);
1383 
1384     switch (tdesc->vt)
1385     {
1386     case VT_PTR:
1387     case VT_SAFEARRAY:
1388         size += TLB_SizeTypeDesc(tdesc->u.lptdesc, TRUE);
1389         break;
1390     case VT_CARRAY:
1391         size += FIELD_OFFSET(ARRAYDESC, rgbounds[tdesc->u.lpadesc->cDims]);
1392         size += TLB_SizeTypeDesc(&tdesc->u.lpadesc->tdescElem, FALSE);
1393         break;
1394     }
1395     return size;
1396 }
1397 
1398 /* deep copy a typedesc into a flat buffer */
1399 static void *TLB_CopyTypeDesc( TYPEDESC *dest, const TYPEDESC *src, void *buffer )
1400 {
1401     if (!dest)
1402     {
1403         dest = buffer;
1404         buffer = (char *)buffer + sizeof(TYPEDESC);
1405     }
1406 
1407     *dest = *src;
1408 
1409     switch (src->vt)
1410     {
1411     case VT_PTR:
1412     case VT_SAFEARRAY:
1413         dest->u.lptdesc = buffer;
1414         buffer = TLB_CopyTypeDesc(NULL, src->u.lptdesc, buffer);
1415         break;
1416     case VT_CARRAY:
1417         dest->u.lpadesc = buffer;
1418         memcpy(dest->u.lpadesc, src->u.lpadesc, FIELD_OFFSET(ARRAYDESC, rgbounds[src->u.lpadesc->cDims]));
1419         buffer = (char *)buffer + FIELD_OFFSET(ARRAYDESC, rgbounds[src->u.lpadesc->cDims]);
1420         buffer = TLB_CopyTypeDesc(&dest->u.lpadesc->tdescElem, &src->u.lpadesc->tdescElem, buffer);
1421         break;
1422     }
1423     return buffer;
1424 }
1425 
1426 /* free custom data allocated by MSFT_CustData */
1427 static inline void TLB_FreeCustData(TLBCustData *pCustData)
1428 {
1429     TLBCustData *pCustDataNext;
1430     for (; pCustData; pCustData = pCustDataNext)
1431     {
1432         VariantClear(&pCustData->data);
1433 
1434         pCustDataNext = pCustData->next;
1435         TLB_Free(pCustData);
1436     }
1437 }
1438 
1439 /**********************************************************************
1440  *
1441  *  Functions for reading MSFT typelibs (those created by CreateTypeLib2)
1442  */
1443 static inline unsigned int MSFT_Tell(const TLBContext *pcx)
1444 {
1445     return pcx->pos;
1446 }
1447 
1448 static inline void MSFT_Seek(TLBContext *pcx, long where)
1449 {
1450     if (where != DO_NOT_SEEK)
1451     {
1452         where += pcx->oStart;
1453         if (where > pcx->length)
1454         {
1455             /* FIXME */
1456             ERR("seek beyond end (%ld/%d)\n", where, pcx->length );
1457             TLB_abort();
1458         }
1459         pcx->pos = where;
1460     }
1461 }
1462 
1463 /* read function */
1464 static DWORD MSFT_Read(void *buffer,  DWORD count, TLBContext *pcx, long where )
1465 {
1466     TRACE_(typelib)("pos=0x%08x len=0x%08x 0x%08x 0x%08x 0x%08lx\n",
1467        pcx->pos, count, pcx->oStart, pcx->length, where);
1468 
1469     MSFT_Seek(pcx, where);
1470     if (pcx->pos + count > pcx->length) count = pcx->length - pcx->pos;
1471     memcpy( buffer, (char *)pcx->mapping + pcx->pos, count );
1472     pcx->pos += count;
1473     return count;
1474 }
1475 
1476 static DWORD MSFT_ReadLEDWords(void *buffer,  DWORD count, TLBContext *pcx,
1477                                long where )
1478 {
1479   DWORD ret;
1480 
1481   ret = MSFT_Read(buffer, count, pcx, where);
1482   FromLEDWords(buffer, ret);
1483 
1484   return ret;
1485 }
1486 
1487 static DWORD MSFT_ReadLEWords(void *buffer,  DWORD count, TLBContext *pcx,
1488                               long where )
1489 {
1490   DWORD ret;
1491 
1492   ret = MSFT_Read(buffer, count, pcx, where);
1493   FromLEWords(buffer, ret);
1494 
1495   return ret;
1496 }
1497 
1498 static void MSFT_ReadGuid( GUID *pGuid, int offset, TLBContext *pcx)
1499 {
1500     if(offset<0 || pcx->pTblDir->pGuidTab.offset <0){
1501         memset(pGuid,0, sizeof(GUID));
1502         return;
1503     }
1504     MSFT_Read(pGuid, sizeof(GUID), pcx, pcx->pTblDir->pGuidTab.offset+offset );
1505     pGuid->Data1 = FromLEDWord(pGuid->Data1);
1506     pGuid->Data2 = FromLEWord(pGuid->Data2);
1507     pGuid->Data3 = FromLEWord(pGuid->Data3);
1508     TRACE_(typelib)("%s\n", debugstr_guid(pGuid));
1509 }
1510 
1511 static HREFTYPE MSFT_ReadHreftype( TLBContext *pcx, int offset )
1512 {
1513     MSFT_NameIntro niName;
1514 
1515     if (offset < 0)
1516     {
1517         ERR_(typelib)("bad offset %d\n", offset);
1518         return -1;
1519     }
1520 
1521     MSFT_ReadLEDWords(&niName, sizeof(niName), pcx,
1522                       pcx->pTblDir->pNametab.offset+offset);
1523 
1524     return niName.hreftype;
1525 }
1526 
1527 static BSTR MSFT_ReadName( TLBContext *pcx, int offset)
1528 {
1529     char * name;
1530     MSFT_NameIntro niName;
1531     int lengthInChars;
1532     BSTR bstrName = NULL;
1533 
1534     if (offset < 0)
1535     {
1536         ERR_(typelib)("bad offset %d\n", offset);
1537         return NULL;
1538     }
1539     MSFT_ReadLEDWords(&niName, sizeof(niName), pcx,
1540                       pcx->pTblDir->pNametab.offset+offset);
1541     niName.namelen &= 0xFF; /* FIXME: correct ? */
1542     name=TLB_Alloc((niName.namelen & 0xff) +1);
1543     MSFT_Read(name, (niName.namelen & 0xff), pcx, DO_NOT_SEEK);
1544     name[niName.namelen & 0xff]='\0';
1545 
1546     lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
1547                                         name, -1, NULL, 0);
1548 
1549     /* no invalid characters in string */
1550     if (lengthInChars)
1551     {
1552         bstrName = SysAllocStringByteLen(NULL, lengthInChars * sizeof(WCHAR));
1553 
1554         /* don't check for invalid character since this has been done previously */
1555         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name, -1, bstrName, lengthInChars);
1556     }
1557     TLB_Free(name);
1558 
1559     TRACE_(typelib)("%s %d\n", debugstr_w(bstrName), lengthInChars);
1560     return bstrName;
1561 }
1562 
1563 static BSTR MSFT_ReadString( TLBContext *pcx, int offset)
1564 {
1565     char * string;
1566     INT16 length;
1567     int lengthInChars;
1568     BSTR bstr = NULL;
1569 
1570     if(offset<0) return NULL;
1571     MSFT_ReadLEWords(&length, sizeof(INT16), pcx, pcx->pTblDir->pStringtab.offset+offset);
1572     if(length <= 0) return 0;
1573     string=TLB_Alloc(length +1);
1574     MSFT_Read(string, length, pcx, DO_NOT_SEEK);
1575     string[length]='\0';
1576 
1577     lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
1578                                         string, -1, NULL, 0);
1579 
1580     /* no invalid characters in string */
1581     if (lengthInChars)
1582     {
1583         bstr = SysAllocStringByteLen(NULL, lengthInChars * sizeof(WCHAR));
1584 
1585         /* don't check for invalid character since this has been done previously */
1586         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, string, -1, bstr, lengthInChars);
1587     }
1588     TLB_Free(string);
1589 
1590     TRACE_(typelib)("%s %d\n", debugstr_w(bstr), lengthInChars);
1591     return bstr;
1592 }
1593 /*
1594  * read a value and fill a VARIANT structure
1595  */
1596 static void MSFT_ReadValue( VARIANT * pVar, int offset, TLBContext *pcx )
1597 {
1598     int size;
1599 
1600     TRACE_(typelib)("\n");
1601 
1602     if(offset <0) { /* data are packed in here */
1603         V_VT(pVar) = (offset & 0x7c000000 )>> 26;
1604         V_I4(pVar) = offset & 0x3ffffff;
1605         return;
1606     }
1607     MSFT_ReadLEWords(&(V_VT(pVar)), sizeof(VARTYPE), pcx,
1608                      pcx->pTblDir->pCustData.offset + offset );
1609     TRACE_(typelib)("Vartype = %x\n", V_VT(pVar));
1610     switch (V_VT(pVar)){
1611         case VT_EMPTY:  /* FIXME: is this right? */
1612         case VT_NULL:   /* FIXME: is this right? */
1613         case VT_I2  :   /* this should not happen */
1614         case VT_I4  :
1615         case VT_R4  :
1616         case VT_ERROR   :
1617         case VT_BOOL    :
1618         case VT_I1  :
1619         case VT_UI1 :
1620         case VT_UI2 :
1621         case VT_UI4 :
1622         case VT_INT :
1623         case VT_UINT    :
1624         case VT_VOID    : /* FIXME: is this right? */
1625         case VT_HRESULT :
1626             size=4; break;
1627         case VT_R8  :
1628         case VT_CY  :
1629         case VT_DATE    :
1630         case VT_I8  :
1631         case VT_UI8 :
1632         case VT_DECIMAL :  /* FIXME: is this right? */
1633         case VT_FILETIME :
1634             size=8;break;
1635             /* pointer types with known behaviour */
1636         case VT_BSTR    :{
1637             char * ptr;
1638             MSFT_ReadLEDWords(&size, sizeof(INT), pcx, DO_NOT_SEEK );
1639             if(size < 0) {
1640                 char next;
1641                 DWORD origPos = MSFT_Tell(pcx), nullPos;
1642 
1643                 do {
1644                     MSFT_Read(&next, 1, pcx, DO_NOT_SEEK);
1645                 } while (next);
1646                 nullPos = MSFT_Tell(pcx);
1647                 size = nullPos - origPos;
1648                 MSFT_Seek(pcx, origPos);
1649             }
1650             ptr=TLB_Alloc(size);/* allocate temp buffer */
1651             MSFT_Read(ptr, size, pcx, DO_NOT_SEEK);/* read string (ANSI) */
1652             V_BSTR(pVar)=SysAllocStringLen(NULL,size);
1653             /* FIXME: do we need a AtoW conversion here? */
1654             V_UNION(pVar, bstrVal[size])='\0';
1655             while(size--) V_UNION(pVar, bstrVal[size])=ptr[size];
1656             TLB_Free(ptr);
1657         }
1658         size=-4; break;
1659     /* FIXME: this will not work AT ALL when the variant contains a pointer */
1660         case VT_DISPATCH :
1661         case VT_VARIANT :
1662         case VT_UNKNOWN :
1663         case VT_PTR :
1664         case VT_SAFEARRAY :
1665         case VT_CARRAY  :
1666         case VT_USERDEFINED :
1667         case VT_LPSTR   :
1668         case VT_LPWSTR  :
1669         case VT_BLOB    :
1670         case VT_STREAM  :
1671         case VT_STORAGE :
1672         case VT_STREAMED_OBJECT :
1673         case VT_STORED_OBJECT   :
1674         case VT_BLOB_OBJECT :
1675         case VT_CF  :
1676         case VT_CLSID   :
1677         default:
1678             size=0;
1679             FIXME("VARTYPE %d is not supported, setting pointer to NULL\n",
1680                 V_VT(pVar));
1681     }
1682 
1683     if(size>0) /* (big|small) endian correct? */
1684         MSFT_Read(&(V_I2(pVar)), size, pcx, DO_NOT_SEEK );
1685     return;
1686 }
1687 /*
1688  * create a linked list with custom data
1689  */
1690 static int MSFT_CustData( TLBContext *pcx, int offset, TLBCustData** ppCustData )
1691 {
1692     MSFT_CDGuid entry;
1693     TLBCustData* pNew;
1694     int count=0;
1695 
1696     TRACE_(typelib)("\n");
1697 
1698     while(offset >=0){
1699         count++;
1700         pNew=TLB_Alloc(sizeof(TLBCustData));
1701         MSFT_ReadLEDWords(&entry, sizeof(entry), pcx, pcx->pTblDir->pCDGuids.offset+offset);
1702         MSFT_ReadGuid(&(pNew->guid), entry.GuidOffset , pcx);
1703         MSFT_ReadValue(&(pNew->data), entry.DataOffset, pcx);
1704         /* add new custom data at head of the list */
1705         pNew->next=*ppCustData;
1706         *ppCustData=pNew;
1707         offset = entry.next;
1708     }
1709     return count;
1710 }
1711 
1712 static void MSFT_GetTdesc(TLBContext *pcx, INT type, TYPEDESC *pTd,
1713                           ITypeInfoImpl *pTI)
1714 {
1715     if(type <0)
1716         pTd->vt=type & VT_TYPEMASK;
1717     else
1718         *pTd=pcx->pLibInfo->pTypeDesc[type/(2*sizeof(INT))];
1719 
1720     if(pTd->vt == VT_USERDEFINED)
1721       MSFT_DoRefType(pcx, pTI->pTypeLib, pTd->u.hreftype);
1722 
1723     TRACE_(typelib)("vt type = %X\n", pTd->vt);
1724 }
1725 
1726 static void MSFT_ResolveReferencedTypes(TLBContext *pcx, ITypeInfoImpl *pTI, TYPEDESC *lpTypeDesc)
1727 {
1728     /* resolve referenced type if any */
1729     while (lpTypeDesc)
1730     {
1731         switch (lpTypeDesc->vt)
1732         {
1733         case VT_PTR:
1734             lpTypeDesc = lpTypeDesc->u.lptdesc;
1735             break;
1736 
1737         case VT_CARRAY:
1738             lpTypeDesc = & (lpTypeDesc->u.lpadesc->tdescElem);
1739             break;
1740 
1741         case VT_USERDEFINED:
1742             MSFT_DoRefType(pcx, pTI->pTypeLib,
1743                            lpTypeDesc->u.hreftype);
1744 
1745             lpTypeDesc = NULL;
1746             break;
1747 
1748         default:
1749             lpTypeDesc = NULL;
1750         }
1751     }
1752 }
1753 
1754 static void
1755 MSFT_DoFuncs(TLBContext*     pcx,
1756             ITypeInfoImpl*  pTI,
1757             int             cFuncs,
1758             int             cVars,
1759             int             offset,
1760             TLBFuncDesc**   pptfd)
1761 {
1762     /*
1763      * member information is stored in a data structure at offset
1764      * indicated by the memoffset field of the typeinfo structure
1765      * There are several distinctive parts.
1766      * The first part starts with a field that holds the total length
1767      * of this (first) part excluding this field. Then follow the records,
1768      * for each member there is one record.
1769      *
1770      * The first entry is always the length of the record (including this
1771      * length word).
1772      * The rest of the record depends on the type of the member. If there is
1773      * a field indicating the member type (function, variable, interface, etc)
1774      * I have not found it yet. At this time we depend on the information
1775      * in the type info and the usual order how things are stored.
1776      *
1777      * Second follows an array sized nrMEM*sizeof(INT) with a member id
1778      * for each member;
1779      *
1780      * Third is an equal sized array with file offsets to the name entry
1781      * of each member.
1782      *
1783      * The fourth and last (?) part is an array with offsets to the records
1784      * in the first part of this file segment.
1785      */
1786 
1787     int infolen, nameoffset, reclength, nrattributes, i;
1788     int recoffset = offset + sizeof(INT);
1789 
1790     char *recbuf = HeapAlloc(GetProcessHeap(), 0, 0xffff);
1791     MSFT_FuncRecord * pFuncRec=(MSFT_FuncRecord *) recbuf;
1792     TLBFuncDesc *ptfd_prev = NULL;
1793 
1794     TRACE_(typelib)("\n");
1795 
1796     MSFT_ReadLEDWords(&infolen, sizeof(INT), pcx, offset);
1797 
1798     for ( i = 0; i < cFuncs ; i++ )
1799     {
1800         *pptfd = TLB_Alloc(sizeof(TLBFuncDesc));
1801 
1802         /* name, eventually add to a hash table */
1803         MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx,
1804                           offset + infolen + (cFuncs + cVars + i + 1) * sizeof(INT));
1805 
1806         /* nameoffset is sometimes -1 on the second half of a propget/propput
1807          * pair of functions */
1808         if ((nameoffset == -1) && (i > 0))
1809             (*pptfd)->Name = SysAllocString(ptfd_prev->Name);
1810         else
1811             (*pptfd)->Name = MSFT_ReadName(pcx, nameoffset);
1812 
1813         /* read the function information record */
1814         MSFT_ReadLEDWords(&reclength, sizeof(INT), pcx, recoffset);
1815 
1816         reclength &= 0xffff;
1817 
1818         MSFT_ReadLEDWords(pFuncRec, reclength - sizeof(INT), pcx, DO_NOT_SEEK);
1819 
1820         /* do the attributes */
1821         nrattributes = (reclength - pFuncRec->nrargs * 3 * sizeof(int) - 0x18)
1822                        / sizeof(int);
1823 
1824         if ( nrattributes > 0 )
1825         {
1826             (*pptfd)->helpcontext = pFuncRec->OptAttr[0] ;
1827 
1828             if ( nrattributes > 1 )
1829             {
1830                 (*pptfd)->HelpString = MSFT_ReadString(pcx,
1831                                                       pFuncRec->OptAttr[1]) ;
1832 
1833                 if ( nrattributes > 2 )
1834                 {
1835                     if ( pFuncRec->FKCCIC & 0x2000 )
1836                     {
1837                        if (HIWORD(pFuncRec->OptAttr[2]) != 0)
1838                            ERR("ordinal 0x%08x invalid, HIWORD != 0\n", pFuncRec->OptAttr[2]);
1839                        (*pptfd)->Entry = (BSTR)pFuncRec->OptAttr[2];
1840                     }
1841                     else
1842                     {
1843                         (*pptfd)->Entry = MSFT_ReadString(pcx,
1844                                                          pFuncRec->OptAttr[2]);
1845                     }
1846                     if( nrattributes > 5 )
1847                     {
1848                         (*pptfd)->HelpStringContext = pFuncRec->OptAttr[5] ;
1849 
1850                         if ( nrattributes > 6 && pFuncRec->FKCCIC & 0x80 )
1851                         {
1852                             MSFT_CustData(pcx,
1853                                           pFuncRec->OptAttr[6],
1854                                           &(*pptfd)->pCustData);
1855                         }
1856                     }
1857                 }
1858                 else
1859                 {
1860                     (*pptfd)->Entry = (BSTR)-1;
1861                 }
1862             }
1863         }
1864 
1865         /* fill the FuncDesc Structure */
1866         MSFT_ReadLEDWords( & (*pptfd)->funcdesc.memid, sizeof(INT), pcx,
1867                            offset + infolen + ( i + 1) * sizeof(INT));
1868 
1869         (*pptfd)->funcdesc.funckind   =  (pFuncRec->FKCCIC)      & 0x7;
1870         (*pptfd)->funcdesc.invkind    =  (pFuncRec->FKCCIC) >> 3 & 0xF;
1871         (*pptfd)->funcdesc.callconv   =  (pFuncRec->FKCCIC) >> 8 & 0xF;
1872         (*pptfd)->funcdesc.cParams    =   pFuncRec->nrargs  ;
1873         (*pptfd)->funcdesc.cParamsOpt =   pFuncRec->nroargs ;
1874         (*pptfd)->funcdesc.oVft       =   pFuncRec->VtableOffset ;
1875         (*pptfd)->funcdesc.wFuncFlags =   LOWORD(pFuncRec->Flags) ;
1876 
1877         MSFT_GetTdesc(pcx,
1878                       pFuncRec->DataType,
1879                       &(*pptfd)->funcdesc.elemdescFunc.tdesc,
1880                       pTI);
1881         MSFT_ResolveReferencedTypes(pcx, pTI, &(*pptfd)->funcdesc.elemdescFunc.tdesc);
1882 
1883         /* do the parameters/arguments */
1884         if(pFuncRec->nrargs)
1885         {
1886             int j = 0;
1887             MSFT_ParameterInfo paraminfo;
1888 
1889             (*pptfd)->funcdesc.lprgelemdescParam =
1890                 TLB_Alloc(pFuncRec->nrargs * sizeof(ELEMDESC));
1891 
1892             (*pptfd)->pParamDesc =
1893                 TLB_Alloc(pFuncRec->nrargs * sizeof(TLBParDesc));
1894 
1895             MSFT_ReadLEDWords(&paraminfo, sizeof(paraminfo), pcx,
1896                               recoffset + reclength - pFuncRec->nrargs * sizeof(MSFT_ParameterInfo));
1897 
1898             for ( j = 0 ; j < pFuncRec->nrargs ; j++ )
1899             {
1900                 ELEMDESC *elemdesc = &(*pptfd)->funcdesc.lprgelemdescParam[j];
1901 
1902                 MSFT_GetTdesc(pcx,
1903                               paraminfo.DataType,
1904                               &elemdesc->tdesc,
1905                               pTI);
1906 
1907                 elemdesc->u.paramdesc.wParamFlags = paraminfo.Flags;
1908 
1909                 /* name */
1910                 if (paraminfo.oName == -1)
1911                     /* this occurs for [propput] or [propget] methods, so
1912                      * we should just set the name of the parameter to the
1913                      * name of the method. */
1914                     (*pptfd)->pParamDesc[j].Name = SysAllocString((*pptfd)->Name);
1915                 else
1916                     (*pptfd)->pParamDesc[j].Name =
1917                         MSFT_ReadName( pcx, paraminfo.oName );
1918                 TRACE_(typelib)("param[%d] = %s\n", j, debugstr_w((*pptfd)->pParamDesc[j].Name));
1919 
1920                 MSFT_ResolveReferencedTypes(pcx, pTI, &elemdesc->tdesc);
1921 
1922                 /* default value */
1923                 if ( (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) &&
1924                      (pFuncRec->FKCCIC & 0x1000) )
1925                 {
1926                     INT* pInt = (INT *)((char *)pFuncRec +
1927                                    reclength -
1928                                    (pFuncRec->nrargs * 4 + 1) * sizeof(INT) );
1929 
1930                     PARAMDESC* pParamDesc = &elemdesc->u.paramdesc;
1931 
1932                     pParamDesc->pparamdescex = TLB_Alloc(sizeof(PARAMDESCEX));
1933                     pParamDesc->pparamdescex->cBytes = sizeof(PARAMDESCEX);
1934 
1935                     MSFT_ReadValue(&(pParamDesc->pparamdescex->varDefaultValue),
1936                         pInt[j], pcx);
1937                 }
1938                 else
1939                     elemdesc->u.paramdesc.pparamdescex = NULL;
1940                 /* custom info */
1941                 if ( nrattributes > 7 + j && pFuncRec->FKCCIC & 0x80 )
1942                 {
1943                     MSFT_CustData(pcx,
1944                                   pFuncRec->OptAttr[7+j],
1945                                   &(*pptfd)->pParamDesc[j].pCustData);
1946                 }
1947 
1948                 /* SEEK value = jump to offset,
1949                  * from there jump to the end of record,
1950                  * go back by (j-1) arguments
1951                  */
1952                 MSFT_ReadLEDWords( &paraminfo ,
1953                            sizeof(MSFT_ParameterInfo), pcx,
1954                            recoffset + reclength - ((pFuncRec->nrargs - j - 1)
1955                                                * sizeof(MSFT_ParameterInfo)));
1956             }
1957         }
1958 
1959         /* scode is not used: archaic win16 stuff FIXME: right? */
1960         (*pptfd)->funcdesc.cScodes   = 0 ;
1961         (*pptfd)->funcdesc.lprgscode = NULL ;
1962 
1963         ptfd_prev = *pptfd;
1964         pptfd      = & ((*pptfd)->next);
1965         recoffset += reclength;
1966     }
1967     HeapFree(GetProcessHeap(), 0, recbuf);
1968 }
1969 
1970 static void MSFT_DoVars(TLBContext *pcx, ITypeInfoImpl *pTI, int cFuncs,
1971                        int cVars, int offset, TLBVarDesc ** pptvd)
1972 {
1973     int infolen, nameoffset, reclength;
1974     char recbuf[256];
1975     MSFT_VarRecord * pVarRec=(MSFT_VarRecord *) recbuf;
1976     int i;
1977     int recoffset;
1978 
1979     TRACE_(typelib)("\n");
1980 
1981     MSFT_ReadLEDWords(&infolen,sizeof(INT), pcx, offset);
1982     MSFT_ReadLEDWords(&recoffset,sizeof(INT), pcx, offset + infolen +
1983                       ((cFuncs+cVars)*2+cFuncs + 1)*sizeof(INT));
1984     recoffset += offset+sizeof(INT);
1985     for(i=0;i<cVars;i++){
1986         *pptvd=TLB_Alloc(sizeof(TLBVarDesc));
1987     /* name, eventually add to a hash table */
1988         MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx,
1989                           offset + infolen + (2*cFuncs + cVars + i + 1) * sizeof(INT));
1990         (*pptvd)->Name=MSFT_ReadName(pcx, nameoffset);
1991     /* read the variable information record */
1992         MSFT_ReadLEDWords(&reclength, sizeof(INT), pcx, recoffset);
1993         reclength &=0xff;
1994         MSFT_ReadLEDWords(pVarRec, reclength - sizeof(INT), pcx, DO_NOT_SEEK);
1995     /* Optional data */
1996         if(reclength >(6*sizeof(INT)) )
1997             (*pptvd)->HelpContext=pVarRec->HelpContext;
1998         if(reclength >(7*sizeof(INT)) )
1999             (*pptvd)->HelpString = MSFT_ReadString(pcx, pVarRec->oHelpString) ;
2000         if(reclength >(8*sizeof(INT)) )
2001         if(reclength >(9*sizeof(INT)) )
2002             (*pptvd)->HelpStringContext=pVarRec->HelpStringContext;
2003     /* fill the VarDesc Structure */
2004         MSFT_ReadLEDWords(&(*pptvd)->vardesc.memid, sizeof(INT), pcx,
2005                           offset + infolen + (cFuncs + i + 1) * sizeof(INT));
2006         (*pptvd)->vardesc.varkind = pVarRec->VarKind;
2007         (*pptvd)->vardesc.wVarFlags = pVarRec->Flags;
2008         MSFT_GetTdesc(pcx, pVarRec->DataType,
2009             &(*pptvd)->vardesc.elemdescVar.tdesc, pTI);
2010 /*   (*pptvd)->vardesc.lpstrSchema; is reserved (SDK) FIXME?? */
2011         if(pVarRec->VarKind == VAR_CONST ){
2012             (*pptvd)->vardesc.u.lpvarValue=TLB_Alloc(sizeof(VARIANT));
2013             MSFT_ReadValue((*pptvd)->vardesc.u.lpvarValue,
2014                 pVarRec->OffsValue, pcx);
2015         } else
2016             (*pptvd)->vardesc.u.oInst=pVarRec->OffsValue;
2017         MSFT_ResolveReferencedTypes(pcx, pTI, &(*pptvd)->vardesc.elemdescVar.tdesc);
2018         pptvd=&((*pptvd)->next);
2019         recoffset += reclength;
2020     }
2021 }
2022 /* fill in data for a hreftype (offset). When the referenced type is contained
2023  * in the typelib, it's just an (file) offset in the type info base dir.
2024  * If comes from import, it's an offset+1 in the ImpInfo table
2025  * */
2026 static void MSFT_DoRefType(TLBContext *pcx, ITypeLibImpl *pTL,
2027                           int offset)
2028 {
2029     TLBRefType *ref;
2030 
2031     TRACE_(typelib)("TLB context %p, TLB offset %x\n", pcx, offset);
2032 
2033     LIST_FOR_EACH_ENTRY(ref, &pTL->ref_list, TLBRefType, entry)
2034     {
2035         if(ref->reference == offset) return;
2036     }
2037 
2038     ref = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ref));
2039     list_add_tail(&pTL->ref_list, &ref->entry);
2040 
2041     if(!MSFT_HREFTYPE_INTHISFILE( offset)) {
2042         /* external typelib */
2043         MSFT_ImpInfo impinfo;
2044         TLBImpLib *pImpLib=(pcx->pLibInfo->pImpLibs);
2045 
2046         TRACE_(typelib)("offset %x, masked offset %x\n", offset, offset + (offset & 0xfffffffc));
2047 
2048         MSFT_ReadLEDWords(&impinfo, sizeof(impinfo), pcx,
2049                           pcx->pTblDir->pImpInfo.offset + (offset & 0xfffffffc));
2050         while (pImpLib){   /* search the known offsets of all import libraries */
2051             if(pImpLib->offset==impinfo.oImpFile) break;
2052             pImpLib=pImpLib->next;
2053         }
2054         if(pImpLib){
2055             ref->reference = offset;
2056             ref->pImpTLInfo = pImpLib;
2057             if(impinfo.flags & MSFT_IMPINFO_OFFSET_IS_GUID) {
2058                 MSFT_ReadGuid(&ref->guid, impinfo.oGuid, pcx);
2059                 TRACE("importing by guid %s\n", debugstr_guid(&ref->guid));
2060                 ref->index = TLB_REF_USE_GUID;
2061             } else
2062                 ref->index = impinfo.oGuid;
2063         }else{
2064             ERR("Cannot find a reference\n");
2065             ref->reference = -1;
2066             ref->pImpTLInfo = TLB_REF_NOT_FOUND;
2067         }
2068     }else{
2069         /* in this typelib */
2070         ref->index = MSFT_HREFTYPE_INDEX(offset);
2071         ref->reference = offset;
2072         ref->pImpTLInfo = TLB_REF_INTERNAL;
2073     }
2074 }
2075 
2076 /* process Implemented Interfaces of a com class */
2077 static void MSFT_DoImplTypes(TLBContext *pcx, ITypeInfoImpl *pTI, int count,
2078                             int offset)
2079 {
2080     int i;
2081     MSFT_RefRecord refrec;
2082     TLBImplType **ppImpl = &pTI->impltypelist;
2083 
2084     TRACE_(typelib)("\n");
2085 
2086     for(i=0;i<count;i++){
2087         if(offset<0) break; /* paranoia */
2088         *ppImpl=TLB_Alloc(sizeof(**ppImpl));
2089         MSFT_ReadLEDWords(&refrec,sizeof(refrec),pcx,offset+pcx->pTblDir->pRefTab.offset);
2090         MSFT_DoRefType(pcx, pTI->pTypeLib, refrec.reftype);
2091         (*ppImpl)->hRef = refrec.reftype;
2092         (*ppImpl)->implflags=refrec.flags;
2093         (*ppImpl)->ctCustData=
2094             MSFT_CustData(pcx, refrec.oCustData, &(*ppImpl)->pCustData);
2095         offset=refrec.onext;
2096         ppImpl=&((*ppImpl)->next);
2097     }
2098 }
2099 /*
2100  * process a typeinfo record
2101  */
2102 static ITypeInfoImpl * MSFT_DoTypeInfo(
2103     TLBContext *pcx,
2104     int count,
2105     ITypeLibImpl * pLibInfo)
2106 {
2107     MSFT_TypeInfoBase tiBase;
2108     ITypeInfoImpl *ptiRet;
2109 
2110     TRACE_(typelib)("count=%u\n", count);
2111 
2112     ptiRet = (ITypeInfoImpl*) ITypeInfo_Constructor();
2113     MSFT_ReadLEDWords(&tiBase, sizeof(tiBase) ,pcx ,
2114                       pcx->pTblDir->pTypeInfoTab.offset+count*sizeof(tiBase));
2115 
2116 /* this is where we are coming from */
2117     ptiRet->pTypeLib = pLibInfo;
2118     ptiRet->index=count;
2119 /* fill in the typeattr fields */
2120 
2121     MSFT_ReadGuid(&ptiRet->TypeAttr.guid, tiBase.posguid, pcx);
2122     ptiRet->TypeAttr.lcid=pLibInfo->LibAttr.lcid;   /* FIXME: correct? */
2123     ptiRet->TypeAttr.lpstrSchema=NULL;              /* reserved */
2124     ptiRet->TypeAttr.cbSizeInstance=tiBase.size;
2125     ptiRet->TypeAttr.typekind=tiBase.typekind & 0xF;
2126     ptiRet->TypeAttr.cFuncs=LOWORD(tiBase.cElement);
2127     ptiRet->TypeAttr.cVars=HIWORD(tiBase.cElement);
2128     ptiRet->TypeAttr.cbAlignment=(tiBase.typekind >> 11 )& 0x1F; /* there are more flags there */
2129     ptiRet->TypeAttr.wTypeFlags=tiBase.flags;
2130     ptiRet->TypeAttr.wMajorVerNum=LOWORD(tiBase.version);
2131     ptiRet->TypeAttr.wMinorVerNum=HIWORD(tiBase.version);
2132     ptiRet->TypeAttr.cImplTypes=tiBase.cImplTypes;
2133     ptiRet->TypeAttr.cbSizeVft=tiBase.cbSizeVft; /* FIXME: this is only the non inherited part */
2134     if(ptiRet->TypeAttr.typekind == TKIND_ALIAS)
2135         MSFT_GetTdesc(pcx, tiBase.datatype1,
2136             &ptiRet->TypeAttr.tdescAlias, ptiRet);
2137 
2138 /*  FIXME: */
2139 /*    IDLDESC  idldescType; *//* never saw this one != zero  */
2140 
2141 /* name, eventually add to a hash table */
2142     ptiRet->Name=MSFT_ReadName(pcx, tiBase.NameOffset);
2143     ptiRet->hreftype = MSFT_ReadHreftype(pcx, tiBase.NameOffset);
2144     TRACE_(typelib)("reading %s\n", debugstr_w(ptiRet->Name));
2145     /* help info */
2146     ptiRet->DocString=MSFT_ReadString(pcx, tiBase.docstringoffs);
2147     ptiRet->dwHelpStringContext=tiBase.helpstringcontext;
2148     ptiRet->dwHelpContext=tiBase.helpcontext;
2149 
2150     if (ptiRet->TypeAttr.typekind == TKIND_MODULE)
2151         ptiRet->DllName = MSFT_ReadString(pcx, tiBase.datatype1);
2152 
2153 /* note: InfoType's Help file and HelpStringDll come from the containing
2154  * library. Further HelpString and Docstring appear to be the same thing :(
2155  */
2156     /* functions */
2157     if(ptiRet->TypeAttr.cFuncs >0 )
2158         MSFT_DoFuncs(pcx, ptiRet, ptiRet->TypeAttr.cFuncs,
2159                     ptiRet->TypeAttr.cVars,
2160                     tiBase.memoffset, & ptiRet->funclist);
2161     /* variables */
2162     if(ptiRet->TypeAttr.cVars >0 )
2163         MSFT_DoVars(pcx, ptiRet, ptiRet->TypeAttr.cFuncs,
2164                    ptiRet->TypeAttr.cVars,
2165                    tiBase.memoffset, & ptiRet->varlist);
2166     if(ptiRet->TypeAttr.cImplTypes >0 ) {
2167         switch(ptiRet->TypeAttr.typekind)
2168         {
2169         case TKIND_COCLASS:
2170             MSFT_DoImplTypes(pcx, ptiRet, ptiRet->TypeAttr.cImplTypes ,
2171                 tiBase.datatype1);
2172             break;
2173         case TKIND_DISPATCH:
2174             /* This is not -1 when the interface is a non-base dual interface or
2175                when a dispinterface wraps an interface, i.e., the idl 'dispinterface x {interface y;};'.
2176                Note however that GetRefTypeOfImplType(0) always returns a ref to IDispatch and
2177                not this interface.
2178             */
2179 
2180             if (tiBase.datatype1 != -1)
2181             {
2182                 ptiRet->impltypelist = TLB_Alloc(sizeof(TLBImplType));
2183                 ptiRet->impltypelist->hRef = tiBase.datatype1;
2184                 MSFT_DoRefType(pcx, pLibInfo, tiBase.datatype1);
2185             }
2186           break;
2187         default:
2188             ptiRet->impltypelist=TLB_Alloc(sizeof(TLBImplType));
2189             MSFT_DoRefType(pcx, pLibInfo, tiBase.datatype1);
2190             ptiRet->impltypelist->hRef = tiBase.datatype1;
2191             break;
2192        }
2193     }
2194     ptiRet->ctCustData=
2195         MSFT_CustData(pcx, tiBase.oCustData, &ptiRet->pCustData);
2196 
2197     TRACE_(typelib)("%s guid: %s kind:%s\n",
2198        debugstr_w(ptiRet->Name),
2199        debugstr_guid(&ptiRet->TypeAttr.guid),
2200        typekind_desc[ptiRet->TypeAttr.typekind]);
2201 
2202     return ptiRet;
2203 }
2204 
2205 /* Because type library parsing has some degree of overhead, and some apps repeatedly load the same
2206  * typelibs over and over, we cache them here. According to MSDN Microsoft have a similar scheme in
2207  * place. This will cause a deliberate memory leak, but generally losing RAM for cycles is an acceptable
2208  * tradeoff here.
2209  */
2210 static ITypeLibImpl *tlb_cache_first;
2211 static CRITICAL_SECTION cache_section;
2212 static CRITICAL_SECTION_DEBUG cache_section_debug =
2213 {
2214     0, 0, &cache_section,
2215     { &cache_section_debug.ProcessLocksList, &cache_section_debug.ProcessLocksList },
2216       0, 0, { (DWORD_PTR)(__FILE__ ": typelib loader cache") }
2217 };
2218 static CRITICAL_SECTION cache_section = { &cache_section_debug, -1, 0, 0, 0, 0 };
2219 
2220 
2221 typedef struct TLB_PEFile
2222 {
2223     const IUnknownVtbl *lpvtbl;
2224     LONG refs;
2225     HMODULE dll;
2226     HRSRC typelib_resource;
2227     HGLOBAL typelib_global;
2228     LPVOID typelib_base;
2229 } TLB_PEFile;
2230 
2231 static HRESULT WINAPI TLB_PEFile_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2232 {
2233     if (IsEqualIID(riid, &IID_IUnknown))
2234     {
2235         *ppv = iface;
2236         IUnknown_AddRef(iface);
2237         return S_OK;
2238     }
2239     *ppv = NULL;
2240     return E_NOINTERFACE;
2241 }
2242 
2243 static ULONG WINAPI TLB_PEFile_AddRef(IUnknown *iface)
2244 {
2245     TLB_PEFile *This = (TLB_PEFile *)iface;
2246     return InterlockedIncrement(&This->refs);
2247 }
2248 
2249 static ULONG WINAPI TLB_PEFile_Release(IUnknown *iface)
2250 {
2251     TLB_PEFile *This = (TLB_PEFile *)iface;
2252     ULONG refs = InterlockedDecrement(&This->refs);
2253     if (!refs)
2254     {
2255         if (This->typelib_global)
2256             FreeResource(This->typelib_global);
2257         if (This->dll)
2258             FreeLibrary(This->dll);
2259         HeapFree(GetProcessHeap(), 0, This);
2260     }
2261     return refs;
2262 }
2263 
2264 static const IUnknownVtbl TLB_PEFile_Vtable =
2265 {
2266     TLB_PEFile_QueryInterface,
2267     TLB_PEFile_AddRef,
2268     TLB_PEFile_Release
2269 };
2270 
2271 static HRESULT TLB_PEFile_Open(LPCWSTR path, INT index, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile)
2272 {
2273     TLB_PEFile *This;
2274 
2275     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
2276     if (!This)
2277         return E_OUTOFMEMORY;
2278 
2279     This->lpvtbl = &TLB_PEFile_Vtable;
2280     This->refs = 1;
2281     This->dll = NULL;
2282     This->typelib_resource = NULL;
2283     This->typelib_global = NULL;
2284     This->typelib_base = NULL;
2285 
2286     This->dll = LoadLibraryExW(path, 0, DONT_RESOLVE_DLL_REFERENCES |
2287                     LOAD_LIBRARY_AS_DATAFILE | LOAD_WITH_ALTERED_SEARCH_PATH);
2288 
2289     if (This->dll)
2290     {
2291         static const WCHAR TYPELIBW[] = {'T','Y','P','E','L','I','B',0};
2292         This->typelib_resource = FindResourceW(This->dll, MAKEINTRESOURCEW(index), TYPELIBW);
2293         if (This->typelib_resource)
2294         {
2295             This->typelib_global = LoadResource(This->dll, This->typelib_resource);
2296             if (This->typelib_global)
2297             {
2298                 This->typelib_base = LockResource(This->typelib_global);
2299 
2300                 if (This->typelib_base)
2301                 {
2302                     *pdwTLBLength = SizeofResource(This->dll, This->typelib_resource);
2303                     *ppBase = This->typelib_base;
2304                     *ppFile = (IUnknown *)&This->lpvtbl;
2305                     return S_OK;
2306                 }
2307             }
2308         }
2309     }
2310 
2311     TLB_PEFile_Release((IUnknown *)&This->lpvtbl);
2312     return TYPE_E_CANTLOADLIBRARY;
2313 }
2314 
2315 
2316 typedef struct TLB_Mapping
2317 {
2318     const IUnknownVtbl *lpvtbl;
2319     LONG refs;
2320     HANDLE file;
2321     HANDLE mapping;
2322     LPVOID typelib_base;
2323 } TLB_Mapping;
2324 
2325 static HRESULT WINAPI TLB_Mapping_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2326 {
2327     if (IsEqualIID(riid, &IID_IUnknown))
2328     {
2329         *ppv = iface;
2330         IUnknown_AddRef(iface);
2331         return S_OK;
2332     }
2333     *ppv = NULL;
2334     return E_NOINTERFACE;
2335 }
2336 
2337 static ULONG WINAPI TLB_Mapping_AddRef(IUnknown *iface)
2338 {
2339     TLB_Mapping *This = (TLB_Mapping *)iface;
2340     return InterlockedIncrement(&This->refs);
2341 }
2342 
2343 static ULONG WINAPI TLB_Mapping_Release(IUnknown *iface)
2344 {
2345     TLB_Mapping *This = (TLB_Mapping *)iface;
2346     ULONG refs = InterlockedDecrement(&This->refs);
2347     if (!refs)
2348     {
2349         if (This->typelib_base)
2350             UnmapViewOfFile(This->typelib_base);
2351         if (This->mapping)
2352             CloseHandle(This->mapping);
2353         if (This->file != INVALID_HANDLE_VALUE)
2354             CloseHandle(This->file);
2355         HeapFree(GetProcessHeap(), 0, This);
2356     }
2357     return refs;
2358 }
2359 
2360 static const IUnknownVtbl TLB_Mapping_Vtable =
2361 {
2362     TLB_Mapping_QueryInterface,
2363     TLB_Mapping_AddRef,
2364     TLB_Mapping_Release
2365 };
2366 
2367 static HRESULT TLB_Mapping_Open(LPCWSTR path, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile)
2368 {
2369     TLB_Mapping *This;
2370 
2371     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
2372     if (!This)
2373         return E_OUTOFMEMORY;
2374 
2375     This->lpvtbl = &TLB_Mapping_Vtable;
2376     This->refs = 1;
2377     This->file = INVALID_HANDLE_VALUE;
2378     This->mapping = NULL;
2379     This->typelib_base = NULL;
2380 
2381     This->file = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
2382     if (INVALID_HANDLE_VALUE != This->file)
2383     {
2384         This->mapping = CreateFileMappingW(This->file, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL);
2385         if (This->mapping)
2386         {
2387             This->typelib_base = MapViewOfFile(This->mapping, FILE_MAP_READ, 0, 0, 0);
2388             if(This->typelib_base)
2389             {
2390                 /* retrieve file size */
2391                 *pdwTLBLength = GetFileSize(This->file, NULL);
2392                 *ppBase = This->typelib_base;
2393                 *ppFile = (IUnknown *)&This->lpvtbl;
2394                 return S_OK;
2395             }
2396         }
2397     }
2398 
2399     IUnknown_Release((IUnknown *)&This->lpvtbl);
2400     return TYPE_E_CANTLOADLIBRARY;
2401 }
2402 
2403 /****************************************************************************
2404  *      TLB_ReadTypeLib
2405  *
2406  * find the type of the typelib file and map the typelib resource into
2407  * the memory
2408  */
2409 #define MSFT_SIGNATURE 0x5446534D /* "MSFT" */
2410 #define SLTG_SIGNATURE 0x47544c53 /* "SLTG" */
2411 static HRESULT TLB_ReadTypeLib(LPCWSTR pszFileName, LPWSTR pszPath, UINT cchPath, ITypeLib2 **ppTypeLib)
2412 {
2413     ITypeLibImpl *entry;
2414     HRESULT ret;
2415     INT index = 1;
2416     LPWSTR index_str, file = (LPWSTR)pszFileName;
2417     LPVOID pBase = NULL;
2418     DWORD dwTLBLength = 0;
2419     IUnknown *pFile = NULL;
2420 
2421     *ppTypeLib = NULL;
2422 
2423     index_str = strrchrW(pszFileName, '\\');
2424     if(index_str && *++index_str != '\0')
2425     {
2426         LPWSTR end_ptr;
2427         long idx = strtolW(index_str, &end_ptr, 10);
2428         if(*end_ptr == '\0')
2429         {
2430             int str_len = index_str - pszFileName - 1;
2431             index = idx;
2432             file = HeapAlloc(GetProcessHeap(), 0, (str_len + 1) * sizeof(WCHAR));
2433             memcpy(file, pszFileName, str_len * sizeof(WCHAR));
2434             file[str_len] = 0;
2435         }
2436     }
2437 
2438     if(!SearchPathW(NULL, file, NULL, cchPath, pszPath, NULL))
2439     {
2440         if(strchrW(file, '\\'))
2441         {
2442             lstrcpyW(pszPath, file);
2443         }
2444         else
2445         {
2446             int len = GetSystemDirectoryW(pszPath, cchPath);
2447             pszPath[len] = '\\';
2448             memcpy(pszPath + len + 1, file, (strlenW(file) + 1) * sizeof(WCHAR));
2449         }
2450     }
2451 
2452     if(file != pszFileName) HeapFree(GetProcessHeap(), 0, file);
2453 
2454     TRACE_(typelib)("File %s index %d\n", debugstr_w(pszPath), index);
2455 
2456     /* We look the path up in the typelib cache. If found, we just addref it, and return the pointer. */
2457     EnterCriticalSection(&cache_section);
2458     for (entry = tlb_cache_first; entry != NULL; entry = entry->next)
2459     {
2460         if (!strcmpiW(entry->path, pszPath) && entry->index == index)
2461         {
2462             TRACE("cache hit\n");
2463             *ppTypeLib = (ITypeLib2*)entry;
2464             ITypeLib_AddRef(*ppTypeLib);
2465             LeaveCriticalSection(&cache_section);
2466             return S_OK;
2467         }
2468     }
2469     LeaveCriticalSection(&cache_section);
2470 
2471     /* now actually load and parse the typelib */
2472 
2473     ret = TLB_PEFile_Open(pszPath, index, &pBase, &dwTLBLength, &pFile);
2474     if (ret == TYPE_E_CANTLOADLIBRARY)
2475         ret = TLB_Mapping_Open(pszPath, &pBase, &dwTLBLength, &pFile);
2476     if (SUCCEEDED(ret))
2477     {
2478         if (dwTLBLength >= 4)
2479         {
2480             DWORD dwSignature = FromLEDWord(*((DWORD*) pBase));
2481             if (dwSignature == MSFT_SIGNATURE)
2482                 *ppTypeLib = ITypeLib2_Constructor_MSFT(pBase, dwTLBLength);
2483             else if (dwSignature == SLTG_SIGNATURE)
2484                 *ppTypeLib = ITypeLib2_Constructor_SLTG(pBase, dwTLBLength);
2485             else
2486             {
2487                 FIXME("Header type magic 0x%08x not supported.\n",dwSignature);
2488                 ret = TYPE_E_CANTLOADLIBRARY;
2489             }
2490         }
2491         else
2492             ret = TYPE_E_CANTLOADLIBRARY;
2493         IUnknown_Release(pFile);
2494     }
2495 
2496     if(*ppTypeLib) {
2497         ITypeLibImpl *impl = (ITypeLibImpl*)*ppTypeLib;
2498 
2499         TRACE("adding to cache\n");
2500         impl->path = HeapAlloc(GetProcessHeap(), 0, (strlenW(pszPath)+1) * sizeof(WCHAR));
2501         lstrcpyW(impl->path, pszPath);
2502         /* We should really canonicalise the path here. */
2503         impl->index = index;
2504 
2505         /* FIXME: check if it has added already in the meantime */
2506         EnterCriticalSection(&cache_section);
2507         if ((impl->next = tlb_cache_first) != NULL) impl->next->prev = impl;
2508         impl->prev = NULL;
2509         tlb_cache_first = impl;
2510         LeaveCriticalSection(&cache_section);
2511         ret = S_OK;
2512     } else
2513         ERR("Loading of typelib %s failed with error %d\n", debugstr_w(pszFileName), GetLastError());
2514 
2515     return ret;
2516 }
2517 
2518 /*================== ITypeLib(2) Methods ===================================*/
2519 
2520 static ITypeLibImpl* TypeLibImpl_Constructor(void)
2521 {
2522     ITypeLibImpl* pTypeLibImpl;
2523 
2524     pTypeLibImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeLibImpl));
2525     if (!pTypeLibImpl) return NULL;
2526 
2527     pTypeLibImpl->lpVtbl = &tlbvt;
2528     pTypeLibImpl->lpVtblTypeComp = &tlbtcvt;
2529     pTypeLibImpl->ref = 1;
2530 
2531     list_init(&pTypeLibImpl->ref_list);
2532     pTypeLibImpl->dispatch_href = -1;
2533 
2534     return pTypeLibImpl;
2535 }
2536 
2537 /****************************************************************************
2538  *      ITypeLib2_Constructor_MSFT
2539  *
2540  * loading an MSFT typelib from an in-memory image
2541  */
2542 static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength)
2543 {
2544     TLBContext cx;
2545     long lPSegDir;
2546     MSFT_Header tlbHeader;
2547     MSFT_SegDir tlbSegDir;
2548     ITypeLibImpl * pTypeLibImpl;
2549 
2550     TRACE("%p, TLB length = %d\n", pLib, dwTLBLength);
2551 
2552     pTypeLibImpl = TypeLibImpl_Constructor();
2553     if (!pTypeLibImpl) return NULL;
2554 
2555     /* get pointer to beginning of typelib data */
2556     cx.pos = 0;
2557     cx.oStart=0;
2558     cx.mapping = pLib;
2559     cx.pLibInfo = pTypeLibImpl;
2560     cx.length = dwTLBLength;
2561 
2562     /* read header */
2563     MSFT_ReadLEDWords((void*)&tlbHeader, sizeof(tlbHeader), &cx, 0);
2564     TRACE_(typelib)("header:\n");
2565     TRACE_(typelib)("\tmagic1=0x%08x ,magic2=0x%08x\n",tlbHeader.magic1,tlbHeader.magic2 );
2566     if (tlbHeader.magic1 != MSFT_SIGNATURE) {
2567         FIXME("Header type magic 0x%08x not supported.\n",tlbHeader.magic1);
2568         return NULL;
2569     }
2570     TRACE_(typelib)("\tdispatchpos = 0x%x\n", tlbHeader.dispatchpos);
2571 
2572     /* there is a small amount of information here until the next important
2573      * part:
2574      * the segment directory . Try to calculate the amount of data */
2575     lPSegDir = sizeof(tlbHeader) + (tlbHeader.nrtypeinfos)*4 + ((tlbHeader.varflags & HELPDLLFLAG)? 4 :0);
2576 
2577     /* now read the segment directory */
2578     TRACE("read segment directory (at %ld)\n",lPSegDir);
2579     MSFT_ReadLEDWords(&tlbSegDir, sizeof(tlbSegDir), &cx, lPSegDir);
2580     cx.pTblDir = &tlbSegDir;
2581 
2582     /* just check two entries */
2583     if ( tlbSegDir.pTypeInfoTab.res0c != 0x0F || tlbSegDir.pImpInfo.res0c != 0x0F)
2584     {
2585         ERR("cannot find the table directory, ptr=0x%lx\n",lPSegDir);
2586         HeapFree(GetProcessHeap(),0,pTypeLibImpl);
2587         return NULL;
2588     }
2589 
2590     /* now fill our internal data */
2591     /* TLIBATTR fields */
2592     MSFT_ReadGuid(&pTypeLibImpl->LibAttr.guid, tlbHeader.posguid, &cx);
2593 
2594     /*    pTypeLibImpl->LibAttr.lcid = tlbHeader.lcid;*/
2595     /* Windows seems to have zero here, is this correct? */
2596     if(SUBLANGID(tlbHeader.lcid) == SUBLANG_NEUTRAL)
2597       pTypeLibImpl->LibAttr.lcid = MAKELCID(MAKELANGID(PRIMARYLANGID(tlbHeader.lcid),0),0);
2598     else
2599       pTypeLibImpl->LibAttr.lcid = 0;
2600 
2601     pTypeLibImpl->LibAttr.syskind = tlbHeader.varflags & 0x0f; /* check the mask */
2602     pTypeLibImpl->LibAttr.wMajorVerNum = LOWORD(tlbHeader.version);
2603     pTypeLibImpl->LibAttr.wMinorVerNum = HIWORD(tlbHeader.version);
2604     pTypeLibImpl->LibAttr.wLibFlags = (WORD) tlbHeader.flags & 0xffff;/* check mask */
2605 
2606     /* name, eventually add to a hash table */
2607     pTypeLibImpl->Name = MSFT_ReadName(&cx, tlbHeader.NameOffset);
2608 
2609     /* help info */
2610     pTypeLibImpl->DocString = MSFT_ReadString(&cx, tlbHeader.helpstring);
2611     pTypeLibImpl->HelpFile = MSFT_ReadString(&cx, tlbHeader.helpfile);
2612 
2613     if( tlbHeader.varflags & HELPDLLFLAG)
2614     {
2615             int offset;
2616             MSFT_ReadLEDWords(&offset, sizeof(offset), &cx, sizeof(tlbHeader));
2617             pTypeLibImpl->HelpStringDll = MSFT_ReadString(&cx, offset);
2618     }
2619 
2620     pTypeLibImpl->dwHelpContext = tlbHeader.helpstringcontext;
2621 
2622     /* custom data */
2623     if(tlbHeader.CustomDataOffset >= 0)
2624     {
2625         pTypeLibImpl->ctCustData = MSFT_CustData(&cx, tlbHeader.CustomDataOffset, &pTypeLibImpl->pCustData);
2626     }
2627 
2628     /* fill in type descriptions */
2629     if(tlbSegDir.pTypdescTab.length > 0)
2630     {
2631         int i, j, cTD = tlbSegDir.pTypdescTab.length / (2*sizeof(INT));
2632         INT16 td[4];
2633         pTypeLibImpl->ctTypeDesc = cTD;
2634         pTypeLibImpl->pTypeDesc = TLB_Alloc( cTD * sizeof(TYPEDESC));
2635         MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pTypdescTab.offset);
2636         for(i=0; i<cTD; )
2637         {
2638             /* FIXME: add several sanity checks here */
2639             pTypeLibImpl->pTypeDesc[i].vt = td[0] & VT_TYPEMASK;
2640             if(td[0] == VT_PTR || td[0] == VT_SAFEARRAY)
2641             {
2642                 /* FIXME: check safearray */
2643                 if(td[3] < 0)
2644                     pTypeLibImpl->pTypeDesc[i].u.lptdesc= & stndTypeDesc[td[2]];
2645                 else
2646                     pTypeLibImpl->pTypeDesc[i].u.lptdesc= & pTypeLibImpl->pTypeDesc[td[2]/8];
2647             }
2648             else if(td[0] == VT_CARRAY)
2649             {
2650                 /* array descr table here */
2651                 pTypeLibImpl->pTypeDesc[i].u.lpadesc = (void *)((int) td[2]);  /* temp store offset in*/
2652             }
2653             else if(td[0] == VT_USERDEFINED)
2654             {
2655                 pTypeLibImpl->pTypeDesc[i].u.hreftype = MAKELONG(td[2],td[3]);
2656             }
2657             if(++i<cTD) MSFT_ReadLEWords(td, sizeof(td), &cx, DO_NOT_SEEK);
2658         }
2659 
2660         /* second time around to fill the array subscript info */
2661         for(i=0;i<cTD;i++)
2662         {
2663             if(pTypeLibImpl->pTypeDesc[i].vt != VT_CARRAY) continue;
2664             if(tlbSegDir.pArrayDescriptions.offset>0)
2665             {
2666                 MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pArrayDescriptions.offset + (int) pTypeLibImpl->pTypeDesc[i].u.lpadesc);
2667                 pTypeLibImpl->pTypeDesc[i].u.lpadesc = TLB_Alloc(sizeof(ARRAYDESC)+sizeof(SAFEARRAYBOUND)*(td[3]-1));
2668 
2669                 if(td[1]<0)
2670                     pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem.vt = td[0] & VT_TYPEMASK;
2671                 else
2672                     pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem = stndTypeDesc[td[0]/8];
2673 
2674                 pTypeLibImpl->pTypeDesc[i].u.lpadesc->cDims = td[2];
2675 
2676                 for(j = 0; j<td[2]; j++)
2677                 {
2678                     MSFT_ReadLEDWords(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].cElements,
2679                                       sizeof(INT), &cx, DO_NOT_SEEK);
2680                     MSFT_ReadLEDWords(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].lLbound,
2681                                       sizeof(INT), &cx, DO_NOT_SEEK);
2682                 }
2683             }
2684             else
2685             {
2686                 pTypeLibImpl->pTypeDesc[i].u.lpadesc = NULL;
2687                 ERR("didn't find array description data\n");
2688             }
2689         }
2690     }
2691 
2692     /* imported type libs */
2693     if(tlbSegDir.pImpFiles.offset>0)
2694     {
2695         TLBImpLib **ppImpLib = &(pTypeLibImpl->pImpLibs);
2696         int oGuid, offset = tlbSegDir.pImpFiles.offset;
2697         UINT16 size;
2698 
2699         while(offset < tlbSegDir.pImpFiles.offset +tlbSegDir.pImpFiles.length)
2700         {
2701             char *name;
2702             DWORD len;
2703 
2704             *ppImpLib = TLB_Alloc(sizeof(TLBImpLib));
2705             (*ppImpLib)->offset = offset - tlbSegDir.pImpFiles.offset;
2706             MSFT_ReadLEDWords(&oGuid, sizeof(INT), &cx, offset);
2707 
2708             MSFT_ReadLEDWords(&(*ppImpLib)->lcid,         sizeof(LCID),   &cx, DO_NOT_SEEK);
2709             MSFT_ReadLEWords(&(*ppImpLib)->wVersionMajor, sizeof(WORD),   &cx, DO_NOT_SEEK);
2710             MSFT_ReadLEWords(&(*ppImpLib)->wVersionMinor, sizeof(WORD),   &cx, DO_NOT_SEEK);
2711             MSFT_ReadLEWords(& size,                      sizeof(UINT16), &cx, DO_NOT_SEEK);
2712 
2713             size >>= 2;
2714             name = TLB_Alloc(size+1);
2715             MSFT_Read(name, size, &cx, DO_NOT_SEEK);
2716             len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0 );
2717             (*ppImpLib)->name = TLB_Alloc(len * sizeof(WCHAR));
2718             MultiByteToWideChar(CP_ACP, 0, name, -1, (*ppImpLib)->name, len );
2719             TLB_Free(name);
2720 
2721             MSFT_ReadGuid(&(*ppImpLib)->guid, oGuid, &cx);
2722             offset = (offset + sizeof(INT) + sizeof(DWORD) + sizeof(LCID) + sizeof(UINT16) + size + 3) & ~3;
2723 
2724             ppImpLib = &(*ppImpLib)->next;
2725         }
2726     }
2727 
2728     pTypeLibImpl->dispatch_href = tlbHeader.dispatchpos;
2729     if(pTypeLibImpl->dispatch_href != -1)
2730         MSFT_DoRefType(&cx, pTypeLibImpl, pTypeLibImpl->dispatch_href);
2731 
2732     /* type info's */
2733     if(tlbHeader.nrtypeinfos >= 0 )
2734     {
2735         /*pTypeLibImpl->TypeInfoCount=tlbHeader.nrtypeinfos; */
2736         ITypeInfoImpl **ppTI = &(pTypeLibImpl->pTypeInfo);
2737         int i;
2738 
2739         for(i = 0; i < tlbHeader.nrtypeinfos; i++)
2740         {
2741             *ppTI = MSFT_DoTypeInfo(&cx, i, pTypeLibImpl);
2742 
2743             ppTI = &((*ppTI)->next);
2744             (pTypeLibImpl->TypeInfoCount)++;
2745         }
2746     }
2747 
2748     TRACE("(%p)\n", pTypeLibImpl);
2749     return (ITypeLib2*) pTypeLibImpl;
2750 }
2751 
2752 
2753 static BSTR TLB_MultiByteToBSTR(const char *ptr)
2754 {
2755     DWORD len;
2756     WCHAR *nameW;
2757     BSTR ret;
2758 
2759     len = MultiByteToWideChar(CP_ACP, 0, ptr, -1, NULL, 0);
2760     nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2761     MultiByteToWideChar(CP_ACP, 0, ptr, -1, nameW, len);
2762     ret = SysAllocString(nameW);
2763     HeapFree(GetProcessHeap(), 0, nameW);
2764     return ret;
2765 }
2766 
2767 static BOOL TLB_GUIDFromString(const char *str, GUID *guid)
2768 {
2769   char b[3];
2770   int i;
2771   short s;
2772 
2773   if(sscanf(str, "%x-%hx-%hx-%hx", &guid->Data1, &guid->Data2, &guid->Data3, &s) != 4) {
2774     FIXME("Can't parse guid %s\n", debugstr_guid(guid));
2775     return FALSE;
2776   }
2777 
2778   guid->Data4[0] = s >> 8;
2779   guid->Data4[1] = s & 0xff;
2780 
2781   b[2] = '\0';
2782   for(i = 0; i < 6; i++) {
2783     memcpy(b, str + 24 + 2 * i, 2);
2784     guid->Data4[i + 2] = strtol(b, NULL, 16);
2785   }
2786   return TRUE;
2787 }
2788 
2789 static WORD SLTG_ReadString(const char *ptr, BSTR *pBstr)
2790 {
2791     WORD bytelen;
2792     DWORD len;
2793     WCHAR *nameW;
2794 
2795     *pBstr = NULL;
2796     bytelen = *(const WORD*)ptr;
2797     if(bytelen == 0xffff) return 2;
2798     len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, NULL, 0);
2799     nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2800     len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, nameW, len);
2801     *pBstr = SysAllocStringLen(nameW, len);
2802     HeapFree(GetProcessHeap(), 0, nameW);
2803     return bytelen + 2;
2804 }
2805 
2806 static WORD SLTG_ReadStringA(const char *ptr, char **str)
2807 {
2808     WORD bytelen;
2809 
2810     *str = NULL;
2811     bytelen = *(const WORD*)ptr;
2812     if(bytelen == 0xffff) return 2;
2813     *str = HeapAlloc(GetProcessHeap(), 0, bytelen + 1);
2814     memcpy(*str, ptr + 2, bytelen);
2815     (*str)[bytelen] = '\0';
2816     return bytelen + 2;
2817 }
2818 
2819 static DWORD SLTG_ReadLibBlk(LPVOID pLibBlk, ITypeLibImpl *pTypeLibImpl)
2820 {
2821     char *ptr = pLibBlk;
2822     WORD w;
2823 
2824     if((w = *(WORD*)ptr) != SLTG_LIBBLK_MAGIC) {
2825         FIXME("libblk magic = %04x\n", w);
2826         return 0;
2827     }
2828 
2829     ptr += 6;
2830     if((w = *(WORD*)ptr) != 0xffff) {
2831         FIXME("LibBlk.res06 = %04x. Assumung string and skipping\n", w);
2832         ptr += w;
2833     }
2834     ptr += 2;
2835 
2836     ptr += SLTG_ReadString(ptr, &pTypeLibImpl->DocString);
2837 
2838     ptr += SLTG_ReadString(ptr, &pTypeLibImpl->HelpFile);
2839 
2840     pTypeLibImpl->dwHelpContext = *(DWORD*)ptr;
2841     ptr += 4;
2842 
2843     pTypeLibImpl->LibAttr.syskind = *(WORD*)ptr;
2844     ptr += 2;
2845 
2846     if(SUBLANGID(*(WORD*)ptr) == SUBLANG_NEUTRAL)
2847         pTypeLibImpl->LibAttr.lcid = MAKELCID(MAKELANGID(PRIMARYLANGID(*(WORD*)ptr),0),0);
2848     else
2849         pTypeLibImpl->LibAttr.lcid = 0;
2850     ptr += 2;
2851 
2852     ptr += 4; /* skip res12 */
2853 
2854     pTypeLibImpl->LibAttr.wLibFlags = *(WORD*)ptr;
2855     ptr += 2;
2856 
2857     pTypeLibImpl->LibAttr.wMajorVerNum = *(WORD*)ptr;
2858     ptr += 2;
2859 
2860     pTypeLibImpl->LibAttr.wMinorVerNum = *(WORD*)ptr;
2861     ptr += 2;
2862 
2863     memcpy(&pTypeLibImpl->LibAttr.guid, ptr, sizeof(GUID));
2864     ptr += sizeof(GUID);
2865 
2866     return ptr - (char*)pLibBlk;
2867 }
2868 
2869 /* stores a mapping between the sltg typeinfo's references and the typelib's HREFTYPEs */
2870 typedef struct
2871 {
2872     unsigned int num;
2873     HREFTYPE refs[1];
2874 } sltg_ref_lookup_t;
2875 
2876 static HRESULT sltg_get_typelib_ref(const sltg_ref_lookup_t *table, DWORD typeinfo_ref,
2877                                     HREFTYPE *typelib_ref)
2878 {
2879     if(typeinfo_ref < table->num)
2880     {
2881         *typelib_ref = table->refs[typeinfo_ref];
2882         return S_OK;
2883     }
2884 
2885     ERR("Unable to find reference\n");
2886     *typelib_ref = -1;
2887     return E_FAIL;
2888 }
2889 
2890 static WORD *SLTG_DoType(WORD *pType, char *pBlk, TYPEDESC *pTD, const sltg_ref_lookup_t *ref_lookup)
2891 {
2892     BOOL done = FALSE;
2893 
2894     while(!done) {
2895         if((*pType & 0xe00) == 0xe00) {
2896             pTD->vt = VT_PTR;
2897             pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2898                                        sizeof(TYPEDESC));
2899             pTD = pTD->u.lptdesc;
2900         }
2901         switch(*pType & 0x3f) {
2902         case VT_PTR:
2903             pTD->vt = VT_PTR;
2904             pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2905                                        sizeof(TYPEDESC));
2906             pTD = pTD->u.lptdesc;
2907             break;
2908 
2909         case VT_USERDEFINED:
2910             pTD->vt = VT_USERDEFINED;
2911             sltg_get_typelib_ref(ref_lookup, *(++pType) / 4, &pTD->u.hreftype);
2912             done = TRUE;
2913             break;
2914 
2915         case VT_CARRAY:
2916           {
2917             /* *(pType+1) is offset to a SAFEARRAY, *(pType+2) is type of
2918                array */
2919 
2920             SAFEARRAY *pSA = (SAFEARRAY *)(pBlk + *(++pType));
2921 
2922             pTD->vt = VT_CARRAY;
2923             pTD->u.lpadesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2924                                 sizeof(ARRAYDESC) +
2925                                 (pSA->cDims - 1) * sizeof(SAFEARRAYBOUND));
2926             pTD->u.lpadesc->cDims = pSA->cDims;
2927             memcpy(pTD->u.lpadesc->rgbounds, pSA->rgsabound,
2928                    pSA->cDims * sizeof(SAFEARRAYBOUND));
2929 
2930             pTD = &pTD->u.lpadesc->tdescElem;
2931             break;
2932           }
2933 
2934         case VT_SAFEARRAY:
2935           {
2936             /* FIXME: *(pType+1) gives an offset to SAFEARRAY, is this
2937                useful? */
2938 
2939             pType++;
2940             pTD->vt = VT_SAFEARRAY;
2941             pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2942                                        sizeof(TYPEDESC));
2943             pTD = pTD->u.lptdesc;
2944             break;
2945           }
2946         default:
2947             pTD->vt = *pType & 0x3f;
2948             done = TRUE;
2949             break;
2950         }
2951         pType++;
2952     }
2953     return pType;
2954 }
2955 
2956 static WORD *SLTG_DoElem(WORD *pType, char *pBlk,
2957                          ELEMDESC *pElem, const sltg_ref_lookup_t *ref_lookup)
2958 {
2959     /* Handle [in/out] first */
2960     if((*pType & 0xc000) == 0xc000)
2961         pElem->u.paramdesc.wParamFlags = PARAMFLAG_NONE;
2962     else if(*pType & 0x8000)
2963         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN | PARAMFLAG_FOUT;
2964     else if(*pType & 0x4000)
2965         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FOUT;
2966     else
2967         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN;
2968 
2969     if(*pType & 0x2000)
2970         pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FLCID;
2971 
2972     if(*pType & 0x80)
2973         pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FRETVAL;
2974 
2975     return SLTG_DoType(pType, pBlk, &pElem->tdesc, ref_lookup);
2976 }
2977 
2978 
2979 static sltg_ref_lookup_t *SLTG_DoRefs(SLTG_RefInfo *pRef, ITypeLibImpl *pTL,
2980                         char *pNameTable)
2981 {
2982     int ref;
2983     char *name;
2984     TLBRefType *ref_type;
2985     sltg_ref_lookup_t *table;
2986     HREFTYPE typelib_ref;
2987 
2988     if(pRef->magic != SLTG_REF_MAGIC) {
2989         FIXME("Ref magic = %x\n", pRef->magic);
2990         return NULL;
2991     }
2992     name = ( (char*)pRef->names + pRef->number);
2993 
2994     table = HeapAlloc(GetProcessHeap(), 0, sizeof(*table) + ((pRef->number >> 3) - 1) * sizeof(table->refs[0]));
2995     table->num = pRef->number >> 3;
2996 
2997     /* FIXME should scan the existing list and reuse matching refs added by previous typeinfos */
2998 
2999     /* We don't want the first href to be 0 */
3000     typelib_ref = (list_count(&pTL->ref_list) + 1) << 2;
3001 
3002     for(ref = 0; ref < pRef->number >> 3; ref++) {
3003         char *refname;
3004         unsigned int lib_offs, type_num;
3005 
3006         ref_type = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ref_type));
3007 
3008         name += SLTG_ReadStringA(name, &refname);
3009         if(sscanf(refname, "*\\R%x*#%x", &lib_offs, &type_num) != 2)
3010             FIXME("Can't sscanf ref\n");
3011         if(lib_offs != 0xffff) {
3012             TLBImpLib **import = &pTL->pImpLibs;
3013 
3014             while(*import) {
3015                 if((*import)->offset == lib_offs)
3016                     break;
3017                 import = &(*import)->next;
3018             }
3019             if(!*import) {
3020                 char fname[MAX_PATH+1];
3021                 int len;
3022 
3023                 *import = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3024                                     sizeof(**import));
3025                 (*import)->offset = lib_offs;
3026                 TLB_GUIDFromString( pNameTable + lib_offs + 4,
3027                                     &(*import)->guid);
3028                 if(sscanf(pNameTable + lib_offs + 40, "}#%hd.%hd#%x#%s",
3029                           &(*import)->wVersionMajor,
3030                           &(*import)->wVersionMinor,
3031                           &(*import)->lcid, fname) != 4) {
3032                   FIXME("can't sscanf ref %s\n",
3033                         pNameTable + lib_offs + 40);
3034                 }
3035                 len = strlen(fname);
3036                 if(fname[len-1] != '#')
3037                     FIXME("fname = %s\n", fname);
3038                 fname[len-1] = '\0';
3039                 (*import)->name = TLB_MultiByteToBSTR(fname);
3040             }
3041             ref_type->pImpTLInfo = *import;
3042 
3043             /* Store a reference to IDispatch */
3044             if(pTL->dispatch_href == -1 && IsEqualGUID(&(*import)->guid, &IID_StdOle) && type_num == 4)
3045                 pTL->dispatch_href = typelib_ref;
3046 
3047         } else { /* internal ref */
3048           ref_type->pImpTLInfo = TLB_REF_INTERNAL;
3049         }
3050         ref_type->reference = typelib_ref;
3051         ref_type->index = type_num;
3052 
3053         HeapFree(GetProcessHeap(), 0, refname);
3054         list_add_tail(&pTL->ref_list, &ref_type->entry);
3055 
3056         table->refs[ref] = typelib_ref;
3057         typelib_ref += 4;
3058     }
3059     if((BYTE)*name != SLTG_REF_MAGIC)
3060       FIXME("End of ref block magic = %x\n", *name);
3061     dump_TLBRefType(pTL);
3062     return table;
3063 }
3064 
3065 static char *SLTG_DoImpls(char *pBlk, ITypeInfoImpl *pTI,
3066                           BOOL OneOnly, const sltg_ref_lookup_t *ref_lookup)
3067 {
3068     SLTG_ImplInfo *info;
3069     TLBImplType **ppImplType = &pTI->impltypelist;
3070     /* I don't really get this structure, usually it's 0x16 bytes
3071        long, but iuser.tlb contains some that are 0x18 bytes long.
3072        That's ok because we can use the next ptr to jump to the next
3073        one. But how do we know the length of the last one?  The WORD
3074        at offs 0x8 might be the clue.  For now I'm just assuming that
3075        the last one is the regular 0x16 bytes. */
3076 
3077     info = (SLTG_ImplInfo*)pBlk;
3078     while(1) {
3079         *ppImplType = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3080                                 sizeof(**ppImplType));
3081         sltg_get_typelib_ref(ref_lookup, info->ref, &(*ppImplType)->hRef);
3082         (*ppImplType)->implflags = info->impltypeflags;
3083         pTI->TypeAttr.cImplTypes++;
3084         ppImplType = &(*ppImplType)->next;
3085 
3086         if(info->next == 0xffff)
3087             break;
3088         if(OneOnly)
3089             FIXME("Interface inheriting more than one interface\n");
3090         info = (SLTG_ImplInfo*)(pBlk + info->next);
3091     }
3092     info++; /* see comment at top of function */
3093     return (char*)info;
3094 }
3095 
3096 static void SLTG_DoVars(char *pBlk, char *pFirstItem, ITypeInfoImpl *pTI, unsigned short cVars,
3097                         const char *pNameTable, const sltg_ref_lookup_t *ref_lookup)
3098 {
3099   TLBVarDesc **ppVarDesc = &pTI->varlist;
3100   BSTR bstrPrevName = NULL;
3101   SLTG_Variable *pItem;
3102   unsigned short i;
3103   WORD *pType;
3104 
3105   for(pItem = (SLTG_Variable *)pFirstItem, i = 0; i < cVars;
3106       pItem = (SLTG_Variable *)(pBlk + pItem->next), i++) {
3107 
3108       *ppVarDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3109                              sizeof(**ppVarDesc));
3110       (*ppVarDesc)->vardesc.memid = pItem->memid;
3111 
3112       if (pItem->magic != SLTG_VAR_MAGIC &&
3113           pItem->magic != SLTG_VAR_WITH_FLAGS_MAGIC) {
3114           FIXME_(typelib)("var magic = %02x\n", pItem->magic);
3115           return;
3116       }
3117 
3118       if (pItem->name == 0xfffe)
3119         (*ppVarDesc)->Name = SysAllocString(bstrPrevName);
3120       else
3121         (*ppVarDesc)->Name = TLB_MultiByteToBSTR(pItem->name + pNameTable);
3122 
3123       TRACE_(typelib)("name: %s\n", debugstr_w((*ppVarDesc)->Name));
3124       TRACE_(typelib)("byte_offs = 0x%x\n", pItem->byte_offs);
3125       TRACE_(typelib)("memid = 0x%x\n", pItem->memid);
3126 
3127       if(pItem->flags & 0x02)
3128           pType = &pItem->type;
3129       else
3130           pType = (WORD*)(pBlk + pItem->type);
3131 
3132       if (pItem->flags & ~0xda)
3133         FIXME_(typelib)("unhandled flags = %02x\n", pItem->flags & ~0xda);
3134 
3135       SLTG_DoElem(pType, pBlk,
3136                   &(*ppVarDesc)->vardesc.elemdescVar, ref_lookup);
3137 
3138       if (pItem->flags & 0x40) {
3139         TRACE_(typelib)("VAR_DISPATCH\n");
3140         (*ppVarDesc)->vardesc.varkind = VAR_DISPATCH;
3141       }
3142       else if (pItem->flags & 0x10) {
3143         TRACE_(typelib)("VAR_CONST\n");
3144         (*ppVarDesc)->vardesc.varkind = VAR_CONST;
3145         (*ppVarDesc)->vardesc.u.lpvarValue = HeapAlloc(GetProcessHeap(), 0,
3146                                                        sizeof(VARIANT));
3147         V_VT((*ppVarDesc)->vardesc.u.lpvarValue) = VT_INT;
3148         if (pItem->flags & 0x08)
3149           V_UNION((*ppVarDesc)->vardesc.u.lpvarValue, intVal) = pItem->byte_offs;
3150         else {
3151           switch ((*ppVarDesc)->vardesc.elemdescVar.tdesc.vt)
3152           {
3153             case VT_LPSTR:
3154             case VT_LPWSTR:
3155             case VT_BSTR:
3156             {
3157               WORD len = *(WORD *)(pBlk + pItem->byte_offs);
3158               INT alloc_len = MultiByteToWideChar(CP_ACP, 0, pBlk + pItem->byte_offs + 2, len, NULL, 0);
3159               BSTR str = SysAllocStringLen(NULL, alloc_len);
3160               MultiByteToWideChar(CP_ACP, 0, pBlk + pItem->byte_offs + 2, len, str, alloc_len);
3161               V_VT((*ppVarDesc)->vardesc.u.lpvarValue) = VT_BSTR;
3162               V_BSTR((*ppVarDesc)->vardesc.u.lpvarValue) = str;
3163               break;
3164             }
3165             case VT_I2:
3166             case VT_UI2:
3167             case VT_I4:
3168             case VT_UI4:
3169               V_UNION((*ppVarDesc)->vardesc.u.lpvarValue, intVal) =
3170                 *(INT*)(pBlk + pItem->byte_offs);
3171               break;
3172             default:
3173               FIXME("VAR_CONST unimplemented for type %d\n", (*ppVarDesc)->vardesc.elemdescVar.tdesc.vt);
3174           }
3175         }
3176       }
3177       else {
3178         TRACE_(typelib)("VAR_PERINSTANCE\n");
3179         (*ppVarDesc)->vardesc.u.oInst = pItem->byte_offs;
3180         (*ppVarDesc)->vardesc.varkind = VAR_PERINSTANCE;
3181       }
3182 
3183       if (pItem->magic == SLTG_VAR_WITH_FLAGS_MAGIC)
3184         (*ppVarDesc)->vardesc.wVarFlags = pItem->varflags;
3185 
3186       if (pItem->flags & 0x80)
3187         (*ppVarDesc)->vardesc.wVarFlags |= VARFLAG_FREADONLY;
3188 
3189       if (TRACE_ON(typelib)) {
3190           char buf[300];
3191           dump_TypeDesc(&(*ppVarDesc)->vardesc.elemdescVar.tdesc, buf);
3192           TRACE_(typelib)("elemdescVar: %s\n", buf);
3193       }
3194 
3195       bstrPrevName = (*ppVarDesc)->Name;
3196       ppVarDesc = &((*ppVarDesc)->next);
3197   }
3198   pTI->TypeAttr.cVars = cVars;
3199 }
3200 
3201 static void SLTG_DoFuncs(char *pBlk, char *pFirstItem, ITypeInfoImpl *pTI,
3202                          unsigned short cFuncs, char *pNameTable, const sltg_ref_lookup_t *ref_lookup)
3203 {
3204     SLTG_Function *pFunc;
3205     unsigned short i;
3206     TLBFuncDesc **ppFuncDesc = &pTI->funclist;
3207 
3208     for(pFunc = (SLTG_Function*)pFirstItem, i = 0; i < cFuncs;
3209         pFunc = (SLTG_Function*)(pBlk + pFunc->next), i++) {
3210 
3211         int param;
3212         WORD *pType, *pArg;
3213 
3214         *ppFuncDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3215                                 sizeof(**ppFuncDesc));
3216 
3217         switch (pFunc->magic & ~SLTG_FUNCTION_FLAGS_PRESENT) {
3218         case SLTG_FUNCTION_MAGIC:
3219             (*ppFuncDesc)->funcdesc.funckind = FUNC_PUREVIRTUAL;
3220             break;
3221         case SLTG_DISPATCH_FUNCTION_MAGIC:
3222             (*ppFuncDesc)->funcdesc.funckind = FUNC_DISPATCH;
3223             break;
3224         case SLTG_STATIC_FUNCTION_MAGIC:
3225             (*ppFuncDesc)->funcdesc.funckind = FUNC_STATIC;
3226             break;
3227         default:
3228             FIXME("unimplemented func magic = %02x\n", pFunc->magic & ~SLTG_FUNCTION_FLAGS_PRESENT);
3229             HeapFree(GetProcessHeap(), 0, *ppFuncDesc);
3230             *ppFuncDesc = NULL;
3231             return;
3232         }
3233         (*ppFuncDesc)->Name = TLB_MultiByteToBSTR(pFunc->name + pNameTable);
3234 
3235         (*ppFuncDesc)->funcdesc.memid = pFunc->dispid;
3236         (*ppFuncDesc)->funcdesc.invkind = pFunc->inv >> 4;
3237         (*ppFuncDesc)->funcdesc.callconv = pFunc->nacc & 0x7;
3238         (*ppFuncDesc)->funcdesc.cParams = pFunc->nacc >> 3;
3239         (*ppFuncDesc)->funcdesc.cParamsOpt = (pFunc->retnextopt & 0x7e) >> 1;
3240         (*ppFuncDesc)->funcdesc.oVft = pFunc->vtblpos;
3241 
3242         if(pFunc->magic & SLTG_FUNCTION_FLAGS_PRESENT)
3243             (*ppFuncDesc)->funcdesc.wFuncFlags = pFunc->funcflags;
3244 
3245         if(pFunc->retnextopt & 0x80)
3246             pType = &pFunc->rettype;
3247         else
3248             pType = (WORD*)(pBlk + pFunc->rettype);
3249 
3250         SLTG_DoElem(pType, pBlk, &(*ppFuncDesc)->funcdesc.elemdescFunc, ref_lookup);
3251 
3252         (*ppFuncDesc)->funcdesc.lprgelemdescParam =
3253           HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3254                     (*ppFuncDesc)->funcdesc.cParams * sizeof(ELEMDESC));
3255         (*ppFuncDesc)->pParamDesc =
3256           HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3257                     (*ppFuncDesc)->funcdesc.cParams * sizeof(TLBParDesc));
3258 
3259         pArg = (WORD*)(pBlk + pFunc->arg_off);
3260 
3261         for(param = 0; param < (*ppFuncDesc)->funcdesc.cParams; param++) {
3262             char *paramName = pNameTable + *pArg;
3263             BOOL HaveOffs;
3264             /* If arg type follows then paramName points to the 2nd
3265                letter of the name, else the next WORD is an offset to
3266                the arg type and paramName points to the first letter.
3267                So let's take one char off paramName and see if we're
3268                pointing at an alpha-numeric char.  However if *pArg is
3269                0xffff or 0xfffe then the param has no name, the former
3270                meaning that the next WORD is the type, the latter
3271                meaning that the next WORD is an offset to the type. */
3272 
3273             HaveOffs = FALSE;
3274             if(*pArg == 0xffff)
3275                 paramName = NULL;
3276             else if(*pArg == 0xfffe) {
3277                 paramName = NULL;
3278                 HaveOffs = TRUE;
3279             }
3280             else if(paramName[-1] && !isalnum(paramName[-1]))
3281                 HaveOffs = TRUE;
3282 
3283             pArg++;
3284 
3285             if(HaveOffs) { /* the next word is an offset to type */
3286                 pType = (WORD*)(pBlk + *pArg);
3287                 SLTG_DoElem(pType, pBlk,
3288                             &(*ppFuncDesc)->funcdesc.lprgelemdescParam[param], ref_lookup);
3289                 pArg++;
3290             } else {
3291                 if(paramName)
3292                   paramName--;
3293                 pArg = SLTG_DoElem(pArg, pBlk,
3294                                    &(*ppFuncDesc)->funcdesc.lprgelemdescParam[param], ref_lookup);
3295             }
3296 
3297             /* Are we an optional param ? */
3298             if((*ppFuncDesc)->funcdesc.cParams - param <=
3299                (*ppFuncDesc)->funcdesc.cParamsOpt)
3300               (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].u.paramdesc.wParamFlags |= PARAMFLAG_FOPT;
3301 
3302             if(paramName) {
3303                 (*ppFuncDesc)->pParamDesc[param].Name =
3304                   TLB_MultiByteToBSTR(paramName);
3305             }
3306         }
3307 
3308         ppFuncDesc = &((*ppFuncDesc)->next);
3309         if(pFunc->next == 0xffff) break;
3310     }
3311     pTI->TypeAttr.cFuncs = cFuncs;
3312 }
3313 
3314 static void SLTG_ProcessCoClass(char *pBlk, ITypeInfoImpl *pTI,
3315                                 char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3316                                 SLTG_TypeInfoTail *pTITail)
3317 {
3318     char *pFirstItem;
3319     sltg_ref_lookup_t *ref_lookup = NULL;
3320 
3321     if(pTIHeader->href_table != 0xffffffff) {
3322         ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3323                     pNameTable);
3324     }
3325 
3326     pFirstItem = pBlk;
3327 
3328     if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
3329         SLTG_DoImpls(pFirstItem, pTI, FALSE, ref_lookup);
3330     }
3331     HeapFree(GetProcessHeap(), 0, ref_lookup);
3332 }
3333 
3334 
3335 static void SLTG_ProcessInterface(char *pBlk, ITypeInfoImpl *pTI,
3336                                   char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3337                                   const SLTG_TypeInfoTail *pTITail)
3338 {
3339     char *pFirstItem;
3340     sltg_ref_lookup_t *ref_lookup = NULL;
3341 
3342     if(pTIHeader->href_table != 0xffffffff) {
3343         ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3344                     pNameTable);
3345     }
3346 
3347     pFirstItem = pBlk;
3348 
3349     if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
3350         SLTG_DoImpls(pFirstItem, pTI, TRUE, ref_lookup);
3351     }
3352 
3353     if (pTITail->funcs_off != 0xffff)
3354         SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup);
3355 
3356     HeapFree(GetProcessHeap(), 0, ref_lookup);
3357 
3358     if (TRACE_ON(typelib))
3359         dump_TLBFuncDesc(pTI->funclist);
3360 }
3361 
3362 static void SLTG_ProcessRecord(char *pBlk, ITypeInfoImpl *pTI,
3363                                const char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3364                                const SLTG_TypeInfoTail *pTITail)
3365 {
3366   SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, NULL);
3367 }
3368 
3369 static void SLTG_ProcessAlias(char *pBlk, ITypeInfoImpl *pTI,
3370                               char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3371                               const SLTG_TypeInfoTail *pTITail)
3372 {
3373   WORD *pType;
3374   sltg_ref_lookup_t *ref_lookup = NULL;
3375 
3376   if (pTITail->simple_alias) {
3377     /* if simple alias, no more processing required */
3378     pTI->TypeAttr.tdescAlias.vt = pTITail->tdescalias_vt;
3379     return;
3380   }
3381 
3382   if(pTIHeader->href_table != 0xffffffff) {
3383       ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3384                   pNameTable);
3385   }
3386 
3387   /* otherwise it is an offset to a type */
3388   pType = (WORD *)(pBlk + pTITail->tdescalias_vt);
3389 
3390   SLTG_DoType(pType, pBlk, &pTI->TypeAttr.tdescAlias, ref_lookup);
3391 
3392   HeapFree(GetProcessHeap(), 0, ref_lookup);
3393 }
3394 
3395 static void SLTG_ProcessDispatch(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 
3410   /* this is necessary to cope with MSFT typelibs that set cFuncs to the number
3411    * of dispinterface functions including the IDispatch ones, so
3412    * ITypeInfo::GetFuncDesc takes the real value for cFuncs from cbSizeVft */
3413   pTI->TypeAttr.cbSizeVft = pTI->TypeAttr.cFuncs * sizeof(void *);
3414 
3415   HeapFree(GetProcessHeap(), 0, ref_lookup);
3416   if (TRACE_ON(typelib))
3417       dump_TLBFuncDesc(pTI->funclist);
3418 }
3419 
3420 static void SLTG_ProcessEnum(char *pBlk, ITypeInfoImpl *pTI,
3421                              const char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3422                              const SLTG_TypeInfoTail *pTITail)