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