~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/oleaut32/typelib.c

Version: ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

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