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

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

Version: ~ [ wine-1.5.31 ] ~ [ wine-1.5.30 ] ~ [ wine-1.5.29 ] ~ [ wine-1.5.28 ] ~ [ wine-1.5.27 ] ~ [ wine-1.5.26 ] ~ [ wine-1.5.25 ] ~ [ wine-1.5.24 ] ~ [ wine-1.5.23 ] ~ [ wine-1.5.22 ] ~ [ wine-1.5.21 ] ~ [ wine-1.5.20 ] ~ [ wine-1.5.19 ] ~ [ wine-1.5.18 ] ~ [ wine-1.5.17 ] ~ [ wine-1.5.16 ] ~ [ wine-1.5.15 ] ~ [ wine-1.5.14 ] ~ [ wine-1.5.13 ] ~ [ wine-1.5.12 ] ~ [ wine-1.5.11 ] ~ [ wine-1.5.10 ] ~ [ wine-1.5.9 ] ~ [ wine-1.5.8 ] ~ [ wine-1.5.7 ] ~ [ wine-1.4.1 ] ~ [ wine-1.5.6 ] ~ [ wine-1.5.5 ] ~ [ wine-1.5.4 ] ~ [ wine-1.5.3 ] ~ [ wine-1.5.2 ] ~ [ wine-1.5.1 ] ~ [ wine-1.5.0 ] ~ [ wine-1.4 ] ~ [ wine-1.4-rc6 ] ~ [ wine-1.4-rc5 ] ~ [ wine-1.4-rc4 ] ~ [ wine-1.4-rc3 ] ~ [ wine-1.4-rc2 ] ~ [ wine-1.4-rc1 ] ~ [ wine-1.3.37 ] ~ [ wine-1.3.36 ] ~ [ wine-1.3.35 ] ~ [ wine-1.3.34 ] ~ [ wine-1.3.33 ] ~ [ wine-1.3.32 ] ~ [ wine-1.3.31 ] ~ [ wine-1.3.30 ] ~ [ wine-1.3.29 ] ~ [ wine-1.3.28 ] ~ [ wine-1.3.27 ] ~ [ wine-1.3.26 ] ~ [ wine-1.3.25 ] ~ [ wine-1.3.24 ] ~ [ wine-1.3.23 ] ~ [ wine-1.3.22 ] ~ [ wine-1.3.21 ] ~ [ wine-1.3.20 ] ~ [ wine-1.3.19 ] ~ [ wine-1.3.18 ] ~ [ wine-1.2.3 ] ~ [ wine-1.3.17 ] ~ [ wine-1.3.16 ] ~ [ wine-1.3.15 ] ~ [ wine-1.3.14 ] ~ [ wine-1.3.13 ] ~ [ wine-1.3.12 ] ~ [ wine-1.3.11 ] ~ [ wine-1.3.10 ] ~ [ wine-1.3.9 ] ~ [ wine-1.2.2 ] ~ [ wine-1.3.8 ] ~ [ wine-1.3.7 ] ~ [ wine-1.3.6 ] ~ [ wine-1.3.5 ] ~ [ wine-1.2.1 ] ~ [ wine-1.3.4 ] ~ [ wine-1.3.3 ] ~ [ wine-1.3.2 ] ~ [ wine-1.3.1 ] ~ [ wine-1.3.0 ] ~ [ wine-1.2 ] ~ [ wine-1.2-rc7 ] ~ [ wine-1.2-rc6 ] ~ [ wine-1.2-rc5 ] ~ [ wine-1.2-rc4 ] ~ [ wine-1.2-rc3 ] ~ [ wine-1.2-rc2 ] ~ [ wine-1.2-rc1 ] ~ [ wine-1.1.44 ] ~ [ wine-1.1.43 ] ~ [ wine-1.1.42 ] ~ [ wine-1.1.41 ] ~ [ wine-1.1.40 ] ~ [ wine-1.1.39 ] ~ [ wine-1.1.38 ] ~ [ wine-1.1.37 ] ~ [ wine-1.1.36 ] ~ [ wine-1.1.35 ] ~ [ wine-1.1.34 ] ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

  1 /*
  2  *      TYPELIB
  3  *
  4  *      Copyright 1997  Marcus Meissner
  5  *                    1999  Rein Klazes
  6  *                    2000  Francois Jacques
  7  *                    2001  Huw D M Davies for CodeWeavers
  8  *                    2005  Robert Shearman, for CodeWeavers
  9  *
 10  * This library is free software; you can redistribute it and/or
 11  * modify it under the terms of the GNU Lesser General Public
 12  * License as published by the Free Software Foundation; either
 13  * version 2.1 of the License, or (at your option) any later version.
 14  *
 15  * This library is distributed in the hope that it will be useful,
 16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 18  * Lesser General Public License for more details.
 19  *
 20  * You should have received a copy of the GNU Lesser General Public
 21  * License along with this library; if not, write to the Free Software
 22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 23  *
 24  * --------------------------------------------------------------------------------------
 25  * Known problems (2000, Francois Jacques)
 26  *
 27  * - Tested using OLEVIEW (Platform SDK tool) only.
 28  *
 29  * - dual interface dispinterfaces. vtable-interface ITypeInfo instances are
 30  *   creating by doing a straight copy of the dispinterface instance and just changing
 31  *   its typekind. Pointed structures aren't copied - only the address of the pointers.
 32  *
 33  * - locale stuff is partially implemented but hasn't been tested.
 34  *
 35  * - typelib file is still read in its entirety, but it is released now.
 36  *
 37  * --------------------------------------------------------------------------------------
 38  *  Known problems left from previous implementation (1999, Rein Klazes) :
 39  *
 40  * -. Data structures are straightforward, but slow for look-ups.
 41  * -. (related) nothing is hashed
 42  * -. Most error return values are just guessed not checked with windows
 43  *      behaviour.
 44  * -. lousy fatal error handling
 45  *
 46  */
 47 
 48 #include "config.h"
 49 #include "wine/port.h"
 50 
 51 #include <stdlib.h>
 52 #include <string.h>
 53 #include <stdarg.h>
 54 #include <stdio.h>
 55 #include <ctype.h>
 56 
 57 #define COBJMACROS
 58 #define NONAMELESSUNION
 59 #define NONAMELESSSTRUCT
 60 
 61 #include "winerror.h"
 62 #include "windef.h"
 63 #include "winbase.h"
 64 #include "winnls.h"
 65 #include "winreg.h"
 66 #include "winuser.h"
 67 #include "lzexpand.h"
 68 
 69 #include "wine/unicode.h"
 70 #include "objbase.h"
 71 #include "typelib.h"
 72 #include "wine/debug.h"
 73 #include "variant.h"
 74 #include "wine/list.h"
 75 
 76 WINE_DEFAULT_DEBUG_CHANNEL(ole);
 77 WINE_DECLARE_DEBUG_CHANNEL(typelib);
 78 
 79 typedef struct
 80 {
 81     WORD     offset;
 82     WORD     length;
 83     WORD     flags;
 84     WORD     id;
 85     WORD     handle;
 86     WORD     usage;
 87 } NE_NAMEINFO;
 88 
 89 typedef struct
 90 {
 91     WORD        type_id;   /* Type identifier */
 92     WORD        count;     /* Number of resources of this type */
 93     DWORD       resloader; /* SetResourceHandler() */
 94     /*
 95      * Name info array.
 96      */
 97 } NE_TYPEINFO;
 98 
 99 static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt);
100 static HRESULT TLB_AllocAndInitVarDesc(const VARDESC *src, VARDESC **dest_ptr);
101 
102 /****************************************************************************
103  *              FromLExxx
104  *
105  * Takes p_iVal (which is in little endian) and returns it
106  *   in the host machine's byte order.
107  */
108 #ifdef WORDS_BIGENDIAN
109 static WORD FromLEWord(WORD p_iVal)
110 {
111   return (((p_iVal & 0x00FF) << 8) |
112           ((p_iVal & 0xFF00) >> 8));
113 }
114 
115 
116 static DWORD FromLEDWord(DWORD p_iVal)
117 {
118   return (((p_iVal & 0x000000FF) << 24) |
119           ((p_iVal & 0x0000FF00) <<  8) |
120           ((p_iVal & 0x00FF0000) >>  8) |
121           ((p_iVal & 0xFF000000) >> 24));
122 }
123 #else
124 #define FromLEWord(X)  (X)
125 #define FromLEDWord(X) (X)
126 #endif
127 
128 #define DISPATCH_HREF_OFFSET 0x01000000
129 #define DISPATCH_HREF_MASK   0xff000000
130 
131 /****************************************************************************
132  *              FromLExxx
133  *
134  * Fix byte order in any structure if necessary
135  */
136 #ifdef WORDS_BIGENDIAN
137 static void FromLEWords(void *p_Val, int p_iSize)
138 {
139   WORD *Val = p_Val;
140 
141   p_iSize /= sizeof(WORD);
142 
143   while (p_iSize) {
144     *Val = FromLEWord(*Val);
145     Val++;
146     p_iSize--;
147   }
148 }
149 
150 
151 static void FromLEDWords(void *p_Val, int p_iSize)
152 {
153   DWORD *Val = p_Val;
154 
155   p_iSize /= sizeof(DWORD);
156 
157   while (p_iSize) {
158     *Val = FromLEDWord(*Val);
159     Val++;
160     p_iSize--;
161   }
162 }
163 #else
164 #define FromLEWords(X,Y) /*nothing*/
165 #define FromLEDWords(X,Y) /*nothing*/
166 #endif
167 
168 /*
169  * Find a typelib key which matches a requested maj.min version.
170  */
171 static BOOL find_typelib_key( REFGUID guid, WORD *wMaj, WORD *wMin )
172 {
173     static const WCHAR typelibW[] = {'T','y','p','e','l','i','b','\\',0};
174     WCHAR buffer[60];
175     char key_name[16];
176     DWORD len, i;
177     INT best_maj = -1, best_min = -1;
178     HKEY hkey;
179 
180     memcpy( buffer, typelibW, sizeof(typelibW) );
181     StringFromGUID2( guid, buffer + strlenW(buffer), 40 );
182 
183     if (RegOpenKeyExW( HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hkey ) != ERROR_SUCCESS)
184         return FALSE;
185 
186     len = sizeof(key_name);
187     i = 0;
188     while (RegEnumKeyExA(hkey, i++, key_name, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
189     {
190         INT v_maj, v_min;
191 
192         if (sscanf(key_name, "%x.%x", &v_maj, &v_min) == 2)
193         {
194             TRACE("found %s: %x.%x\n", debugstr_w(buffer), v_maj, v_min);
195 
196             if (*wMaj == 0xffff && *wMin == 0xffff)
197             {
198                 if (v_maj > best_maj) best_maj = v_maj;
199                 if (v_min > best_min) best_min = v_min;
200             }
201             else if (*wMaj == v_maj)
202             {
203                 best_maj = v_maj;
204 
205                 if (*wMin == v_min)
206                 {
207                     best_min = v_min;
208                     break; /* exact match */
209                 }
210                 if (*wMin != 0xffff && v_min > best_min) best_min = v_min;
211             }
212         }
213         len = sizeof(key_name);
214     }
215     RegCloseKey( hkey );
216 
217     TRACE("found best_maj %d, best_min %d\n", best_maj, best_min);
218 
219     if (*wMaj == 0xffff && *wMin == 0xffff)
220     {
221         if (best_maj >= 0 && best_min >= 0)
222         {
223             *wMaj = best_maj;
224             *wMin = best_min;
225             return TRUE;
226         }
227     }
228 
229     if (*wMaj == best_maj && best_min >= 0)
230     {
231         *wMin = best_min;
232         return TRUE;
233     }
234     return FALSE;
235 }
236 
237 /* get the path of a typelib key, in the form "Typelib\\<guid>\\<maj>.<min>" */
238 /* buffer must be at least 60 characters long */
239 static WCHAR *get_typelib_key( REFGUID guid, WORD wMaj, WORD wMin, WCHAR *buffer )
240 {
241     static const WCHAR TypelibW[] = {'T','y','p','e','l','i','b','\\',0};
242     static const WCHAR VersionFormatW[] = {'\\','%','x','.','%','x',0};
243 
244     memcpy( buffer, TypelibW, sizeof(TypelibW) );
245     StringFromGUID2( guid, buffer + strlenW(buffer), 40 );
246     sprintfW( buffer + strlenW(buffer), VersionFormatW, wMaj, wMin );
247     return buffer;
248 }
249 
250 /* get the path of an interface key, in the form "Interface\\<guid>" */
251 /* buffer must be at least 50 characters long */
252 static WCHAR *get_interface_key( REFGUID guid, WCHAR *buffer )
253 {
254     static const WCHAR InterfaceW[] = {'I','n','t','e','r','f','a','c','e','\\',0};
255 
256     memcpy( buffer, InterfaceW, sizeof(InterfaceW) );
257     StringFromGUID2( guid, buffer + strlenW(buffer), 40 );
258     return buffer;
259 }
260 
261 /* get the lcid subkey for a typelib, in the form "<lcid>\\<syskind>" */
262 /* buffer must be at least 16 characters long */
263 static WCHAR *get_lcid_subkey( LCID lcid, SYSKIND syskind, WCHAR *buffer )
264 {
265     static const WCHAR LcidFormatW[] = {'%','l','x','\\',0};
266     static const WCHAR win16W[] = {'w','i','n','1','6',0};
267     static const WCHAR win32W[] = {'w','i','n','3','2',0};
268     static const WCHAR win64W[] = {'w','i','n','6','4',0};
269 
270     sprintfW( buffer, LcidFormatW, lcid );
271     switch(syskind)
272     {
273     case SYS_WIN16: strcatW( buffer, win16W ); break;
274     case SYS_WIN32: strcatW( buffer, win32W ); break;
275     case SYS_WIN64: strcatW( buffer, win64W ); break;
276     default:
277         TRACE("Typelib is for unsupported syskind %i\n", syskind);
278         return NULL;
279     }
280     return buffer;
281 }
282 
283 static HRESULT TLB_ReadTypeLib(LPCWSTR pszFileName, LPWSTR pszPath, UINT cchPath, ITypeLib2 **ppTypeLib);
284 
285 
286 /* Get the path to a registered type library. Helper for QueryPathOfRegTypeLib. */
287 static HRESULT query_typelib_path( REFGUID guid, WORD wMaj, WORD wMin,
288                                    SYSKIND syskind, LCID lcid, LPBSTR path )
289 {
290     HRESULT hr = TYPE_E_LIBNOTREGISTERED;
291     LCID myLCID = lcid;
292     HKEY hkey;
293     WCHAR buffer[60];
294     WCHAR Path[MAX_PATH];
295     LONG res;
296 
297     TRACE_(typelib)("(%s, %x.%x, 0x%x, %p)\n", debugstr_guid(guid), wMaj, wMin, lcid, path);
298 
299     if (!find_typelib_key( guid, &wMaj, &wMin )) return TYPE_E_LIBNOTREGISTERED;
300     get_typelib_key( guid, wMaj, wMin, buffer );
301 
302     res = RegOpenKeyExW( HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hkey );
303     if (res == ERROR_FILE_NOT_FOUND)
304     {
305         TRACE_(typelib)("%s not found\n", debugstr_w(buffer));
306         return TYPE_E_LIBNOTREGISTERED;
307     }
308     else if (res != ERROR_SUCCESS)
309     {
310         TRACE_(typelib)("failed to open %s for read access\n", debugstr_w(buffer));
311         return TYPE_E_REGISTRYACCESS;
312     }
313 
314     while (hr != S_OK)
315     {
316         LONG dwPathLen = sizeof(Path);
317 
318         get_lcid_subkey( myLCID, syskind, buffer );
319 
320         if (RegQueryValueW(hkey, buffer, Path, &dwPathLen))
321         {
322             if (!lcid)
323                 break;
324             else if (myLCID == lcid)
325             {
326                 /* try with sub-langid */
327                 myLCID = SUBLANGID(lcid);
328             }
329             else if ((myLCID == SUBLANGID(lcid)) && myLCID)
330             {
331                 /* try with system langid */
332                 myLCID = 0;
333             }
334             else
335             {
336                 break;
337             }
338         }
339         else
340         {
341             *path = SysAllocString( Path );
342             hr = S_OK;
343         }
344     }
345     RegCloseKey( hkey );
346     TRACE_(typelib)("-- 0x%08x\n", hr);
347     return hr;
348 }
349 
350 /****************************************************************************
351  *              QueryPathOfRegTypeLib   [OLEAUT32.164]
352  *
353  * Gets the path to a registered type library.
354  *
355  * PARAMS
356  *  guid [I] referenced guid
357  *  wMaj [I] major version
358  *  wMin [I] minor version
359  *  lcid [I] locale id
360  *  path [O] path of typelib
361  *
362  * RETURNS
363  *  Success: S_OK.
364  *  Failure: If the type library is not registered then TYPE_E_LIBNOTREGISTERED
365  *  or TYPE_E_REGISTRYACCESS if the type library registration key couldn't be
366  *  opened.
367  */
368 HRESULT WINAPI QueryPathOfRegTypeLib( REFGUID guid, WORD wMaj, WORD wMin, LCID lcid, LPBSTR path )
369 {
370 #ifdef _WIN64
371     HRESULT hres = query_typelib_path( guid, wMaj, wMin, SYS_WIN64, lcid, path );
372     if(SUCCEEDED(hres))
373         return hres;
374 #endif
375     return query_typelib_path( guid, wMaj, wMin, SYS_WIN32, lcid, path );
376 }
377 
378 /******************************************************************************
379  * CreateTypeLib [OLEAUT32.160]  creates a typelib
380  *
381  * RETURNS
382  *    Success: S_OK
383  *    Failure: Status
384  */
385 HRESULT WINAPI CreateTypeLib(
386         SYSKIND syskind, LPCOLESTR szFile, ICreateTypeLib** ppctlib
387 ) {
388     FIXME("(%d,%s,%p), stub!\n",syskind,debugstr_w(szFile),ppctlib);
389     return E_FAIL;
390 }
391 
392 /******************************************************************************
393  *              LoadTypeLib     [OLEAUT32.161]
394  *
395  * Loads a type library
396  *
397  * PARAMS
398  *  szFile [I] Name of file to load from.
399  *  pptLib [O] Pointer that receives ITypeLib object on success.
400  *
401  * RETURNS
402  *    Success: S_OK
403  *    Failure: Status
404  *
405  * SEE
406  *  LoadTypeLibEx, LoadRegTypeLib, CreateTypeLib.
407  */
408 HRESULT WINAPI LoadTypeLib(const OLECHAR *szFile, ITypeLib * *pptLib)
409 {
410     TRACE("(%s,%p)\n",debugstr_w(szFile), pptLib);
411     return LoadTypeLibEx(szFile, REGKIND_DEFAULT, pptLib);
412 }
413 
414 /******************************************************************************
415  *              LoadTypeLibEx   [OLEAUT32.183]
416  *
417  * Loads and optionally registers a type library
418  *
419  * RETURNS
420  *    Success: S_OK
421  *    Failure: Status
422  */
423 HRESULT WINAPI LoadTypeLibEx(
424     LPCOLESTR szFile,  /* [in] Name of file to load from */
425     REGKIND  regkind,  /* [in] Specify kind of registration */
426     ITypeLib **pptLib) /* [out] Pointer to pointer to loaded type library */
427 {
428     WCHAR szPath[MAX_PATH+1];
429     HRESULT res;
430 
431     TRACE("(%s,%d,%p)\n",debugstr_w(szFile), regkind, pptLib);
432 
433     *pptLib = NULL;
434 
435     res = TLB_ReadTypeLib(szFile, szPath, MAX_PATH + 1, (ITypeLib2**)pptLib);
436 
437     if (SUCCEEDED(res))
438         switch(regkind)
439         {
440             case REGKIND_DEFAULT:
441                 /* don't register typelibs supplied with full path. Experimentation confirms the following */
442                 if (((szFile[0] == '\\') && (szFile[1] == '\\')) ||
443                     (szFile[0] && (szFile[1] == ':'))) break;
444                 /* else fall-through */
445 
446             case REGKIND_REGISTER:
447                 if (FAILED(res = RegisterTypeLib(*pptLib, szPath, NULL)))
448                 {
449                     IUnknown_Release(*pptLib);
450                     *pptLib = 0;
451                 }
452                 break;
453             case REGKIND_NONE:
454                 break;
455         }
456 
457     TRACE(" returns %08x\n",res);
458     return res;
459 }
460 
461 /******************************************************************************
462  *              LoadRegTypeLib  [OLEAUT32.162]
463  *
464  * Loads a registered type library.
465  *
466  * PARAMS
467  *  rguid     [I] GUID of the registered type library.
468  *  wVerMajor [I] major version.
469  *  wVerMinor [I] minor version.
470  *  lcid      [I] locale ID.
471  *  ppTLib    [O] pointer that receives an ITypeLib object on success.
472  *
473  * RETURNS
474  *  Success: S_OK.
475  *  Failure: Any HRESULT code returned from QueryPathOfRegTypeLib or
476  *  LoadTypeLib.
477  */
478 HRESULT WINAPI LoadRegTypeLib(
479         REFGUID rguid,
480         WORD wVerMajor,
481         WORD wVerMinor,
482         LCID lcid,
483         ITypeLib **ppTLib)
484 {
485     BSTR bstr=NULL;
486     HRESULT res;
487 
488     *ppTLib = NULL;
489 
490     res = QueryPathOfRegTypeLib( rguid, wVerMajor, wVerMinor, lcid, &bstr);
491 
492     if(SUCCEEDED(res))
493     {
494         res= LoadTypeLib(bstr, ppTLib);
495         SysFreeString(bstr);
496     }
497 
498     TRACE("(IID: %s) load %s (%p)\n",debugstr_guid(rguid), SUCCEEDED(res)? "SUCCESS":"FAILED", *ppTLib);
499 
500     return res;
501 }
502 
503 
504 /* some string constants shared between RegisterTypeLib and UnRegisterTypeLib */
505 static const WCHAR TypeLibW[] = {'T','y','p','e','L','i','b',0};
506 static const WCHAR FLAGSW[] = {'F','L','A','G','S',0};
507 static const WCHAR HELPDIRW[] = {'H','E','L','P','D','I','R',0};
508 static const WCHAR ProxyStubClsidW[] = {'P','r','o','x','y','S','t','u','b','C','l','s','i','d',0};
509 static const WCHAR ProxyStubClsid32W[] = {'P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
510 
511 /******************************************************************************
512  *              RegisterTypeLib [OLEAUT32.163]
513  * Adds information about a type library to the System Registry
514  * NOTES
515  *    Docs: ITypeLib FAR * ptlib
516  *    Docs: OLECHAR FAR* szFullPath
517  *    Docs: OLECHAR FAR* szHelpDir
518  *
519  * RETURNS
520  *    Success: S_OK
521  *    Failure: Status
522  */
523 HRESULT WINAPI RegisterTypeLib(
524      ITypeLib * ptlib,     /* [in] Pointer to the library*/
525      OLECHAR * szFullPath, /* [in] full Path of the library*/
526      OLECHAR * szHelpDir)  /* [in] dir to the helpfile for the library,
527                                                          may be NULL*/
528 {
529     static const WCHAR PSOA[] = {'{','','','','2','','4','2','4','-',
530                                  '','','','','-','','','','','-','C','','','','-',
531                                  '','','','','','','','','','','4','6','}',0};
532     HRESULT res;
533     TLIBATTR *attr;
534     WCHAR keyName[60];
535     WCHAR tmp[16];
536     HKEY key, subKey;
537     UINT types, tidx;
538     TYPEKIND kind;
539     DWORD disposition;
540 
541     if (ptlib == NULL || szFullPath == NULL)
542         return E_INVALIDARG;
543 
544     if (FAILED(ITypeLib_GetLibAttr(ptlib, &attr)))
545         return E_FAIL;
546 
547 #ifdef _WIN64
548     if (attr->syskind != SYS_WIN64) return TYPE_E_BADMODULEKIND;
549 #else
550     if (attr->syskind != SYS_WIN32 && attr->syskind != SYS_WIN16) return TYPE_E_BADMODULEKIND;
551 #endif
552 
553     get_typelib_key( &attr->guid, attr->wMajorVerNum, attr->wMinorVerNum, keyName );
554 
555     res = S_OK;
556     if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0,
557         KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS)
558     {
559         LPOLESTR doc;
560 
561         /* Set the human-readable name of the typelib */
562         if (FAILED(ITypeLib_GetDocumentation(ptlib, -1, NULL, &doc, NULL, NULL)))
563             res = E_FAIL;
564         else if (doc)
565         {
566             if (RegSetValueExW(key, NULL, 0, REG_SZ,
567                 (BYTE *)doc, (lstrlenW(doc)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS)
568                 res = E_FAIL;
569 
570             SysFreeString(doc);
571         }
572 
573         /* Make up the name of the typelib path subkey */
574         if (!get_lcid_subkey( attr->lcid, attr->syskind, tmp )) res = E_FAIL;
575 
576         /* Create the typelib path subkey */
577         if (res == S_OK && RegCreateKeyExW(key, tmp, 0, NULL, 0,
578             KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
579         {
580             if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
581                 (BYTE *)szFullPath, (lstrlenW(szFullPath)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS)
582                 res = E_FAIL;
583 
584             RegCloseKey(subKey);
585         }
586         else
587             res = E_FAIL;
588 
589         /* Create the flags subkey */
590         if (res == S_OK && RegCreateKeyExW(key, FLAGSW, 0, NULL, 0,
591             KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
592         {
593             /* FIXME: is %u correct? */
594             static const WCHAR formatW[] = {'%','u',0};
595             WCHAR buf[20];
596             sprintfW(buf, formatW, attr->wLibFlags);
597             if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
598                                (BYTE *)buf, (strlenW(buf) + 1)*sizeof(WCHAR) ) != ERROR_SUCCESS)
599                 res = E_FAIL;
600 
601             RegCloseKey(subKey);
602         }
603         else
604             res = E_FAIL;
605 
606         /* create the helpdir subkey */
607         if (res == S_OK && RegCreateKeyExW(key, HELPDIRW, 0, NULL, 0,
608             KEY_WRITE, NULL, &subKey, &disposition) == ERROR_SUCCESS)
609         {
610             BOOL freeHelpDir = FALSE;
611             OLECHAR* pIndexStr;
612 
613             /* if we created a new key, and helpDir was null, set the helpdir
614                to the directory which contains the typelib. However,
615                if we just opened an existing key, we leave the helpdir alone */
616             if ((disposition == REG_CREATED_NEW_KEY) && (szHelpDir == NULL)) {
617                 szHelpDir = SysAllocString(szFullPath);
618                 pIndexStr = strrchrW(szHelpDir, '\\');
619                 if (pIndexStr) {
620                     *pIndexStr = 0;
621                 }
622                 freeHelpDir = TRUE;
623             }
624 
625             /* if we have an szHelpDir, set it! */
626             if (szHelpDir != NULL) {
627                 if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
628                     (BYTE *)szHelpDir, (lstrlenW(szHelpDir)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS) {
629                     res = E_FAIL;
630                 }
631             }
632 
633             /* tidy up */
634             if (freeHelpDir) SysFreeString(szHelpDir);
635             RegCloseKey(subKey);
636 
637         } else {
638             res = E_FAIL;
639         }
640 
641         RegCloseKey(key);
642     }
643     else
644         res = E_FAIL;
645 
646     /* register OLE Automation-compatible interfaces for this typelib */
647     types = ITypeLib_GetTypeInfoCount(ptlib);
648     for (tidx=0; tidx<types; tidx++) {
649         if (SUCCEEDED(ITypeLib_GetTypeInfoType(ptlib, tidx, &kind))) {
650             LPOLESTR name = NULL;
651             ITypeInfo *tinfo = NULL;
652 
653             ITypeLib_GetDocumentation(ptlib, tidx, &name, NULL, NULL, NULL);
654 
655             switch (kind) {
656             case TKIND_INTERFACE:
657                 TRACE_(typelib)("%d: interface %s\n", tidx, debugstr_w(name));
658                 ITypeLib_GetTypeInfo(ptlib, tidx, &tinfo);
659                 break;
660 
661             case TKIND_DISPATCH:
662                 TRACE_(typelib)("%d: dispinterface %s\n", tidx, debugstr_w(name));
663                 ITypeLib_GetTypeInfo(ptlib, tidx, &tinfo);
664                 break;
665 
666             default:
667                 TRACE_(typelib)("%d: %s\n", tidx, debugstr_w(name));
668                 break;
669             }
670 
671             if (tinfo) {
672                 TYPEATTR *tattr = NULL;
673                 ITypeInfo_GetTypeAttr(tinfo, &tattr);
674 
675                 if (tattr) {
676                     TRACE_(typelib)("guid=%s, flags=%04x (",
677                                     debugstr_guid(&tattr->guid),
678                                     tattr->wTypeFlags);
679 
680                     if (TRACE_ON(typelib)) {
681 #define XX(x) if (TYPEFLAG_##x & tattr->wTypeFlags) MESSAGE(#x"|");
682                         XX(FAPPOBJECT);
683                         XX(FCANCREATE);
684                         XX(FLICENSED);
685                         XX(FPREDECLID);
686                         XX(FHIDDEN);
687                         XX(FCONTROL);
688                         XX(FDUAL);
689                         XX(FNONEXTENSIBLE);
690                         XX(FOLEAUTOMATION);
691                         XX(FRESTRICTED);
692                         XX(FAGGREGATABLE);
693                         XX(FREPLACEABLE);
694                         XX(FDISPATCHABLE);
695                         XX(FREVERSEBIND);
696                         XX(FPROXY);
697 #undef XX
698                         MESSAGE("\n");
699                     }
700 
701                     /* Register all dispinterfaces (which includes dual interfaces) and
702                        oleautomation interfaces */
703                     if ((kind == TKIND_INTERFACE && (tattr->wTypeFlags & TYPEFLAG_FOLEAUTOMATION)) ||
704                         kind == TKIND_DISPATCH)
705                     {
706                         /* register interface<->typelib coupling */
707                         get_interface_key( &tattr->guid, keyName );
708                         if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0,
709                                             KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS)
710                         {
711                             if (name)
712                                 RegSetValueExW(key, NULL, 0, REG_SZ,
713                                                (BYTE *)name, (strlenW(name)+1) * sizeof(OLECHAR));
714 
715                             if (RegCreateKeyExW(key, ProxyStubClsidW, 0, NULL, 0,
716                                 KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) {
717                                 RegSetValueExW(subKey, NULL, 0, REG_SZ,
718                                                (const BYTE *)PSOA, sizeof PSOA);
719                                 RegCloseKey(subKey);
720                             }
721 
722                             if (RegCreateKeyExW(key, ProxyStubClsid32W, 0, NULL, 0,
723                                 KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) {
724                                 RegSetValueExW(subKey, NULL, 0, REG_SZ,
725                                                (const BYTE *)PSOA, sizeof PSOA);
726                                 RegCloseKey(subKey);
727                             }
728 
729                             if (RegCreateKeyExW(key, TypeLibW, 0, NULL, 0,
730                                 KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
731                             {
732                                 WCHAR buffer[40];
733                                 static const WCHAR fmtver[] = {'%','x','.','%','x',0 };
734                                 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
735 
736                                 StringFromGUID2(&attr->guid, buffer, 40);
737                                 RegSetValueExW(subKey, NULL, 0, REG_SZ,
738                                                (BYTE *)buffer, (strlenW(buffer)+1) * sizeof(WCHAR));
739                                 sprintfW(buffer, fmtver, attr->wMajorVerNum, attr->wMinorVerNum);
740                                 RegSetValueExW(subKey, VersionW, 0, REG_SZ,
741                                                (BYTE*)buffer, (strlenW(buffer)+1) * sizeof(WCHAR));
742                                 RegCloseKey(subKey);
743                             }
744 
745                             RegCloseKey(key);
746                         }
747                     }
748 
749                     ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
750                 }
751 
752                 ITypeInfo_Release(tinfo);
753             }
754 
755             SysFreeString(name);
756         }
757     }
758 
759     ITypeLib_ReleaseTLibAttr(ptlib, attr);
760 
761     return res;
762 }
763 
764 
765 /******************************************************************************
766  *      UnRegisterTypeLib       [OLEAUT32.186]
767  * Removes information about a type library from the System Registry
768  * NOTES
769  *
770  * RETURNS
771  *    Success: S_OK
772  *    Failure: Status
773  */
774 HRESULT WINAPI UnRegisterTypeLib(
775     REFGUID libid,      /* [in] Guid of the library */
776         WORD wVerMajor, /* [in] major version */
777         WORD wVerMinor, /* [in] minor version */
778         LCID lcid,      /* [in] locale id */
779         SYSKIND syskind)
780 {
781     BSTR tlibPath = NULL;
782     DWORD tmpLength;
783     WCHAR keyName[60];
784     WCHAR subKeyName[50];
785     int result = S_OK;
786     DWORD i = 0;
787     BOOL deleteOtherStuff;
788     HKEY key = NULL;
789     HKEY subKey = NULL;
790     TYPEATTR* typeAttr = NULL;
791     TYPEKIND kind;
792     ITypeInfo* typeInfo = NULL;
793     ITypeLib* typeLib = NULL;
794     int numTypes;
795 
796     TRACE("(IID: %s)\n",debugstr_guid(libid));
797 
798     /* Create the path to the key */
799     get_typelib_key( libid, wVerMajor, wVerMinor, keyName );
800 
801     if (syskind != SYS_WIN16 && syskind != SYS_WIN32 && syskind != SYS_WIN64)
802     {
803         TRACE("Unsupported syskind %i\n", syskind);
804         result = E_INVALIDARG;
805         goto end;
806     }
807 
808     /* get the path to the typelib on disk */
809     if (query_typelib_path(libid, wVerMajor, wVerMinor, syskind, lcid, &tlibPath) != S_OK) {
810         result = E_INVALIDARG;
811         goto end;
812     }
813 
814     /* Try and open the key to the type library. */
815     if (RegOpenKeyExW(HKEY_CLASSES_ROOT, keyName, 0, KEY_READ | KEY_WRITE, &key) != ERROR_SUCCESS) {
816         result = E_INVALIDARG;
817         goto end;
818     }
819 
820     /* Try and load the type library */
821     if (LoadTypeLibEx(tlibPath, REGKIND_NONE, &typeLib) != S_OK) {
822         result = TYPE_E_INVALIDSTATE;
823         goto end;
824     }
825 
826     /* remove any types registered with this typelib */
827     numTypes = ITypeLib_GetTypeInfoCount(typeLib);
828     for (i=0; i<numTypes; i++) {
829         /* get the kind of type */
830         if (ITypeLib_GetTypeInfoType(typeLib, i, &kind) != S_OK) {
831             goto enddeleteloop;
832         }
833 
834         /* skip non-interfaces, and get type info for the type */
835         if ((kind != TKIND_INTERFACE) && (kind != TKIND_DISPATCH)) {
836             goto enddeleteloop;
837         }
838         if (ITypeLib_GetTypeInfo(typeLib, i, &typeInfo) != S_OK) {
839             goto enddeleteloop;
840         }
841         if (ITypeInfo_GetTypeAttr(typeInfo, &typeAttr) != S_OK) {
842             goto enddeleteloop;
843         }
844 
845         if ((kind == TKIND_INTERFACE && (typeAttr->wTypeFlags & TYPEFLAG_FOLEAUTOMATION)) ||
846             kind == TKIND_DISPATCH)
847         {
848             /* the path to the type */
849             get_interface_key( &typeAttr->guid, subKeyName );
850 
851             /* Delete its bits */
852             if (RegOpenKeyExW(HKEY_CLASSES_ROOT, subKeyName, 0, KEY_WRITE, &subKey) != ERROR_SUCCESS)
853                 goto enddeleteloop;
854 
855             RegDeleteKeyW(subKey, ProxyStubClsidW);
856             RegDeleteKeyW(subKey, ProxyStubClsid32W);
857             RegDeleteKeyW(subKey, TypeLibW);
858             RegCloseKey(subKey);
859             subKey = NULL;
860             RegDeleteKeyW(HKEY_CLASSES_ROOT, subKeyName);
861         }
862 
863 enddeleteloop:
864         if (typeAttr) ITypeInfo_ReleaseTypeAttr(typeInfo, typeAttr);
865         typeAttr = NULL;
866         if (typeInfo) ITypeInfo_Release(typeInfo);
867         typeInfo = NULL;
868     }
869 
870     /* Now, delete the type library path subkey */
871     get_lcid_subkey( lcid, syskind, subKeyName );
872     RegDeleteKeyW(key, subKeyName);
873     *strrchrW( subKeyName, '\\' ) = 0;  /* remove last path component */
874     RegDeleteKeyW(key, subKeyName);
875 
876     /* check if there is anything besides the FLAGS/HELPDIR keys.
877        If there is, we don't delete them */
878     tmpLength = sizeof(subKeyName)/sizeof(WCHAR);
879     deleteOtherStuff = TRUE;
880     i = 0;
881     while(RegEnumKeyExW(key, i++, subKeyName, &tmpLength, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
882         tmpLength = sizeof(subKeyName)/sizeof(WCHAR);
883 
884         /* if its not FLAGS or HELPDIR, then we must keep the rest of the key */
885         if (!strcmpW(subKeyName, FLAGSW)) continue;
886         if (!strcmpW(subKeyName, HELPDIRW)) continue;
887         deleteOtherStuff = FALSE;
888         break;
889     }
890 
891     /* only delete the other parts of the key if we're absolutely sure */
892     if (deleteOtherStuff) {
893         RegDeleteKeyW(key, FLAGSW);
894         RegDeleteKeyW(key, HELPDIRW);
895         RegCloseKey(key);
896         key = NULL;
897 
898         RegDeleteKeyW(HKEY_CLASSES_ROOT, keyName);
899         *strrchrW( keyName, '\\' ) = 0;  /* remove last path component */
900         RegDeleteKeyW(HKEY_CLASSES_ROOT, keyName);
901     }
902 
903 end:
904     SysFreeString(tlibPath);
905     if (typeLib) ITypeLib_Release(typeLib);
906     if (subKey) RegCloseKey(subKey);
907     if (key) RegCloseKey(key);
908     return result;
909 }
910 
911 /******************************************************************************
912  *              RegisterTypeLibForUser  [OLEAUT32.442]
913  * Adds information about a type library to the user registry
914  * NOTES
915  *    Docs: ITypeLib FAR * ptlib
916  *    Docs: OLECHAR FAR* szFullPath
917  *    Docs: OLECHAR FAR* szHelpDir
918  *
919  * RETURNS
920  *    Success: S_OK
921  *    Failure: Status
922  */
923 HRESULT WINAPI RegisterTypeLibForUser(
924      ITypeLib * ptlib,     /* [in] Pointer to the library*/
925      OLECHAR * szFullPath, /* [in] full Path of the library*/
926      OLECHAR * szHelpDir)  /* [in] dir to the helpfile for the library,
927                                                          may be NULL*/
928 {
929     FIXME("(%p, %s, %s) registering the typelib system-wide\n", ptlib,
930           debugstr_w(szFullPath), debugstr_w(szHelpDir));
931     return RegisterTypeLib(ptlib, szFullPath, szHelpDir);
932 }
933 
934 /******************************************************************************
935  *      UnRegisterTypeLibForUser        [OLEAUT32.443]
936  * Removes information about a type library from the user registry
937  *
938  * RETURNS
939  *    Success: S_OK
940  *    Failure: Status
941  */
942 HRESULT WINAPI UnRegisterTypeLibForUser(
943     REFGUID libid,      /* [in] GUID of the library */
944     WORD wVerMajor,     /* [in] major version */
945     WORD wVerMinor,     /* [in] minor version */
946     LCID lcid,  /* [in] locale id */
947     SYSKIND syskind)
948 {
949     FIXME("(%s, %u, %u, %u, %u) unregistering the typelib system-wide\n",
950           debugstr_guid(libid), wVerMajor, wVerMinor, lcid, syskind);
951     return UnRegisterTypeLib(libid, wVerMajor, wVerMinor, lcid, syskind);
952 }
953 
954 /*======================= ITypeLib implementation =======================*/
955 
956 typedef struct tagTLBCustData
957 {
958     GUID guid;
959     VARIANT data;
960     struct tagTLBCustData* next;
961 } TLBCustData;
962 
963 /* data structure for import typelibs */
964 typedef struct tagTLBImpLib
965 {
966     int offset;                 /* offset in the file (MSFT)
967                                    offset in nametable (SLTG)
968                                    just used to identify library while reading
969                                    data from file */
970     GUID guid;                  /* libid */
971     BSTR name;                  /* name */
972 
973     LCID lcid;                  /* lcid of imported typelib */
974 
975     WORD wVersionMajor;         /* major version number */
976     WORD wVersionMinor;         /* minor version number */
977 
978     struct tagITypeLibImpl *pImpTypeLib; /* pointer to loaded typelib, or
979                                             NULL if not yet loaded */
980     struct tagTLBImpLib * next;
981 } TLBImpLib;
982 
983 /* internal ITypeLib data */
984 typedef struct tagITypeLibImpl
985 {
986     const ITypeLib2Vtbl *lpVtbl;
987     const ITypeCompVtbl *lpVtblTypeComp;
988     LONG ref;
989     TLIBATTR LibAttr;            /* guid,lcid,syskind,version,flags */
990     LCID lcid;
991 
992     /* strings can be stored in tlb as multibyte strings BUT they are *always*
993      * exported to the application as a UNICODE string.
994      */
995     BSTR Name;
996     BSTR DocString;
997     BSTR HelpFile;
998     BSTR HelpStringDll;
999     DWORD dwHelpContext;
1000     int TypeInfoCount;          /* nr of typeinfo's in librarry */
1001     struct tagITypeInfoImpl *pTypeInfo;   /* linked list of type info data */
1002     int ctCustData;             /* number of items in cust data list */
1003     TLBCustData * pCustData;    /* linked list to cust data */
1004     TLBImpLib   * pImpLibs;     /* linked list to all imported typelibs */
1005     int ctTypeDesc;             /* number of items in type desc array */
1006     TYPEDESC * pTypeDesc;       /* array of TypeDescriptions found in the
1007                                    library. Only used while reading MSFT
1008                                    typelibs */
1009     struct list ref_list;       /* list of ref types in this typelib */
1010     HREFTYPE dispatch_href;     /* reference to IDispatch, -1 if unused */
1011 
1012 
1013     /* typelibs are cached, keyed by path and index, so store the linked list info within them */
1014     struct tagITypeLibImpl *next, *prev;
1015     WCHAR *path;
1016     INT index;
1017 } ITypeLibImpl;
1018 
1019 static const ITypeLib2Vtbl tlbvt;
1020 static const ITypeCompVtbl tlbtcvt;
1021 
1022 static inline ITypeLibImpl *impl_from_ITypeComp( ITypeComp *iface )
1023 {
1024     return (ITypeLibImpl *)((char*)iface - FIELD_OFFSET(ITypeLibImpl, lpVtblTypeComp));
1025 }
1026 
1027 /* ITypeLib methods */
1028 static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength);
1029 static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength);
1030 
1031 /*======================= ITypeInfo implementation =======================*/
1032 
1033 /* data for referenced types */
1034 typedef struct tagTLBRefType
1035 {
1036     INT index;              /* Type index for internal ref or for external ref
1037                                it the format is SLTG.  -2 indicates to
1038                                use guid */
1039 
1040     GUID guid;              /* guid of the referenced type */
1041                             /* if index == TLB_REF_USE_GUID */
1042 
1043     HREFTYPE reference;     /* The href of this ref */
1044     TLBImpLib *pImpTLInfo;  /* If ref is external ptr to library data
1045                                TLB_REF_INTERNAL for internal refs
1046                                TLB_REF_NOT_FOUND for broken refs */
1047 
1048     struct list entry;
1049 } TLBRefType;
1050 
1051 #define TLB_REF_USE_GUID -2
1052 
1053 #define TLB_REF_INTERNAL (void*)-2
1054 #define TLB_REF_NOT_FOUND (void*)-1
1055 
1056 /* internal Parameter data */
1057 typedef struct tagTLBParDesc
1058 {
1059     BSTR Name;
1060     int ctCustData;
1061     TLBCustData * pCustData;        /* linked list to cust data */
1062 } TLBParDesc;
1063 
1064 /* internal Function data */
1065 typedef struct tagTLBFuncDesc
1066 {
1067     FUNCDESC funcdesc;      /* lots of info on the function and its attributes. */
1068     BSTR Name;             /* the name of this function */
1069     TLBParDesc *pParamDesc; /* array with param names and custom data */
1070     int helpcontext;
1071     int HelpStringContext;
1072     BSTR HelpString;
1073     BSTR Entry;            /* if IS_INTRESOURCE true, it's numeric; if -1 it isn't present */
1074     int ctCustData;
1075     TLBCustData * pCustData;        /* linked list to cust data; */
1076     struct tagTLBFuncDesc * next;
1077 } TLBFuncDesc;
1078 
1079 /* internal Variable data */
1080 typedef struct tagTLBVarDesc
1081 {
1082     VARDESC vardesc;        /* lots of info on the variable and its attributes. */
1083     BSTR Name;             /* the name of this variable */
1084     int HelpContext;
1085     int HelpStringContext;
1086     BSTR HelpString;
1087     int ctCustData;
1088     TLBCustData * pCustData;/* linked list to cust data; */
1089     struct tagTLBVarDesc * next;
1090 } TLBVarDesc;
1091 
1092 /* internal implemented interface data */
1093 typedef struct tagTLBImplType
1094 {
1095     HREFTYPE hRef;          /* hRef of interface */
1096     int implflags;          /* IMPLFLAG_*s */
1097     int ctCustData;
1098     TLBCustData * pCustData;/* linked list to custom data; */
1099     struct tagTLBImplType *next;
1100 } TLBImplType;
1101 
1102 /* internal TypeInfo data */
1103 typedef struct tagITypeInfoImpl
1104 {
1105     const ITypeInfo2Vtbl *lpVtbl;
1106     const ITypeCompVtbl  *lpVtblTypeComp;
1107     LONG ref;
1108     BOOL not_attached_to_typelib;
1109     TYPEATTR TypeAttr ;         /* _lots_ of type information. */
1110     ITypeLibImpl * pTypeLib;        /* back pointer to typelib */
1111     int index;                  /* index in this typelib; */
1112     HREFTYPE hreftype;          /* hreftype for app object binding */
1113     /* type libs seem to store the doc strings in ascii
1114      * so why should we do it in unicode?
1115      */
1116     BSTR Name;
1117     BSTR DocString;
1118     BSTR DllName;
1119     DWORD dwHelpContext;
1120     DWORD dwHelpStringContext;
1121 
1122     /* functions  */
1123     TLBFuncDesc * funclist;     /* linked list with function descriptions */
1124 
1125     /* variables  */
1126     TLBVarDesc * varlist;       /* linked list with variable descriptions */
1127 
1128     /* Implemented Interfaces  */
1129     TLBImplType * impltypelist;
1130 
1131     int ctCustData;
1132     TLBCustData * pCustData;        /* linked list to cust data; */
1133     struct tagITypeInfoImpl * next;
1134 } ITypeInfoImpl;
1135 
1136 static inline ITypeInfoImpl *info_impl_from_ITypeComp( ITypeComp *iface )
1137 {
1138     return (ITypeInfoImpl *)((char*)iface - FIELD_OFFSET(ITypeInfoImpl, lpVtblTypeComp));
1139 }
1140 
1141 static const ITypeInfo2Vtbl tinfvt;
1142 static const ITypeCompVtbl  tcompvt;
1143 
1144 static ITypeInfoImpl* ITypeInfoImpl_Constructor(void);
1145 static void ITypeInfoImpl_Destroy(ITypeInfoImpl *This);
1146 
1147 typedef struct tagTLBContext
1148 {
1149         unsigned int oStart;  /* start of TLB in file */
1150         unsigned int pos;     /* current pos */
1151         unsigned int length;  /* total length */
1152         void *mapping;        /* memory mapping */
1153         MSFT_SegDir * pTblDir;
1154         ITypeLibImpl* pLibInfo;
1155 } TLBContext;
1156 
1157 
1158 static void MSFT_DoRefType(TLBContext *pcx, ITypeLibImpl *pTL, int offset);
1159 
1160 /*
1161  debug
1162 */
1163 static void dump_TypeDesc(const TYPEDESC *pTD,char *szVarType) {
1164     if (pTD->vt & VT_RESERVED)
1165         szVarType += strlen(strcpy(szVarType, "reserved | "));
1166     if (pTD->vt & VT_BYREF)
1167         szVarType += strlen(strcpy(szVarType, "ref to "));
1168     if (pTD->vt & VT_ARRAY)
1169         szVarType += strlen(strcpy(szVarType, "array of "));
1170     if (pTD->vt & VT_VECTOR)
1171         szVarType += strlen(strcpy(szVarType, "vector of "));
1172     switch(pTD->vt & VT_TYPEMASK) {
1173     case VT_UI1: sprintf(szVarType, "VT_UI1"); break;
1174     case VT_I2: sprintf(szVarType, "VT_I2"); break;
1175     case VT_I4: sprintf(szVarType, "VT_I4"); break;
1176     case VT_R4: sprintf(szVarType, "VT_R4"); break;
1177     case VT_R8: sprintf(szVarType, "VT_R8"); break;
1178     case VT_BOOL: sprintf(szVarType, "VT_BOOL"); break;
1179     case VT_ERROR: sprintf(szVarType, "VT_ERROR"); break;
1180     case VT_CY: sprintf(szVarType, "VT_CY"); break;
1181     case VT_DATE: sprintf(szVarType, "VT_DATE"); break;
1182     case VT_BSTR: sprintf(szVarType, "VT_BSTR"); break;
1183     case VT_UNKNOWN: sprintf(szVarType, "VT_UNKNOWN"); break;
1184     case VT_DISPATCH: sprintf(szVarType, "VT_DISPATCH"); break;
1185     case VT_I1: sprintf(szVarType, "VT_I1"); break;
1186     case VT_UI2: sprintf(szVarType, "VT_UI2"); break;
1187     case VT_UI4: sprintf(szVarType, "VT_UI4"); break;
1188     case VT_INT: sprintf(szVarType, "VT_INT"); break;
1189     case VT_UINT: sprintf(szVarType, "VT_UINT"); break;
1190     case VT_VARIANT: sprintf(szVarType, "VT_VARIANT"); break;
1191     case VT_VOID: sprintf(szVarType, "VT_VOID"); break;
1192     case VT_HRESULT: sprintf(szVarType, "VT_HRESULT"); break;
1193     case VT_USERDEFINED: sprintf(szVarType, "VT_USERDEFINED ref = %x",
1194                                  pTD->u.hreftype); break;
1195     case VT_LPSTR: sprintf(szVarType, "VT_LPSTR"); break;
1196     case VT_LPWSTR: sprintf(szVarType, "VT_LPWSTR"); break;
1197     case VT_PTR: sprintf(szVarType, "ptr to ");
1198       dump_TypeDesc(pTD->u.lptdesc, szVarType + 7);
1199       break;
1200     case VT_SAFEARRAY: sprintf(szVarType, "safearray of ");
1201       dump_TypeDesc(pTD->u.lptdesc, szVarType + 13);
1202       break;
1203     case VT_CARRAY: sprintf(szVarType, "%d dim array of ",
1204                             pTD->u.lpadesc->cDims); /* FIXME print out sizes */
1205       dump_TypeDesc(&pTD->u.lpadesc->tdescElem, szVarType + strlen(szVarType));
1206       break;
1207 
1208     default: sprintf(szVarType, "unknown(%d)", pTD->vt & VT_TYPEMASK); break;
1209     }
1210 }
1211 
1212 static void dump_ELEMDESC(const ELEMDESC *edesc) {
1213   char buf[200];
1214   USHORT flags = edesc->u.paramdesc.wParamFlags;
1215   dump_TypeDesc(&edesc->tdesc,buf);
1216   MESSAGE("\t\ttdesc.vartype %d (%s)\n",edesc->tdesc.vt,buf);
1217   MESSAGE("\t\tu.paramdesc.wParamFlags");
1218   if (!flags) MESSAGE(" PARAMFLAGS_NONE");
1219   if (flags & PARAMFLAG_FIN) MESSAGE(" PARAMFLAG_FIN");
1220   if (flags & PARAMFLAG_FOUT) MESSAGE(" PARAMFLAG_FOUT");
1221   if (flags & PARAMFLAG_FLCID) MESSAGE(" PARAMFLAG_FLCID");
1222   if (flags & PARAMFLAG_FRETVAL) MESSAGE(" PARAMFLAG_FRETVAL");
1223   if (flags & PARAMFLAG_FOPT) MESSAGE(" PARAMFLAG_FOPT");
1224   if (flags & PARAMFLAG_FHASDEFAULT) MESSAGE(" PARAMFLAG_FHASDEFAULT");
1225   if (flags & PARAMFLAG_FHASCUSTDATA) MESSAGE(" PARAMFLAG_FHASCUSTDATA");
1226   MESSAGE("\n\t\tu.paramdesc.lpex %p\n",edesc->u.paramdesc.pparamdescex);
1227 }
1228 static void dump_FUNCDESC(const FUNCDESC *funcdesc) {
1229   int i;
1230   MESSAGE("memid is %08x\n",funcdesc->memid);
1231   for (i=0;i<funcdesc->cParams;i++) {
1232       MESSAGE("Param %d:\n",i);
1233       dump_ELEMDESC(funcdesc->lprgelemdescParam+i);
1234   }
1235   MESSAGE("\tfunckind: %d (",funcdesc->funckind);
1236   switch (funcdesc->funckind) {
1237   case FUNC_VIRTUAL: MESSAGE("virtual");break;
1238   case FUNC_PUREVIRTUAL: MESSAGE("pure virtual");break;
1239   case FUNC_NONVIRTUAL: MESSAGE("nonvirtual");break;
1240   case FUNC_STATIC: MESSAGE("static");break;
1241   case FUNC_DISPATCH: MESSAGE("dispatch");break;
1242   default: MESSAGE("unknown");break;
1243   }
1244   MESSAGE(")\n\tinvkind: %d (",funcdesc->invkind);
1245   switch (funcdesc->invkind) {
1246   case INVOKE_FUNC: MESSAGE("func");break;
1247   case INVOKE_PROPERTYGET: MESSAGE("property get");break;
1248   case INVOKE_PROPERTYPUT: MESSAGE("property put");break;
1249   case INVOKE_PROPERTYPUTREF: MESSAGE("property put ref");break;
1250   }
1251   MESSAGE(")\n\tcallconv: %d (",funcdesc->callconv);
1252   switch (funcdesc->callconv) {
1253   case CC_CDECL: MESSAGE("cdecl");break;
1254   case CC_PASCAL: MESSAGE("pascal");break;
1255   case CC_STDCALL: MESSAGE("stdcall");break;
1256   case CC_SYSCALL: MESSAGE("syscall");break;
1257   default:break;
1258   }
1259   MESSAGE(")\n\toVft: %d\n", funcdesc->oVft);
1260   MESSAGE("\tcParamsOpt: %d\n", funcdesc->cParamsOpt);
1261   MESSAGE("\twFlags: %x\n", funcdesc->wFuncFlags);
1262 
1263   MESSAGE("\telemdescFunc (return value type):\n");
1264   dump_ELEMDESC(&funcdesc->elemdescFunc);
1265 }
1266 
1267 static const char * const typekind_desc[] =
1268 {
1269         "TKIND_ENUM",
1270         "TKIND_RECORD",
1271         "TKIND_MODULE",
1272         "TKIND_INTERFACE",
1273         "TKIND_DISPATCH",
1274         "TKIND_COCLASS",
1275         "TKIND_ALIAS",
1276         "TKIND_UNION",
1277         "TKIND_MAX"
1278 };
1279 
1280 static void dump_TLBFuncDescOne(const TLBFuncDesc * pfd)
1281 {
1282   int i;
1283   MESSAGE("%s(%u)\n", debugstr_w(pfd->Name), pfd->funcdesc.cParams);
1284   for (i=0;i<pfd->funcdesc.cParams;i++)
1285       MESSAGE("\tparm%d: %s\n",i,debugstr_w(pfd->pParamDesc[i].Name));
1286 
1287 
1288   dump_FUNCDESC(&(pfd->funcdesc));
1289 
1290   MESSAGE("\thelpstring: %s\n", debugstr_w(pfd->HelpString));
1291   MESSAGE("\tentry: %s\n", (pfd->Entry == (void *)-1) ? "invalid" : debugstr_w(pfd->Entry));
1292 }
1293 static void dump_TLBFuncDesc(const TLBFuncDesc * pfd)
1294 {
1295         while (pfd)
1296         {
1297           dump_TLBFuncDescOne(pfd);
1298           pfd = pfd->next;
1299         };
1300 }
1301 static void dump_TLBVarDesc(const TLBVarDesc * pvd)
1302 {
1303         while (pvd)
1304         {
1305           TRACE_(typelib)("%s\n", debugstr_w(pvd->Name));
1306           pvd = pvd->next;
1307         };
1308 }
1309 
1310 static void dump_TLBImpLib(const TLBImpLib *import)
1311 {
1312     TRACE_(typelib)("%s %s\n", debugstr_guid(&(import->guid)),
1313                     debugstr_w(import->name));
1314     TRACE_(typelib)("v%d.%d lcid=%x offset=%x\n", import->wVersionMajor,
1315                     import->wVersionMinor, import->lcid, import->offset);
1316 }
1317 
1318 static void dump_TLBRefType(const ITypeLibImpl *pTL)
1319 {
1320     TLBRefType *ref;
1321 
1322     LIST_FOR_EACH_ENTRY(ref, &pTL->ref_list, TLBRefType, entry)
1323     {
1324         TRACE_(typelib)("href:0x%08x\n", ref->reference);
1325         if(ref->index == -1)
1326             TRACE_(typelib)("%s\n", debugstr_guid(&(ref->guid)));
1327         else
1328             TRACE_(typelib)("type no: %d\n", ref->index);
1329 
1330         if(ref->pImpTLInfo != TLB_REF_INTERNAL && ref->pImpTLInfo != TLB_REF_NOT_FOUND)
1331         {
1332             TRACE_(typelib)("in lib\n");
1333             dump_TLBImpLib(ref->pImpTLInfo);
1334         }
1335     }
1336 }
1337 
1338 static void dump_TLBImplType(const TLBImplType * impl)
1339 {
1340     while (impl) {
1341         TRACE_(typelib)(
1342                 "implementing/inheriting interface hRef = %x implflags %x\n",
1343                 impl->hRef, impl->implflags);
1344         impl = impl->next;
1345     }
1346 }
1347 
1348 static void dump_Variant(const VARIANT * pvar)
1349 {
1350     SYSTEMTIME st;
1351 
1352     TRACE("%p->{%s%s", pvar, debugstr_VT(pvar), debugstr_VF(pvar));
1353 
1354     if (pvar)
1355     {
1356       if (V_ISBYREF(pvar) || V_TYPE(pvar) == VT_UNKNOWN ||
1357           V_TYPE(pvar) == VT_DISPATCH || V_TYPE(pvar) == VT_RECORD)
1358       {
1359         TRACE(",%p", V_BYREF(pvar));
1360       }
1361       else if (V_ISARRAY(pvar) || V_ISVECTOR(pvar))
1362       {
1363         TRACE(",%p", V_ARRAY(pvar));
1364       }
1365       else switch (V_TYPE(pvar))
1366       {
1367       case VT_I1:   TRACE(",%d", V_I1(pvar)); break;
1368       case VT_UI1:  TRACE(",%d", V_UI1(pvar)); break;
1369       case VT_I2:   TRACE(",%d", V_I2(pvar)); break;
1370       case VT_UI2:  TRACE(",%d", V_UI2(pvar)); break;
1371       case VT_INT:
1372       case VT_I4:   TRACE(",%d", V_I4(pvar)); break;
1373       case VT_UINT:
1374       case VT_UI4:  TRACE(",%d", V_UI4(pvar)); break;
1375       case VT_I8:   TRACE(",0x%08x,0x%08x", (ULONG)(V_I8(pvar) >> 32),
1376                           (ULONG)(V_I8(pvar) & 0xffffffff)); break;
1377       case VT_UI8:  TRACE(",0x%08x,0x%08x", (ULONG)(V_UI8(pvar) >> 32),
1378                           (ULONG)(V_UI8(pvar) & 0xffffffff)); break;
1379       case VT_R4:   TRACE(",%3.3e", V_R4(pvar)); break;
1380       case VT_R8:   TRACE(",%3.3e", V_R8(pvar)); break;
1381       case VT_BOOL: TRACE(",%s", V_BOOL(pvar) ? "TRUE" : "FALSE"); break;
1382       case VT_BSTR: TRACE(",%s", debugstr_w(V_BSTR(pvar))); break;
1383       case VT_CY:   TRACE(",0x%08x,0x%08x", V_CY(pvar).s.Hi,
1384                            V_CY(pvar).s.Lo); break;
1385       case VT_DATE:
1386         if(!VariantTimeToSystemTime(V_DATE(pvar), &st))
1387           TRACE(",<invalid>");
1388         else
1389           TRACE(",%04d/%02d/%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay,
1390                 st.wHour, st.wMinute, st.wSecond);
1391         break;
1392       case VT_ERROR:
1393       case VT_VOID:
1394       case VT_USERDEFINED:
1395       case VT_EMPTY:
1396       case VT_NULL:  break;
1397       default:       TRACE(",?"); break;
1398       }
1399     }
1400     TRACE("}\n");
1401 }
1402 
1403 static void dump_DispParms(const DISPPARAMS * pdp)
1404 {
1405     unsigned int index;
1406 
1407     TRACE("args=%u named args=%u\n", pdp->cArgs, pdp->cNamedArgs);
1408 
1409     if (pdp->cNamedArgs && pdp->rgdispidNamedArgs)
1410     {
1411         TRACE("named args:\n");
1412         for (index = 0; index < pdp->cNamedArgs; index++)
1413             TRACE( "\t0x%x\n", pdp->rgdispidNamedArgs[index] );
1414     }
1415 
1416     if (pdp->cArgs && pdp->rgvarg)
1417     {
1418         TRACE("args:\n");
1419         for (index = 0; index < pdp->cArgs; index++)
1420             dump_Variant( &pdp->rgvarg[index] );
1421     }
1422 }
1423 
1424 static void dump_TypeInfo(const ITypeInfoImpl * pty)
1425 {
1426     TRACE("%p ref=%u\n", pty, pty->ref);
1427     TRACE("%s %s\n", debugstr_w(pty->Name), debugstr_w(pty->DocString));
1428     TRACE("attr:%s\n", debugstr_guid(&(pty->TypeAttr.guid)));
1429     TRACE("kind:%s\n", typekind_desc[pty->TypeAttr.typekind]);
1430     TRACE("fct:%u var:%u impl:%u\n",
1431       pty->TypeAttr.cFuncs, pty->TypeAttr.cVars, pty->TypeAttr.cImplTypes);
1432     TRACE("wTypeFlags: 0x%04x\n", pty->TypeAttr.wTypeFlags);
1433     TRACE("parent tlb:%p index in TLB:%u\n",pty->pTypeLib, pty->index);
1434     if (pty->TypeAttr.typekind == TKIND_MODULE) TRACE("dllname:%s\n", debugstr_w(pty->DllName));
1435     if (TRACE_ON(ole))
1436         dump_TLBFuncDesc(pty->funclist);
1437     dump_TLBVarDesc(pty->varlist);
1438     dump_TLBImplType(pty->impltypelist);
1439 }
1440 
1441 static void dump_VARDESC(const VARDESC *v)
1442 {
1443     MESSAGE("memid %d\n",v->memid);
1444     MESSAGE("lpstrSchema %s\n",debugstr_w(v->lpstrSchema));
1445     MESSAGE("oInst %d\n",v->u.oInst);
1446     dump_ELEMDESC(&(v->elemdescVar));
1447     MESSAGE("wVarFlags %x\n",v->wVarFlags);
1448     MESSAGE("varkind %d\n",v->varkind);
1449 }
1450 
1451 static TYPEDESC std_typedesc[VT_LPWSTR+1] =
1452 {
1453     /* VT_LPWSTR is largest type that, may appear in type description */
1454     {{0}, VT_EMPTY},  {{0}, VT_NULL},        {{0}, VT_I2},      {{0}, VT_I4},
1455     {{0}, VT_R4},     {{0}, VT_R8},          {{0}, VT_CY},      {{0}, VT_DATE},
1456     {{0}, VT_BSTR},   {{0}, VT_DISPATCH},    {{0}, VT_ERROR},   {{0}, VT_BOOL},
1457     {{0}, VT_VARIANT},{{0}, VT_UNKNOWN},     {{0}, VT_DECIMAL}, {{0}, 15}, /* unused in VARENUM */
1458     {{0}, VT_I1},     {{0}, VT_UI1},         {{0}, VT_UI2},     {{0}, VT_UI4},
1459     {{0}, VT_I8},     {{0}, VT_UI8},         {{0}, VT_INT},     {{0}, VT_UINT},
1460     {{0}, VT_VOID},   {{0}, VT_HRESULT},     {{0}, VT_PTR},     {{0}, VT_SAFEARRAY},
1461     {{0}, VT_CARRAY}, {{0}, VT_USERDEFINED}, {{0}, VT_LPSTR},   {{0}, VT_LPWSTR}
1462 };
1463 
1464 static void TLB_abort(void)
1465 {
1466     DebugBreak();
1467 }
1468 
1469 void* __WINE_ALLOC_SIZE(1) heap_alloc_zero(unsigned size)
1470 {
1471     void *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
1472     if (!ret) ERR("cannot allocate memory\n");
1473     return ret;
1474 }
1475 
1476 void* __WINE_ALLOC_SIZE(1) heap_alloc(unsigned size)
1477 {
1478     void *ret = HeapAlloc(GetProcessHeap(), 0, size);
1479     if (!ret) ERR("cannot allocate memory\n");
1480     return ret;
1481 }
1482 
1483 void* __WINE_ALLOC_SIZE(2) heap_realloc(void *ptr, unsigned size)
1484 {
1485     return HeapReAlloc(GetProcessHeap(), 0, ptr, size);
1486 }
1487 
1488 void heap_free(void *ptr)
1489 {
1490     HeapFree(GetProcessHeap(), 0, ptr);
1491 }
1492 
1493 /* returns the size required for a deep copy of a typedesc into a
1494  * flat buffer */
1495 static SIZE_T TLB_SizeTypeDesc( const TYPEDESC *tdesc, BOOL alloc_initial_space )
1496 {
1497     SIZE_T size = 0;
1498 
1499     if (alloc_initial_space)
1500         size += sizeof(TYPEDESC);
1501 
1502     switch (tdesc->vt)
1503     {
1504     case VT_PTR:
1505     case VT_SAFEARRAY:
1506         size += TLB_SizeTypeDesc(tdesc->u.lptdesc, TRUE);
1507         break;
1508     case VT_CARRAY:
1509         size += FIELD_OFFSET(ARRAYDESC, rgbounds[tdesc->u.lpadesc->cDims]);
1510         size += TLB_SizeTypeDesc(&tdesc->u.lpadesc->tdescElem, FALSE);
1511         break;
1512     }
1513     return size;
1514 }
1515 
1516 /* deep copy a typedesc into a flat buffer */
1517 static void *TLB_CopyTypeDesc( TYPEDESC *dest, const TYPEDESC *src, void *buffer )
1518 {
1519     if (!dest)
1520     {
1521         dest = buffer;
1522         buffer = (char *)buffer + sizeof(TYPEDESC);
1523     }
1524 
1525     *dest = *src;
1526 
1527     switch (src->vt)
1528     {
1529     case VT_PTR:
1530     case VT_SAFEARRAY:
1531         dest->u.lptdesc = buffer;
1532         buffer = TLB_CopyTypeDesc(NULL, src->u.lptdesc, buffer);
1533         break;
1534     case VT_CARRAY:
1535         dest->u.lpadesc = buffer;
1536         memcpy(dest->u.lpadesc, src->u.lpadesc, FIELD_OFFSET(ARRAYDESC, rgbounds[src->u.lpadesc->cDims]));
1537         buffer = (char *)buffer + FIELD_OFFSET(ARRAYDESC, rgbounds[src->u.lpadesc->cDims]);
1538         buffer = TLB_CopyTypeDesc(&dest->u.lpadesc->tdescElem, &src->u.lpadesc->tdescElem, buffer);
1539         break;
1540     }
1541     return buffer;
1542 }
1543 
1544 /* free custom data allocated by MSFT_CustData */
1545 static inline void TLB_FreeCustData(TLBCustData *pCustData)
1546 {
1547     TLBCustData *pCustDataNext;
1548     for (; pCustData; pCustData = pCustDataNext)
1549     {
1550         VariantClear(&pCustData->data);
1551 
1552         pCustDataNext = pCustData->next;
1553         heap_free(pCustData);
1554     }
1555 }
1556 
1557 static BSTR TLB_MultiByteToBSTR(const char *ptr)
1558 {
1559     DWORD len;
1560     BSTR ret;
1561 
1562     len = MultiByteToWideChar(CP_ACP, 0, ptr, -1, NULL, 0);
1563     ret = SysAllocStringLen(NULL, len - 1);
1564     if (!ret) return ret;
1565     MultiByteToWideChar(CP_ACP, 0, ptr, -1, ret, len);
1566     return ret;
1567 }
1568 
1569 /**********************************************************************
1570  *
1571  *  Functions for reading MSFT typelibs (those created by CreateTypeLib2)
1572  */
1573 static inline unsigned int MSFT_Tell(const TLBContext *pcx)
1574 {
1575     return pcx->pos;
1576 }
1577 
1578 static inline void MSFT_Seek(TLBContext *pcx, LONG where)
1579 {
1580     if (where != DO_NOT_SEEK)
1581     {
1582         where += pcx->oStart;
1583         if (where > pcx->length)
1584         {
1585             /* FIXME */
1586             ERR("seek beyond end (%d/%d)\n", where, pcx->length );
1587             TLB_abort();
1588         }
1589         pcx->pos = where;
1590     }
1591 }
1592 
1593 /* read function */
1594 static DWORD MSFT_Read(void *buffer,  DWORD count, TLBContext *pcx, LONG where )
1595 {
1596     TRACE_(typelib)("pos=0x%08x len=0x%08x 0x%08x 0x%08x 0x%08x\n",
1597        pcx->pos, count, pcx->oStart, pcx->length, where);
1598 
1599     MSFT_Seek(pcx, where);
1600     if (pcx->pos + count > pcx->length) count = pcx->length - pcx->pos;
1601     memcpy( buffer, (char *)pcx->mapping + pcx->pos, count );
1602     pcx->pos += count;
1603     return count;
1604 }
1605 
1606 static DWORD MSFT_ReadLEDWords(void *buffer,  DWORD count, TLBContext *pcx,
1607                                LONG where )
1608 {
1609   DWORD ret;
1610 
1611   ret = MSFT_Read(buffer, count, pcx, where);
1612   FromLEDWords(buffer, ret);
1613 
1614   return ret;
1615 }
1616 
1617 static DWORD MSFT_ReadLEWords(void *buffer,  DWORD count, TLBContext *pcx,
1618                               LONG where )
1619 {
1620   DWORD ret;
1621 
1622   ret = MSFT_Read(buffer, count, pcx, where);
1623   FromLEWords(buffer, ret);
1624 
1625   return ret;
1626 }
1627 
1628 static void MSFT_ReadGuid( GUID *pGuid, int offset, TLBContext *pcx)
1629 {
1630     if(offset<0 || pcx->pTblDir->pGuidTab.offset <0){
1631         memset(pGuid,0, sizeof(GUID));
1632         return;
1633     }
1634     MSFT_Read(pGuid, sizeof(GUID), pcx, pcx->pTblDir->pGuidTab.offset+offset );
1635     pGuid->Data1 = FromLEDWord(pGuid->Data1);
1636     pGuid->Data2 = FromLEWord(pGuid->Data2);
1637     pGuid->Data3 = FromLEWord(pGuid->Data3);
1638     TRACE_(typelib)("%s\n", debugstr_guid(pGuid));
1639 }
1640 
1641 static HREFTYPE MSFT_ReadHreftype( TLBContext *pcx, int offset )
1642 {
1643     MSFT_NameIntro niName;
1644 
1645     if (offset < 0)
1646     {
1647         ERR_(typelib)("bad offset %d\n", offset);
1648         return -1;
1649     }
1650 
1651     MSFT_ReadLEDWords(&niName, sizeof(niName), pcx,
1652                       pcx->pTblDir->pNametab.offset+offset);
1653 
1654     return niName.hreftype;
1655 }
1656 
1657 static BSTR MSFT_ReadName( TLBContext *pcx, int offset)
1658 {
1659     char * name;
1660     MSFT_NameIntro niName;
1661     int lengthInChars;
1662     BSTR bstrName = NULL;
1663 
1664     if (offset < 0)
1665     {
1666         ERR_(typelib)("bad offset %d\n", offset);
1667         return NULL;
1668     }
1669     MSFT_ReadLEDWords(&niName, sizeof(niName), pcx,
1670                       pcx->pTblDir->pNametab.offset+offset);
1671     niName.namelen &= 0xFF; /* FIXME: correct ? */
1672     name = heap_alloc_zero((niName.namelen & 0xff) +1);
1673     MSFT_Read(name, (niName.namelen & 0xff), pcx, DO_NOT_SEEK);
1674     name[niName.namelen & 0xff]='\0';
1675 
1676     lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
1677                                         name, -1, NULL, 0);
1678 
1679     /* no invalid characters in string */
1680     if (lengthInChars)
1681     {
1682         bstrName = SysAllocStringByteLen(NULL, lengthInChars * sizeof(WCHAR));
1683 
1684         /* don't check for invalid character since this has been done previously */
1685         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name, -1, bstrName, lengthInChars);
1686     }
1687     heap_free(name);
1688 
1689     TRACE_(typelib)("%s %d\n", debugstr_w(bstrName), lengthInChars);
1690     return bstrName;
1691 }
1692 
1693 static BSTR MSFT_ReadString( TLBContext *pcx, int offset)
1694 {
1695     char * string;
1696     INT16 length;
1697     int lengthInChars;
1698     BSTR bstr = NULL;
1699 
1700     if(offset<0) return NULL;
1701     MSFT_ReadLEWords(&length, sizeof(INT16), pcx, pcx->pTblDir->pStringtab.offset+offset);
1702     if(length <= 0) return 0;
1703     string = heap_alloc_zero(length +1);
1704     MSFT_Read(string, length, pcx, DO_NOT_SEEK);
1705     string[length]='\0';
1706 
1707     lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
1708                                         string, -1, NULL, 0);
1709 
1710     /* no invalid characters in string */
1711     if (lengthInChars)
1712     {
1713         bstr = SysAllocStringByteLen(NULL, lengthInChars * sizeof(WCHAR));
1714 
1715         /* don't check for invalid character since this has been done previously */
1716         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, string, -1, bstr, lengthInChars);
1717     }
1718     heap_free(string);
1719 
1720     TRACE_(typelib)("%s %d\n", debugstr_w(bstr), lengthInChars);
1721     return bstr;
1722 }
1723 /*
1724  * read a value and fill a VARIANT structure
1725  */
1726 static void MSFT_ReadValue( VARIANT * pVar, int offset, TLBContext *pcx )
1727 {
1728     int size;
1729 
1730     TRACE_(typelib)("\n");
1731 
1732     if(offset <0) { /* data are packed in here */
1733         V_VT(pVar) = (offset & 0x7c000000 )>> 26;
1734         V_I4(pVar) = offset & 0x3ffffff;
1735         return;
1736     }
1737     MSFT_ReadLEWords(&(V_VT(pVar)), sizeof(VARTYPE), pcx,
1738                      pcx->pTblDir->pCustData.offset + offset );
1739     TRACE_(typelib)("Vartype = %x\n", V_VT(pVar));
1740     switch (V_VT(pVar)){
1741         case VT_EMPTY:  /* FIXME: is this right? */
1742         case VT_NULL:   /* FIXME: is this right? */
1743         case VT_I2  :   /* this should not happen */
1744         case VT_I4  :
1745         case VT_R4  :
1746         case VT_ERROR   :
1747         case VT_BOOL    :
1748         case VT_I1  :
1749         case VT_UI1 :
1750         case VT_UI2 :
1751         case VT_UI4 :
1752         case VT_INT :
1753         case VT_UINT    :
1754         case VT_VOID    : /* FIXME: is this right? */
1755         case VT_HRESULT :
1756             size=4; break;
1757         case VT_R8  :
1758         case VT_CY  :
1759         case VT_DATE    :
1760         case VT_I8  :
1761         case VT_UI8 :
1762         case VT_DECIMAL :  /* FIXME: is this right? */
1763         case VT_FILETIME :
1764             size=8;break;
1765             /* pointer types with known behaviour */
1766         case VT_BSTR    :{
1767             char * ptr;
1768             MSFT_ReadLEDWords(&size, sizeof(INT), pcx, DO_NOT_SEEK );
1769             if(size < 0) {
1770                 char next;
1771                 DWORD origPos = MSFT_Tell(pcx), nullPos;
1772 
1773                 do {
1774                     MSFT_Read(&next, 1, pcx, DO_NOT_SEEK);
1775                 } while (next);
1776                 nullPos = MSFT_Tell(pcx);
1777                 size = nullPos - origPos;
1778                 MSFT_Seek(pcx, origPos);
1779             }
1780             ptr = heap_alloc_zero(size);/* allocate temp buffer */
1781             MSFT_Read(ptr, size, pcx, DO_NOT_SEEK);/* read string (ANSI) */
1782             V_BSTR(pVar)=SysAllocStringLen(NULL,size);
1783             /* FIXME: do we need a AtoW conversion here? */
1784             V_UNION(pVar, bstrVal[size])='\0';
1785             while(size--) V_UNION(pVar, bstrVal[size])=ptr[size];
1786             heap_free(ptr);
1787         }
1788         size=-4; break;
1789     /* FIXME: this will not work AT ALL when the variant contains a pointer */
1790         case VT_DISPATCH :
1791         case VT_VARIANT :
1792         case VT_UNKNOWN :
1793         case VT_PTR :
1794         case VT_SAFEARRAY :
1795         case VT_CARRAY  :
1796         case VT_USERDEFINED :
1797         case VT_LPSTR   :
1798         case VT_LPWSTR  :
1799         case VT_BLOB    :
1800         case VT_STREAM  :
1801         case VT_STORAGE :
1802         case VT_STREAMED_OBJECT :
1803         case VT_STORED_OBJECT   :
1804         case VT_BLOB_OBJECT :
1805         case VT_CF  :
1806         case VT_CLSID   :
1807         default:
1808             size=0;
1809             FIXME("VARTYPE %d is not supported, setting pointer to NULL\n",
1810                 V_VT(pVar));
1811     }
1812 
1813     if(size>0) /* (big|small) endian correct? */
1814         MSFT_Read(&(V_I2(pVar)), size, pcx, DO_NOT_SEEK );
1815     return;
1816 }
1817 /*
1818  * create a linked list with custom data
1819  */
1820 static int MSFT_CustData( TLBContext *pcx, int offset, TLBCustData** ppCustData )
1821 {
1822     MSFT_CDGuid entry;
1823     TLBCustData* pNew;
1824     int count=0;
1825 
1826     TRACE_(typelib)("\n");
1827 
1828     while(offset >=0){
1829         count++;
1830         pNew=heap_alloc_zero(sizeof(TLBCustData));
1831         MSFT_ReadLEDWords(&entry, sizeof(entry), pcx, pcx->pTblDir->pCDGuids.offset+offset);
1832         MSFT_ReadGuid(&(pNew->guid), entry.GuidOffset , pcx);
1833         MSFT_ReadValue(&(pNew->data), entry.DataOffset, pcx);
1834         /* add new custom data at head of the list */
1835         pNew->next=*ppCustData;
1836         *ppCustData=pNew;
1837         offset = entry.next;
1838     }
1839     return count;
1840 }
1841 
1842 static void MSFT_GetTdesc(TLBContext *pcx, INT type, TYPEDESC *pTd,
1843                           ITypeInfoImpl *pTI)
1844 {
1845     if(type <0)
1846         pTd->vt=type & VT_TYPEMASK;
1847     else
1848         *pTd=pcx->pLibInfo->pTypeDesc[type/(2*sizeof(INT))];
1849 
1850     if(pTd->vt == VT_USERDEFINED)
1851       MSFT_DoRefType(pcx, pTI->pTypeLib, pTd->u.hreftype);
1852 
1853     TRACE_(typelib)("vt type = %X\n", pTd->vt);
1854 }
1855 
1856 static void MSFT_ResolveReferencedTypes(TLBContext *pcx, ITypeInfoImpl *pTI, TYPEDESC *lpTypeDesc)
1857 {
1858     /* resolve referenced type if any */
1859     while (lpTypeDesc)
1860     {
1861         switch (lpTypeDesc->vt)
1862         {
1863         case VT_PTR:
1864             lpTypeDesc = lpTypeDesc->u.lptdesc;
1865             break;
1866 
1867         case VT_CARRAY:
1868             lpTypeDesc = & (lpTypeDesc->u.lpadesc->tdescElem);
1869             break;
1870 
1871         case VT_USERDEFINED:
1872             MSFT_DoRefType(pcx, pTI->pTypeLib,
1873                            lpTypeDesc->u.hreftype);
1874 
1875             lpTypeDesc = NULL;
1876             break;
1877 
1878         default:
1879             lpTypeDesc = NULL;
1880         }
1881     }
1882 }
1883 
1884 static void
1885 MSFT_DoFuncs(TLBContext*     pcx,
1886             ITypeInfoImpl*  pTI,
1887             int             cFuncs,
1888             int             cVars,
1889             int             offset,
1890             TLBFuncDesc**   pptfd)
1891 {
1892     /*
1893      * member information is stored in a data structure at offset
1894      * indicated by the memoffset field of the typeinfo structure
1895      * There are several distinctive parts.
1896      * The first part starts with a field that holds the total length
1897      * of this (first) part excluding this field. Then follow the records,
1898      * for each member there is one record.
1899      *
1900      * The first entry is always the length of the record (including this
1901      * length word).
1902      * The rest of the record depends on the type of the member. If there is
1903      * a field indicating the member type (function, variable, interface, etc)
1904      * I have not found it yet. At this time we depend on the information
1905      * in the type info and the usual order how things are stored.
1906      *
1907      * Second follows an array sized nrMEM*sizeof(INT) with a member id
1908      * for each member;
1909      *
1910      * Third is an equal sized array with file offsets to the name entry
1911      * of each member.
1912      *
1913      * The fourth and last (?) part is an array with offsets to the records
1914      * in the first part of this file segment.
1915      */
1916 
1917     int infolen, nameoffset, reclength, i;
1918     int recoffset = offset + sizeof(INT);
1919 
1920     char *recbuf = heap_alloc(0xffff);
1921     MSFT_FuncRecord *pFuncRec = (MSFT_FuncRecord*)recbuf;
1922     TLBFuncDesc *ptfd_prev = NULL;
1923 
1924     TRACE_(typelib)("\n");
1925 
1926     MSFT_ReadLEDWords(&infolen, sizeof(INT), pcx, offset);
1927 
1928     for ( i = 0; i < cFuncs ; i++ )
1929     {
1930         int optional;
1931 
1932         *pptfd = heap_alloc_zero(sizeof(TLBFuncDesc));
1933 
1934         /* name, eventually add to a hash table */
1935         MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx,
1936                           offset + infolen + (cFuncs + cVars + i + 1) * sizeof(INT));
1937 
1938         /* nameoffset is sometimes -1 on the second half of a propget/propput
1939          * pair of functions */
1940         if ((nameoffset == -1) && (i > 0))
1941             (*pptfd)->Name = SysAllocString(ptfd_prev->Name);
1942         else
1943             (*pptfd)->Name = MSFT_ReadName(pcx, nameoffset);
1944 
1945         /* read the function information record */
1946         MSFT_ReadLEDWords(&reclength, sizeof(pFuncRec->Info), pcx, recoffset);
1947 
1948         reclength &= 0xffff;
1949 
1950         MSFT_ReadLEDWords(&pFuncRec->DataType, reclength - FIELD_OFFSET(MSFT_FuncRecord, DataType), pcx, DO_NOT_SEEK);
1951 
1952         /* size without argument data */
1953         optional = reclength - pFuncRec->nrargs*sizeof(MSFT_ParameterInfo);
1954 
1955         if (optional > FIELD_OFFSET(MSFT_FuncRecord, HelpContext))
1956             (*pptfd)->helpcontext = pFuncRec->HelpContext;
1957 
1958         if (optional > FIELD_OFFSET(MSFT_FuncRecord, oHelpString))
1959             (*pptfd)->HelpString = MSFT_ReadString(pcx, pFuncRec->oHelpString);
1960 
1961         if (optional > FIELD_OFFSET(MSFT_FuncRecord, oEntry))
1962         {
1963             if (pFuncRec->FKCCIC & 0x2000 )
1964             {
1965                 if (!IS_INTRESOURCE(pFuncRec->oEntry))
1966                     ERR("ordinal 0x%08x invalid, IS_INTRESOURCE is false\n", pFuncRec->oEntry);
1967                 (*pptfd)->Entry = (BSTR)(DWORD_PTR)LOWORD(pFuncRec->oEntry);
1968             }
1969             else
1970                 (*pptfd)->Entry = MSFT_ReadString(pcx, pFuncRec->oEntry);
1971         }
1972         else
1973             (*pptfd)->Entry = (BSTR)-1;
1974 
1975         if (optional > FIELD_OFFSET(MSFT_FuncRecord, HelpStringContext))
1976             (*pptfd)->HelpStringContext = pFuncRec->HelpStringContext;
1977 
1978         if (optional > FIELD_OFFSET(MSFT_FuncRecord, oCustData) && pFuncRec->FKCCIC & 0x80)
1979             MSFT_CustData(pcx, pFuncRec->oCustData, &(*pptfd)->pCustData);
1980 
1981         /* fill the FuncDesc Structure */
1982         MSFT_ReadLEDWords( & (*pptfd)->funcdesc.memid, sizeof(INT), pcx,
1983                            offset + infolen + ( i + 1) * sizeof(INT));
1984 
1985         (*pptfd)->funcdesc.funckind   =  (pFuncRec->FKCCIC)      & 0x7;
1986         (*pptfd)->funcdesc.invkind    =  (pFuncRec->FKCCIC) >> 3 & 0xF;
1987         (*pptfd)->funcdesc.callconv   =  (pFuncRec->FKCCIC) >> 8 & 0xF;
1988         (*pptfd)->funcdesc.cParams    =   pFuncRec->nrargs  ;
1989         (*pptfd)->funcdesc.cParamsOpt =   pFuncRec->nroargs ;
1990         (*pptfd)->funcdesc.oVft       =   pFuncRec->VtableOffset;
1991         (*pptfd)->funcdesc.wFuncFlags =   LOWORD(pFuncRec->Flags) ;
1992 
1993         MSFT_GetTdesc(pcx,
1994                       pFuncRec->DataType,
1995                       &(*pptfd)->funcdesc.elemdescFunc.tdesc,
1996                       pTI);
1997         MSFT_ResolveReferencedTypes(pcx, pTI, &(*pptfd)->funcdesc.elemdescFunc.tdesc);
1998 
1999         /* do the parameters/arguments */
2000         if(pFuncRec->nrargs)
2001         {
2002             int j = 0;
2003             MSFT_ParameterInfo paraminfo;
2004 
2005             (*pptfd)->funcdesc.lprgelemdescParam =
2006                 heap_alloc_zero(pFuncRec->nrargs * sizeof(ELEMDESC));
2007 
2008             (*pptfd)->pParamDesc =
2009                 heap_alloc_zero(pFuncRec->nrargs * sizeof(TLBParDesc));
2010 
2011             MSFT_ReadLEDWords(&paraminfo, sizeof(paraminfo), pcx,
2012                               recoffset + reclength - pFuncRec->nrargs * sizeof(MSFT_ParameterInfo));
2013 
2014             for ( j = 0 ; j < pFuncRec->nrargs ; j++ )
2015             {
2016                 ELEMDESC *elemdesc = &(*pptfd)->funcdesc.lprgelemdescParam[j];
2017 
2018                 MSFT_GetTdesc(pcx,
2019                               paraminfo.DataType,
2020                               &elemdesc->tdesc,
2021                               pTI);
2022 
2023                 elemdesc->u.paramdesc.wParamFlags = paraminfo.Flags;
2024 
2025                 /* name */
2026                 if (paraminfo.oName == -1)
2027                     /* this occurs for [propput] or [propget] methods, so
2028                      * we should just set the name of the parameter to the
2029                      * name of the method. */
2030                     (*pptfd)->pParamDesc[j].Name = SysAllocString((*pptfd)->Name);
2031                 else
2032                     (*pptfd)->pParamDesc[j].Name =
2033                         MSFT_ReadName( pcx, paraminfo.oName );
2034                 TRACE_(typelib)("param[%d] = %s\n", j, debugstr_w((*pptfd)->pParamDesc[j].Name));
2035 
2036                 MSFT_ResolveReferencedTypes(pcx, pTI, &elemdesc->tdesc);
2037 
2038                 /* default value */
2039                 if ( (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) &&
2040                      (pFuncRec->FKCCIC & 0x1000) )
2041                 {
2042                     INT* pInt = (INT *)((char *)pFuncRec +
2043                                    reclength -
2044                                    (pFuncRec->nrargs * 4) * sizeof(INT) );
2045 
2046                     PARAMDESC* pParamDesc = &elemdesc->u.paramdesc;
2047 
2048                     pParamDesc->pparamdescex = heap_alloc_zero(sizeof(PARAMDESCEX));
2049                     pParamDesc->pparamdescex->cBytes = sizeof(PARAMDESCEX);
2050 
2051                     MSFT_ReadValue(&(pParamDesc->pparamdescex->varDefaultValue),
2052                         pInt[j], pcx);
2053                 }
2054                 else
2055                     elemdesc->u.paramdesc.pparamdescex = NULL;
2056 
2057                 /* custom info */
2058                 if (optional > (FIELD_OFFSET(MSFT_FuncRecord, oArgCustData) +
2059                                 j*sizeof(pFuncRec->oArgCustData[0])) &&
2060                     pFuncRec->FKCCIC & 0x80 )
2061                 {
2062                     MSFT_CustData(pcx,
2063                                   pFuncRec->oArgCustData[j],
2064                                   &(*pptfd)->pParamDesc[j].pCustData);
2065                 }
2066 
2067                 /* SEEK value = jump to offset,
2068                  * from there jump to the end of record,
2069                  * go back by (j-1) arguments
2070                  */
2071                 MSFT_ReadLEDWords( &paraminfo ,
2072                            sizeof(MSFT_ParameterInfo), pcx,
2073                            recoffset + reclength - ((pFuncRec->nrargs - j - 1)
2074                                                * sizeof(MSFT_ParameterInfo)));
2075             }
2076         }
2077 
2078         /* scode is not used: archaic win16 stuff FIXME: right? */
2079         (*pptfd)->funcdesc.cScodes   = 0 ;
2080         (*pptfd)->funcdesc.lprgscode = NULL ;
2081 
2082         ptfd_prev = *pptfd;
2083         pptfd      = & ((*pptfd)->next);
2084         recoffset += reclength;
2085     }
2086     heap_free(recbuf);
2087 }
2088 
2089 static void MSFT_DoVars(TLBContext *pcx, ITypeInfoImpl *pTI, int cFuncs,
2090                        int cVars, int offset, TLBVarDesc ** pptvd)
2091 {
2092     int infolen, nameoffset, reclength;
2093     char recbuf[256];
2094     MSFT_VarRecord *pVarRec = (MSFT_VarRecord*)recbuf;
2095     int i;
2096     int recoffset;
2097 
2098     TRACE_(typelib)("\n");
2099 
2100     MSFT_ReadLEDWords(&infolen,sizeof(INT), pcx, offset);
2101     MSFT_ReadLEDWords(&recoffset,sizeof(INT), pcx, offset + infolen +
2102                       ((cFuncs+cVars)*2+cFuncs + 1)*sizeof(INT));
2103     recoffset += offset+sizeof(INT);
2104     for(i=0;i<cVars;i++){
2105         *pptvd = heap_alloc_zero(sizeof(TLBVarDesc));
2106     /* name, eventually add to a hash table */
2107         MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx,
2108                           offset + infolen + (2*cFuncs + cVars + i + 1) * sizeof(INT));
2109         (*pptvd)->Name=MSFT_ReadName(pcx, nameoffset);
2110     /* read the variable information record */
2111         MSFT_ReadLEDWords(&reclength, sizeof(pVarRec->Info), pcx, recoffset);
2112         reclength &= 0xff;
2113         MSFT_ReadLEDWords(&pVarRec->DataType, reclength - FIELD_OFFSET(MSFT_VarRecord, DataType), pcx, DO_NOT_SEEK);
2114 
2115         /* optional data */
2116         if(reclength > FIELD_OFFSET(MSFT_VarRecord, HelpContext))
2117             (*pptvd)->HelpContext = pVarRec->HelpContext;
2118 
2119         if(reclength > FIELD_OFFSET(MSFT_VarRecord, HelpString))
2120             (*pptvd)->HelpString = MSFT_ReadString(pcx, pVarRec->HelpString);
2121 
2122         if(reclength > FIELD_OFFSET(MSFT_VarRecord, HelpStringContext))
2123             (*pptvd)->HelpStringContext = pVarRec->HelpStringContext;
2124 
2125     /* fill the VarDesc Structure */
2126         MSFT_ReadLEDWords(&(*pptvd)->vardesc.memid, sizeof(INT), pcx,
2127                           offset + infolen + (cFuncs + i + 1) * sizeof(INT));
2128         (*pptvd)->vardesc.varkind = pVarRec->VarKind;
2129         (*pptvd)->vardesc.wVarFlags = pVarRec->Flags;
2130         MSFT_GetTdesc(pcx, pVarRec->DataType,
2131             &(*pptvd)->vardesc.elemdescVar.tdesc, pTI);
2132 /*   (*pptvd)->vardesc.lpstrSchema; is reserved (SDK) FIXME?? */
2133         if(pVarRec->VarKind == VAR_CONST ){
2134             (*pptvd)->vardesc.u.lpvarValue = heap_alloc_zero(sizeof(VARIANT));
2135             MSFT_ReadValue((*pptvd)->vardesc.u.lpvarValue,
2136                 pVarRec->OffsValue, pcx);
2137         } else
2138             (*pptvd)->vardesc.u.oInst=pVarRec->OffsValue;
2139         MSFT_ResolveReferencedTypes(pcx, pTI, &(*pptvd)->vardesc.elemdescVar.tdesc);
2140         pptvd=&((*pptvd)->next);
2141         recoffset += reclength;
2142     }
2143 }
2144 /* fill in data for a hreftype (offset). When the referenced type is contained
2145  * in the typelib, it's just an (file) offset in the type info base dir.
2146  * If comes from import, it's an offset+1 in the ImpInfo table
2147  * */
2148 static void MSFT_DoRefType(TLBContext *pcx, ITypeLibImpl *pTL,
2149                           int offset)
2150 {
2151     TLBRefType *ref;
2152 
2153     TRACE_(typelib)("TLB context %p, TLB offset %x\n", pcx, offset);
2154 
2155     LIST_FOR_EACH_ENTRY(ref, &pTL->ref_list, TLBRefType, entry)
2156     {
2157         if(ref->reference == offset) return;
2158     }
2159 
2160     ref = heap_alloc_zero(sizeof(TLBRefType));
2161     list_add_tail(&pTL->ref_list, &ref->entry);
2162 
2163     if(!MSFT_HREFTYPE_INTHISFILE( offset)) {
2164         /* external typelib */
2165         MSFT_ImpInfo impinfo;
2166         TLBImpLib *pImpLib=(pcx->pLibInfo->pImpLibs);
2167 
2168         TRACE_(typelib)("offset %x, masked offset %x\n", offset, offset + (offset & 0xfffffffc));
2169 
2170         MSFT_ReadLEDWords(&impinfo, sizeof(impinfo), pcx,
2171                           pcx->pTblDir->pImpInfo.offset + (offset & 0xfffffffc));
2172         while (pImpLib){   /* search the known offsets of all import libraries */
2173             if(pImpLib->offset==impinfo.oImpFile) break;
2174             pImpLib=pImpLib->next;
2175         }
2176         if(pImpLib){
2177             ref->reference = offset;
2178             ref->pImpTLInfo = pImpLib;
2179             if(impinfo.flags & MSFT_IMPINFO_OFFSET_IS_GUID) {
2180                 MSFT_ReadGuid(&ref->guid, impinfo.oGuid, pcx);
2181                 TRACE("importing by guid %s\n", debugstr_guid(&ref->guid));
2182                 ref->index = TLB_REF_USE_GUID;
2183             } else
2184                 ref->index = impinfo.oGuid;
2185         }else{
2186             ERR("Cannot find a reference\n");
2187             ref->reference = -1;
2188             ref->pImpTLInfo = TLB_REF_NOT_FOUND;
2189         }
2190     }else{
2191         /* in this typelib */
2192         ref->index = MSFT_HREFTYPE_INDEX(offset);
2193         ref->reference = offset;
2194         ref->pImpTLInfo = TLB_REF_INTERNAL;
2195     }
2196 }
2197 
2198 /* process Implemented Interfaces of a com class */
2199 static void MSFT_DoImplTypes(TLBContext *pcx, ITypeInfoImpl *pTI, int count,
2200                             int offset)
2201 {
2202     int i;
2203     MSFT_RefRecord refrec;
2204     TLBImplType **ppImpl = &pTI->impltypelist;
2205 
2206     TRACE_(typelib)("\n");
2207 
2208     for(i=0;i<count;i++){
2209         if(offset<0) break; /* paranoia */
2210         *ppImpl = heap_alloc_zero(sizeof(**ppImpl));
2211         MSFT_ReadLEDWords(&refrec,sizeof(refrec),pcx,offset+pcx->pTblDir->pRefTab.offset);
2212         MSFT_DoRefType(pcx, pTI->pTypeLib, refrec.reftype);
2213         (*ppImpl)->hRef = refrec.reftype;
2214         (*ppImpl)->implflags=refrec.flags;
2215         (*ppImpl)->ctCustData=
2216             MSFT_CustData(pcx, refrec.oCustData, &(*ppImpl)->pCustData);
2217         offset=refrec.onext;
2218         ppImpl=&((*ppImpl)->next);
2219     }
2220 }
2221 /*
2222  * process a typeinfo record
2223  */
2224 static ITypeInfoImpl * MSFT_DoTypeInfo(
2225     TLBContext *pcx,
2226     int count,
2227     ITypeLibImpl * pLibInfo)
2228 {
2229     MSFT_TypeInfoBase tiBase;
2230     ITypeInfoImpl *ptiRet;
2231 
2232     TRACE_(typelib)("count=%u\n", count);
2233 
2234     ptiRet = ITypeInfoImpl_Constructor();
2235     MSFT_ReadLEDWords(&tiBase, sizeof(tiBase) ,pcx ,
2236                       pcx->pTblDir->pTypeInfoTab.offset+count*sizeof(tiBase));
2237 
2238 /* this is where we are coming from */
2239     ptiRet->pTypeLib = pLibInfo;
2240     ptiRet->index=count;
2241 /* fill in the typeattr fields */
2242 
2243     MSFT_ReadGuid(&ptiRet->TypeAttr.guid, tiBase.posguid, pcx);
2244     ptiRet->TypeAttr.lcid=pLibInfo->LibAttr.lcid;   /* FIXME: correct? */
2245     ptiRet->TypeAttr.lpstrSchema=NULL;              /* reserved */
2246     ptiRet->TypeAttr.cbSizeInstance=tiBase.size;
2247     ptiRet->TypeAttr.typekind=tiBase.typekind & 0xF;
2248     ptiRet->TypeAttr.cFuncs=LOWORD(tiBase.cElement);
2249     ptiRet->TypeAttr.cVars=HIWORD(tiBase.cElement);
2250     ptiRet->TypeAttr.cbAlignment=(tiBase.typekind >> 11 )& 0x1F; /* there are more flags there */
2251     ptiRet->TypeAttr.wTypeFlags=tiBase.flags;
2252     ptiRet->TypeAttr.wMajorVerNum=LOWORD(tiBase.version);
2253     ptiRet->TypeAttr.wMinorVerNum=HIWORD(tiBase.version);
2254     ptiRet->TypeAttr.cImplTypes=tiBase.cImplTypes;
2255     ptiRet->TypeAttr.cbSizeVft=tiBase.cbSizeVft; /* FIXME: this is only the non inherited part */
2256     if(ptiRet->TypeAttr.typekind == TKIND_ALIAS)
2257         MSFT_GetTdesc(pcx, tiBase.datatype1,
2258             &ptiRet->TypeAttr.tdescAlias, ptiRet);
2259 
2260 /*  FIXME: */
2261 /*    IDLDESC  idldescType; *//* never saw this one != zero  */
2262 
2263 /* name, eventually add to a hash table */
2264     ptiRet->Name=MSFT_ReadName(pcx, tiBase.NameOffset);
2265     ptiRet->hreftype = MSFT_ReadHreftype(pcx, tiBase.NameOffset);
2266     TRACE_(typelib)("reading %s\n", debugstr_w(ptiRet->Name));
2267     /* help info */
2268     ptiRet->DocString=MSFT_ReadString(pcx, tiBase.docstringoffs);
2269     ptiRet->dwHelpStringContext=tiBase.helpstringcontext;
2270     ptiRet->dwHelpContext=tiBase.helpcontext;
2271 
2272     if (ptiRet->TypeAttr.typekind == TKIND_MODULE)
2273         ptiRet->DllName = MSFT_ReadString(pcx, tiBase.datatype1);
2274 
2275 /* note: InfoType's Help file and HelpStringDll come from the containing
2276  * library. Further HelpString and Docstring appear to be the same thing :(
2277  */
2278     /* functions */
2279     if(ptiRet->TypeAttr.cFuncs >0 )
2280         MSFT_DoFuncs(pcx, ptiRet, ptiRet->TypeAttr.cFuncs,
2281                     ptiRet->TypeAttr.cVars,
2282                     tiBase.memoffset, & ptiRet->funclist);
2283     /* variables */
2284     if(ptiRet->TypeAttr.cVars >0 )
2285         MSFT_DoVars(pcx, ptiRet, ptiRet->TypeAttr.cFuncs,
2286                    ptiRet->TypeAttr.cVars,
2287                    tiBase.memoffset, & ptiRet->varlist);
2288     if(ptiRet->TypeAttr.cImplTypes >0 ) {
2289         switch(ptiRet->TypeAttr.typekind)
2290         {
2291         case TKIND_COCLASS:
2292             MSFT_DoImplTypes(pcx, ptiRet, ptiRet->TypeAttr.cImplTypes ,
2293                 tiBase.datatype1);
2294             break;
2295         case TKIND_DISPATCH:
2296             /* This is not -1 when the interface is a non-base dual interface or
2297                when a dispinterface wraps an interface, i.e., the idl 'dispinterface x {interface y;};'.
2298                Note however that GetRefTypeOfImplType(0) always returns a ref to IDispatch and
2299                not this interface.
2300             */
2301 
2302             if (tiBase.datatype1 != -1)
2303             {
2304                 ptiRet->impltypelist = heap_alloc_zero(sizeof(TLBImplType));
2305                 ptiRet->impltypelist->hRef = tiBase.datatype1;
2306                 MSFT_DoRefType(pcx, pLibInfo, tiBase.datatype1);
2307             }
2308           break;
2309         default:
2310             ptiRet->impltypelist = heap_alloc_zero(sizeof(TLBImplType));
2311             MSFT_DoRefType(pcx, pLibInfo, tiBase.datatype1);
2312             ptiRet->impltypelist->hRef = tiBase.datatype1;
2313             break;
2314        }
2315     }
2316     ptiRet->ctCustData=
2317         MSFT_CustData(pcx, tiBase.oCustData, &ptiRet->pCustData);
2318 
2319     TRACE_(typelib)("%s guid: %s kind:%s\n",
2320        debugstr_w(ptiRet->Name),
2321        debugstr_guid(&ptiRet->TypeAttr.guid),
2322        typekind_desc[ptiRet->TypeAttr.typekind]);
2323     if (TRACE_ON(typelib))
2324       dump_TypeInfo(ptiRet);
2325 
2326     return ptiRet;
2327 }
2328 
2329 /* Because type library parsing has some degree of overhead, and some apps repeatedly load the same
2330  * typelibs over and over, we cache them here. According to MSDN Microsoft have a similar scheme in
2331  * place. This will cause a deliberate memory leak, but generally losing RAM for cycles is an acceptable
2332  * tradeoff here.
2333  */
2334 static ITypeLibImpl *tlb_cache_first;
2335 static CRITICAL_SECTION cache_section;
2336 static CRITICAL_SECTION_DEBUG cache_section_debug =
2337 {
2338     0, 0, &cache_section,
2339     { &cache_section_debug.ProcessLocksList, &cache_section_debug.ProcessLocksList },
2340       0, 0, { (DWORD_PTR)(__FILE__ ": typelib loader cache") }
2341 };
2342 static CRITICAL_SECTION cache_section = { &cache_section_debug, -1, 0, 0, 0, 0 };
2343 
2344 
2345 typedef struct TLB_PEFile
2346 {
2347     const IUnknownVtbl *lpvtbl;
2348     LONG refs;
2349     HMODULE dll;
2350     HRSRC typelib_resource;
2351     HGLOBAL typelib_global;
2352     LPVOID typelib_base;
2353 } TLB_PEFile;
2354 
2355 static HRESULT WINAPI TLB_PEFile_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2356 {
2357     if (IsEqualIID(riid, &IID_IUnknown))
2358     {
2359         *ppv = iface;
2360         IUnknown_AddRef(iface);
2361         return S_OK;
2362     }
2363     *ppv = NULL;
2364     return E_NOINTERFACE;
2365 }
2366 
2367 static ULONG WINAPI TLB_PEFile_AddRef(IUnknown *iface)
2368 {
2369     TLB_PEFile *This = (TLB_PEFile *)iface;
2370     return InterlockedIncrement(&This->refs);
2371 }
2372 
2373 static ULONG WINAPI TLB_PEFile_Release(IUnknown *iface)
2374 {
2375     TLB_PEFile *This = (TLB_PEFile *)iface;
2376     ULONG refs = InterlockedDecrement(&This->refs);
2377     if (!refs)
2378     {
2379         if (This->typelib_global)
2380             FreeResource(This->typelib_global);
2381         if (This->dll)
2382             FreeLibrary(This->dll);
2383         heap_free(This);
2384     }
2385     return refs;
2386 }
2387 
2388 static const IUnknownVtbl TLB_PEFile_Vtable =
2389 {
2390     TLB_PEFile_QueryInterface,
2391     TLB_PEFile_AddRef,
2392     TLB_PEFile_Release
2393 };
2394 
2395 static HRESULT TLB_PEFile_Open(LPCWSTR path, INT index, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile)
2396 {
2397     TLB_PEFile *This;
2398 
2399     This = heap_alloc(sizeof(TLB_PEFile));
2400     if (!This)
2401         return E_OUTOFMEMORY;
2402 
2403     This->lpvtbl = &TLB_PEFile_Vtable;
2404     This->refs = 1;
2405     This->dll = NULL;
2406     This->typelib_resource = NULL;
2407     This->typelib_global = NULL;
2408     This->typelib_base = NULL;
2409 
2410     This->dll = LoadLibraryExW(path, 0, DONT_RESOLVE_DLL_REFERENCES |
2411                     LOAD_LIBRARY_AS_DATAFILE | LOAD_WITH_ALTERED_SEARCH_PATH);
2412 
2413     if (This->dll)
2414     {
2415         static const WCHAR TYPELIBW[] = {'T','Y','P','E','L','I','B',0};
2416         This->typelib_resource = FindResourceW(This->dll, MAKEINTRESOURCEW(index), TYPELIBW);
2417         if (This->typelib_resource)
2418         {
2419             This->typelib_global = LoadResource(This->dll, This->typelib_resource);
2420             if (This->typelib_global)
2421             {
2422                 This->typelib_base = LockResource(This->typelib_global);
2423 
2424                 if (This->typelib_base)
2425                 {
2426                     *pdwTLBLength = SizeofResource(This->dll, This->typelib_resource);
2427                     *ppBase = This->typelib_base;
2428                     *ppFile = (IUnknown *)&This->lpvtbl;
2429                     return S_OK;
2430                 }
2431             }
2432         }
2433     }
2434 
2435     TLB_PEFile_Release((IUnknown *)&This->lpvtbl);
2436     return TYPE_E_CANTLOADLIBRARY;
2437 }
2438 
2439 typedef struct TLB_NEFile
2440 {
2441     const IUnknownVtbl *lpvtbl;
2442     LONG refs;
2443     LPVOID typelib_base;
2444 } TLB_NEFile;
2445 
2446 static HRESULT WINAPI TLB_NEFile_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2447 {
2448     if (IsEqualIID(riid, &IID_IUnknown))
2449     {
2450         *ppv = iface;
2451         IUnknown_AddRef(iface);
2452         return S_OK;
2453     }
2454     *ppv = NULL;
2455     return E_NOINTERFACE;
2456 }
2457 
2458 static ULONG WINAPI TLB_NEFile_AddRef(IUnknown *iface)
2459 {
2460     TLB_NEFile *This = (TLB_NEFile *)iface;
2461     return InterlockedIncrement(&This->refs);
2462 }
2463 
2464 static ULONG WINAPI TLB_NEFile_Release(IUnknown *iface)
2465 {
2466     TLB_NEFile *This = (TLB_NEFile *)iface;
2467     ULONG refs = InterlockedDecrement(&This->refs);
2468     if (!refs)
2469     {
2470         heap_free(This->typelib_base);
2471         heap_free(This);
2472     }
2473     return refs;
2474 }
2475 
2476 static const IUnknownVtbl TLB_NEFile_Vtable =
2477 {
2478     TLB_NEFile_QueryInterface,
2479     TLB_NEFile_AddRef,
2480     TLB_NEFile_Release
2481 };
2482 
2483 /***********************************************************************
2484  *           read_xx_header         [internal]
2485  */
2486 static int read_xx_header( HFILE lzfd )
2487 {
2488     IMAGE_DOS_HEADER mzh;
2489     char magic[3];
2490 
2491     LZSeek( lzfd, 0, SEEK_SET );
2492     if ( sizeof(mzh) != LZRead( lzfd, (LPSTR)&mzh, sizeof(mzh) ) )
2493         return 0;
2494     if ( mzh.e_magic != IMAGE_DOS_SIGNATURE )
2495         return 0;
2496 
2497     LZSeek( lzfd, mzh.e_lfanew, SEEK_SET );
2498     if ( 2 != LZRead( lzfd, magic, 2 ) )
2499         return 0;
2500 
2501     LZSeek( lzfd, mzh.e_lfanew, SEEK_SET );
2502 
2503     if ( magic[0] == 'N' && magic[1] == 'E' )
2504         return IMAGE_OS2_SIGNATURE;
2505     if ( magic[0] == 'P' && magic[1] == 'E' )
2506         return IMAGE_NT_SIGNATURE;
2507 
2508     magic[2] = '\0';
2509     WARN("Can't handle %s files.\n", magic );
2510     return 0;
2511 }
2512 
2513 
2514 /***********************************************************************
2515  *           find_ne_resource         [internal]
2516  */
2517 static BOOL find_ne_resource( HFILE lzfd, LPCSTR typeid, LPCSTR resid,
2518                                 DWORD *resLen, DWORD *resOff )
2519 {
2520     IMAGE_OS2_HEADER nehd;
2521     NE_TYPEINFO *typeInfo;
2522     NE_NAMEINFO *nameInfo;
2523     DWORD nehdoffset;
2524     LPBYTE resTab;
2525     DWORD resTabSize;
2526     int count;
2527 
2528     /* Read in NE header */
2529     nehdoffset = LZSeek( lzfd, 0, SEEK_CUR );
2530     if ( sizeof(nehd) != LZRead( lzfd, (LPSTR)&nehd, sizeof(nehd) ) ) return 0;
2531 
2532     resTabSize = nehd.ne_restab - nehd.ne_rsrctab;
2533     if ( !resTabSize )
2534     {
2535         TRACE("No resources in NE dll\n" );
2536         return FALSE;
2537     }
2538 
2539     /* Read in resource table */
2540     resTab = heap_alloc( resTabSize );
2541     if ( !resTab ) return FALSE;
2542 
2543     LZSeek( lzfd, nehd.ne_rsrctab + nehdoffset, SEEK_SET );
2544     if ( resTabSize != LZRead( lzfd, (char*)resTab, resTabSize ) )
2545     {
2546         heap_free( resTab );
2547         return FALSE;
2548     }
2549 
2550     /* Find resource */
2551     typeInfo = (NE_TYPEINFO *)(resTab + 2);
2552 
2553     if (!IS_INTRESOURCE(typeid))  /* named type */
2554     {
2555         BYTE len = strlen( typeid );
2556         while (typeInfo->type_id)
2557         {
2558             if (!(typeInfo->type_id & 0x8000))
2559             {
2560                 BYTE *p = resTab + typeInfo->type_id;
2561                 if ((*p == len) && !strncasecmp( (char*)p+1, typeid, len )) goto found_type;
2562             }
2563             typeInfo = (NE_TYPEINFO *)((char *)(typeInfo + 1) +
2564                                        typeInfo->count * sizeof(NE_NAMEINFO));
2565         }
2566     }
2567     else  /* numeric type id */
2568     {
2569         WORD id = LOWORD(typeid) | 0x8000;
2570         while (typeInfo->type_id)
2571         {
2572             if (typeInfo->type_id == id) goto found_type;
2573             typeInfo = (NE_TYPEINFO *)((char *)(typeInfo + 1) +
2574                                        typeInfo->count * sizeof(NE_NAMEINFO));
2575         }
2576     }
2577     TRACE("No typeid entry found for %p\n", typeid );
2578     heap_free( resTab );
2579     return FALSE;
2580 
2581  found_type:
2582     nameInfo = (NE_NAMEINFO *)(typeInfo + 1);
2583 
2584     if (!IS_INTRESOURCE(resid))  /* named resource */
2585     {
2586         BYTE len = strlen( resid );
2587         for (count = typeInfo->count; count > 0; count--, nameInfo++)
2588         {
2589             BYTE *p = resTab + nameInfo->id;
2590             if (nameInfo->id & 0x8000) continue;
2591             if ((*p == len) && !strncasecmp( (char*)p+1, resid, len )) goto found_name;
2592         }
2593     }
2594     else  /* numeric resource id */
2595     {
2596         WORD id = LOWORD(resid) | 0x8000;
2597         for (count = typeInfo->count; count > 0; count--, nameInfo++)
2598             if (nameInfo->id == id) goto found_name;
2599     }
2600     TRACE("No resid entry found for %p\n", typeid );
2601     heap_free( resTab );
2602     return FALSE;
2603 
2604  found_name:
2605     /* Return resource data */
2606     if ( resLen ) *resLen = nameInfo->length << *(WORD *)resTab;
2607     if ( resOff ) *resOff = nameInfo->offset << *(WORD *)resTab;
2608 
2609     heap_free( resTab );
2610     return TRUE;
2611 }
2612 
2613 static HRESULT TLB_NEFile_Open(LPCWSTR path, INT index, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile){
2614 
2615     HFILE lzfd = -1;
2616     OFSTRUCT ofs;
2617     HRESULT hr = TYPE_E_CANTLOADLIBRARY;
2618     TLB_NEFile *This;
2619 
2620     This = heap_alloc(sizeof(TLB_NEFile));
2621     if (!This) return E_OUTOFMEMORY;
2622 
2623     This->lpvtbl = &TLB_NEFile_Vtable;
2624     This->refs = 1;
2625     This->typelib_base = NULL;
2626 
2627     lzfd = LZOpenFileW( (LPWSTR)path, &ofs, OF_READ );
2628     if ( lzfd >= 0 && read_xx_header( lzfd ) == IMAGE_OS2_SIGNATURE )
2629     {
2630         DWORD reslen, offset;
2631         if( find_ne_resource( lzfd, "TYPELIB", MAKEINTRESOURCEA(index), &reslen, &offset ) )
2632         {
2633             This->typelib_base = heap_alloc(reslen);
2634             if( !This->typelib_base )
2635                 hr = E_OUTOFMEMORY;
2636             else
2637             {
2638                 LZSeek( lzfd, offset, SEEK_SET );
2639                 reslen = LZRead( lzfd, This->typelib_base, reslen );
2640                 LZClose( lzfd );
2641                 *ppBase = This->typelib_base;
2642                 *pdwTLBLength = reslen;
2643                 *ppFile = (IUnknown *)&This->lpvtbl;
2644                 return S_OK;
2645             }
2646         }
2647     }
2648 
2649     if( lzfd >= 0) LZClose( lzfd );
2650     TLB_NEFile_Release((IUnknown *)&This->lpvtbl);
2651     return hr;
2652 }
2653 
2654 typedef struct TLB_Mapping
2655 {
2656     const IUnknownVtbl *lpvtbl;
2657     LONG refs;
2658     HANDLE file;
2659     HANDLE mapping;
2660     LPVOID typelib_base;
2661 } TLB_Mapping;
2662 
2663 static HRESULT WINAPI TLB_Mapping_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2664 {
2665     if (IsEqualIID(riid, &IID_IUnknown))
2666     {
2667         *ppv = iface;
2668         IUnknown_AddRef(iface);
2669         return S_OK;
2670     }
2671     *ppv = NULL;
2672     return E_NOINTERFACE;
2673 }
2674 
2675 static ULONG WINAPI TLB_Mapping_AddRef(IUnknown *iface)
2676 {
2677     TLB_Mapping *This = (TLB_Mapping *)iface;
2678     return InterlockedIncrement(&This->refs);
2679 }
2680 
2681 static ULONG WINAPI TLB_Mapping_Release(IUnknown *iface)
2682 {
2683     TLB_Mapping *This = (TLB_Mapping *)iface;
2684     ULONG refs = InterlockedDecrement(&This->refs);
2685     if (!refs)
2686     {
2687         if (This->typelib_base)
2688             UnmapViewOfFile(This->typelib_base);
2689         if (This->mapping)
2690             CloseHandle(This->mapping);
2691         if (This->file != INVALID_HANDLE_VALUE)
2692             CloseHandle(This->file);
2693         heap_free(This);
2694     }
2695     return refs;
2696 }
2697 
2698 static const IUnknownVtbl TLB_Mapping_Vtable =
2699 {
2700     TLB_Mapping_QueryInterface,
2701     TLB_Mapping_AddRef,
2702     TLB_Mapping_Release
2703 };
2704 
2705 static HRESULT TLB_Mapping_Open(LPCWSTR path, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile)
2706 {
2707     TLB_Mapping *This;
2708 
2709     This = heap_alloc(sizeof(TLB_Mapping));
2710     if (!This)
2711         return E_OUTOFMEMORY;
2712 
2713     This->lpvtbl = &TLB_Mapping_Vtable;
2714     This->refs = 1;
2715     This->file = INVALID_HANDLE_VALUE;
2716     This->mapping = NULL;
2717     This->typelib_base = NULL;
2718 
2719     This->file = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
2720     if (INVALID_HANDLE_VALUE != This->file)
2721     {
2722         This->mapping = CreateFileMappingW(This->file, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL);
2723         if (This->mapping)
2724         {
2725             This->typelib_base = MapViewOfFile(This->mapping, FILE_MAP_READ, 0, 0, 0);
2726             if(This->typelib_base)
2727             {
2728                 /* retrieve file size */
2729                 *pdwTLBLength = GetFileSize(This->file, NULL);
2730                 *ppBase = This->typelib_base;
2731                 *ppFile = (IUnknown *)&This->lpvtbl;
2732                 return S_OK;
2733             }
2734         }
2735     }
2736 
2737     IUnknown_Release((IUnknown *)&This->lpvtbl);
2738     return TYPE_E_CANTLOADLIBRARY;
2739 }
2740 
2741 /****************************************************************************
2742  *      TLB_ReadTypeLib
2743  *
2744  * find the type of the typelib file and map the typelib resource into
2745  * the memory
2746  */
2747 
2748 #define SLTG_SIGNATURE 0x47544c53 /* "SLTG" */
2749 static HRESULT TLB_ReadTypeLib(LPCWSTR pszFileName, LPWSTR pszPath, UINT cchPath, ITypeLib2 **ppTypeLib)
2750 {
2751     ITypeLibImpl *entry;
2752     HRESULT ret;
2753     INT index = 1;
2754     LPWSTR index_str, file = (LPWSTR)pszFileName;
2755     LPVOID pBase = NULL;
2756     DWORD dwTLBLength = 0;
2757     IUnknown *pFile = NULL;
2758 
2759     *ppTypeLib = NULL;
2760 
2761     index_str = strrchrW(pszFileName, '\\');
2762     if(index_str && *++index_str != '\0')
2763     {
2764         LPWSTR end_ptr;
2765         LONG idx = strtolW(index_str, &end_ptr, 10);
2766         if(*end_ptr == '\0')
2767         {
2768             int str_len = index_str - pszFileName - 1;
2769             index = idx;
2770             file = heap_alloc((str_len + 1) * sizeof(WCHAR));
2771             memcpy(file, pszFileName, str_len * sizeof(WCHAR));
2772             file[str_len] = 0;
2773         }
2774     }
2775 
2776     if(!SearchPathW(NULL, file, NULL, cchPath, pszPath, NULL))
2777     {
2778         if(strchrW(file, '\\'))
2779         {
2780             lstrcpyW(pszPath, file);
2781         }
2782         else
2783         {
2784             int len = GetSystemDirectoryW(pszPath, cchPath);
2785             pszPath[len] = '\\';
2786             memcpy(pszPath + len + 1, file, (strlenW(file) + 1) * sizeof(WCHAR));
2787         }
2788     }
2789 
2790     if(file != pszFileName) heap_free(file);
2791 
2792     TRACE_(typelib)("File %s index %d\n", debugstr_w(pszPath), index);
2793 
2794     /* We look the path up in the typelib cache. If found, we just addref it, and return the pointer. */
2795     EnterCriticalSection(&cache_section);
2796     for (entry = tlb_cache_first; entry != NULL; entry = entry->next)
2797     {
2798         if (!strcmpiW(entry->path, pszPath) && entry->index == index)
2799         {
2800             TRACE("cache hit\n");
2801             *ppTypeLib = (ITypeLib2*)entry;
2802             ITypeLib_AddRef(*ppTypeLib);
2803             LeaveCriticalSection(&cache_section);
2804             return S_OK;
2805         }
2806     }
2807     LeaveCriticalSection(&cache_section);
2808 
2809     /* now actually load and parse the typelib */
2810 
2811     ret = TLB_PEFile_Open(pszPath, index, &pBase, &dwTLBLength, &pFile);
2812     if (ret == TYPE_E_CANTLOADLIBRARY)
2813         ret = TLB_NEFile_Open(pszPath, index, &pBase, &dwTLBLength, &pFile);
2814     if (ret == TYPE_E_CANTLOADLIBRARY)
2815         ret = TLB_Mapping_Open(pszPath, &pBase, &dwTLBLength, &pFile);
2816     if (SUCCEEDED(ret))
2817     {
2818         if (dwTLBLength >= 4)
2819         {
2820             DWORD dwSignature = FromLEDWord(*((DWORD*) pBase));
2821             if (dwSignature == MSFT_SIGNATURE)
2822                 *ppTypeLib = ITypeLib2_Constructor_MSFT(pBase, dwTLBLength);
2823             else if (dwSignature == SLTG_SIGNATURE)
2824                 *ppTypeLib = ITypeLib2_Constructor_SLTG(pBase, dwTLBLength);
2825             else
2826             {
2827                 FIXME("Header type magic 0x%08x not supported.\n",dwSignature);
2828                 ret = TYPE_E_CANTLOADLIBRARY;
2829             }
2830         }
2831         else
2832             ret = TYPE_E_CANTLOADLIBRARY;
2833         IUnknown_Release(pFile);
2834     }
2835 
2836     if(*ppTypeLib) {
2837         ITypeLibImpl *impl = (ITypeLibImpl*)*ppTypeLib;
2838 
2839         TRACE("adding to cache\n");
2840         impl->path = heap_alloc((strlenW(pszPath)+1) * sizeof(WCHAR));
2841         lstrcpyW(impl->path, pszPath);
2842         /* We should really canonicalise the path here. */
2843         impl->index = index;
2844 
2845         /* FIXME: check if it has added already in the meantime */
2846         EnterCriticalSection(&cache_section);
2847         if ((impl->next = tlb_cache_first) != NULL) impl->next->prev = impl;
2848         impl->prev = NULL;
2849         tlb_cache_first = impl;
2850         LeaveCriticalSection(&cache_section);
2851         ret = S_OK;
2852     } else
2853         ERR("Loading of typelib %s failed with error %d\n", debugstr_w(pszFileName), GetLastError());
2854 
2855     return ret;
2856 }
2857 
2858 /*================== ITypeLib(2) Methods ===================================*/
2859 
2860 static ITypeLibImpl* TypeLibImpl_Constructor(void)
2861 {
2862     ITypeLibImpl* pTypeLibImpl;
2863 
2864     pTypeLibImpl = heap_alloc_zero(sizeof(ITypeLibImpl));
2865     if (!pTypeLibImpl) return NULL;
2866 
2867     pTypeLibImpl->lpVtbl = &tlbvt;
2868     pTypeLibImpl->lpVtblTypeComp = &tlbtcvt;
2869     pTypeLibImpl->ref = 1;
2870 
2871     list_init(&pTypeLibImpl->ref_list);
2872     pTypeLibImpl->dispatch_href = -1;
2873 
2874     return pTypeLibImpl;
2875 }
2876 
2877 /****************************************************************************
2878  *      ITypeLib2_Constructor_MSFT
2879  *
2880  * loading an MSFT typelib from an in-memory image
2881  */
2882 static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength)
2883 {
2884     TLBContext cx;
2885     LONG lPSegDir;
2886     MSFT_Header tlbHeader;
2887     MSFT_SegDir tlbSegDir;
2888     ITypeLibImpl * pTypeLibImpl;
2889 
2890     TRACE("%p, TLB length = %d\n", pLib, dwTLBLength);
2891 
2892     pTypeLibImpl = TypeLibImpl_Constructor();
2893     if (!pTypeLibImpl) return NULL;
2894 
2895     /* get pointer to beginning of typelib data */
2896     cx.pos = 0;
2897     cx.oStart=0;
2898     cx.mapping = pLib;
2899     cx.pLibInfo = pTypeLibImpl;
2900     cx.length = dwTLBLength;
2901 
2902     /* read header */
2903     MSFT_ReadLEDWords((void*)&tlbHeader, sizeof(tlbHeader), &cx, 0);
2904     TRACE_(typelib)("header:\n");
2905     TRACE_(typelib)("\tmagic1=0x%08x ,magic2=0x%08x\n",tlbHeader.magic1,tlbHeader.magic2 );
2906     if (tlbHeader.magic1 != MSFT_SIGNATURE) {
2907         FIXME("Header type magic 0x%08x not supported.\n",tlbHeader.magic1);
2908         return NULL;
2909     }
2910     TRACE_(typelib)("\tdispatchpos = 0x%x\n", tlbHeader.dispatchpos);
2911 
2912     /* there is a small amount of information here until the next important
2913      * part:
2914      * the segment directory . Try to calculate the amount of data */
2915     lPSegDir = sizeof(tlbHeader) + (tlbHeader.nrtypeinfos)*4 + ((tlbHeader.varflags & HELPDLLFLAG)? 4 :0);
2916 
2917     /* now read the segment directory */
2918     TRACE("read segment directory (at %d)\n",lPSegDir);
2919     MSFT_ReadLEDWords(&tlbSegDir, sizeof(tlbSegDir), &cx, lPSegDir);
2920     cx.pTblDir = &tlbSegDir;
2921 
2922     /* just check two entries */
2923     if ( tlbSegDir.pTypeInfoTab.res0c != 0x0F || tlbSegDir.pImpInfo.res0c != 0x0F)
2924     {
2925         ERR("cannot find the table directory, ptr=0x%x\n",lPSegDir);
2926         heap_free(pTypeLibImpl);
2927         return NULL;
2928     }
2929 
2930     /* now fill our internal data */
2931     /* TLIBATTR fields */
2932     MSFT_ReadGuid(&pTypeLibImpl->LibAttr.guid, tlbHeader.posguid, &cx);
2933 
2934     pTypeLibImpl->LibAttr.lcid = tlbHeader.lcid2;
2935     pTypeLibImpl->LibAttr.syskind = tlbHeader.varflags & 0x0f; /* check the mask */
2936     pTypeLibImpl->LibAttr.wMajorVerNum = LOWORD(tlbHeader.version);
2937     pTypeLibImpl->LibAttr.wMinorVerNum = HIWORD(tlbHeader.version);
2938     pTypeLibImpl->LibAttr.wLibFlags = (WORD) tlbHeader.flags & 0xffff;/* check mask */
2939 
2940     pTypeLibImpl->lcid = tlbHeader.lcid;
2941 
2942     /* name, eventually add to a hash table */
2943     pTypeLibImpl->Name = MSFT_ReadName(&cx, tlbHeader.NameOffset);
2944 
2945     /* help info */
2946     pTypeLibImpl->DocString = MSFT_ReadString(&cx, tlbHeader.helpstring);
2947     pTypeLibImpl->HelpFile = MSFT_ReadString(&cx, tlbHeader.helpfile);
2948 
2949     if( tlbHeader.varflags & HELPDLLFLAG)
2950     {
2951             int offset;
2952             MSFT_ReadLEDWords(&offset, sizeof(offset), &cx, sizeof(tlbHeader));
2953             pTypeLibImpl->HelpStringDll = MSFT_ReadString(&cx, offset);
2954     }
2955 
2956     pTypeLibImpl->dwHelpContext = tlbHeader.helpstringcontext;
2957 
2958     /* custom data */
2959     if(tlbHeader.CustomDataOffset >= 0)
2960     {
2961         pTypeLibImpl->ctCustData = MSFT_CustData(&cx, tlbHeader.CustomDataOffset, &pTypeLibImpl->pCustData);
2962     }
2963 
2964     /* fill in type descriptions */
2965     if(tlbSegDir.pTypdescTab.length > 0)
2966     {
2967         int i, j, cTD = tlbSegDir.pTypdescTab.length / (2*sizeof(INT));
2968         INT16 td[4];
2969         pTypeLibImpl->ctTypeDesc = cTD;
2970         pTypeLibImpl->pTypeDesc = heap_alloc_zero( cTD * sizeof(TYPEDESC));
2971         MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pTypdescTab.offset);
2972         for(i=0; i<cTD; )
2973         {
2974             /* FIXME: add several sanity checks here */
2975             pTypeLibImpl->pTypeDesc[i].vt = td[0] & VT_TYPEMASK;
2976             if(td[0] == VT_PTR || td[0] == VT_SAFEARRAY)
2977             {
2978                 /* FIXME: check safearray */
2979                 if(td[3] < 0)
2980                     pTypeLibImpl->pTypeDesc[i].u.lptdesc = &std_typedesc[td[2]];
2981                 else
2982                     pTypeLibImpl->pTypeDesc[i].u.lptdesc = &pTypeLibImpl->pTypeDesc[td[2]/8];
2983             }
2984             else if(td[0] == VT_CARRAY)
2985             {
2986                 /* array descr table here */
2987                 pTypeLibImpl->pTypeDesc[i].u.lpadesc = (void *)(INT_PTR)td[2];  /* temp store offset in*/
2988             }
2989             else if(td[0] == VT_USERDEFINED)
2990             {
2991                 pTypeLibImpl->pTypeDesc[i].u.hreftype = MAKELONG(td[2],td[3]);
2992             }
2993             if(++i<cTD) MSFT_ReadLEWords(td, sizeof(td), &cx, DO_NOT_SEEK);
2994         }
2995 
2996         /* second time around to fill the array subscript info */
2997         for(i=0;i<cTD;i++)
2998         {
2999             if(pTypeLibImpl->pTypeDesc[i].vt != VT_CARRAY) continue;
3000             if(tlbSegDir.pArrayDescriptions.offset>0)
3001             {
3002                 MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pArrayDescriptions.offset + (INT_PTR)pTypeLibImpl->pTypeDesc[i].u.lpadesc);
3003                 pTypeLibImpl->pTypeDesc[i].u.lpadesc = heap_alloc_zero(sizeof(ARRAYDESC)+sizeof(SAFEARRAYBOUND)*(td[3]-1));
3004 
3005                 if(td[1]<0)
3006                     pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem.vt = td[0] & VT_TYPEMASK;
3007                 else
3008                     pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem = cx.pLibInfo->pTypeDesc[td[0]/(2*sizeof(INT))];
3009 
3010                 pTypeLibImpl->pTypeDesc[i].u.lpadesc->cDims = td[2];
3011 
3012                 for(j = 0; j<td[2]; j++)
3013                 {
3014                     MSFT_ReadLEDWords(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].cElements,
3015                                       sizeof(INT), &cx, DO_NOT_SEEK);
3016                     MSFT_ReadLEDWords(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].lLbound,
3017                                       sizeof(INT), &cx, DO_NOT_SEEK);
3018                 }
3019             }
3020             else
3021             {
3022                 pTypeLibImpl->pTypeDesc[i].u.lpadesc = NULL;
3023                 ERR("didn't find array description data\n");
3024             }
3025         }
3026     }
3027 
3028     /* imported type libs */
3029     if(tlbSegDir.pImpFiles.offset>0)
3030     {
3031         TLBImpLib **ppImpLib = &(pTypeLibImpl->pImpLibs);
3032         int oGuid, offset = tlbSegDir.pImpFiles.offset;
3033         UINT16 size;
3034 
3035         while(offset < tlbSegDir.pImpFiles.offset +tlbSegDir.pImpFiles.length)
3036         {
3037             char *name;
3038 
3039             *ppImpLib = heap_alloc_zero(sizeof(TLBImpLib));
3040             (*ppImpLib)->offset = offset - tlbSegDir.pImpFiles.offset;
3041             MSFT_ReadLEDWords(&oGuid, sizeof(INT), &cx, offset);
3042 
3043             MSFT_ReadLEDWords(&(*ppImpLib)->lcid,         sizeof(LCID),   &cx, DO_NOT_SEEK);
3044             MSFT_ReadLEWords(&(*ppImpLib)->wVersionMajor, sizeof(WORD),   &cx, DO_NOT_SEEK);
3045             MSFT_ReadLEWords(&(*ppImpLib)->wVersionMinor, sizeof(WORD),   &cx, DO_NOT_SEEK);
3046             MSFT_ReadLEWords(& size,                      sizeof(UINT16), &cx, DO_NOT_SEEK);
3047 
3048             size >>= 2;
3049             name = heap_alloc_zero(size+1);
3050             MSFT_Read(name, size, &cx, DO_NOT_SEEK);
3051             (*ppImpLib)->name = TLB_MultiByteToBSTR(name);
3052             heap_free(name);
3053 
3054             MSFT_ReadGuid(&(*ppImpLib)->guid, oGuid, &cx);
3055             offset = (offset + sizeof(INT) + sizeof(DWORD) + sizeof(LCID) + sizeof(UINT16) + size + 3) & ~3;
3056 
3057             ppImpLib = &(*ppImpLib)->next;
3058         }
3059     }
3060 
3061     pTypeLibImpl->dispatch_href = tlbHeader.dispatchpos;
3062     if(pTypeLibImpl->dispatch_href != -1)
3063         MSFT_DoRefType(&cx, pTypeLibImpl, pTypeLibImpl->dispatch_href);
3064 
3065     /* type info's */
3066     if(tlbHeader.nrtypeinfos >= 0 )
3067     {
3068         /*pTypeLibImpl->TypeInfoCount=tlbHeader.nrtypeinfos; */
3069         ITypeInfoImpl **ppTI = &(pTypeLibImpl->pTypeInfo);
3070         int i;
3071 
3072         for(i = 0; i < tlbHeader.nrtypeinfos; i++)
3073         {
3074             *ppTI = MSFT_DoTypeInfo(&cx, i, pTypeLibImpl);
3075 
3076             ppTI = &((*ppTI)->next);
3077             (pTypeLibImpl->TypeInfoCount)++;
3078         }
3079     }
3080 
3081     TRACE("(%p)\n", pTypeLibImpl);
3082     return (ITypeLib2*) pTypeLibImpl;
3083 }
3084 
3085 
3086 static BOOL TLB_GUIDFromString(const char *str, GUID *guid)
3087 {
3088   char b[3];
3089   int i;
3090   short s;
3091 
3092   if(sscanf(str, "%x-%hx-%hx-%hx", &guid->Data1, &guid->Data2, &guid->Data3, &s) != 4) {
3093     FIXME("Can't parse guid %s\n", debugstr_guid(guid));
3094     return FALSE;
3095   }
3096 
3097   guid->Data4[0] = s >> 8;
3098   guid->Data4[1] = s & 0xff;
3099 
3100   b[2] = '\0';
3101   for(i = 0; i < 6; i++) {
3102     memcpy(b, str + 24 + 2 * i, 2);
3103     guid->Data4[i + 2] = strtol(b, NULL, 16);
3104   }
3105   return TRUE;
3106 }
3107 
3108 static WORD SLTG_ReadString(const char *ptr, BSTR *pBstr)
3109 {
3110     WORD bytelen;
3111     DWORD len;
3112 
3113     *pBstr = NULL;
3114     bytelen = *(const WORD*)ptr;
3115     if(bytelen == 0xffff) return 2;
3116     len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, NULL, 0);
3117     *pBstr = SysAllocStringLen(NULL, len);
3118     if (*pBstr)
3119         len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, *pBstr, len);
3120     return bytelen + 2;
3121 }
3122 
3123 static WORD SLTG_ReadStringA(const char *ptr, char **str)
3124 {
3125     WORD bytelen;
3126 
3127     *str = NULL;
3128     bytelen = *(const WORD*)ptr;
3129     if(bytelen == 0xffff) return 2;
3130     *str = heap_alloc(bytelen + 1);
3131     memcpy(*str, ptr + 2, bytelen);
3132     (*str)[bytelen] = '\0';
3133     return bytelen + 2;
3134 }
3135 
3136 static DWORD SLTG_ReadLibBlk(LPVOID pLibBlk, ITypeLibImpl *pTypeLibImpl)
3137 {
3138     char *ptr = pLibBlk;
3139     WORD w;
3140 
3141     if((w = *(WORD*)ptr) != SLTG_LIBBLK_MAGIC) {
3142         FIXME("libblk magic = %04x\n", w);
3143         return 0;
3144     }
3145 
3146     ptr += 6;
3147     if((w = *(WORD*)ptr) != 0xffff) {
3148         FIXME("LibBlk.res06 = %04x. Assumung string and skipping\n", w);
3149         ptr += w;
3150     }
3151     ptr += 2;
3152 
3153     ptr += SLTG_ReadString(ptr, &pTypeLibImpl->DocString);
3154 
3155     ptr += SLTG_ReadString(ptr, &pTypeLibImpl->HelpFile);
3156 
3157     pTypeLibImpl->dwHelpContext = *(DWORD*)ptr;
3158     ptr += 4;
3159 
3160     pTypeLibImpl->LibAttr.syskind = *(WORD*)ptr;
3161     ptr += 2;
3162 
3163     if(SUBLANGID(*(WORD*)ptr) == SUBLANG_NEUTRAL)
3164         pTypeLibImpl->lcid = pTypeLibImpl->LibAttr.lcid = MAKELCID(MAKELANGID(PRIMARYLANGID(*(WORD*)ptr),0),0);
3165     else
3166         pTypeLibImpl->lcid = pTypeLibImpl->LibAttr.lcid = 0;
3167     ptr += 2;
3168 
3169     ptr += 4; /* skip res12 */
3170 
3171     pTypeLibImpl->LibAttr.wLibFlags = *(WORD*)ptr;
3172     ptr += 2;
3173 
3174     pTypeLibImpl->LibAttr.wMajorVerNum = *(WORD*)ptr;
3175     ptr += 2;
3176 
3177     pTypeLibImpl->LibAttr.wMinorVerNum = *(WORD*)ptr;
3178     ptr += 2;
3179 
3180     memcpy(&pTypeLibImpl->LibAttr.guid, ptr, sizeof(GUID));
3181     ptr += sizeof(GUID);
3182 
3183     return ptr - (char*)pLibBlk;
3184 }
3185 
3186 /* stores a mapping between the sltg typeinfo's references and the typelib's HREFTYPEs */
3187 typedef struct
3188 {
3189     unsigned int num;
3190     HREFTYPE refs[1];
3191 } sltg_ref_lookup_t;
3192 
3193 static HRESULT sltg_get_typelib_ref(const sltg_ref_lookup_t *table, DWORD typeinfo_ref,
3194                                     HREFTYPE *typelib_ref)
3195 {
3196     if(table && typeinfo_ref < table->num)
3197     {
3198         *typelib_ref = table->refs[typeinfo_ref];
3199         return S_OK;
3200     }
3201 
3202     ERR_(typelib)("Unable to find reference\n");
3203     *typelib_ref = -1;
3204     return E_FAIL;
3205 }
3206 
3207 static WORD *SLTG_DoType(WORD *pType, char *pBlk, TYPEDESC *pTD, const sltg_ref_lookup_t *ref_lookup)
3208 {
3209     BOOL done = FALSE;
3210 
3211     while(!done) {
3212         if((*pType & 0xe00) == 0xe00) {
3213             pTD->vt = VT_PTR;
3214             pTD->u.lptdesc = heap_alloc_zero(sizeof(TYPEDESC));
3215             pTD = pTD->u.lptdesc;
3216         }
3217         switch(*pType & 0x3f) {
3218         case VT_PTR:
3219             pTD->vt = VT_PTR;
3220             pTD->u.lptdesc = heap_alloc_zero(sizeof(TYPEDESC));
3221             pTD = pTD->u.lptdesc;
3222             break;
3223 
3224         case VT_USERDEFINED:
3225             pTD->vt = VT_USERDEFINED;
3226             sltg_get_typelib_ref(ref_lookup, *(++pType) / 4, &pTD->u.hreftype);
3227             done = TRUE;
3228             break;
3229 
3230         case VT_CARRAY:
3231           {
3232             /* *(pType+1) is offset to a SAFEARRAY, *(pType+2) is type of
3233                array */
3234 
3235             SAFEARRAY *pSA = (SAFEARRAY *)(pBlk + *(++pType));
3236 
3237             pTD->vt = VT_CARRAY;
3238             pTD->u.lpadesc = heap_alloc_zero(sizeof(ARRAYDESC) + (pSA->cDims - 1) * sizeof(SAFEARRAYBOUND));
3239             pTD->u.lpadesc->cDims = pSA->cDims;
3240             memcpy(pTD->u.lpadesc->rgbounds, pSA->rgsabound,
3241                    pSA->cDims * sizeof(SAFEARRAYBOUND));
3242 
3243             pTD = &pTD->u.lpadesc->tdescElem;
3244             break;
3245           }
3246 
3247         case VT_SAFEARRAY:
3248           {
3249             /* FIXME: *(pType+1) gives an offset to SAFEARRAY, is this
3250                useful? */
3251 
3252             pType++;
3253             pTD->vt = VT_SAFEARRAY;
3254             pTD->u.lptdesc = heap_alloc_zero(sizeof(TYPEDESC));
3255             pTD = pTD->u.lptdesc;
3256             break;
3257           }
3258         default:
3259             pTD->vt = *pType & 0x3f;
3260             done = TRUE;
3261             break;
3262         }
3263         pType++;
3264     }
3265     return pType;
3266 }
3267 
3268 static WORD *SLTG_DoElem(WORD *pType, char *pBlk,
3269                          ELEMDESC *pElem, const sltg_ref_lookup_t *ref_lookup)
3270 {
3271     /* Handle [in/out] first */
3272     if((*pType & 0xc000) == 0xc000)
3273         pElem->u.paramdesc.wParamFlags = PARAMFLAG_NONE;
3274     else if(*pType & 0x8000)
3275         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN | PARAMFLAG_FOUT;
3276     else if(*pType & 0x4000)
3277         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FOUT;
3278     else
3279         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN;
3280 
3281     if(*pType & 0x2000)
3282         pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FLCID;
3283 
3284     if(*pType & 0x80)
3285         pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FRETVAL;
3286 
3287     return SLTG_DoType(pType, pBlk, &pElem->tdesc, ref_lookup);
3288 }
3289 
3290 
3291 static sltg_ref_lookup_t *SLTG_DoRefs(SLTG_RefInfo *pRef, ITypeLibImpl *pTL,
3292                         char *pNameTable)
3293 {
3294     unsigned int ref;
3295     char *name;
3296     TLBRefType *ref_type;
3297     sltg_ref_lookup_t *table;
3298     HREFTYPE typelib_ref;
3299 
3300     if(pRef->magic != SLTG_REF_MAGIC) {
3301         FIXME("Ref magic = %x\n", pRef->magic);
3302         return NULL;
3303     }
3304     name = ( (char*)pRef->names + pRef->number);
3305 
3306     table = heap_alloc(sizeof(*table) + ((pRef->number >> 3) - 1) * sizeof(table->refs[0]));
3307     table->num = pRef->number >> 3;
3308 
3309     /* FIXME should scan the existing list and reuse matching refs added by previous typeinfos */
3310 
3311     /* We don't want the first href to be 0 */
3312     typelib_ref = (list_count(&pTL->ref_list) + 1) << 2;
3313 
3314     for(ref = 0; ref < pRef->number >> 3; ref++) {
3315         char *refname;
3316         unsigned int lib_offs, type_num;
3317 
3318         ref_type = heap_alloc_zero(sizeof(TLBRefType));
3319 
3320         name += SLTG_ReadStringA(name, &refname);
3321         if(sscanf(refname, "*\\R%x*#%x", &lib_offs, &type_num) != 2)
3322             FIXME_(typelib)("Can't sscanf ref\n");
3323         if(lib_offs != 0xffff) {
3324             TLBImpLib **import = &pTL->pImpLibs;
3325 
3326             while(*import) {
3327                 if((*import)->offset == lib_offs)
3328                     break;
3329                 import = &(*import)->next;
3330             }
3331             if(!*import) {
3332                 char fname[MAX_PATH+1];
3333                 int len;
3334 
3335                 *import = heap_alloc_zero(sizeof(**import));
3336                 (*import)->offset = lib_offs;
3337                 TLB_GUIDFromString( pNameTable + lib_offs + 4,
3338                                     &(*import)->guid);
3339                 if(sscanf(pNameTable + lib_offs + 40, "}#%hd.%hd#%x#%s",
3340                           &(*import)->wVersionMajor,
3341                           &(*import)->wVersionMinor,
3342                           &(*import)->lcid, fname) != 4) {
3343                   FIXME_(typelib)("can't sscanf ref %s\n",
3344                         pNameTable + lib_offs + 40);
3345                 }
3346                 len = strlen(fname);
3347                 if(fname[len-1] != '#')
3348                     FIXME("fname = %s\n", fname);
3349                 fname[len-1] = '\0';
3350                 (*import)->name = TLB_MultiByteToBSTR(fname);
3351             }
3352             ref_type->pImpTLInfo = *import;
3353 
3354             /* Store a reference to IDispatch */
3355             if(pTL->dispatch_href == -1 && IsEqualGUID(&(*import)->guid, &IID_StdOle) && type_num == 4)
3356                 pTL->dispatch_href = typelib_ref;
3357 
3358         } else { /* internal ref */
3359           ref_type->pImpTLInfo = TLB_REF_INTERNAL;
3360         }
3361         ref_type->reference = typelib_ref;
3362         ref_type->index = type_num;
3363 
3364         heap_free(refname);
3365         list_add_tail(&pTL->ref_list, &ref_type->entry);
3366 
3367         table->refs[ref] = typelib_ref;
3368         typelib_ref += 4;
3369     }
3370     if((BYTE)*name != SLTG_REF_MAGIC)
3371       FIXME_(typelib)("End of ref block magic = %x\n", *name);
3372     dump_TLBRefType(pTL);
3373     return table;
3374 }
3375 
3376 static char *SLTG_DoImpls(char *pBlk, ITypeInfoImpl *pTI,
3377                           BOOL OneOnly, const sltg_ref_lookup_t *ref_lookup)
3378 {
3379     SLTG_ImplInfo *info;
3380     TLBImplType **ppImplType = &pTI->impltypelist;
3381     /* I don't really get this structure, usually it's 0x16 bytes
3382        long, but iuser.tlb contains some that are 0x18 bytes long.
3383        That's ok because we can use the next ptr to jump to the next
3384        one. But how do we know the length of the last one?  The WORD
3385        at offs 0x8 might be the clue.  For now I'm just assuming that
3386        the last one is the regular 0x16 bytes. */
3387 
3388     info = (SLTG_ImplInfo*)pBlk;
3389     while(1) {
3390         *ppImplType = heap_alloc_zero(sizeof(**ppImplType));
3391         sltg_get_typelib_ref(ref_lookup, info->ref, &(*ppImplType)->hRef);
3392         (*ppImplType)->implflags = info->impltypeflags;
3393         pTI->TypeAttr.cImplTypes++;
3394         ppImplType = &(*ppImplType)->next;
3395 
3396         if(info->next == 0xffff)
3397             break;
3398         if(OneOnly)
3399             FIXME_(typelib)("Interface inheriting more than one interface\n");
3400         info = (SLTG_ImplInfo*)(pBlk + info->next);
3401     }
3402     info++; /* see comment at top of function */
3403     return (char*)info;
3404 }
3405 
3406 static void SLTG_DoVars(char *pBlk, char *pFirstItem, ITypeInfoImpl *pTI, unsigned short cVars,
3407                         const char *pNameTable, const sltg_ref_lookup_t *ref_lookup)
3408 {
3409   TLBVarDesc **ppVarDesc = &pTI->varlist;
3410   BSTR bstrPrevName = NULL;
3411   SLTG_Variable *pItem;
3412   unsigned short i;
3413   WORD *pType;
3414 
3415   for(pItem = (SLTG_Variable *)pFirstItem, i = 0; i < cVars;
3416       pItem = (SLTG_Variable *)(pBlk + pItem->next), i++) {
3417 
3418       *ppVarDesc = heap_alloc_zero(sizeof(**ppVarDesc));
3419       (*ppVarDesc)->vardesc.memid = pItem->memid;
3420 
3421       if (pItem->magic != SLTG_VAR_MAGIC &&
3422           pItem->magic != SLTG_VAR_WITH_FLAGS_MAGIC) {
3423           FIXME_(typelib)("var magic = %02x\n", pItem->magic);
3424           return;
3425       }
3426 
3427       if (pItem->name == 0xfffe)
3428         (*ppVarDesc)->Name = SysAllocString(bstrPrevName);
3429       else
3430         (*ppVarDesc)->Name = TLB_MultiByteToBSTR(pItem->name + pNameTable);
3431 
3432       TRACE_(typelib)("name: %s\n", debugstr_w((*ppVarDesc)->Name));
3433       TRACE_(typelib)("byte_offs = 0x%x\n", pItem->byte_offs);
3434       TRACE_(typelib)("memid = 0x%x\n", pItem->memid);
3435 
3436       if(pItem->flags & 0x02)
3437           pType = &pItem->type;
3438       else
3439           pType = (WORD*)(pBlk + pItem->type);
3440 
3441       if (pItem->flags & ~0xda)
3442         FIXME_(typelib)("unhandled flags = %02x\n", pItem->flags & ~0xda);
3443 
3444       SLTG_DoElem(pType, pBlk,
3445                   &(*ppVarDesc)->vardesc.elemdescVar, ref_lookup);
3446 
3447       if (TRACE_ON(typelib)) {
3448           char buf[300];
3449           dump_TypeDesc(&(*ppVarDesc)->vardesc.elemdescVar.tdesc, buf);
3450           TRACE_(typelib)("elemdescVar: %s\n", buf);
3451       }
3452 
3453       if (pItem->flags & 0x40) {
3454         TRACE_(typelib)("VAR_DISPATCH\n");
3455         (*ppVarDesc)->vardesc.varkind = VAR_DISPATCH;
3456       }
3457       else if (pItem->flags & 0x10) {
3458         TRACE_(typelib)("VAR_CONST\n");
3459         (*ppVarDesc)->vardesc.varkind = VAR_CONST;
3460         (*ppVarDesc)->vardesc.u.lpvarValue = heap_alloc(sizeof(VARIANT));
3461         V_VT((*ppVarDesc)->vardesc.u.lpvarValue) = VT_INT;
3462         if (pItem->flags & 0x08)
3463           V_INT((*ppVarDesc)->vardesc.u.lpvarValue) = pItem->byte_offs;
3464         else {
3465           switch ((*ppVarDesc)->vardesc.elemdescVar.tdesc.vt)
3466           {
3467             case VT_LPSTR:
3468             case VT_LPWSTR:
3469             case VT_BSTR:
3470             {
3471               WORD len = *(WORD *)(pBlk + pItem->byte_offs);
3472               BSTR str;
3473               TRACE_(typelib)("len = %u\n", len);
3474               if (len == 0xffff) {
3475                 str = NULL;
3476               } else {
3477                 INT alloc_len = MultiByteToWideChar(CP_ACP, 0, pBlk + pItem->byte_offs + 2, len, NULL, 0);
3478                 str = SysAllocStringLen(NULL, alloc_len);
3479                 MultiByteToWideChar(CP_ACP, 0, pBlk + pItem->byte_offs + 2, len, str, alloc_len);
3480               }
3481               V_VT((*ppVarDesc)->vardesc.u.lpvarValue) = VT_BSTR;
3482               V_BSTR((*ppVarDesc)->vardesc.u.lpvarValue) = str;
3483               break;
3484             }
3485             case VT_I2:
3486             case VT_UI2:
3487             case VT_I4:
3488             case VT_UI4:
3489             case VT_INT:
3490             case VT_UINT:
3491               V_INT((*ppVarDesc)->vardesc.u.lpvarValue) =
3492                 *(INT*)(pBlk + pItem->byte_offs);
3493               break;
3494             default:
3495               FIXME_(typelib)("VAR_CONST unimplemented for type %d\n", (*ppVarDesc)->vardesc.elemdescVar.tdesc.vt);
3496           }
3497         }
3498       }
3499       else {
3500         TRACE_(typelib)("VAR_PERINSTANCE\n");
3501         (*ppVarDesc)->vardesc.u.oInst = pItem->byte_offs;
3502         (*ppVarDesc)->vardesc.varkind = VAR_PERINSTANCE;
3503       }
3504 
3505       if (pItem->magic == SLTG_VAR_WITH_FLAGS_MAGIC)
3506         (*ppVarDesc)->vardesc.wVarFlags = pItem->varflags;
3507 
3508       if (pItem->flags & 0x80)
3509         (*ppVarDesc)->vardesc.wVarFlags |= VARFLAG_FREADONLY;
3510 
3511       bstrPrevName = (*ppVarDesc)->Name;
3512       ppVarDesc = &((*ppVarDesc)->next);
3513   }
3514   pTI->TypeAttr.cVars = cVars;
3515 }
3516 
3517 static void SLTG_DoFuncs(char *pBlk, char *pFirstItem, ITypeInfoImpl *pTI,
3518                          unsigned short cFuncs, char *pNameTable, const sltg_ref_lookup_t *ref_lookup)
3519 {
3520     SLTG_Function *pFunc;
3521     unsigned short i;
3522     TLBFuncDesc **ppFuncDesc = &pTI->funclist;
3523 
3524     for(pFunc = (SLTG_Function*)pFirstItem, i = 0; i < cFuncs;
3525         pFunc = (SLTG_Function*)(pBlk + pFunc->next), i++) {
3526 
3527         int param;
3528         WORD *pType, *pArg;
3529 
3530         *ppFuncDesc = heap_alloc_zero(sizeof(**ppFuncDesc));
3531 
3532         switch (pFunc->magic & ~SLTG_FUNCTION_FLAGS_PRESENT) {
3533         case SLTG_FUNCTION_MAGIC:
3534             (*ppFuncDesc)->funcdesc.funckind = FUNC_PUREVIRTUAL;
3535             break;
3536         case SLTG_DISPATCH_FUNCTION_MAGIC:
3537             (*ppFuncDesc)->funcdesc.funckind = FUNC_DISPATCH;
3538             break;
3539         case SLTG_STATIC_FUNCTION_MAGIC:
3540             (*ppFuncDesc)->funcdesc.funckind = FUNC_STATIC;
3541             break;
3542         default:
3543             FIXME("unimplemented func magic = %02x\n", pFunc->magic & ~SLTG_FUNCTION_FLAGS_PRESENT);
3544             heap_free(*ppFuncDesc);
3545             *ppFuncDesc = NULL;
3546             return;
3547         }
3548         (*ppFuncDesc)->Name = TLB_MultiByteToBSTR(pFunc->name + pNameTable);
3549 
3550         (*ppFuncDesc)->funcdesc.memid = pFunc->dispid;
3551         (*ppFuncDesc)->funcdesc.invkind = pFunc->inv >> 4;
3552         (*ppFuncDesc)->funcdesc.callconv = pFunc->nacc & 0x7;
3553         (*ppFuncDesc)->funcdesc.cParams = pFunc->nacc >> 3;
3554         (*ppFuncDesc)->funcdesc.cParamsOpt = (pFunc->retnextopt & 0x7e) >> 1;
3555         (*ppFuncDesc)->funcdesc.oVft = pFunc->vtblpos;
3556 
3557         if(pFunc->magic & SLTG_FUNCTION_FLAGS_PRESENT)
3558             (*ppFuncDesc)->funcdesc.wFuncFlags = pFunc->funcflags;
3559 
3560         if(pFunc->retnextopt & 0x80)
3561             pType = &pFunc->rettype;
3562         else
3563             pType = (WORD*)(pBlk + pFunc->rettype);
3564 
3565         SLTG_DoElem(pType, pBlk, &(*ppFuncDesc)->funcdesc.elemdescFunc, ref_lookup);
3566 
3567         (*ppFuncDesc)->funcdesc.lprgelemdescParam =
3568           heap_alloc_zero((*ppFuncDesc)->funcdesc.cParams * sizeof(ELEMDESC));
3569         (*ppFuncDesc)->pParamDesc =
3570           heap_alloc_zero((*ppFuncDesc)->funcdesc.cParams * sizeof(TLBParDesc));
3571 
3572         pArg = (WORD*)(pBlk + pFunc->arg_off);
3573 
3574         for(param = 0; param < (*ppFuncDesc)->funcdesc.cParams; param++) {
3575             char *paramName = pNameTable + *pArg;
3576             BOOL HaveOffs;
3577             /* If arg type follows then paramName points to the 2nd
3578                letter of the name, else the next WORD is an offset to
3579                the arg type and paramName points to the first letter.
3580                So let's take one char off paramName and see if we're
3581                pointing at an alpha-numeric char.  However if *pArg is
3582                0xffff or 0xfffe then the param has no name, the former
3583                meaning that the next WORD is the type, the latter
3584                meaning that the next WORD is an offset to the type. */
3585 
3586             HaveOffs = FALSE;
3587             if(*pArg == 0xffff)
3588                 paramName = NULL;
3589             else if(*pArg == 0xfffe) {
3590                 paramName = NULL;
3591                 HaveOffs = TRUE;
3592             }
3593             else if(paramName[-1] && !isalnum(paramName[-1]))
3594                 HaveOffs = TRUE;
3595 
3596             pArg++;
3597 
3598             if(HaveOffs) { /* the next word is an offset to type */
3599                 pType = (WORD*)(pBlk + *pArg);
3600                 SLTG_DoElem(pType, pBlk,
3601                             &(*ppFuncDesc)->funcdesc.lprgelemdescParam[param], ref_lookup);
3602                 pArg++;
3603             } else {
3604                 if(paramName)
3605                   paramName--;
3606                 pArg = SLTG_DoElem(pArg, pBlk,
3607                                    &(*ppFuncDesc)->funcdesc.lprgelemdescParam[param], ref_lookup);
3608             }
3609 
3610             /* Are we an optional param ? */
3611             if((*ppFuncDesc)->funcdesc.cParams - param <=
3612                (*ppFuncDesc)->funcdesc.cParamsOpt)
3613               (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].u.paramdesc.wParamFlags |= PARAMFLAG_FOPT;
3614 
3615             if(paramName) {
3616                 (*ppFuncDesc)->pParamDesc[param].Name =
3617                   TLB_MultiByteToBSTR(paramName);
3618             } else {
3619                 (*ppFuncDesc)->pParamDesc[param].Name =
3620                   SysAllocString((*ppFuncDesc)->Name);
3621             }
3622         }
3623 
3624         ppFuncDesc = &((*ppFuncDesc)->next);
3625         if(pFunc->next == 0xffff) break;
3626     }
3627     pTI->TypeAttr.cFuncs = cFuncs;
3628 }
3629 
3630 static void SLTG_ProcessCoClass(char *pBlk, ITypeInfoImpl *pTI,
3631                                 char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3632                                 SLTG_TypeInfoTail *pTITail)
3633 {
3634     char *pFirstItem;
3635     sltg_ref_lookup_t *ref_lookup = NULL;
3636 
3637     if(pTIHeader->href_table != 0xffffffff) {
3638         ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3639                     pNameTable);
3640     }
3641 
3642     pFirstItem = pBlk;
3643 
3644     if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
3645         SLTG_DoImpls(pFirstItem, pTI, FALSE, ref_lookup);
3646     }
3647     heap_free(ref_lookup);
3648 }
3649 
3650 
3651 static void SLTG_ProcessInterface(char *pBlk, ITypeInfoImpl *pTI,
3652                                   char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3653                                   const SLTG_TypeInfoTail *pTITail)
3654 {
3655     char *pFirstItem;
3656     sltg_ref_lookup_t *ref_lookup = NULL;
3657 
3658     if(pTIHeader->href_table != 0xffffffff) {
3659         ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3660                     pNameTable);
3661     }
3662 
3663     pFirstItem = pBlk;
3664 
3665     if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
3666         SLTG_DoImpls(pFirstItem, pTI, TRUE, ref_lookup);
3667     }
3668 
3669     if (pTITail->funcs_off != 0xffff)
3670         SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup);
3671 
3672     heap_free(ref_lookup);
3673 
3674     if (TRACE_ON(typelib))
3675         dump_TLBFuncDesc(pTI->funclist);
3676 }
3677 
3678 static void SLTG_ProcessRecord(char *pBlk, ITypeInfoImpl *pTI,
3679                                const char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3680                                const SLTG_TypeInfoTail *pTITail)
3681 {
3682   SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, NULL);
3683 }
3684 
3685 static void SLTG_ProcessAlias(char *pBlk, ITypeInfoImpl *pTI,
3686                               char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3687                               const SLTG_TypeInfoTail *pTITail)
3688 {
3689   WORD *pType;
3690   sltg_ref_lookup_t *ref_lookup = NULL;
3691 
3692   if (pTITail->simple_alias) {
3693     /* if simple alias, no more processing required */
3694     pTI->TypeAttr.tdescAlias.vt = pTITail->tdescalias_vt;
3695     return;
3696   }
3697 
3698   if(pTIHeader->href_table != 0xffffffff) {
3699       ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3700                   pNameTable);
3701   }
3702 
3703   /* otherwise it is an offset to a type */
3704   pType = (WORD *)(pBlk + pTITail->tdescalias_vt);
3705 
3706   SLTG_DoType(pType, pBlk, &pTI->TypeAttr.tdescAlias, ref_lookup);
3707 
3708   heap_free(ref_lookup);
3709 }
3710 
3711 static void SLTG_ProcessDispatch(char *pBlk, ITypeInfoImpl *pTI,
3712                                  char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3713                                  const SLTG_TypeInfoTail *pTITail)
3714 {
3715   sltg_ref_lookup_t *ref_lookup = NULL;
3716   if (pTIHeader->href_table != 0xffffffff)
3717       ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3718                                   pNameTable);
3719 
3720   if (pTITail->vars_off != 0xffff)
3721     SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, ref_lookup);
3722 
3723   if (pTITail->funcs_off != 0xffff)
3724     SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup);
3725 
3726   if (pTITail->impls_off != 0xffff)
3727     SLTG_DoImpls(pBlk + pTITail->impls_off, pTI, FALSE, ref_lookup);
3728 
3729   /* this is necessary to cope with MSFT typelibs that set cFuncs to the number
3730    * of dispinterface functions including the IDispatch ones, so
3731    * ITypeInfo::GetFuncDesc takes the real value for cFuncs from cbSizeVft */
3732   pTI->TypeAttr.cbSizeVft = pTI->TypeAttr.cFuncs * sizeof(void *);
3733 
3734   heap_free(ref_lookup);
3735   if (TRACE_ON(typelib))
3736       dump_TLBFuncDesc(pTI->funclist);
3737 }
3738 
3739 static void SLTG_ProcessEnum(char *pBlk, ITypeInfoImpl *pTI,
3740                              const char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3741                              const SLTG_TypeInfoTail *pTITail)
3742 {
3743   SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, NULL);
3744 }
3745 
3746 static void SLTG_ProcessModule(char *pBlk, ITypeInfoImpl *pTI,
3747                                char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3748                                const SLTG_TypeInfoTail *pTITail)
3749 {
3750   sltg_ref_lookup_t *ref_lookup = NULL;
3751   if (pTIHeader->href_table != 0xffffffff)
3752       ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3753                                   pNameTable);
3754 
3755   if (pTITail->vars_off != 0xffff)
3756     SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, ref_lookup);
3757 
3758   if (pTITail->funcs_off != 0xffff)
3759     SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup);
3760   heap_free(ref_lookup);
3761   if (TRACE_ON(typelib))
3762     dump_TypeInfo(pTI);
3763 }
3764 
3765 /* Because SLTG_OtherTypeInfo is such a painful struct, we make a more
3766    managable copy of it into this */
3767 typedef struct {
3768   WORD small_no;
3769   char *index_name;
3770   char *other_name;
3771   WORD res1a;
3772   WORD name_offs;
3773   WORD more_bytes;
3774   char *extra;
3775   WORD res20;
3776   DWORD helpcontext;
3777   WORD res26;
3778   GUID uuid;
3779 } SLTG_InternalOtherTypeInfo;
3780 
3781 /****************************************************************************
3782  *      ITypeLib2_Constructor_SLTG
3783  *
3784  * loading a SLTG typelib from an in-memory image
3785  */
3786 static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength)
3787 {
3788     ITypeLibImpl *pTypeLibImpl;
3789     SLTG_Header *pHeader;
3790     SLTG_BlkEntry *pBlkEntry;
3791     SLTG_Magic *pMagic;
3792     SLTG_Index *pIndex;
3793     SLTG_Pad9 *pPad9;
3794     LPVOID pBlk, pFirstBlk;
3795     SLTG_LibBlk *pLibBlk;
3796     SLTG_InternalOtherTypeInfo *pOtherTypeInfoBlks;
3797     char *pAfterOTIBlks = NULL;
3798     char *pNameTable, *ptr;
3799     int i;
3800     DWORD len, order;
3801     ITypeInfoImpl **ppTypeInfoImpl;
3802 
3803     TRACE_(typelib)("%p, TLB length = %d\n", pLib, dwTLBLength);
3804 
3805 
3806     pTypeLibImpl = TypeLibImpl_Constructor();
3807     if (!pTypeLibImpl) return NULL;
3808 
3809     pHeader = pLib;
3810 
3811     TRACE_(typelib)("header:\n");
3812     TRACE_(typelib)("\tmagic=0x%08x, file blocks = %d\n", pHeader->SLTG_magic,
3813           pHeader->nrOfFileBlks );
3814     if (pHeader->SLTG_magic != SLTG_SIGNATURE) {
3815         FIXME_(typelib)("Header type magic 0x%08x not supported.\n",
3816               pHeader->SLTG_magic);
3817         return NULL;
3818     }
3819 
3820     /* There are pHeader->nrOfFileBlks - 2 TypeInfo records in this typelib */
3821     pTypeLibImpl->TypeInfoCount = pHeader->nrOfFileBlks - 2;
3822 
3823     /* This points to pHeader->nrOfFileBlks - 1 of SLTG_BlkEntry */
3824     pBlkEntry = (SLTG_BlkEntry*)(pHeader + 1);
3825 
3826     /* Next we have a magic block */
3827     pMagic = (SLTG_Magic*)(pBlkEntry + pHeader->nrOfFileBlks - 1);
3828 
3829     /* Let's see if we're still in sync */
3830     if(memcmp(pMagic->CompObj_magic, SLTG_COMPOBJ_MAGIC,
3831               sizeof(SLTG_COMPOBJ_MAGIC))) {
3832         FIXME_(typelib)("CompObj magic = %s\n", pMagic->CompObj_magic);
3833         return NULL;
3834     }
3835     if(memcmp(pMagic->dir_magic, SLTG_DIR_MAGIC,
3836               sizeof(SLTG_DIR_MAGIC))) {
3837         FIXME_(typelib)("dir magic = %s\n", pMagic->dir_magic);
3838         return NULL;
3839     }
3840 
3841     pIndex = (SLTG_Index*)(pMagic+1);
3842 
3843     pPad9 = (SLTG_Pad9*)(pIndex + pTypeLibImpl->TypeInfoCount);
3844 
3845     pFirstBlk = pPad9 + 1;
3846 
3847     /* We'll set up a ptr to the main library block, which is the last one. */
3848 
3849     for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0;
3850           pBlkEntry[order].next != 0;
3851           order = pBlkEntry[order].next - 1, i++) {
3852        pBlk = (char*)pBlk + pBlkEntry[order].len;
3853     }
3854     pLibBlk = pBlk;
3855 
3856     len = SLTG_ReadLibBlk(pLibBlk, pTypeLibImpl);
3857 
3858     /* Now there's 0x40 bytes of 0xffff with the numbers 0 to TypeInfoCount
3859        interspersed */
3860 
3861     len += 0x40;
3862 
3863     /* And now TypeInfoCount of SLTG_OtherTypeInfo */
3864 
3865     pOtherTypeInfoBlks = heap_alloc_zero(sizeof(*pOtherTypeInfoBlks) * pTypeLibImpl->TypeInfoCount);
3866 
3867 
3868     ptr = (char*)pLibBlk + len;
3869 
3870     for(i = 0; i < pTypeLibImpl->TypeInfoCount; i++) {
3871         WORD w, extra;
3872         len = 0;
3873 
3874         pOtherTypeInfoBlks[i].small_no = *(WORD*)ptr;
3875 
3876         w = *(WORD*)(ptr + 2);
3877         if(w != 0xffff) {
3878             len += w;
3879             pOtherTypeInfoBlks[i].index_name = heap_alloc(w+1);
3880             memcpy(pOtherTypeInfoBlks[i].index_name, ptr + 4, w);
3881             pOtherTypeInfoBlks[i].index_name[w] = '\0';
3882         }
3883         w = *(WORD*)(ptr + 4 + len);
3884         if(w != 0xffff) {
3885             TRACE_(typelib)("\twith %s\n", debugstr_an(ptr + 6 + len, w));
3886             len += w;
3887             pOtherTypeInfoBlks[i].other_name = heap_alloc(w+1);
3888             memcpy(pOtherTypeInfoBlks[i].other_name, ptr + 6 + len, w);
3889             pOtherTypeInfoBlks[i].other_name[w] = '\0';
3890         }
3891         pOtherTypeInfoBlks[i].res1a = *(WORD*)(ptr + len + 6);
3892         pOtherTypeInfoBlks[i].name_offs = *(WORD*)(ptr + len + 8);
3893         extra = pOtherTypeInfoBlks[i].more_bytes = *(WORD*)(ptr + 10 + len);
3894         if(extra) {
3895             pOtherTypeInfoBlks[i].extra = heap_alloc(extra);
3896             memcpy(pOtherTypeInfoBlks[i].extra, ptr + 12, extra);
3897             len += extra;
3898         }
3899         pOtherTypeInfoBlks[i].res20 = *(WORD*)(ptr + 12 + len);
3900         pOtherTypeInfoBlks[i].helpcontext = *(DWORD*)(ptr + 14 + len);
3901         pOtherTypeInfoBlks[i].res26 = *(WORD*)(ptr + 18 + len);
3902         memcpy(&pOtherTypeInfoBlks[i].uuid, ptr + 20 + len, sizeof(GUID));
3903         len += sizeof(SLTG_OtherTypeInfo);
3904         ptr += len;
3905     }
3906 
3907     pAfterOTIBlks = ptr;
3908 
3909     /* Skip this WORD and get the next DWORD */
3910     len = *(DWORD*)(pAfterOTIBlks + 2);
3911 
3912     /* Now add this to pLibBLk look at what we're pointing at and
3913        possibly add 0x20, then add 0x216, sprinkle a bit a magic
3914        dust and we should be pointing at the beginning of the name
3915        table */
3916 
3917     pNameTable = (char*)pLibBlk + len;
3918 
3919    switch(*(WORD*)pNameTable) {
3920    case 0xffff:
3921        break;
3922    case 0x0200:
3923        pNameTable += 0x20;
3924        break;
3925    default:
3926        FIXME_(typelib)("pNameTable jump = %x\n", *(WORD*)pNameTable);
3927        break;
3928    }
3929 
3930     pNameTable += 0x216;
3931 
3932     pNameTable += 2;
3933 
3934     TRACE_(typelib)("Library name is %s\n", pNameTable + pLibBlk->name);
3935 
3936     pTypeLibImpl->Name = TLB_MultiByteToBSTR(pNameTable + pLibBlk->name);
3937 
3938 
3939     /* Hopefully we now have enough ptrs set up to actually read in
3940        some TypeInfos.  It's not clear which order to do them in, so
3941        I'll just follow the links along the BlkEntry chain and read
3942        them in the order in which they are in the file */
3943 
3944     ppTypeInfoImpl = &(pTypeLibImpl->pTypeInfo);
3945 
3946     for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0;
3947         pBlkEntry[order].next != 0;
3948         order = pBlkEntry[order].next - 1, i++) {
3949 
3950       SLTG_TypeInfoHeader *pTIHeader;
3951       SLTG_TypeInfoTail *pTITail;
3952       SLTG_MemberHeader *pMemHeader;
3953 
3954       if(strcmp(pBlkEntry[order].index_string + (char*)pMagic,
3955                 pOtherTypeInfoBlks[i].index_name)) {
3956         FIXME_(typelib)("Index strings don't match\n");
3957         return NULL;
3958       }
3959 
3960       pTIHeader = pBlk;
3961       if(pTIHeader->magic != SLTG_TIHEADER_MAGIC) {
3962         FIXME_(typelib)("TypeInfoHeader magic = %04x\n", pTIHeader->magic);
3963         return NULL;
3964       }
3965       TRACE_(typelib)("pTIHeader->res06 = %x, pTIHeader->res0e = %x, "
3966         "pTIHeader->res16 = %x, pTIHeader->res1e = %x\n",
3967         pTIHeader->res06, pTIHeader->res0e, pTIHeader->res16, pTIHeader->res1e);
3968 
3969       *ppTypeInfoImpl = ITypeInfoImpl_Constructor();
3970       (*ppTypeInfoImpl)->pTypeLib = pTypeLibImpl;
3971       (*ppTypeInfoImpl)->index = i;
3972       (*ppTypeInfoImpl)->Name = TLB_MultiByteToBSTR(
3973                                              pOtherTypeInfoBlks[i].name_offs +
3974                                              pNameTable);
3975       (*ppTypeInfoImpl)->dwHelpContext = pOtherTypeInfoBlks[i].helpcontext;
3976       (*ppTypeInfoImpl)->TypeAttr.guid = pOtherTypeInfoBlks[i].uuid;
3977       (*ppTypeInfoImpl)->TypeAttr.typekind = pTIHeader->typekind;
3978       (*ppTypeInfoImpl)->TypeAttr.wMajorVerNum = pTIHeader->major_version;
3979       (*ppTypeInfoImpl)->TypeAttr.wMinorVerNum = pTIHeader->minor_version;
3980       (*ppTypeInfoImpl)->TypeAttr.wTypeFlags =
3981         (pTIHeader->typeflags1 >> 3) | (pTIHeader->typeflags2 << 5);
3982 
3983       if((*ppTypeInfoImpl)->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL)
3984         (*ppTypeInfoImpl)->TypeAttr.typekind = TKIND_DISPATCH;
3985 
3986       if((pTIHeader->typeflags1 & 7) != 2)
3987         FIXME_(typelib)("typeflags1 = %02x\n", pTIHeader->typeflags1);
3988       if(pTIHeader->typeflags3 != 2)
3989         FIXME_(typelib)("typeflags3 = %02x\n", pTIHeader->typeflags3);
3990 
3991       TRACE_(typelib)("TypeInfo %s of kind %s guid %s typeflags %04x\n",
3992             debugstr_w((*ppTypeInfoImpl)->Name),
3993             typekind_desc[pTIHeader->typekind],
3994             debugstr_guid(&(*ppTypeInfoImpl)->TypeAttr.guid),
3995             (*ppTypeInfoImpl)->TypeAttr.wTypeFlags);
3996 
3997       pMemHeader = (SLTG_MemberHeader*)((char *)pBlk + pTIHeader->elem_table);
3998 
3999       pTITail = (SLTG_TypeInfoTail*)((char *)(pMemHeader + 1) + pMemHeader->cbExtra);
4000 
4001       (*ppTypeInfoImpl)->TypeAttr.cbAlignment = pTITail->cbAlignment;
4002       (*ppTypeInfoImpl)->TypeAttr.cbSizeInstance = pTITail->cbSizeInstance;
4003       (*ppTypeInfoImpl)->TypeAttr.cbSizeVft = pTITail->cbSizeVft;
4004 
4005       switch(pTIHeader->typekind) {
4006       case TKIND_ENUM:
4007         SLTG_ProcessEnum((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
4008                          pTIHeader, pTITail);
4009         break;
4010 
4011       case TKIND_RECORD:
4012         SLTG_ProcessRecord((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
4013                            pTIHeader, pTITail);
4014         break;
4015 
4016       case TKIND_INTERFACE:
4017         SLTG_ProcessInterface((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
4018                               pTIHeader, pTITail);
4019         break;
4020 
4021       case TKIND_COCLASS:
4022         SLTG_ProcessCoClass((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
4023                             pTIHeader, pTITail);
4024         break;
4025 
4026       case TKIND_ALIAS:
4027         SLTG_ProcessAlias((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
4028                           pTIHeader, pTITail);
4029         break;
4030 
4031       case TKIND_DISPATCH:
4032         SLTG_ProcessDispatch((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
4033                              pTIHeader, pTITail);
4034         break;
4035 
4036       case TKIND_MODULE:
4037         SLTG_ProcessModule((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
4038                            pTIHeader, pTITail);
4039         break;
4040 
4041       default:
4042         FIXME("Not processing typekind %d\n", pTIHeader->typekind);
4043         break;
4044 
4045       }
4046 
4047       /* could get cFuncs, cVars and cImplTypes from here
4048                        but we've already set those */
4049 #define X(x) TRACE_(typelib)("tt "#x": %x\n",pTITail->res##x);
4050       X(06);
4051       X(16);
4052       X(18);
4053       X(1a);
4054       X(1e);
4055       X(24);
4056       X(26);
4057       X(2a);
4058       X(2c);
4059       X(2e);
4060       X(30);
4061       X(32);
4062       X(34);
4063 #undef X
4064       ppTypeInfoImpl = &((*ppTypeInfoImpl)->next);
4065       pBlk = (char*)pBlk + pBlkEntry[order].len;
4066     }
4067 
4068     if(i != pTypeLibImpl->TypeInfoCount) {
4069       FIXME("Somehow processed %d TypeInfos\n", i);
4070       return NULL;
4071     }
4072 
4073     heap_free(pOtherTypeInfoBlks);
4074     return (ITypeLib2*)pTypeLibImpl;
4075 }
4076 
4077 /* ITypeLib::QueryInterface
4078  */
4079 static HRESULT WINAPI ITypeLib2_fnQueryInterface(
4080         ITypeLib2 * iface,
4081         REFIID riid,
4082         VOID **ppvObject)
4083 {
4084     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4085 
4086     TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
4087 
4088     *ppvObject=NULL;
4089     if(IsEqualIID(riid, &IID_IUnknown) ||
4090        IsEqualIID(riid,&IID_ITypeLib)||
4091        IsEqualIID(riid,&IID_ITypeLib2))
4092     {
4093         *ppvObject = This;
4094     }
4095 
4096     if(*ppvObject)
4097     {
4098         ITypeLib2_AddRef(iface);
4099         TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
4100         return S_OK;
4101     }
4102     TRACE("-- Interface: E_NOINTERFACE\n");
4103     return E_NOINTERFACE;
4104 }
4105 
4106 /* ITypeLib::AddRef
4107  */
4108 static ULONG WINAPI ITypeLib2_fnAddRef( ITypeLib2 *iface)
4109 {
4110     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4111     ULONG ref = InterlockedIncrement(&This->ref);
4112 
4113     TRACE("(%p)->ref was %u\n",This, ref - 1);
4114 
4115     return ref;
4116 }
4117 
4118 /* ITypeLib::Release
4119  */
4120 static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface)
4121 {
4122     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4123     ULONG ref = InterlockedDecrement(&This->ref);
4124 
4125     TRACE("(%p)->(%u)\n",This, ref);
4126 
4127     if (!ref)
4128     {
4129       TLBImpLib *pImpLib, *pImpLibNext;
4130       TLBCustData *pCustData, *pCustDataNext;
4131       TLBRefType *ref_type;
4132       void *cursor2;
4133       int i;
4134       ITypeInfoImpl *pTI, *pTINext;
4135 
4136       /* remove cache entry */
4137       if(This->path)
4138       {
4139           TRACE("removing from cache list\n");
4140           EnterCriticalSection(&cache_section);
4141           if (This->next) This->next->prev = This->prev;
4142           if (This->prev) This->prev->next = This->next;
4143           else tlb_cache_first = This->next;
4144           LeaveCriticalSection(&cache_section);
4145           heap_free(This->path);
4146       }
4147       TRACE(" destroying ITypeLib(%p)\n",This);
4148 
4149       SysFreeString(This->Name);
4150       This->Name = NULL;
4151 
4152       SysFreeString(This->DocString);
4153       This->DocString = NULL;
4154 
4155       SysFreeString(This->HelpFile);
4156       This->HelpFile = NULL;
4157 
4158       SysFreeString(This->HelpStringDll);
4159       This->HelpStringDll = NULL;
4160 
4161       for (pCustData = This->pCustData; pCustData; pCustData = pCustDataNext)
4162       {
4163           VariantClear(&pCustData->data);
4164 
4165           pCustDataNext = pCustData->next;
4166           heap_free(pCustData);
4167       }
4168 
4169       for (i = 0; i < This->ctTypeDesc; i++)
4170           if (This->pTypeDesc[i].vt == VT_CARRAY)
4171               heap_free(This->pTypeDesc[i].u.lpadesc);
4172 
4173       heap_free(This->pTypeDesc);
4174 
4175       for (pImpLib = This->pImpLibs; pImpLib; pImpLib = pImpLibNext)
4176       {
4177           if (pImpLib->pImpTypeLib)
4178               ITypeLib_Release((ITypeLib *)pImpLib->pImpTypeLib);
4179           SysFreeString(pImpLib->name);
4180 
4181           pImpLibNext = pImpLib->next;
4182           heap_free(pImpLib);
4183       }
4184 
4185       LIST_FOR_EACH_ENTRY_SAFE(ref_type, cursor2, &This->ref_list, TLBRefType, entry)
4186       {
4187           list_remove(&ref_type->entry);
4188           heap_free(ref_type);
4189       }
4190 
4191       for (pTI = This->pTypeInfo; pTI; pTI = pTINext)
4192       {
4193           pTINext = pTI->next;
4194           ITypeInfoImpl_Destroy(pTI);
4195       }
4196       heap_free(This);
4197       return 0;
4198     }
4199 
4200     return ref;
4201 }
4202 
4203 /* ITypeLib::GetTypeInfoCount
4204  *
4205  * Returns the number of type descriptions in the type library
4206  */
4207 static UINT WINAPI ITypeLib2_fnGetTypeInfoCount( ITypeLib2 *iface)
4208 {
4209     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4210     TRACE("(%p)->count is %d\n",This, This->TypeInfoCount);
4211     return This->TypeInfoCount;
4212 }
4213 
4214 /* ITypeLib::GetTypeInfo
4215  *
4216  * retrieves the specified type description in the library.
4217  */
4218 static HRESULT WINAPI ITypeLib2_fnGetTypeInfo(
4219     ITypeLib2 *iface,
4220     UINT index,
4221     ITypeInfo **ppTInfo)
4222 {
4223     UINT i;
4224 
4225     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4226     ITypeInfoImpl *pTypeInfo = This->pTypeInfo;
4227 
4228     TRACE("(%p)->(index=%d)\n", This, index);
4229 
4230     if (!ppTInfo) return E_INVALIDARG;
4231 
4232     /* search element n in list */
4233     for(i=0; i < index; i++)
4234     {
4235       pTypeInfo = pTypeInfo->next;
4236       if (!pTypeInfo)
4237       {
4238         TRACE("-- element not found\n");
4239         return TYPE_E_ELEMENTNOTFOUND;
4240       }
4241     }
4242 
4243     *ppTInfo = (ITypeInfo *) pTypeInfo;
4244 
4245     ITypeInfo_AddRef(*ppTInfo);
4246     TRACE("-- found (%p)\n",*ppTInfo);
4247     return S_OK;
4248 }
4249 
4250 
4251 /* ITypeLibs::GetTypeInfoType
4252  *
4253  * Retrieves the type of a type description.
4254  */
4255 static HRESULT WINAPI ITypeLib2_fnGetTypeInfoType(
4256     ITypeLib2 *iface,
4257     UINT index,
4258     TYPEKIND *pTKind)
4259 {
4260     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4261     UINT i;
4262     ITypeInfoImpl *pTInfo = This->pTypeInfo;
4263 
4264     TRACE("(%p, %d, %p)\n", This, index, pTKind);
4265 
4266     if(!pTKind) return E_INVALIDARG;
4267 
4268     if(ITypeLib2_GetTypeInfoCount(iface) <= index)
4269         return TYPE_E_ELEMENTNOTFOUND;
4270 
4271     /* search element n in list */
4272     for(i=0; i < index; i++)
4273     {
4274       if(!pTInfo)
4275       {
4276         TRACE("-- element not found\n");
4277         return TYPE_E_ELEMENTNOTFOUND;
4278       }
4279       pTInfo = pTInfo->next;
4280     }
4281 
4282     *pTKind = pTInfo->TypeAttr.typekind;
4283     TRACE("-- found Type (%d)\n", *pTKind);
4284     return S_OK;
4285 }
4286 
4287 /* ITypeLib::GetTypeInfoOfGuid
4288  *
4289  * Retrieves the type description that corresponds to the specified GUID.
4290  *
4291  */
4292 static HRESULT WINAPI ITypeLib2_fnGetTypeInfoOfGuid(
4293     ITypeLib2 *iface,
4294     REFGUID guid,
4295     ITypeInfo **ppTInfo)
4296 {
4297     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4298     ITypeInfoImpl *pTypeInfo = This->pTypeInfo; /* head of list */
4299 
4300     TRACE("(%p)\n\tguid:\t%s)\n",This,debugstr_guid(guid));
4301 
4302     if (!pTypeInfo)
4303     {
4304         WARN("-- element not found\n");
4305         return TYPE_E_ELEMENTNOTFOUND;
4306     }
4307 
4308     /* search linked list for guid */
4309     while( !IsEqualIID(guid,&pTypeInfo->TypeAttr.guid) )
4310     {
4311       pTypeInfo = pTypeInfo->next;
4312 
4313       if (!pTypeInfo)
4314       {
4315         /* end of list reached */
4316         WARN("-- element not found\n");
4317         return TYPE_E_ELEMENTNOTFOUND;
4318       }
4319     }
4320 
4321     TRACE("-- found (%p, %s)\n",
4322           pTypeInfo,
4323           debugstr_w(pTypeInfo->Name));
4324 
4325     *ppTInfo = (ITypeInfo*)pTypeInfo;
4326     ITypeInfo_AddRef(*ppTInfo);
4327     return S_OK;
4328 }
4329 
4330 /* ITypeLib::GetLibAttr
4331  *
4332  * Retrieves the structure that contains the library's attributes.
4333  *
4334  */
4335 static HRESULT WINAPI ITypeLib2_fnGetLibAttr(
4336         ITypeLib2 *iface,
4337         LPTLIBATTR *attr)
4338 {
4339     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4340 
4341     TRACE("(%p, %p)\n", This, attr);
4342 
4343     if (!attr) return E_INVALIDARG;
4344 
4345     *attr = heap_alloc(sizeof(**attr));
4346     if (!*attr) return E_OUTOFMEMORY;
4347 
4348     **attr = This->LibAttr;
4349     return S_OK;
4350 }
4351 
4352 /* ITypeLib::GetTypeComp
4353  *
4354  * Enables a client compiler to bind to a library's types, variables,
4355  * constants, and global functions.
4356  *
4357  */
4358 static HRESULT WINAPI ITypeLib2_fnGetTypeComp(
4359         ITypeLib2 *iface,
4360         ITypeComp **ppTComp)
4361 {
4362     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4363 
4364     TRACE("(%p)->(%p)\n",This,ppTComp);
4365     *ppTComp = (ITypeComp *)&This->lpVtblTypeComp;
4366     ITypeComp_AddRef(*ppTComp);
4367 
4368     return S_OK;
4369 }
4370 
4371 /* ITypeLib::GetDocumentation
4372  *
4373  * Retrieves the library's documentation string, the complete Help file name
4374  * and path, and the context identifier for the library Help topic in the Help
4375  * file.
4376  *
4377  * On a successful return all non-null BSTR pointers will have been set,
4378  * possibly to NULL.
4379  */
4380 static HRESULT WINAPI ITypeLib2_fnGetDocumentation(
4381     ITypeLib2 *iface,
4382     INT index,
4383     BSTR *pBstrName,
4384     BSTR *pBstrDocString,
4385     DWORD *pdwHelpContext,
4386     BSTR *pBstrHelpFile)
4387 {
4388     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4389 
4390     HRESULT result = E_INVALIDARG;
4391 
4392     ITypeInfo *pTInfo;
4393 
4394 
4395     TRACE("(%p) index %d Name(%p) DocString(%p) HelpContext(%p) HelpFile(%p)\n",
4396         This, index,
4397         pBstrName, pBstrDocString,
4398         pdwHelpContext, pBstrHelpFile);
4399 
4400     if(index<0)
4401     {
4402         /* documentation for the typelib */
4403         if(pBstrName)
4404         {
4405             if (This->Name)
4406             {
4407                 if(!(*pBstrName = SysAllocString(This->Name)))
4408                     goto memerr1;
4409             }
4410             else
4411                 *pBstrName = NULL;
4412         }
4413         if(pBstrDocString)
4414         {
4415             if (This->DocString)
4416             {
4417                 if(!(*pBstrDocString = SysAllocString(This->DocString)))
4418                     goto memerr2;
4419             }
4420             else if (This->Name)
4421             {
4422                 if(!(*pBstrDocString = SysAllocString(This->Name)))
4423                     goto memerr2;
4424             }
4425             else
4426                 *pBstrDocString = NULL;
4427         }
4428         if(pdwHelpContext)
4429         {
4430             *pdwHelpContext = This->dwHelpContext;
4431         }
4432         if(pBstrHelpFile)
4433         {
4434             if (This->HelpFile)
4435             {
4436                 if(!(*pBstrHelpFile = SysAllocString(This->HelpFile)))
4437                     goto memerr3;
4438             }
4439             else
4440                 *pBstrHelpFile = NULL;
4441         }
4442 
4443         result = S_OK;
4444     }
4445     else
4446     {
4447         /* for a typeinfo */
4448         result = ITypeLib2_fnGetTypeInfo(iface, index, &pTInfo);
4449 
4450         if(SUCCEEDED(result))
4451         {
4452             result = ITypeInfo_GetDocumentation(pTInfo,
4453                                           MEMBERID_NIL,
4454                                           pBstrName,
4455                                           pBstrDocString,
4456                                           pdwHelpContext, pBstrHelpFile);
4457 
4458             ITypeInfo_Release(pTInfo);
4459         }
4460     }
4461     return result;
4462 memerr3:
4463     if (pBstrDocString) SysFreeString (*pBstrDocString);
4464 memerr2:
4465     if (pBstrName) SysFreeString (*pBstrName);
4466 memerr1:
4467     return STG_E_INSUFFICIENTMEMORY;
4468 }
4469 
4470 /* ITypeLib::IsName
4471  *
4472  * Indicates whether a passed-in string contains the name of a type or member
4473  * described in the library.
4474  *
4475  */
4476 static HRESULT WINAPI ITypeLib2_fnIsName(
4477         ITypeLib2 *iface,
4478         LPOLESTR szNameBuf,
4479         ULONG lHashVal,
4480         BOOL *pfName)
4481 {
4482     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4483     ITypeInfoImpl *pTInfo;
4484     TLBFuncDesc *pFInfo;
4485     TLBVarDesc *pVInfo;
4486     int i;
4487     UINT nNameBufLen = (lstrlenW(szNameBuf)+1)*sizeof(WCHAR);
4488 
4489     TRACE("(%p)->(%s,%08x,%p)\n", This, debugstr_w(szNameBuf), lHashVal,
4490           pfName);
4491 
4492     *pfName=TRUE;
4493     for(pTInfo=This->pTypeInfo;pTInfo;pTInfo=pTInfo->next){
4494         if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
4495         for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
4496             if(!memcmp(szNameBuf,pFInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
4497             for(i=0;i<pFInfo->funcdesc.cParams;i++)
4498                 if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name, nNameBufLen))
4499                     goto ITypeLib2_fnIsName_exit;
4500         }
4501         for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next)
4502             if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
4503 
4504     }
4505     *pfName=FALSE;
4506 
4507 ITypeLib2_fnIsName_exit:
4508     TRACE("(%p)slow! search for %s: %s found!\n", This,
4509           debugstr_w(szNameBuf), *pfName?"NOT":"");
4510 
4511     return S_OK;
4512 }
4513 
4514 /* ITypeLib::FindName
4515  *
4516  * Finds occurrences of a type description in a type library. This may be used
4517  * to quickly verify that a name exists in a type library.
4518  *
4519  */
4520 static HRESULT WINAPI ITypeLib2_fnFindName(
4521         ITypeLib2 *iface,
4522         LPOLESTR szNameBuf,
4523         ULONG lHashVal,
4524         ITypeInfo **ppTInfo,
4525         MEMBERID *rgMemId,
4526         UINT16 *pcFound)
4527 {
4528     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4529     ITypeInfoImpl *pTInfo;
4530     TLBFuncDesc *pFInfo;
4531     TLBVarDesc *pVInfo;
4532     int i,j = 0;
4533     UINT nNameBufLen = (lstrlenW(szNameBuf)+1)*sizeof(WCHAR);
4534 
4535     for(pTInfo=This->pTypeInfo;pTInfo && j<*pcFound; pTInfo=pTInfo->next){
4536         if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit;
4537         for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
4538             if(!memcmp(szNameBuf,pFInfo->Name,nNameBufLen)) goto ITypeLib2_fnFindName_exit;
4539             for(i=0;i<pFInfo->funcdesc.cParams;i++) {
4540                 if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name,nNameBufLen))
4541                     goto ITypeLib2_fnFindName_exit;
4542             }
4543         }
4544         for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next)
4545             if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit;
4546         continue;
4547 ITypeLib2_fnFindName_exit:
4548         ITypeInfo_AddRef((ITypeInfo*)pTInfo);
4549         ppTInfo[j]=(LPTYPEINFO)pTInfo;
4550         j++;
4551     }
4552     TRACE("(%p)slow! search for %d with %s: found %d TypeInfo's!\n",
4553           This, *pcFound, debugstr_w(szNameBuf), j);
4554 
4555     *pcFound=j;
4556 
4557     return S_OK;
4558 }
4559 
4560 /* ITypeLib::ReleaseTLibAttr
4561  *
4562  * Releases the TLIBATTR originally obtained from ITypeLib::GetLibAttr.
4563  *
4564  */
4565 static VOID WINAPI ITypeLib2_fnReleaseTLibAttr(
4566         ITypeLib2 *iface,
4567         TLIBATTR *pTLibAttr)
4568 {
4569     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4570     TRACE("freeing (%p)\n",This);
4571     heap_free(pTLibAttr);
4572 
4573 }
4574 
4575 /* ITypeLib2::GetCustData
4576  *
4577  * gets the custom data
4578  */
4579 static HRESULT WINAPI ITypeLib2_fnGetCustData(
4580         ITypeLib2 * iface,
4581         REFGUID guid,
4582         VARIANT *pVarVal)
4583 {
4584     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4585     TLBCustData *pCData;
4586 
4587     for(pCData=This->pCustData; pCData; pCData = pCData->next)
4588     {
4589       if( IsEqualIID(guid, &pCData->guid)) break;
4590     }
4591 
4592     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
4593 
4594     if(pCData)
4595     {
4596         VariantInit( pVarVal);
4597         VariantCopy( pVarVal, &pCData->data);
4598         return S_OK;
4599     }
4600     return E_INVALIDARG;  /* FIXME: correct? */
4601 }
4602 
4603 /* ITypeLib2::GetLibStatistics
4604  *
4605  * Returns statistics about a type library that are required for efficient
4606  * sizing of hash tables.
4607  *
4608  */
4609 static HRESULT WINAPI ITypeLib2_fnGetLibStatistics(
4610         ITypeLib2 * iface,
4611         ULONG *pcUniqueNames,
4612         ULONG *pcchUniqueNames)
4613 {
4614     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4615 
4616     FIXME("(%p): stub!\n", This);
4617 
4618     if(pcUniqueNames) *pcUniqueNames=1;
4619     if(pcchUniqueNames) *pcchUniqueNames=1;
4620     return S_OK;
4621 }
4622 
4623 /* ITypeLib2::GetDocumentation2
4624  *
4625  * Retrieves the library's documentation string, the complete Help file name
4626  * and path, the localization context to use, and the context ID for the
4627  * library Help topic in the Help file.
4628  *
4629  */
4630 static HRESULT WINAPI ITypeLib2_fnGetDocumentation2(
4631         ITypeLib2 * iface,
4632         INT index,
4633         LCID lcid,
4634         BSTR *pbstrHelpString,
4635         DWORD *pdwHelpStringContext,
4636         BSTR *pbstrHelpStringDll)
4637 {
4638     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4639     HRESULT result;
4640     ITypeInfo *pTInfo;
4641 
4642     FIXME("(%p) index %d lcid %d half implemented stub!\n", This, index, lcid);
4643 
4644     /* the help string should be obtained from the helpstringdll,
4645      * using the _DLLGetDocumentation function, based on the supplied
4646      * lcid. Nice to do sometime...
4647      */
4648     if(index<0)
4649     {
4650       /* documentation for the typelib */
4651       if(pbstrHelpString)
4652         *pbstrHelpString=SysAllocString(This->DocString);
4653       if(pdwHelpStringContext)
4654         *pdwHelpStringContext=This->dwHelpContext;
4655       if(pbstrHelpStringDll)
4656         *pbstrHelpStringDll=SysAllocString(This->HelpStringDll);
4657 
4658       result = S_OK;
4659     }
4660     else
4661     {
4662       /* for a typeinfo */
4663       result=ITypeLib2_GetTypeInfo(iface, index, &pTInfo);
4664 
4665       if(SUCCEEDED(result))
4666       {
4667         ITypeInfo2 * pTInfo2;
4668         result = ITypeInfo_QueryInterface(pTInfo,
4669                                           &IID_ITypeInfo2,
4670                                           (LPVOID*) &pTInfo2);
4671 
4672         if(SUCCEEDED(result))
4673         {
4674           result = ITypeInfo2_GetDocumentation2(pTInfo2,
4675                                            MEMBERID_NIL,
4676                                            lcid,
4677                                            pbstrHelpString,
4678                                            pdwHelpStringContext,
4679                                            pbstrHelpStringDll);
4680 
4681           ITypeInfo2_Release(pTInfo2);
4682         }
4683 
4684         ITypeInfo_Release(pTInfo);
4685       }
4686     }
4687     return result;
4688 }
4689 
4690 /* ITypeLib2::GetAllCustData
4691  *
4692  * Gets all custom data items for the library.
4693  *
4694  */
4695 static HRESULT WINAPI ITypeLib2_fnGetAllCustData(
4696         ITypeLib2 * iface,
4697         CUSTDATA *pCustData)
4698 {
4699     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4700     TLBCustData *pCData;
4701     int i;
4702     TRACE("(%p) returning %d items\n", This, This->ctCustData);
4703     pCustData->prgCustData = heap_alloc_zero(This->ctCustData * sizeof(CUSTDATAITEM));
4704     if(pCustData->prgCustData ){
4705         pCustData->cCustData=This->ctCustData;
4706         for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
4707             pCustData->prgCustData[i].guid=pCData->guid;
4708             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
4709         }
4710     }else{
4711         ERR(" OUT OF MEMORY!\n");
4712         return E_OUTOFMEMORY;
4713     }
4714     return S_OK;
4715 }
4716 
4717 static const ITypeLib2Vtbl tlbvt = {
4718     ITypeLib2_fnQueryInterface,
4719     ITypeLib2_fnAddRef,
4720     ITypeLib2_fnRelease,
4721     ITypeLib2_fnGetTypeInfoCount,
4722     ITypeLib2_fnGetTypeInfo,
4723     ITypeLib2_fnGetTypeInfoType,
4724     ITypeLib2_fnGetTypeInfoOfGuid,
4725     ITypeLib2_fnGetLibAttr,
4726     ITypeLib2_fnGetTypeComp,
4727     ITypeLib2_fnGetDocumentation,
4728     ITypeLib2_fnIsName,
4729     ITypeLib2_fnFindName,
4730     ITypeLib2_fnReleaseTLibAttr,
4731 
4732     ITypeLib2_fnGetCustData,
4733     ITypeLib2_fnGetLibStatistics,
4734     ITypeLib2_fnGetDocumentation2,
4735     ITypeLib2_fnGetAllCustData
4736  };
4737 
4738 
4739 static HRESULT WINAPI ITypeLibComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
4740 {
4741     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4742 
4743     return ITypeLib2_QueryInterface((ITypeLib *)This, riid, ppv);
4744 }
4745 
4746 static ULONG WINAPI ITypeLibComp_fnAddRef(ITypeComp * iface)
4747 {
4748     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4749 
4750     return ITypeLib2_AddRef((ITypeLib2 *)This);
4751 }
4752 
4753 static ULONG WINAPI ITypeLibComp_fnRelease(ITypeComp * iface)
4754 {
4755     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4756 
4757     return ITypeLib2_Release((ITypeLib2 *)This);
4758 }
4759 
4760 static HRESULT WINAPI ITypeLibComp_fnBind(
4761     ITypeComp * iface,
4762     OLECHAR * szName,
4763     ULONG lHash,
4764     WORD wFlags,
4765     ITypeInfo ** ppTInfo,
4766     DESCKIND * pDescKind,
4767     BINDPTR * pBindPtr)
4768 {
4769     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4770     ITypeInfoImpl *pTypeInfo;
4771     int typemismatch=0;
4772 
4773     TRACE("(%s, 0x%x, 0x%x, %p, %p, %p)\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
4774 
4775     *pDescKind = DESCKIND_NONE;
4776     pBindPtr->lptcomp = NULL;
4777     *ppTInfo = NULL;
4778 
4779     for (pTypeInfo = This->pTypeInfo; pTypeInfo; pTypeInfo = pTypeInfo->next)
4780     {
4781         TRACE("testing %s\n", debugstr_w(pTypeInfo->Name));
4782 
4783         /* FIXME: check wFlags here? */
4784         /* FIXME: we should use a hash table to look this info up using lHash
4785          * instead of an O(n) search */
4786         if ((pTypeInfo->TypeAttr.typekind == TKIND_ENUM) ||
4787             (pTypeInfo->TypeAttr.typekind == TKIND_MODULE))
4788         {
4789             if (pTypeInfo->Name && !strcmpW(pTypeInfo->Name, szName))
4790             {
4791                 *pDescKind = DESCKIND_TYPECOMP;
4792                 pBindPtr->lptcomp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4793                 ITypeComp_AddRef(pBindPtr->lptcomp);
4794                 TRACE("module or enum: %s\n", debugstr_w(szName));
4795                 return S_OK;
4796             }
4797         }
4798 
4799         if ((pTypeInfo->TypeAttr.typekind == TKIND_MODULE) ||
4800             (pTypeInfo->TypeAttr.typekind == TKIND_ENUM))
4801         {
4802             ITypeComp *pSubTypeComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4803             HRESULT hr;
4804 
4805             hr = ITypeComp_Bind(pSubTypeComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
4806             if (SUCCEEDED(hr) && (*pDescKind != DESCKIND_NONE))
4807             {
4808                 TRACE("found in module or in enum: %s\n", debugstr_w(szName));
4809                 return S_OK;
4810             }
4811             else if (hr == TYPE_E_TYPEMISMATCH)
4812                 typemismatch = 1;
4813         }
4814 
4815         if ((pTypeInfo->TypeAttr.typekind == TKIND_COCLASS) &&
4816             (pTypeInfo->TypeAttr.wTypeFlags & TYPEFLAG_FAPPOBJECT))
4817         {
4818             ITypeComp *pSubTypeComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4819             HRESULT hr;
4820             ITypeInfo *subtypeinfo;
4821             BINDPTR subbindptr;
4822             DESCKIND subdesckind;
4823 
4824             hr = ITypeComp_Bind(pSubTypeComp, szName, lHash, wFlags,
4825                 &subtypeinfo, &subdesckind, &subbindptr);
4826             if (SUCCEEDED(hr) && (subdesckind != DESCKIND_NONE))
4827             {
4828                 TYPEDESC tdesc_appobject;
4829                 const VARDESC vardesc_appobject =
4830                 {
4831                     -2,         /* memid */
4832                     NULL,       /* lpstrSchema */
4833                     {
4834                         0       /* oInst */
4835                     },
4836                     {
4837                                 /* ELEMDESC */
4838                         {
4839                                 /* TYPEDESC */
4840                                 {
4841                                     &tdesc_appobject
4842                                 },
4843                                 VT_PTR
4844                         },
4845                     },
4846                     0,          /* wVarFlags */
4847                     VAR_STATIC  /* varkind */
4848                 };
4849 
4850                 tdesc_appobject.u.hreftype = pTypeInfo->hreftype;
4851                 tdesc_appobject.vt = VT_USERDEFINED;
4852 
4853                 TRACE("found in implicit app object: %s\n", debugstr_w(szName));
4854 
4855                 /* cleanup things filled in by Bind call so we can put our
4856                  * application object data in there instead */
4857                 switch (subdesckind)
4858                 {
4859                 case DESCKIND_FUNCDESC:
4860                     ITypeInfo_ReleaseFuncDesc(subtypeinfo, subbindptr.lpfuncdesc);
4861                     break;
4862                 case DESCKIND_VARDESC:
4863                     ITypeInfo_ReleaseVarDesc(subtypeinfo, subbindptr.lpvardesc);
4864                     break;
4865                 default:
4866                     break;
4867                 }
4868                 if (subtypeinfo) ITypeInfo_Release(subtypeinfo);
4869 
4870                 if (pTypeInfo->hreftype == -1)
4871                     FIXME("no hreftype for interface %p\n", pTypeInfo);
4872 
4873                 hr = TLB_AllocAndInitVarDesc(&vardesc_appobject, &pBindPtr->lpvardesc);
4874                 if (FAILED(hr))
4875                     return hr;
4876 
4877                 *pDescKind = DESCKIND_IMPLICITAPPOBJ;
4878                 *ppTInfo = (ITypeInfo *)pTypeInfo;
4879                 ITypeInfo_AddRef(*ppTInfo);
4880                 return S_OK;
4881             }
4882             else if (hr == TYPE_E_TYPEMISMATCH)
4883                 typemismatch = 1;
4884         }
4885     }
4886 
4887     if (typemismatch)
4888     {
4889         TRACE("type mismatch %s\n", debugstr_w(szName));
4890         return TYPE_E_TYPEMISMATCH;
4891     }
4892     else
4893     {
4894         TRACE("name not found %s\n", debugstr_w(szName));
4895         return S_OK;
4896     }
4897 }
4898 
4899 static HRESULT WINAPI ITypeLibComp_fnBindType(
4900     ITypeComp * iface,
4901     OLECHAR * szName,
4902     ULONG lHash,
4903     ITypeInfo ** ppTInfo,
4904     ITypeComp ** ppTComp)
4905 {
4906     ITypeLibImpl *This = impl_from_ITypeComp(iface);
4907     ITypeInfoImpl *pTypeInfo;
4908 
4909     TRACE("(%s, %x, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
4910 
4911     if(!szName || !ppTInfo || !ppTComp)
4912         return E_INVALIDARG;
4913 
4914     for (pTypeInfo = This->pTypeInfo; pTypeInfo; pTypeInfo = pTypeInfo->next)
4915     {
4916         /* FIXME: should use lHash to do the search */
4917         if (pTypeInfo->Name && !strcmpiW(pTypeInfo->Name, szName))
4918         {
4919             TRACE("returning %p\n", pTypeInfo);
4920             *ppTInfo = (ITypeInfo *)&pTypeInfo->lpVtbl;
4921             ITypeInfo_AddRef(*ppTInfo);
4922             *ppTComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4923             ITypeComp_AddRef(*ppTComp);
4924             return S_OK;
4925         }
4926     }
4927 
4928     TRACE("not found\n");
4929     *ppTInfo = NULL;
4930     *ppTComp = NULL;
4931     return S_OK;
4932 }
4933 
4934 static const ITypeCompVtbl tlbtcvt =
4935 {
4936 
4937     ITypeLibComp_fnQueryInterface,
4938     ITypeLibComp_fnAddRef,
4939     ITypeLibComp_fnRelease,
4940 
4941     ITypeLibComp_fnBind,
4942     ITypeLibComp_fnBindType
4943 };
4944 
4945 /*================== ITypeInfo(2) Methods ===================================*/
4946 static ITypeInfoImpl* ITypeInfoImpl_Constructor(void)
4947 {
4948     ITypeInfoImpl *pTypeInfoImpl;
4949 
4950     pTypeInfoImpl = heap_alloc_zero(sizeof(ITypeInfoImpl));
4951     if (pTypeInfoImpl)
4952     {
4953       pTypeInfoImpl->lpVtbl = &tinfvt;
4954       pTypeInfoImpl->lpVtblTypeComp = &tcompvt;
4955       pTypeInfoImpl->ref = 0;
4956       pTypeInfoImpl->hreftype = -1;
4957       pTypeInfoImpl->TypeAttr.memidConstructor = MEMBERID_NIL;
4958       pTypeInfoImpl->TypeAttr.memidDestructor = MEMBERID_NIL;
4959     }
4960     TRACE("(%p)\n", pTypeInfoImpl);
4961     return pTypeInfoImpl;
4962 }
4963 
4964 /* ITypeInfo::QueryInterface
4965  */
4966 static HRESULT WINAPI ITypeInfo_fnQueryInterface(
4967         ITypeInfo2 *iface,
4968         REFIID riid,
4969         VOID **ppvObject)
4970 {
4971     ITypeLibImpl *This = (ITypeLibImpl *)iface;
4972 
4973     TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
4974 
4975     *ppvObject=NULL;
4976     if(IsEqualIID(riid, &IID_IUnknown) ||
4977             IsEqualIID(riid,&IID_ITypeInfo)||
4978             IsEqualIID(riid,&IID_ITypeInfo2))
4979         *ppvObject = This;
4980 
4981     if(*ppvObject){
4982         ITypeInfo_AddRef(iface);
4983         TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
4984         return S_OK;
4985     }
4986     TRACE("-- Interface: E_NOINTERFACE\n");
4987     return E_NOINTERFACE;
4988 }
4989 
4990 /* ITypeInfo::AddRef
4991  */
4992 static ULONG WINAPI ITypeInfo_fnAddRef( ITypeInfo2 *iface)
4993 {
4994     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
4995     ULONG ref = InterlockedIncrement(&This->ref);
4996 
4997     TRACE("(%p)->ref is %u\n",This, ref);
4998 
4999     if (ref == 1 /* incremented from 0 */)
5000         ITypeLib2_AddRef((ITypeLib2*)This->pTypeLib);
5001 
5002     return ref;
5003 }
5004 
5005 static void ITypeInfoImpl_Destroy(ITypeInfoImpl *This)
5006 {
5007     TLBFuncDesc *pFInfo, *pFInfoNext;
5008     TLBVarDesc *pVInfo, *pVInfoNext;
5009     TLBImplType *pImpl, *pImplNext;
5010 
5011     TRACE("destroying ITypeInfo(%p)\n",This);
5012 
5013     SysFreeString(This->Name);
5014     This->Name = NULL;
5015 
5016     SysFreeString(This->DocString);
5017     This->DocString = NULL;
5018 
5019     SysFreeString(This->DllName);
5020     This->DllName = NULL;
5021 
5022     for (pFInfo = This->funclist; pFInfo; pFInfo = pFInfoNext)
5023     {
5024         INT i;
5025         for(i = 0;i < pFInfo->funcdesc.cParams; i++)
5026         {
5027             ELEMDESC *elemdesc = &pFInfo->funcdesc.lprgelemdescParam[i];
5028             if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
5029             {
5030                 VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue);
5031                 heap_free(elemdesc->u.paramdesc.pparamdescex);
5032             }
5033             SysFreeString(pFInfo->pParamDesc[i].Name);
5034         }
5035         heap_free(pFInfo->funcdesc.lprgelemdescParam);
5036         heap_free(pFInfo->pParamDesc);
5037         TLB_FreeCustData(pFInfo->pCustData);
5038         if (!IS_INTRESOURCE(pFInfo->Entry) && pFInfo->Entry != (BSTR)-1)
5039             SysFreeString(pFInfo->Entry);
5040         SysFreeString(pFInfo->HelpString);
5041         SysFreeString(pFInfo->Name);
5042 
5043         pFInfoNext = pFInfo->next;
5044         heap_free(pFInfo);
5045     }
5046     for (pVInfo = This->varlist; pVInfo; pVInfo = pVInfoNext)
5047     {
5048         if (pVInfo->vardesc.varkind == VAR_CONST)
5049         {
5050             VariantClear(pVInfo->vardesc.u.lpvarValue);
5051             heap_free(pVInfo->vardesc.u.lpvarValue);
5052         }
5053         TLB_FreeCustData(pVInfo->pCustData);
5054         SysFreeString(pVInfo->Name);
5055         pVInfoNext = pVInfo->next;
5056         heap_free(pVInfo);
5057     }
5058     for (pImpl = This->impltypelist; pImpl; pImpl = pImplNext)
5059     {
5060         TLB_FreeCustData(pImpl->pCustData);
5061         pImplNext = pImpl->next;
5062         heap_free(pImpl);
5063     }
5064     TLB_FreeCustData(This->pCustData);
5065 
5066     heap_free(This);
5067 }
5068 
5069 /* ITypeInfo::Release
5070  */
5071 static ULONG WINAPI ITypeInfo_fnRelease(ITypeInfo2 *iface)
5072 {
5073     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5074     ULONG ref = InterlockedDecrement(&This->ref);
5075 
5076     TRACE("(%p)->(%u)\n",This, ref);
5077 
5078     if (!ref)
5079     {
5080         BOOL not_attached_to_typelib = This->not_attached_to_typelib;
5081         ITypeLib2_Release((ITypeLib2*)This->pTypeLib);
5082         if (not_attached_to_typelib)
5083             heap_free(This);
5084         /* otherwise This will be freed when typelib is freed */
5085     }
5086 
5087     return ref;
5088 }
5089 
5090 /* ITypeInfo::GetTypeAttr
5091  *
5092  * Retrieves a TYPEATTR structure that contains the attributes of the type
5093  * description.
5094  *
5095  */
5096 static HRESULT WINAPI ITypeInfo_fnGetTypeAttr( ITypeInfo2 *iface,
5097         LPTYPEATTR  *ppTypeAttr)
5098 {
5099     const ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5100     SIZE_T size;
5101 
5102     TRACE("(%p)\n",This);
5103 
5104     size = sizeof(**ppTypeAttr);
5105     if (This->TypeAttr.typekind == TKIND_ALIAS)
5106         size += TLB_SizeTypeDesc(&This->TypeAttr.tdescAlias, FALSE);
5107 
5108     *ppTypeAttr = heap_alloc(size);
5109     if (!*ppTypeAttr)
5110         return E_OUTOFMEMORY;
5111 
5112     **ppTypeAttr = This->TypeAttr;
5113 
5114     if (This->TypeAttr.typekind == TKIND_ALIAS)
5115         TLB_CopyTypeDesc(&(*ppTypeAttr)->tdescAlias,
5116             &This->TypeAttr.tdescAlias, *ppTypeAttr + 1);
5117 
5118     if((*ppTypeAttr)->typekind == TKIND_DISPATCH) {
5119         /* This should include all the inherited funcs */
5120         (*ppTypeAttr)->cFuncs = (*ppTypeAttr)->cbSizeVft / sizeof(void *);
5121         /* This is always the size of IDispatch's vtbl */
5122         (*ppTypeAttr)->cbSizeVft = sizeof(IDispatchVtbl);
5123         (*ppTypeAttr)->wTypeFlags &= ~TYPEFLAG_FOLEAUTOMATION;
5124     }
5125     return S_OK;
5126 }
5127 
5128 /* ITypeInfo::GetTypeComp
5129  *
5130  * Retrieves the ITypeComp interface for the type description, which enables a
5131  * client compiler to bind to the type description's members.
5132  *
5133  */
5134 static HRESULT WINAPI ITypeInfo_fnGetTypeComp( ITypeInfo2 *iface,
5135         ITypeComp  * *ppTComp)
5136 {
5137     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5138 
5139     TRACE("(%p)->(%p)\n", This, ppTComp);
5140 
5141     *ppTComp = (ITypeComp *)&This->lpVtblTypeComp;
5142     ITypeComp_AddRef(*ppTComp);
5143     return S_OK;
5144 }
5145 
5146 static SIZE_T TLB_SizeElemDesc( const ELEMDESC *elemdesc )
5147 {
5148     SIZE_T size = TLB_SizeTypeDesc(&elemdesc->tdesc, FALSE);
5149     if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
5150         size += sizeof(*elemdesc->u.paramdesc.pparamdescex);
5151     return size;
5152 }
5153 
5154 static HRESULT TLB_CopyElemDesc( const ELEMDESC *src, ELEMDESC *dest, char **buffer )
5155 {
5156     *dest = *src;
5157     *buffer = TLB_CopyTypeDesc(&dest->tdesc, &src->tdesc, *buffer);
5158     if (src->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
5159     {
5160         const PARAMDESCEX *pparamdescex_src = src->u.paramdesc.pparamdescex;
5161         PARAMDESCEX *pparamdescex_dest = dest->u.paramdesc.pparamdescex = (PARAMDESCEX *)*buffer;
5162         *buffer += sizeof(PARAMDESCEX);
5163         *pparamdescex_dest = *pparamdescex_src;
5164         VariantInit(&pparamdescex_dest->varDefaultValue);
5165         return VariantCopy(&pparamdescex_dest->varDefaultValue, 
5166                            (VARIANTARG *)&pparamdescex_src->varDefaultValue);
5167     }
5168     else
5169         dest->u.paramdesc.pparamdescex = NULL;
5170     return S_OK;
5171 }
5172 
5173 static void TLB_FreeElemDesc( ELEMDESC *elemdesc )
5174 {
5175     if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
5176         VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue);
5177 }
5178 
5179 static HRESULT TLB_AllocAndInitFuncDesc( const FUNCDESC *src, FUNCDESC **dest_ptr, BOOL dispinterface )
5180 {
5181     FUNCDESC *dest;
5182     char *buffer;
5183     SIZE_T size = sizeof(*src);
5184     SHORT i;
5185     HRESULT hr;
5186 
5187     size += sizeof(*src->lprgscode) * src->cScodes;
5188     size += TLB_SizeElemDesc(&src->elemdescFunc);
5189     for (i = 0; i < src->cParams; i++)
5190     {
5191         size += sizeof(ELEMDESC);
5192         size += TLB_SizeElemDesc(&src->lprgelemdescParam[i]);
5193     }
5194 
5195     dest = (FUNCDESC *)SysAllocStringByteLen(NULL, size);
5196     if (!dest) return E_OUTOFMEMORY;
5197 
5198     *dest = *src;
5199     if (dispinterface)    /* overwrite funckind */
5200         dest->funckind = FUNC_DISPATCH;
5201     buffer = (char *)(dest + 1);
5202 
5203     dest->lprgscode = (SCODE *)buffer;
5204     memcpy(dest->lprgscode, src->lprgscode, sizeof(*src->lprgscode) * src->cScodes);
5205     buffer += sizeof(*src->lprgscode) * src->cScodes;
5206 
5207     hr = TLB_CopyElemDesc(&src->elemdescFunc, &dest->elemdescFunc, &buffer);
5208     if (FAILED(hr))
5209     {
5210         SysFreeString((BSTR)dest);
5211         return hr;
5212     }
5213 
5214     dest->lprgelemdescParam = (ELEMDESC *)buffer;
5215     buffer += sizeof(ELEMDESC) * src->cParams;
5216     for (i = 0; i < src->cParams; i++)
5217     {
5218         hr = TLB_CopyElemDesc(&src->lprgelemdescParam[i], &dest->lprgelemdescParam[i], &buffer);
5219         if (FAILED(hr))
5220             break;
5221     }
5222     if (FAILED(hr))
5223     {
5224         /* undo the above actions */
5225         for (i = i - 1; i >= 0; i--)
5226             TLB_FreeElemDesc(&dest->lprgelemdescParam[i]);
5227         TLB_FreeElemDesc(&dest->elemdescFunc);
5228         SysFreeString((BSTR)dest);
5229         return hr;
5230     }
5231 
5232     /* special treatment for dispinterfaces: this makes functions appear
5233      * to return their [retval] value when it is really returning an
5234      * HRESULT */
5235     if (dispinterface && dest->elemdescFunc.tdesc.vt == VT_HRESULT)
5236     {
5237         if (dest->cParams &&
5238             (dest->lprgelemdescParam[dest->cParams - 1].u.paramdesc.wParamFlags & PARAMFLAG_FRETVAL))
5239         {
5240             ELEMDESC *elemdesc = &dest->lprgelemdescParam[dest->cParams - 1];
5241             if (elemdesc->tdesc.vt != VT_PTR)
5242             {
5243                 ERR("elemdesc should have started with VT_PTR instead of:\n");
5244                 if (ERR_ON(ole))
5245                     dump_ELEMDESC(elemdesc);
5246                 return E_UNEXPECTED;
5247             }
5248 
5249             /* copy last parameter to the return value. we are using a flat
5250              * buffer so there is no danger of leaking memory in
5251              * elemdescFunc */
5252             dest->elemdescFunc.tdesc = *elemdesc->tdesc.u.lptdesc;
5253 
5254             /* remove the last parameter */
5255             dest->cParams--;
5256         }
5257         else
5258             /* otherwise this function is made to appear to have no return
5259              * value */
5260             dest->elemdescFunc.tdesc.vt = VT_VOID;
5261 
5262     }
5263 
5264     *dest_ptr = dest;
5265     return S_OK;
5266 }
5267 
5268 HRESULT ITypeInfoImpl_GetInternalFuncDesc( ITypeInfo *iface, UINT index, const FUNCDESC **ppFuncDesc )
5269 {
5270     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5271     const TLBFuncDesc *pFDesc;
5272     UINT i;
5273 
5274     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++, pFDesc=pFDesc->next)
5275         ;
5276 
5277     if (pFDesc)
5278     {
5279         *ppFuncDesc = &pFDesc->funcdesc;
5280         return S_OK;
5281     }
5282 
5283     return TYPE_E_ELEMENTNOTFOUND;
5284 }
5285 
5286 /* internal function to make the inherited interfaces' methods appear
5287  * part of the interface */
5288 static HRESULT ITypeInfoImpl_GetInternalDispatchFuncDesc( ITypeInfo *iface,
5289     UINT index, const FUNCDESC **ppFuncDesc, UINT *funcs, UINT *hrefoffset)
5290 {
5291     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5292     HRESULT hr;
5293     UINT implemented_funcs = 0;
5294 
5295     if (funcs)
5296         *funcs = 0;
5297     else
5298         *hrefoffset = DISPATCH_HREF_OFFSET;
5299 
5300     if(This->impltypelist)
5301     {
5302         ITypeInfo *pSubTypeInfo;
5303         UINT sub_funcs;
5304 
5305         hr = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef, &pSubTypeInfo);
5306         if (FAILED(hr))
5307             return hr;
5308 
5309         hr = ITypeInfoImpl_GetInternalDispatchFuncDesc(pSubTypeInfo,
5310                                                        index,
5311                                                        ppFuncDesc,
5312                                                        &sub_funcs, hrefoffset);
5313         implemented_funcs += sub_funcs;
5314         ITypeInfo_Release(pSubTypeInfo);
5315         if (SUCCEEDED(hr))
5316             return hr;
5317         *hrefoffset += DISPATCH_HREF_OFFSET;
5318     }
5319 
5320     if (funcs)
5321         *funcs = implemented_funcs + This->TypeAttr.cFuncs;
5322     else
5323         *hrefoffset = 0;
5324     
5325     if (index < implemented_funcs)
5326         return E_INVALIDARG;
5327     return ITypeInfoImpl_GetInternalFuncDesc(iface, index - implemented_funcs,
5328                                              ppFuncDesc);
5329 }
5330 
5331 static inline void ITypeInfoImpl_ElemDescAddHrefOffset( LPELEMDESC pElemDesc, UINT hrefoffset)
5332 {
5333     TYPEDESC *pTypeDesc = &pElemDesc->tdesc;
5334     while (TRUE)
5335     {
5336         switch (pTypeDesc->vt)
5337         {
5338         case VT_USERDEFINED:
5339             pTypeDesc->u.hreftype += hrefoffset;
5340             return;
5341         case VT_PTR:
5342         case VT_SAFEARRAY:
5343             pTypeDesc = pTypeDesc->u.lptdesc;
5344             break;
5345         case VT_CARRAY:
5346             pTypeDesc = &pTypeDesc->u.lpadesc->tdescElem;
5347             break;
5348         default:
5349             return;
5350         }
5351     }
5352 }
5353 
5354 static inline void ITypeInfoImpl_FuncDescAddHrefOffset( LPFUNCDESC pFuncDesc, UINT hrefoffset)
5355 {
5356     SHORT i;
5357     for (i = 0; i < pFuncDesc->cParams; i++)
5358         ITypeInfoImpl_ElemDescAddHrefOffset(&pFuncDesc->lprgelemdescParam[i], hrefoffset);
5359     ITypeInfoImpl_ElemDescAddHrefOffset(&pFuncDesc->elemdescFunc, hrefoffset);
5360 }
5361 
5362 /* ITypeInfo::GetFuncDesc
5363  *
5364  * Retrieves the FUNCDESC structure that contains information about a
5365  * specified function.
5366  *
5367  */
5368 static HRESULT WINAPI ITypeInfo_fnGetFuncDesc( ITypeInfo2 *iface, UINT index,
5369         LPFUNCDESC  *ppFuncDesc)
5370 {
5371     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5372     const FUNCDESC *internal_funcdesc;
5373     HRESULT hr;
5374     UINT hrefoffset = 0;
5375 
5376     TRACE("(%p) index %d\n", This, index);
5377 
5378     if (This->TypeAttr.typekind == TKIND_DISPATCH)
5379         hr = ITypeInfoImpl_GetInternalDispatchFuncDesc((ITypeInfo *)iface, index,
5380                                                        &internal_funcdesc, NULL,
5381                                                        &hrefoffset);
5382     else
5383         hr = ITypeInfoImpl_GetInternalFuncDesc((ITypeInfo *)iface, index,
5384                                                &internal_funcdesc);
5385     if (FAILED(hr))
5386     {
5387         WARN("description for function %d not found\n", index);
5388         return hr;
5389     }
5390 
5391     hr = TLB_AllocAndInitFuncDesc(
5392         internal_funcdesc,
5393         ppFuncDesc,
5394         This->TypeAttr.typekind == TKIND_DISPATCH);
5395 
5396     if ((This->TypeAttr.typekind == TKIND_DISPATCH) && hrefoffset)
5397         ITypeInfoImpl_FuncDescAddHrefOffset(*ppFuncDesc, hrefoffset);
5398 
5399     TRACE("-- 0x%08x\n", hr);
5400     return hr;
5401 }
5402 
5403 static HRESULT TLB_AllocAndInitVarDesc( const VARDESC *src, VARDESC **dest_ptr )
5404 {
5405     VARDESC *dest;
5406     char *buffer;
5407     SIZE_T size = sizeof(*src);
5408     HRESULT hr;
5409 
5410     if (src->lpstrSchema) size += (strlenW(src->lpstrSchema) + 1) * sizeof(WCHAR);
5411     if (src->varkind == VAR_CONST)
5412         size += sizeof(VARIANT);
5413     size += TLB_SizeElemDesc(&src->elemdescVar);
5414 
5415     dest = (VARDESC *)SysAllocStringByteLen(NULL, size);
5416     if (!dest) return E_OUTOFMEMORY;
5417 
5418     *dest = *src;
5419     buffer = (char *)(dest + 1);
5420     if (src->lpstrSchema)
5421     {
5422         int len;
5423         dest->lpstrSchema = (LPOLESTR)buffer;
5424         len = strlenW(src->lpstrSchema);
5425         memcpy(dest->lpstrSchema, src->lpstrSchema, (len + 1) * sizeof(WCHAR));
5426         buffer += (len + 1) * sizeof(WCHAR);
5427     }
5428 
5429     if (src->varkind == VAR_CONST)
5430     {
5431         HRESULT hr;
5432 
5433         dest->u.lpvarValue = (VARIANT *)buffer;
5434         *dest->u.lpvarValue = *src->u.lpvarValue;
5435         buffer += sizeof(VARIANT);
5436         VariantInit(dest->u.lpvarValue);
5437         hr = VariantCopy(dest->u.lpvarValue, src->u.lpvarValue);
5438         if (FAILED(hr))
5439         {
5440             SysFreeString((BSTR)dest);
5441             return hr;
5442         }
5443     }
5444     hr = TLB_CopyElemDesc(&src->elemdescVar, &dest->elemdescVar, &buffer);
5445     if (FAILED(hr))
5446     {
5447         if (src->varkind == VAR_CONST)
5448             VariantClear(dest->u.lpvarValue);
5449         SysFreeString((BSTR)dest);
5450         return hr;
5451     }
5452     *dest_ptr = dest;
5453     return S_OK;
5454 }
5455 
5456 /* ITypeInfo::GetVarDesc
5457  *
5458  * Retrieves a VARDESC structure that describes the specified variable.
5459  *
5460  */
5461 static HRESULT WINAPI ITypeInfo_fnGetVarDesc( ITypeInfo2 *iface, UINT index,
5462         LPVARDESC  *ppVarDesc)
5463 {
5464     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5465     UINT i;
5466     const TLBVarDesc *pVDesc;
5467 
5468     TRACE("(%p) index %d\n", This, index);
5469 
5470     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next)
5471         ;
5472 
5473     if (pVDesc)
5474         return TLB_AllocAndInitVarDesc(&pVDesc->vardesc, ppVarDesc);
5475 
5476     return E_INVALIDARG;
5477 }
5478 
5479 /* ITypeInfo_GetNames
5480  *
5481  * Retrieves the variable with the specified member ID (or the name of the
5482  * property or method and its parameters) that correspond to the specified
5483  * function ID.
5484  */
5485 static HRESULT WINAPI ITypeInfo_fnGetNames( ITypeInfo2 *iface, MEMBERID memid,
5486         BSTR  *rgBstrNames, UINT cMaxNames, UINT  *pcNames)
5487 {
5488     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5489     const TLBFuncDesc *pFDesc;
5490     const TLBVarDesc *pVDesc;
5491     int i;
5492     TRACE("(%p) memid=0x%08x Maxname=%d\n", This, memid, cMaxNames);
5493     for(pFDesc=This->funclist; pFDesc && pFDesc->funcdesc.memid != memid; pFDesc=pFDesc->next);
5494     if(pFDesc)
5495     {
5496       /* function found, now return function and parameter names */
5497       for(i=0; i<cMaxNames && i <= pFDesc->funcdesc.cParams; i++)
5498       {
5499         if(!i)
5500           *rgBstrNames=SysAllocString(pFDesc->Name);
5501         else
5502           rgBstrNames[i]=SysAllocString(pFDesc->pParamDesc[i-1].Name);
5503       }
5504       *pcNames=i;
5505     }
5506     else
5507     {
5508       for(pVDesc=This->varlist; pVDesc && pVDesc->vardesc.memid != memid; pVDesc=pVDesc->next);
5509       if(pVDesc)
5510       {
5511         *rgBstrNames=SysAllocString(pVDesc->Name);
5512         *pcNames=1;
5513       }
5514       else
5515       {
5516         if(This->impltypelist &&
5517            (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
5518           /* recursive search */
5519           ITypeInfo *pTInfo;
5520           HRESULT result;
5521           result=ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef,
5522                                           &pTInfo);
5523           if(SUCCEEDED(result))
5524           {
5525             result=ITypeInfo_GetNames(pTInfo, memid, rgBstrNames, cMaxNames, pcNames);
5526             ITypeInfo_Release(pTInfo);
5527             return result;
5528           }
5529           WARN("Could not search inherited interface!\n");
5530         }
5531         else
5532         {
5533           WARN("no names found\n");
5534         }
5535         *pcNames=0;
5536         return TYPE_E_ELEMENTNOTFOUND;
5537       }
5538     }
5539     return S_OK;
5540 }
5541 
5542 
5543 /* ITypeInfo::GetRefTypeOfImplType
5544  *
5545  * If a type description describes a COM class, it retrieves the type
5546  * description of the implemented interface types. For an interface,
5547  * GetRefTypeOfImplType returns the type information for inherited interfaces,
5548  * if any exist.
5549  *
5550  */
5551 static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType(
5552         ITypeInfo2 *iface,
5553         UINT index,
5554         HREFTYPE  *pRefType)
5555 {
5556     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5557     UINT i;
5558     HRESULT hr = S_OK;
5559     const TLBImplType *pImpl = This->impltypelist;
5560 
5561     TRACE("(%p) index %d\n", This, index);
5562     if (TRACE_ON(ole)) dump_TypeInfo(This);
5563 
5564     if(index==(UINT)-1)
5565     {
5566       /* only valid on dual interfaces;
5567          retrieve the associated TKIND_INTERFACE handle for the current TKIND_DISPATCH
5568       */
5569       if( This->TypeAttr.typekind != TKIND_DISPATCH) return E_INVALIDARG;
5570 
5571       if (This->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL)
5572       {
5573         *pRefType = -1;
5574       }
5575       else
5576       {
5577         hr = TYPE_E_ELEMENTNOTFOUND;
5578       }
5579     }
5580     else if(index == 0 && This->TypeAttr.typekind == TKIND_DISPATCH)
5581     {
5582       /* All TKIND_DISPATCHs are made to look like they inherit from IDispatch */
5583       *pRefType = This->pTypeLib->dispatch_href;
5584     }
5585     else
5586     {
5587       /* get element n from linked list */
5588       for(i=0; pImpl && i<index; i++)
5589       {
5590         pImpl = pImpl->next;
5591       }
5592 
5593       if (pImpl)
5594         *pRefType = pImpl->hRef;
5595       else
5596         hr = TYPE_E_ELEMENTNOTFOUND;
5597     }
5598 
5599     if(TRACE_ON(ole))
5600     {
5601         if(SUCCEEDED(hr))
5602             TRACE("SUCCESS -- hRef = 0x%08x\n", *pRefType );
5603         else
5604             TRACE("FAILURE -- hresult = 0x%08x\n", hr);
5605     }
5606 
5607     return hr;
5608 }
5609 
5610 /* ITypeInfo::GetImplTypeFlags
5611  *
5612  * Retrieves the IMPLTYPEFLAGS enumeration for one implemented interface
5613  * or base interface in a type description.
5614  */
5615 static HRESULT WINAPI ITypeInfo_fnGetImplTypeFlags( ITypeInfo2 *iface,
5616         UINT index, INT  *pImplTypeFlags)
5617 {
5618     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5619     UINT i;
5620     TLBImplType *pImpl;
5621 
5622     TRACE("(%p) index %d\n", This, index);
5623     for(i=0, pImpl=This->impltypelist; i<index && pImpl;
5624         i++, pImpl=pImpl->next)
5625         ;
5626     if(i==index && pImpl){
5627         *pImplTypeFlags=pImpl->implflags;
5628         return S_OK;
5629     }
5630     *pImplTypeFlags=0;
5631 
5632     if(This->TypeAttr.typekind==TKIND_DISPATCH && !index)
5633         return S_OK;
5634 
5635     WARN("ImplType %d not found\n", index);
5636     return TYPE_E_ELEMENTNOTFOUND;
5637 }
5638 
5639 /* GetIDsOfNames
5640  * Maps between member names and member IDs, and parameter names and
5641  * parameter IDs.
5642  */
5643 static HRESULT WINAPI ITypeInfo_fnGetIDsOfNames( ITypeInfo2 *iface,
5644         LPOLESTR  *rgszNames, UINT cNames, MEMBERID  *pMemId)
5645 {
5646     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5647     const TLBFuncDesc *pFDesc;
5648     const TLBVarDesc *pVDesc;
5649     HRESULT ret=S_OK;
5650     UINT i;
5651 
5652     TRACE("(%p) Name %s cNames %d\n", This, debugstr_w(*rgszNames),
5653             cNames);
5654 
5655     /* init out parameters in case of failure */
5656     for (i = 0; i < cNames; i++)
5657         pMemId[i] = MEMBERID_NIL;
5658 
5659     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next) {
5660         int j;
5661         if(!lstrcmpiW(*rgszNames, pFDesc->Name)) {
5662             if(cNames) *pMemId=pFDesc->funcdesc.memid;
5663             for(i=1; i < cNames; i++){
5664                 for(j=0; j<pFDesc->funcdesc.cParams; j++)
5665                     if(!lstrcmpiW(rgszNames[i],pFDesc->pParamDesc[j].Name))
5666                             break;
5667                 if( j<pFDesc->funcdesc.cParams)
5668                     pMemId[i]=j;
5669                 else
5670                    ret=DISP_E_UNKNOWNNAME;
5671             };
5672             TRACE("-- 0x%08x\n", ret);
5673             return ret;
5674         }
5675     }
5676     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) {
5677         if(!lstrcmpiW(*rgszNames, pVDesc->Name)) {
5678             if(cNames) *pMemId=pVDesc->vardesc.memid;
5679             return ret;
5680         }
5681     }
5682     /* not found, see if it can be found in an inherited interface */
5683     if(This->impltypelist) {
5684         /* recursive search */
5685         ITypeInfo *pTInfo;
5686         ret=ITypeInfo_GetRefTypeInfo(iface,
5687                 This->impltypelist->hRef, &pTInfo);
5688         if(SUCCEEDED(ret)){
5689             ret=ITypeInfo_GetIDsOfNames(pTInfo, rgszNames, cNames, pMemId );
5690             ITypeInfo_Release(pTInfo);
5691             return ret;
5692         }
5693         WARN("Could not search inherited interface!\n");
5694     } else
5695         WARN("no names found\n");
5696     return DISP_E_UNKNOWNNAME;
5697 }
5698 
5699 
5700 #ifdef __i386__
5701 
5702 extern LONGLONG call_method( void *func, int nb_args, const DWORD *args, int *stack_offset );
5703 __ASM_GLOBAL_FUNC( call_method,
5704                    "pushl %ebp\n\t"
5705                    __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
5706                    __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
5707                    "movl %esp,%ebp\n\t"
5708                    __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
5709                    "pushl %esi\n\t"
5710                   __ASM_CFI(".cfi_rel_offset %esi,-4\n\t")
5711                    "pushl %edi\n\t"
5712                   __ASM_CFI(".cfi_rel_offset %edi,-8\n\t")
5713                    "movl 12(%ebp),%edx\n\t"
5714                    "movl %esp,%edi\n\t"
5715                    "shll $2,%edx\n\t"
5716                    "jz 1f\n\t"
5717                    "subl %edx,%edi\n\t"
5718                    "andl $~15,%edi\n\t"
5719                    "movl %edi,%esp\n\t"
5720                    "movl 12(%ebp),%ecx\n\t"
5721                    "movl 16(%ebp),%esi\n\t"
5722                    "cld\n\t"
5723                    "rep; movsl\n"
5724                    "1:\tcall *8(%ebp)\n\t"
5725                    "subl %esp,%edi\n\t"
5726                    "movl 20(%ebp),%ecx\n\t"
5727                    "movl %edi,(%ecx)\n\t"
5728                    "leal -8(%ebp),%esp\n\t"
5729                    "popl %edi\n\t"
5730                    __ASM_CFI(".cfi_same_value %edi\n\t")
5731                    "popl %esi\n\t"
5732                    __ASM_CFI(".cfi_same_value %esi\n\t")
5733                    "popl %ebp\n\t"
5734                    __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
5735                    __ASM_CFI(".cfi_same_value %ebp\n\t")
5736                    "ret" )
5737 
5738 /* same function but returning floating point */
5739 static double (* const call_double_method)(void*,int,const DWORD*,int*) = (void *)call_method;
5740 
5741 /* ITypeInfo::Invoke
5742  *
5743  * Invokes a method, or accesses a property of an object, that implements the
5744  * interface described by the type description.
5745  */
5746 DWORD
5747 _invoke(FARPROC func,CALLCONV callconv, int nrargs, DWORD *args) {
5748     DWORD res;
5749     int stack_offset;
5750 
5751     if (TRACE_ON(ole)) {
5752         int i;
5753         TRACE("Calling %p(",func);
5754         for (i=0;i<min(nrargs,30);i++) TRACE("%08x,",args[i]);
5755         if (nrargs > 30) TRACE("...");
5756         TRACE(")\n");
5757     }
5758 
5759     switch (callconv) {
5760     case CC_STDCALL:
5761     case CC_CDECL:
5762         res = call_method( func, nrargs, args, &stack_offset );
5763         break;
5764     default:
5765         FIXME("unsupported calling convention %d\n",callconv);
5766         res = -1;
5767         break;
5768     }
5769     TRACE("returns %08x\n",res);
5770     return res;
5771 }
5772 
5773 #elif defined(__x86_64__)
5774 
5775 extern DWORD_PTR CDECL call_method( void *func, int nb_args, const DWORD_PTR *args );
5776 __ASM_GLOBAL_FUNC( call_method,
5777                    "pushq %rbp\n\t"
5778                    __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t")
5779                    __ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
5780                    "movq %rsp,%rbp\n\t"
5781                    __ASM_CFI(".cfi_def_cfa_register %rbp\n\t")
5782                    "pushq %rsi\n\t"
5783                    __ASM_CFI(".cfi_rel_offset %rsi,-8\n\t")
5784                    "pushq %rdi\n\t"
5785                    __ASM_CFI(".cfi_rel_offset %rdi,-16\n\t")
5786                    "movq %rcx,%rax\n\t"
5787                    "movq $4,%rcx\n\t"
5788                    "cmp %rcx,%rdx\n\t"
5789                    "cmovgq %rdx,%rcx\n\t"
5790                    "leaq 0(,%rcx,8),%rdx\n\t"
5791                    "subq %rdx,%rsp\n\t"
5792                    "andq $~15,%rsp\n\t"
5793                    "movq %rsp,%rdi\n\t"
5794                    "movq %r8,%rsi\n\t"
5795                    "rep; movsq\n\t"
5796                    "movq 0(%rsp),%rcx\n\t"
5797                    "movq 8(%rsp),%rdx\n\t"
5798                    "movq 16(%rsp),%r8\n\t"
5799                    "movq 24(%rsp),%r9\n\t"
5800                    "movq %rcx,%xmm0\n\t"
5801                    "movq %rdx,%xmm1\n\t"
5802                    "movq %r8,%xmm2\n\t"
5803                    "movq %r9,%xmm3\n\t"
5804                    "callq *%rax\n\t"
5805                    "leaq -16(%rbp),%rsp\n\t"
5806                    "popq %rdi\n\t"
5807                    __ASM_CFI(".cfi_same_value %rdi\n\t")
5808                    "popq %rsi\n\t"
5809                    __ASM_CFI(".cfi_same_value %rsi\n\t")
5810                    __ASM_CFI(".cfi_def_cfa_register %rsp\n\t")
5811                    "popq %rbp\n\t"
5812                    __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t")
5813                    __ASM_CFI(".cfi_same_value %rbp\n\t")
5814                    "ret")
5815 
5816 /* same function but returning floating point */
5817 static double (CDECL * const call_double_method)(void*,int,const DWORD_PTR*) = (void *)call_method;
5818 
5819 #endif  /* __x86_64__ */
5820 
5821 static HRESULT userdefined_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
5822 {
5823     HRESULT hr = S_OK;
5824     ITypeInfo *tinfo2 = NULL;
5825     TYPEATTR *tattr = NULL;
5826 
5827     hr = ITypeInfo_GetRefTypeInfo(tinfo, tdesc->u.hreftype, &tinfo2);
5828     if (hr)
5829     {
5830         ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED, "
5831             "hr = 0x%08x\n",
5832               tdesc->u.hreftype, hr);
5833         return hr;
5834     }
5835     hr = ITypeInfo_GetTypeAttr(tinfo2, &tattr);
5836     if (hr)
5837     {
5838         ERR("ITypeInfo_GetTypeAttr failed, hr = 0x%08x\n", hr);
5839         ITypeInfo_Release(tinfo2);
5840         return hr;
5841     }
5842 
5843     switch (tattr->typekind)
5844     {
5845     case TKIND_ENUM:
5846         *vt |= VT_I4;
5847         break;
5848 
5849     case TKIND_ALIAS:
5850         tdesc = &tattr->tdescAlias;
5851         hr = typedescvt_to_variantvt(tinfo2, &tattr->tdescAlias, vt);
5852         break;
5853 
5854     case TKIND_INTERFACE:
5855         if (tattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE)
5856            *vt |= VT_DISPATCH;
5857         else
5858            *vt |= VT_UNKNOWN;
5859         break;
5860 
5861     case TKIND_DISPATCH:
5862         *vt |= VT_DISPATCH;
5863         break;
5864 
5865     case TKIND_COCLASS:
5866         *vt |= VT_DISPATCH;
5867         break;
5868 
5869     case TKIND_RECORD:
5870         FIXME("TKIND_RECORD unhandled.\n");
5871         hr = E_NOTIMPL;
5872         break;
5873 
5874     case TKIND_UNION:
5875         FIXME("TKIND_UNION unhandled.\n");
5876         hr = E_NOTIMPL;
5877         break;
5878 
5879     default:
5880         FIXME("TKIND %d unhandled.\n",tattr->typekind);
5881         hr = E_NOTIMPL;
5882         break;
5883     }
5884     ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
5885     ITypeInfo_Release(tinfo2);
5886     return hr;
5887 }
5888 
5889 static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
5890 {
5891     HRESULT hr = S_OK;
5892 
5893     /* enforce only one level of pointer indirection */
5894     if (!(*vt & VT_BYREF) && !(*vt & VT_ARRAY) && (tdesc->vt == VT_PTR))
5895     {
5896         tdesc = tdesc->u.lptdesc;
5897 
5898         /* munch VT_PTR -> VT_USERDEFINED(interface) into VT_UNKNOWN or
5899          * VT_DISPATCH and VT_PTR -> VT_PTR -> VT_USERDEFINED(interface) into 
5900          * VT_BYREF|VT_DISPATCH or VT_BYREF|VT_UNKNOWN */
5901         if ((tdesc->vt == VT_USERDEFINED) ||
5902             ((tdesc->vt == VT_PTR) && (tdesc->u.lptdesc->vt == VT_USERDEFINED)))
5903         {
5904             VARTYPE vt_userdefined = 0;
5905             const TYPEDESC *tdesc_userdefined = tdesc;
5906             if (tdesc->vt == VT_PTR)
5907             {
5908                 vt_userdefined = VT_BYREF;
5909                 tdesc_userdefined = tdesc->u.lptdesc;
5910             }
5911             hr = userdefined_to_variantvt(tinfo, tdesc_userdefined, &vt_userdefined);
5912             if ((hr == S_OK) && 
5913                 (((vt_userdefined & VT_TYPEMASK) == VT_UNKNOWN) ||
5914                  ((vt_userdefined & VT_TYPEMASK) == VT_DISPATCH)))
5915             {
5916                 *vt |= vt_userdefined;
5917                 return S_OK;
5918             }
5919         }
5920         *vt = VT_BYREF;
5921     }
5922 
5923     switch (tdesc->vt)
5924     {
5925     case VT_HRESULT:
5926         *vt |= VT_ERROR;
5927         break;
5928     case VT_USERDEFINED:
5929         hr = userdefined_to_variantvt(tinfo, tdesc, vt);
5930         break;
5931     case VT_VOID:
5932     case VT_CARRAY:
5933     case VT_PTR:
5934     case VT_LPSTR:
5935     case VT_LPWSTR:
5936         ERR("cannot convert type %d into variant VT\n", tdesc->vt);
5937         hr = DISP_E_BADVARTYPE;
5938         break;
5939     case VT_SAFEARRAY:
5940         *vt |= VT_ARRAY;
5941         hr = typedescvt_to_variantvt(tinfo, tdesc->u.lptdesc, vt);
5942         break;
5943     case VT_INT:
5944         *vt |= VT_I4;
5945         break;
5946     case VT_UINT:
5947         *vt |= VT_UI4;
5948         break;
5949     default:
5950         *vt |= tdesc->vt;
5951         break;
5952     }
5953     return hr;
5954 }
5955 
5956 /***********************************************************************
5957  *              DispCallFunc (OLEAUT32.@)
5958  *
5959  * Invokes a function of the specified calling convention, passing the
5960  * specified arguments and returns the result.
5961  *
5962  * PARAMS
5963  *  pvInstance  [I] Optional pointer to the instance whose function to invoke.
5964  *  oVft        [I] The offset in the vtable. See notes.
5965  *  cc          [I] Calling convention of the function to call.
5966  *  vtReturn    [I] The return type of the function.
5967  *  cActuals    [I] Number of parameters.
5968  *  prgvt       [I] The types of the parameters to pass. This is used for sizing only.
5969  *  prgpvarg    [I] The arguments to pass.
5970  *  pvargResult [O] The return value of the function. Can be NULL.
5971  *
5972  * RETURNS
5973  *  Success: S_OK.
5974  *  Failure: HRESULT code.
5975  *
5976  * NOTES
5977  *  The HRESULT return value of this function is not affected by the return
5978  *  value of the user supplied function, which is returned in pvargResult.
5979  *
5980  *  If pvInstance is NULL then a non-object function is to be called and oVft
5981  *  is the address of the function to call.
5982  *
5983  * The cc parameter can be one of the following values:
5984  *|CC_FASTCALL
5985  *|CC_CDECL
5986  *|CC_PASCAL
5987  *|CC_STDCALL
5988  *|CC_FPFASTCALL
5989  *|CC_SYSCALL
5990  *|CC_MPWCDECL
5991  *|CC_MPWPASCAL
5992  *
5993  */
5994 HRESULT WINAPI
5995 DispCallFunc(
5996     void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals,
5997     VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult)
5998 {
5999 #ifdef __i386__
6000     int argspos, stack_offset;
6001     void *func;
6002     UINT i;
6003     DWORD *args;
6004 
6005     TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
6006         pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
6007         pvargResult, V_VT(pvargResult));
6008 
6009     if (cc != CC_STDCALL && cc != CC_CDECL)
6010     {
6011         FIXME("unsupported calling convention %d\n",cc);
6012         return E_INVALIDARG;
6013     }
6014 
6015     /* maximum size for an argument is sizeof(VARIANT) */
6016     args = heap_alloc(sizeof(VARIANT) * cActuals + sizeof(DWORD) * 2 );
6017 
6018     /* start at 1 in case we need to pass a pointer to the return value as arg 0 */
6019     argspos = 1;
6020     if (pvInstance)
6021     {
6022         const FARPROC *vtable = *(FARPROC **)pvInstance;
6023         func = vtable[oVft/sizeof(void *)];
6024         args[argspos++] = (DWORD)pvInstance; /* the This pointer is always the first parameter */
6025     }
6026     else func = (void *)oVft;
6027 
6028     for (i = 0; i < cActuals; i++)
6029     {
6030         VARIANT *arg = prgpvarg[i];
6031 
6032         switch (prgvt[i])
6033         {
6034         case VT_EMPTY:
6035             break;
6036         case VT_I8:
6037         case VT_UI8:
6038         case VT_R8:
6039         case VT_DATE:
6040         case VT_CY:
6041             memcpy( &args[argspos], &V_I8(arg), sizeof(V_I8(arg)) );
6042             argspos += sizeof(V_I8(arg)) / sizeof(DWORD);
6043             break;
6044         case VT_DECIMAL:
6045         case VT_VARIANT:
6046             memcpy( &args[argspos], arg, sizeof(*arg) );
6047             argspos += sizeof(*arg) / sizeof(DWORD);
6048             break;
6049         case VT_BOOL:  /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
6050             args[argspos++] = V_BOOL(arg);
6051             break;
6052         default:
6053             args[argspos++] = V_UI4(arg);
6054             break;
6055         }
6056         TRACE("arg %u: type %d\n",i,prgvt[i]);
6057         dump_Variant(arg);
6058     }
6059 
6060     switch (vtReturn)
6061     {
6062     case VT_EMPTY:
6063         call_method( func, argspos - 1, args + 1, &stack_offset );
6064         break;
6065     case VT_R4:
6066         V_R4(pvargResult) = call_double_method( func, argspos - 1, args + 1, &stack_offset );
6067         break;
6068     case VT_R8:
6069     case VT_DATE:
6070         V_R8(pvargResult) = call_double_method( func, argspos - 1, args + 1, &stack_offset );
6071         break;
6072     case VT_DECIMAL:
6073     case VT_VARIANT:
6074         args[0] = (DWORD)pvargResult;  /* arg 0 is a pointer to the result */
6075         call_method( func, argspos, args, &stack_offset );
6076         break;
6077     case VT_I8:
6078     case VT_UI8:
6079     case VT_CY:
6080         V_UI8(pvargResult) = call_method( func, argspos - 1, args + 1, &stack_offset );
6081         break;
6082     default:
6083         V_UI4(pvargResult) = call_method( func, argspos - 1, args + 1, &stack_offset );
6084         break;
6085     }
6086     heap_free( args );
6087     if (stack_offset && cc == CC_STDCALL)
6088     {
6089         WARN( "stack pointer off by %d\n", stack_offset );
6090         return DISP_E_BADCALLEE;
6091     }
6092     if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
6093     TRACE("retval: "); dump_Variant(pvargResult);
6094     return S_OK;
6095 
6096 #elif defined(__x86_64__)
6097     int argspos;
6098     UINT i;
6099     DWORD_PTR *args;
6100     void *func;
6101 
6102     TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
6103           pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
6104           pvargResult, V_VT(pvargResult));
6105 
6106     if (cc != CC_STDCALL && cc != CC_CDECL)
6107     {
6108         FIXME("unsupported calling convention %d\n",cc);
6109         return E_INVALIDARG;
6110     }
6111 
6112     /* maximum size for an argument is sizeof(DWORD_PTR) */
6113     args = heap_alloc( sizeof(DWORD_PTR) * (cActuals + 2) );
6114 
6115     /* start at 1 in case we need to pass a pointer to the return value as arg 0 */
6116     argspos = 1;
6117     if (pvInstance)
6118     {
6119         const FARPROC *vtable = *(FARPROC **)pvInstance;
6120         func = vtable[oVft/sizeof(void *)];
6121         args[argspos++] = (DWORD_PTR)pvInstance; /* the This pointer is always the first parameter */
6122     }
6123     else func = (void *)oVft;
6124 
6125     for (i = 0; i < cActuals; i++)
6126     {
6127         VARIANT *arg = prgpvarg[i];
6128 
6129         switch (prgvt[i])
6130         {
6131         case VT_DECIMAL:
6132         case VT_VARIANT:
6133             args[argspos++] = (ULONG_PTR)arg;
6134             break;
6135         case VT_BOOL:  /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
6136             args[argspos++] = V_BOOL(arg);
6137             break;
6138         default:
6139             args[argspos++] = V_UI8(arg);
6140             break;
6141         }
6142         TRACE("arg %u: type %d\n",i,prgvt[i]);
6143         dump_Variant(arg);
6144     }
6145 
6146     switch (vtReturn)
6147     {
6148     case VT_R4:
6149         V_R4(pvargResult) = call_double_method( func, argspos - 1, args + 1 );
6150         break;
6151     case VT_R8:
6152     case VT_DATE:
6153         V_R8(pvargResult) = call_double_method( func, argspos - 1, args + 1 );
6154         break;
6155     case VT_DECIMAL:
6156     case VT_VARIANT:
6157         args[0] = (DWORD_PTR)pvargResult;  /* arg 0 is a pointer to the result */
6158         call_method( func, argspos, args );
6159         break;
6160     default:
6161         V_UI8(pvargResult) = call_method( func, argspos - 1, args + 1 );
6162         break;
6163     }
6164     heap_free( args );
6165     if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
6166     TRACE("retval: "); dump_Variant(pvargResult);
6167     return S_OK;
6168 
6169 #else
6170     FIXME( "(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d)): not implemented for this CPU\n",
6171            pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg, pvargResult, V_VT(pvargResult));
6172     return E_NOTIMPL;
6173 #endif
6174 }
6175 
6176 #define INVBUF_ELEMENT_SIZE \
6177     (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *) + sizeof(VARTYPE))
6178 #define INVBUF_GET_ARG_ARRAY(buffer, params) (buffer)
6179 #define INVBUF_GET_MISSING_ARG_ARRAY(buffer, params) \
6180     ((VARIANTARG *)((char *)(buffer) + sizeof(VARIANTARG) * (params)))
6181 #define INVBUF_GET_ARG_PTR_ARRAY(buffer, params) \
6182     ((VARIANTARG **)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG)) * (params)))
6183 #define INVBUF_GET_ARG_TYPE_ARRAY(buffer, params) \
6184     ((VARTYPE *)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *)) * (params)))
6185 
6186 static HRESULT WINAPI ITypeInfo_fnInvoke(
6187     ITypeInfo2 *iface,
6188     VOID  *pIUnk,
6189     MEMBERID memid,
6190     UINT16 wFlags,
6191     DISPPARAMS  *pDispParams,
6192     VARIANT  *pVarResult,
6193     EXCEPINFO  *pExcepInfo,
6194     UINT  *pArgErr)
6195 {
6196     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6197     int i;
6198     unsigned int var_index;
6199     TYPEKIND type_kind;
6200     HRESULT hres;
6201     const TLBFuncDesc *pFuncInfo;
6202 
6203     TRACE("(%p)(%p,id=%d,flags=0x%08x,%p,%p,%p,%p)\n",
6204       This,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr
6205     );
6206 
6207     if( This->TypeAttr.wTypeFlags & TYPEFLAG_FRESTRICTED )
6208         return DISP_E_MEMBERNOTFOUND;
6209 
6210     if (!pDispParams)
6211     {
6212         ERR("NULL pDispParams not allowed\n");
6213         return E_INVALIDARG;
6214     }
6215 
6216     dump_DispParms(pDispParams);
6217 
6218     if (pDispParams->cNamedArgs > pDispParams->cArgs)
6219     {
6220         ERR("named argument array cannot be bigger than argument array (%d/%d)\n",
6221             pDispParams->cNamedArgs, pDispParams->cArgs);
6222         return E_INVALIDARG;
6223     }
6224 
6225     /* we do this instead of using GetFuncDesc since it will return a fake
6226      * FUNCDESC for dispinterfaces and we want the real function description */
6227     for (pFuncInfo = This->funclist; pFuncInfo; pFuncInfo=pFuncInfo->next)
6228         if ((memid == pFuncInfo->funcdesc.memid) &&
6229             (wFlags & pFuncInfo->funcdesc.invkind) &&
6230             (pFuncInfo->funcdesc.wFuncFlags & FUNCFLAG_FRESTRICTED) == 0)
6231             break;
6232 
6233     if (pFuncInfo) {
6234         const FUNCDESC *func_desc = &pFuncInfo->funcdesc;
6235 
6236         if (TRACE_ON(ole))
6237         {
6238             TRACE("invoking:\n");
6239             dump_TLBFuncDescOne(pFuncInfo);
6240         }
6241         
6242         switch (func_desc->funckind) {
6243         case FUNC_PUREVIRTUAL:
6244         case FUNC_VIRTUAL: {
6245             void *buffer = heap_alloc_zero(INVBUF_ELEMENT_SIZE * func_desc->cParams);
6246             VARIANT varresult;
6247             VARIANT retval; /* pointer for storing byref retvals in */
6248             VARIANTARG **prgpvarg = INVBUF_GET_ARG_PTR_ARRAY(buffer, func_desc->cParams);
6249             VARIANTARG *rgvarg = INVBUF_GET_ARG_ARRAY(buffer, func_desc->cParams);
6250             VARTYPE *rgvt = INVBUF_GET_ARG_TYPE_ARRAY(buffer, func_desc->cParams);
6251             UINT cNamedArgs = pDispParams->cNamedArgs;
6252             DISPID *rgdispidNamedArgs = pDispParams->rgdispidNamedArgs;
6253             UINT vargs_converted=0;
6254 
6255             hres = S_OK;
6256 
6257             if (func_desc->invkind & (INVOKE_PROPERTYPUT|INVOKE_PROPERTYPUTREF))
6258             {
6259                 if (!cNamedArgs || (rgdispidNamedArgs[0] != DISPID_PROPERTYPUT))
6260                 {
6261                     ERR("first named arg for property put invocation must be DISPID_PROPERTYPUT\n");
6262                     hres = DISP_E_PARAMNOTFOUND;
6263                     goto func_fail;
6264                 }
6265             }
6266 
6267             if (func_desc->cParamsOpt < 0 && cNamedArgs)
6268             {
6269                 ERR("functions with the vararg attribute do not support named arguments\n");
6270                 hres = DISP_E_NONAMEDARGS;
6271                 goto func_fail;
6272             }
6273 
6274             for (i = 0; i < func_desc->cParams; i++)
6275             {
6276                 TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc;
6277                 hres = typedescvt_to_variantvt((ITypeInfo *)iface, tdesc, &rgvt[i]);
6278                 if (FAILED(hres))
6279                     goto func_fail;
6280             }
6281 
6282             TRACE("changing args\n");
6283             for (i = 0; i < func_desc->cParams; i++)
6284             {
6285                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
6286                 VARIANTARG *src_arg;
6287 
6288                 if (wParamFlags & PARAMFLAG_FLCID)
6289                 {
6290                     VARIANTARG *arg;
6291                     arg = prgpvarg[i] = &rgvarg[i];
6292                     V_VT(arg) = VT_I4;
6293                     V_I4(arg) = This->pTypeLib->lcid;
6294                     continue;
6295                 }
6296 
6297                 src_arg = NULL;
6298 
6299                 if (cNamedArgs)
6300                 {
6301                     USHORT j;
6302                     for (j = 0; j < cNamedArgs; j++)
6303                         if (rgdispidNamedArgs[j] == i || (i == func_desc->cParams-1 && rgdispidNamedArgs[j] == DISPID_PROPERTYPUT))
6304                         {
6305                             src_arg = &pDispParams->rgvarg[j];
6306                             break;
6307                         }
6308                 }
6309 
6310                 if (!src_arg && vargs_converted + cNamedArgs < pDispParams->cArgs)
6311                 {
6312                     src_arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted];
6313                     vargs_converted++;
6314                 }
6315 
6316                 if (wParamFlags & PARAMFLAG_FRETVAL)
6317                 {
6318                     /* under most conditions the caller is not allowed to
6319                      * pass in a dispparam arg in the index of what would be
6320                      * the retval parameter. however, there is an exception
6321                      * where the extra parameter is used in an extra
6322                      * IDispatch::Invoke below */
6323                     if ((i < pDispParams->cArgs) &&
6324                         ((func_desc->cParams != 1) || !pVarResult ||
6325                          !(func_desc->invkind & INVOKE_PROPERTYGET)))
6326                     {
6327                         hres = DISP_E_BADPARAMCOUNT;
6328                         break;
6329                     }
6330 
6331                     /* note: this check is placed so that if the caller passes
6332                      * in a VARIANTARG for the retval we just ignore it, like
6333                      * native does */
6334                     if (i == func_desc->cParams - 1)
6335                     {
6336                         VARIANTARG *arg;
6337                         arg = prgpvarg[i] = &rgvarg[i];
6338                         memset(arg, 0, sizeof(*arg));
6339                         V_VT(arg) = rgvt[i];
6340                         memset(&retval, 0, sizeof(retval));
6341                         V_BYREF(arg) = &retval;
6342                     }
6343                     else
6344                     {
6345                         ERR("[retval] parameter must be the last parameter of the method (%d/%d)\n", i, func_desc->cParams);
6346                         hres = E_UNEXPECTED;
6347                         break;
6348                     }
6349                 }
6350                 else if (src_arg)
6351                 {
6352                     dump_Variant(src_arg);
6353 
6354                     if (rgvt[i] == VT_VARIANT)
6355                         hres = VariantCopy(&rgvarg[i], src_arg);
6356                     else if (rgvt[i] == (VT_VARIANT | VT_BYREF))
6357                     {
6358                         if (rgvt[i] == V_VT(src_arg))
6359                             V_VARIANTREF(&rgvarg[i]) = V_VARIANTREF(src_arg);
6360                         else
6361                         {
6362                             VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
6363                             if (wParamFlags & PARAMFLAG_FIN)
6364                                 hres = VariantCopy(&missing_arg[i], src_arg);
6365                             V_VARIANTREF(&rgvarg[i]) = &missing_arg[i];
6366                         }
6367                         V_VT(&rgvarg[i]) = rgvt[i];
6368                     }
6369                     else if (rgvt[i] == (VT_VARIANT | VT_ARRAY) && func_desc->cParamsOpt < 0 && i == func_desc->cParams-1)
6370                     {
6371                         SAFEARRAY *a;
6372                         SAFEARRAYBOUND bound;
6373                         VARIANT *v;
6374                         LONG j;
6375                         bound.lLbound = 0;
6376                         bound.cElements = pDispParams->cArgs-i;
6377                         if (!(a = SafeArrayCreate(VT_VARIANT, 1, &bound)))
6378                         {
6379                             ERR("SafeArrayCreate failed\n");
6380                             break;
6381                         }
6382                         hres = SafeArrayAccessData(a, (LPVOID)&v);
6383                         if (hres != S_OK)
6384                         {
6385                             ERR("SafeArrayAccessData failed with %x\n", hres);
6386                             break;
6387                         }
6388                         for (j = 0; j < bound.cElements; j++)
6389                             VariantCopy(&v[j], &pDispParams->rgvarg[pDispParams->cArgs - 1 - i - j]);
6390                         hres = SafeArrayUnaccessData(a);
6391                         if (hres != S_OK)
6392                         {
6393                             ERR("SafeArrayUnaccessData failed with %x\n", hres);
6394                             break;
6395                         }
6396                         V_ARRAY(&rgvarg[i]) = a;
6397                         V_VT(&rgvarg[i]) = rgvt[i];
6398                     }
6399                     else if ((rgvt[i] & VT_BYREF) && !V_ISBYREF(src_arg))
6400                     {
6401                         VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
6402                         if (wParamFlags & PARAMFLAG_FIN)
6403                             hres = VariantChangeType(&missing_arg[i], src_arg, 0, rgvt[i] & ~VT_BYREF);
6404                         else
6405                             V_VT(&missing_arg[i]) = rgvt[i] & ~VT_BYREF;
6406                         V_BYREF(&rgvarg[i]) = &V_NONE(&missing_arg[i]);
6407                         V_VT(&rgvarg[i]) = rgvt[i];
6408                     }
6409                     else if ((rgvt[i] & VT_BYREF) && (rgvt[i] == V_VT(src_arg)))
6410                     {
6411                         V_BYREF(&rgvarg[i]) = V_BYREF(src_arg);
6412                         V_VT(&rgvarg[i]) = rgvt[i];
6413                     }
6414                     else
6415                     {
6416                         /* FIXME: this doesn't work for VT_BYREF arguments if
6417                          * they are not the same type as in the paramdesc */
6418                         V_VT(&rgvarg[i]) = V_VT(src_arg);
6419                         hres = VariantChangeType(&rgvarg[i], src_arg, 0, rgvt[i]);
6420                         V_VT(&rgvarg[i]) = rgvt[i];
6421                     }
6422 
6423                     if (FAILED(hres))
6424                     {
6425                         ERR("failed to convert param %d to %s%s from %s%s\n", i,
6426                             debugstr_vt(rgvt[i]), debugstr_vf(rgvt[i]),
6427                             debugstr_VT(src_arg), debugstr_VF(src_arg));
6428                         break;
6429                     }
6430                     prgpvarg[i] = &rgvarg[i];
6431                 }
6432                 else if (wParamFlags & PARAMFLAG_FOPT)
6433                 {
6434                     VARIANTARG *arg;
6435                     arg = prgpvarg[i] = &rgvarg[i];
6436                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
6437                     {
6438                         hres = VariantCopy(arg, &func_desc->lprgelemdescParam[i].u.paramdesc.pparamdescex->varDefaultValue);
6439                         if (FAILED(hres))
6440                             break;
6441                     }
6442                     else
6443                     {
6444                         VARIANTARG *missing_arg;
6445                         /* if the function wants a pointer to a variant then
6446                          * set that up, otherwise just pass the VT_ERROR in
6447                          * the argument by value */
6448                         if (rgvt[i] & VT_BYREF)
6449                         {
6450                             missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams) + i;
6451                             V_VT(arg) = VT_VARIANT | VT_BYREF;
6452                             V_VARIANTREF(arg) = missing_arg;
6453                         }
6454                         else
6455                             missing_arg = arg;
6456                         V_VT(missing_arg) = VT_ERROR;
6457                         V_ERROR(missing_arg) = DISP_E_PARAMNOTFOUND;
6458                     }
6459                 }
6460                 else
6461                 {
6462                     hres = DISP_E_BADPARAMCOUNT;
6463                     break;
6464                 }
6465             }
6466             if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
6467 
6468             /* VT_VOID is a special case for return types, so it is not
6469              * handled in the general function */
6470             if (func_desc->elemdescFunc.tdesc.vt == VT_VOID)
6471                 V_VT(&varresult) = VT_EMPTY;
6472             else
6473             {
6474                 V_VT(&varresult) = 0;
6475                 hres = typedescvt_to_variantvt((ITypeInfo *)iface, &func_desc->elemdescFunc.tdesc, &V_VT(&varresult));
6476                 if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
6477             }
6478 
6479             hres = DispCallFunc(pIUnk, func_desc->oVft, func_desc->callconv,
6480                                 V_VT(&varresult), func_desc->cParams, rgvt,
6481                                 prgpvarg, &varresult);
6482 
6483             vargs_converted = 0;
6484 
6485             for (i = 0; i < func_desc->cParams; i++)
6486             {
6487                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
6488                 VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
6489 
6490                 if (wParamFlags & PARAMFLAG_FLCID)
6491                     continue;
6492                 else if (wParamFlags & PARAMFLAG_FRETVAL)
6493                 {
6494                     if (TRACE_ON(ole))
6495                     {
6496                         TRACE("[retval] value: ");
6497                         dump_Variant(prgpvarg[i]);
6498                     }
6499 
6500                     if (pVarResult)
6501                     {
6502                         VariantInit(pVarResult);
6503                         /* deref return value */
6504                         hres = VariantCopyInd(pVarResult, prgpvarg[i]);
6505                     }
6506 
6507                     VARIANT_ClearInd(prgpvarg[i]);
6508                 }
6509                 else if (vargs_converted < pDispParams->cArgs)
6510                 {
6511                     VARIANTARG *arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted];
6512                     if (wParamFlags & PARAMFLAG_FOUT)
6513                     {
6514                         if ((rgvt[i] & VT_BYREF) && !(V_VT(arg) & VT_BYREF))
6515                         {
6516                             hres = VariantChangeType(arg, &rgvarg[i], 0, V_VT(arg));
6517 
6518                             if (FAILED(hres))
6519                             {
6520                                 ERR("failed to convert param %d to vt %d\n", i,
6521                                     V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted]));
6522                                 break;
6523                             }
6524                         }
6525                     }
6526                     else if (V_VT(prgpvarg[i]) == (VT_VARIANT | VT_ARRAY) &&
6527                              func_desc->cParamsOpt < 0 &&
6528                              i == func_desc->cParams-1)
6529                     {
6530                         SAFEARRAY *a = V_ARRAY(prgpvarg[i]);
6531                         LONG j, ubound;
6532                         VARIANT *v;
6533                         hres = SafeArrayGetUBound(a, 1, &ubound);
6534                         if (hres != S_OK)
6535                         {
6536                             ERR("SafeArrayGetUBound failed with %x\n", hres);
6537                             break;
6538                         }
6539                         hres = SafeArrayAccessData(a, (LPVOID)&v);
6540                         if (hres != S_OK)
6541                         {
6542                             ERR("SafeArrayAccessData failed with %x\n", hres);
6543                             break;
6544                         }
6545                         for (j = 0; j <= ubound; j++)
6546                             VariantClear(&v[j]);
6547                         hres = SafeArrayUnaccessData(a);
6548                         if (hres != S_OK)
6549                         {
6550                             ERR("SafeArrayUnaccessData failed with %x\n", hres);
6551                             break;
6552                         }
6553                     }
6554                     VariantClear(&rgvarg[i]);
6555                     vargs_converted++;
6556                 }
6557                 else if (wParamFlags & PARAMFLAG_FOPT)
6558                 {
6559                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
6560                         VariantClear(&rgvarg[i]);
6561                 }
6562 
6563                 VariantClear(&missing_arg[i]);
6564             }
6565 
6566             if ((V_VT(&varresult) == VT_ERROR) && FAILED(V_ERROR(&varresult)))
6567             {
6568                 WARN("invoked function failed with error 0x%08x\n", V_ERROR(&varresult));
6569                 hres = DISP_E_EXCEPTION;
6570                 if (pExcepInfo)
6571                 {
6572                     IErrorInfo *pErrorInfo;
6573                     pExcepInfo->scode = V_ERROR(&varresult);
6574                     if (GetErrorInfo(0, &pErrorInfo) == S_OK)
6575                     {
6576                         IErrorInfo_GetDescription(pErrorInfo, &pExcepInfo->bstrDescription);
6577                         IErrorInfo_GetHelpFile(pErrorInfo, &pExcepInfo->bstrHelpFile);
6578                         IErrorInfo_GetSource(pErrorInfo, &pExcepInfo->bstrSource);
6579                         IErrorInfo_GetHelpContext(pErrorInfo, &pExcepInfo->dwHelpContext);
6580 
6581                         IErrorInfo_Release(pErrorInfo);
6582                     }
6583                 }
6584             }
6585             if (V_VT(&varresult) != VT_ERROR)
6586             {
6587                 TRACE("varresult value: ");
6588                 dump_Variant(&varresult);
6589 
6590                 if (pVarResult)
6591                 {
6592                     VariantClear(pVarResult);
6593                     *pVarResult = varresult;
6594                 }
6595                 else
6596                     VariantClear(&varresult);
6597             }
6598 
6599             if (SUCCEEDED(hres) && pVarResult && (func_desc->cParams == 1) &&
6600                 (func_desc->invkind & INVOKE_PROPERTYGET) &&
6601                 (func_desc->lprgelemdescParam[0].u.paramdesc.wParamFlags & PARAMFLAG_FRETVAL) &&
6602                 (pDispParams->cArgs != 0))
6603             {
6604                 if (V_VT(pVarResult) == VT_DISPATCH)
6605                 {
6606                     IDispatch *pDispatch = V_DISPATCH(pVarResult);
6607                     /* Note: not VariantClear; we still need the dispatch
6608                      * pointer to be valid */
6609                     VariantInit(pVarResult);
6610                     hres = IDispatch_Invoke(pDispatch, DISPID_VALUE, &IID_NULL,
6611                         GetSystemDefaultLCID(), INVOKE_PROPERTYGET,
6612                         pDispParams, pVarResult, pExcepInfo, pArgErr);
6613                     IDispatch_Release(pDispatch);
6614                 }
6615                 else
6616                 {
6617                     VariantClear(pVarResult);
6618                     hres = DISP_E_NOTACOLLECTION;
6619                 }
6620             }
6621 
6622 func_fail:
6623             heap_free(buffer);
6624             break;
6625         }
6626         case FUNC_DISPATCH:  {
6627            IDispatch *disp;
6628 
6629            hres = IUnknown_QueryInterface((LPUNKNOWN)pIUnk,&IID_IDispatch,(LPVOID*)&disp);
6630            if (SUCCEEDED(hres)) {
6631                FIXME("Calling Invoke in IDispatch iface. untested!\n");
6632                hres = IDispatch_Invoke(
6633                                      disp,memid,&IID_NULL,LOCALE_USER_DEFAULT,wFlags,pDispParams,
6634                                      pVarResult,pExcepInfo,pArgErr
6635                                      );
6636                if (FAILED(hres))
6637                    FIXME("IDispatch::Invoke failed with %08x. (Could be not a real error?)\n", hres);
6638                IDispatch_Release(disp);
6639            } else
6640                FIXME("FUNC_DISPATCH used on object without IDispatch iface?\n");
6641            break;
6642         }
6643         default:
6644             FIXME("Unknown function invocation type %d\n", func_desc->funckind);
6645             hres = E_FAIL;
6646             break;
6647         }
6648 
6649         TRACE("-- 0x%08x\n", hres);
6650         return hres;
6651 
6652     } else if(SUCCEEDED(hres = ITypeInfo2_GetVarIndexOfMemId(iface, memid, &var_index))) {
6653         VARDESC *var_desc;
6654 
6655         hres = ITypeInfo2_GetVarDesc(iface, var_index, &var_desc);
6656         if(FAILED(hres)) return hres;
6657         
6658         FIXME("varseek: Found memid, but variable-based invoking not supported\n");
6659         dump_VARDESC(var_desc);
6660         ITypeInfo2_ReleaseVarDesc(iface, var_desc);
6661         return E_NOTIMPL;
6662     }
6663 
6664     /* not found, look for it in inherited interfaces */
6665     ITypeInfo2_GetTypeKind(iface, &type_kind);
6666     if(type_kind == TKIND_INTERFACE || type_kind == TKIND_DISPATCH) {
6667         if(This->impltypelist) {
6668             /* recursive search */
6669             ITypeInfo *pTInfo;
6670             hres = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef, &pTInfo);
6671             if(SUCCEEDED(hres)){
6672                 hres = ITypeInfo_Invoke(pTInfo,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr);
6673                 ITypeInfo_Release(pTInfo);
6674                 return hres;
6675             }
6676             WARN("Could not search inherited interface!\n");
6677         }
6678     }
6679     WARN("did not find member id %d, flags 0x%x!\n", memid, wFlags);
6680     return DISP_E_MEMBERNOTFOUND;
6681 }
6682 
6683 /* ITypeInfo::GetDocumentation
6684  *
6685  * Retrieves the documentation string, the complete Help file name and path,
6686  * and the context ID for the Help topic for a specified type description.
6687  *
6688  * (Can be tested by the Visual Basic Editor in Word for instance.)
6689  */
6690 static HRESULT WINAPI ITypeInfo_fnGetDocumentation( ITypeInfo2 *iface,
6691         MEMBERID memid, BSTR  *pBstrName, BSTR  *pBstrDocString,
6692         DWORD  *pdwHelpContext, BSTR  *pBstrHelpFile)
6693 {
6694     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6695     const TLBFuncDesc *pFDesc;
6696     const TLBVarDesc *pVDesc;
6697     TRACE("(%p) memid %d Name(%p) DocString(%p)"
6698           " HelpContext(%p) HelpFile(%p)\n",
6699         This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
6700     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
6701         if(pBstrName)
6702             *pBstrName=SysAllocString(This->Name);
6703         if(pBstrDocString)
6704             *pBstrDocString=SysAllocString(This->DocString);
6705         if(pdwHelpContext)
6706             *pdwHelpContext=This->dwHelpContext;
6707         if(pBstrHelpFile)
6708             *pBstrHelpFile=SysAllocString(This->DocString);/* FIXME */
6709         return S_OK;
6710     }else {/* for a member */
6711     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
6712         if(pFDesc->funcdesc.memid==memid){
6713           if(pBstrName)
6714             *pBstrName = SysAllocString(pFDesc->Name);
6715           if(pBstrDocString)
6716             *pBstrDocString=SysAllocString(pFDesc->HelpString);
6717           if(pdwHelpContext)
6718             *pdwHelpContext=pFDesc->helpcontext;
6719           return S_OK;
6720         }
6721     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
6722         if(pVDesc->vardesc.memid==memid){
6723             if(pBstrName)
6724               *pBstrName = SysAllocString(pVDesc->Name);
6725             if(pBstrDocString)
6726               *pBstrDocString=SysAllocString(pVDesc->HelpString);
6727             if(pdwHelpContext)
6728               *pdwHelpContext=pVDesc->HelpContext;
6729             return S_OK;
6730         }
6731     }
6732 
6733     if(This->impltypelist &&
6734        (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
6735         /* recursive search */
6736         ITypeInfo *pTInfo;
6737         HRESULT result;
6738         result = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef,
6739                                         &pTInfo);
6740         if(SUCCEEDED(result)) {
6741             result = ITypeInfo_GetDocumentation(pTInfo, memid, pBstrName,
6742                 pBstrDocString, pdwHelpContext, pBstrHelpFile);
6743             ITypeInfo_Release(pTInfo);
6744             return result;
6745         }
6746         WARN("Could not search inherited interface!\n");
6747     }
6748 
6749     WARN("member %d not found\n", memid);
6750     return TYPE_E_ELEMENTNOTFOUND;
6751 }
6752 
6753 /*  ITypeInfo::GetDllEntry
6754  *
6755  * Retrieves a description or specification of an entry point for a function
6756  * in a DLL.
6757  */
6758 static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid,
6759         INVOKEKIND invKind, BSTR  *pBstrDllName, BSTR  *pBstrName,
6760         WORD  *pwOrdinal)
6761 {
6762     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6763     const TLBFuncDesc *pFDesc;
6764 
6765     TRACE("(%p)->(memid %x, %d, %p, %p, %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
6766 
6767     if (pBstrDllName) *pBstrDllName = NULL;
6768     if (pBstrName) *pBstrName = NULL;
6769     if (pwOrdinal) *pwOrdinal = 0;
6770 
6771     if (This->TypeAttr.typekind != TKIND_MODULE)
6772         return TYPE_E_BADMODULEKIND;
6773 
6774     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
6775         if(pFDesc->funcdesc.memid==memid){
6776             dump_TypeInfo(This);
6777             if (TRACE_ON(ole))
6778                 dump_TLBFuncDescOne(pFDesc);
6779 
6780             if (pBstrDllName)
6781                 *pBstrDllName = SysAllocString(This->DllName);
6782 
6783             if (!IS_INTRESOURCE(pFDesc->Entry) && (pFDesc->Entry != (void*)-1)) {