xref: /reactos/dll/win32/oleaut32/typelib.c (revision 53221834)
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  *		      2004  Alastair Bridgewater
9  *		      2005  Robert Shearman, for CodeWeavers
10  *		      2013  Andrew Eikum for CodeWeavers
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public
14  * License as published by the Free Software Foundation; either
15  * version 2.1 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with this library; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25  *
26  * --------------------------------------------------------------------------------------
27  * Known problems (2000, Francois Jacques)
28  *
29  * - Tested using OLEVIEW (Platform SDK tool) only.
30  *
31  * - dual interface dispinterfaces. vtable-interface ITypeInfo instances are
32  *   creating by doing a straight copy of the dispinterface instance and just changing
33  *   its typekind. Pointed structures aren't copied - only the address of the pointers.
34  *
35  * - locale stuff is partially implemented but hasn't been tested.
36  *
37  * - typelib file is still read in its entirety, but it is released now.
38  *
39  * --------------------------------------------------------------------------------------
40  *  Known problems left from previous implementation (1999, Rein Klazes) :
41  *
42  * -. Data structures are straightforward, but slow for look-ups.
43  * -. (related) nothing is hashed
44  * -. Most error return values are just guessed not checked with windows
45  *      behaviour.
46  * -. lousy fatal error handling
47  *
48  */
49 
50 #include <stdlib.h>
51 #include <string.h>
52 #include <stdarg.h>
53 #include <stdio.h>
54 #include <ctype.h>
55 
56 #define COBJMACROS
57 #define NONAMELESSUNION
58 
59 #include "winerror.h"
60 #include "windef.h"
61 #include "winbase.h"
62 #include "winnls.h"
63 #include "winreg.h"
64 #include "winuser.h"
65 #include "winternl.h"
66 #include "lzexpand.h"
67 
68 #include "objbase.h"
69 #include "typelib.h"
70 #include "wine/debug.h"
71 #include "variant.h"
72 #include "wine/asm.h"
73 #include "wine/heap.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 static void TLB_FreeVarDesc(VARDESC*);
102 
103 /****************************************************************************
104  *              FromLExxx
105  *
106  * Takes p_iVal (which is in little endian) and returns it
107  *   in the host machine's byte order.
108  */
109 #ifdef WORDS_BIGENDIAN
110 static WORD FromLEWord(WORD p_iVal)
111 {
112   return (((p_iVal & 0x00FF) << 8) |
113 	  ((p_iVal & 0xFF00) >> 8));
114 }
115 
116 
117 static DWORD FromLEDWord(DWORD p_iVal)
118 {
119   return (((p_iVal & 0x000000FF) << 24) |
120 	  ((p_iVal & 0x0000FF00) <<  8) |
121 	  ((p_iVal & 0x00FF0000) >>  8) |
122 	  ((p_iVal & 0xFF000000) >> 24));
123 }
124 #else
125 #define FromLEWord(X)  (X)
126 #define FromLEDWord(X) (X)
127 #endif
128 
129 #define DISPATCH_HREF_OFFSET 0x01000000
130 #define DISPATCH_HREF_MASK   0xff000000
131 
132 /****************************************************************************
133  *              FromLExxx
134  *
135  * Fix byte order in any structure if necessary
136  */
137 #ifdef WORDS_BIGENDIAN
138 static void FromLEWords(void *p_Val, int p_iSize)
139 {
140   WORD *Val = p_Val;
141 
142   p_iSize /= sizeof(WORD);
143 
144   while (p_iSize) {
145     *Val = FromLEWord(*Val);
146     Val++;
147     p_iSize--;
148   }
149 }
150 
151 
152 static void FromLEDWords(void *p_Val, int p_iSize)
153 {
154   DWORD *Val = p_Val;
155 
156   p_iSize /= sizeof(DWORD);
157 
158   while (p_iSize) {
159     *Val = FromLEDWord(*Val);
160     Val++;
161     p_iSize--;
162   }
163 }
164 #else
165 #define FromLEWords(X,Y) /*nothing*/
166 #define FromLEDWords(X,Y) /*nothing*/
167 #endif
168 
169 /*
170  * Find a typelib key which matches a requested maj.min version.
171  */
172 static BOOL find_typelib_key( REFGUID guid, WORD *wMaj, WORD *wMin )
173 {
174     static const WCHAR typelibW[] = {'T','y','p','e','l','i','b','\\',0};
175     WCHAR buffer[60];
176     char key_name[16];
177     DWORD len, i;
178     INT best_maj = -1, best_min = -1;
179     HKEY hkey;
180 
181     memcpy( buffer, typelibW, sizeof(typelibW) );
182     StringFromGUID2( guid, buffer + lstrlenW(buffer), 40 );
183 
184     if (RegOpenKeyExW( HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hkey ) != ERROR_SUCCESS)
185         return FALSE;
186 
187     len = sizeof(key_name);
188     i = 0;
189     while (RegEnumKeyExA(hkey, i++, key_name, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
190     {
191         INT v_maj, v_min;
192 
193         if (sscanf(key_name, "%x.%x", &v_maj, &v_min) == 2)
194         {
195             TRACE("found %s: %x.%x\n", debugstr_w(buffer), v_maj, v_min);
196 
197             if (*wMaj == 0xffff && *wMin == 0xffff)
198             {
199                 if (v_maj > best_maj) best_maj = v_maj;
200                 if (v_min > best_min) best_min = v_min;
201             }
202             else if (*wMaj == v_maj)
203             {
204                 best_maj = v_maj;
205 
206                 if (*wMin == v_min)
207                 {
208                     best_min = v_min;
209                     break; /* exact match */
210                 }
211                 if (*wMin != 0xffff && v_min > best_min) best_min = v_min;
212             }
213         }
214         len = sizeof(key_name);
215     }
216     RegCloseKey( hkey );
217 
218     TRACE("found best_maj %d, best_min %d\n", best_maj, best_min);
219 
220     if (*wMaj == 0xffff && *wMin == 0xffff)
221     {
222         if (best_maj >= 0 && best_min >= 0)
223         {
224             *wMaj = best_maj;
225             *wMin = best_min;
226             return TRUE;
227         }
228     }
229 
230     if (*wMaj == best_maj && best_min >= 0)
231     {
232         *wMin = best_min;
233         return TRUE;
234     }
235     return FALSE;
236 }
237 
238 /* get the path of a typelib key, in the form "Typelib\\<guid>\\<maj>.<min>" */
239 /* buffer must be at least 60 characters long */
240 static WCHAR *get_typelib_key( REFGUID guid, WORD wMaj, WORD wMin, WCHAR *buffer )
241 {
242     static const WCHAR TypelibW[] = {'T','y','p','e','l','i','b','\\',0};
243     static const WCHAR VersionFormatW[] = {'\\','%','x','.','%','x',0};
244 
245     memcpy( buffer, TypelibW, sizeof(TypelibW) );
246     StringFromGUID2( guid, buffer + lstrlenW(buffer), 40 );
247     swprintf( buffer + lstrlenW(buffer), VersionFormatW, wMaj, wMin );
248     return buffer;
249 }
250 
251 /* get the path of an interface key, in the form "Interface\\<guid>" */
252 /* buffer must be at least 50 characters long */
253 static WCHAR *get_interface_key( REFGUID guid, WCHAR *buffer )
254 {
255     static const WCHAR InterfaceW[] = {'I','n','t','e','r','f','a','c','e','\\',0};
256 
257     memcpy( buffer, InterfaceW, sizeof(InterfaceW) );
258     StringFromGUID2( guid, buffer + lstrlenW(buffer), 40 );
259     return buffer;
260 }
261 
262 /* get the lcid subkey for a typelib, in the form "<lcid>\\<syskind>" */
263 /* buffer must be at least 16 characters long */
264 static WCHAR *get_lcid_subkey( LCID lcid, SYSKIND syskind, WCHAR *buffer )
265 {
266     static const WCHAR LcidFormatW[] = {'%','l','x','\\',0};
267     static const WCHAR win16W[] = {'w','i','n','1','6',0};
268     static const WCHAR win32W[] = {'w','i','n','3','2',0};
269     static const WCHAR win64W[] = {'w','i','n','6','4',0};
270 
271     swprintf( buffer, LcidFormatW, lcid );
272     switch(syskind)
273     {
274     case SYS_WIN16: lstrcatW( buffer, win16W ); break;
275     case SYS_WIN32: lstrcatW( buffer, win32W ); break;
276     case SYS_WIN64: lstrcatW( buffer, win64W ); break;
277     default:
278         TRACE("Typelib is for unsupported syskind %i\n", syskind);
279         return NULL;
280     }
281     return buffer;
282 }
283 
284 static HRESULT TLB_ReadTypeLib(LPCWSTR pszFileName, LPWSTR pszPath, UINT cchPath, ITypeLib2 **ppTypeLib);
285 
286 struct tlibredirect_data
287 {
288     ULONG  size;
289     DWORD  res;
290     ULONG  name_len;
291     ULONG  name_offset;
292     LANGID langid;
293     WORD   flags;
294     ULONG  help_len;
295     ULONG  help_offset;
296     WORD   major_version;
297     WORD   minor_version;
298 };
299 
300 /* Get the path to a registered type library. Helper for QueryPathOfRegTypeLib. */
301 static HRESULT query_typelib_path( REFGUID guid, WORD wMaj, WORD wMin,
302                                    SYSKIND syskind, LCID lcid, BSTR *path, BOOL redir )
303 {
304     HRESULT hr = TYPE_E_LIBNOTREGISTERED;
305     LCID myLCID = lcid;
306     HKEY hkey;
307     WCHAR buffer[60];
308     WCHAR Path[MAX_PATH];
309     LONG res;
310 
311     TRACE_(typelib)("(%s, %x.%x, 0x%x, %p)\n", debugstr_guid(guid), wMaj, wMin, lcid, path);
312 
313     if (redir)
314     {
315         ACTCTX_SECTION_KEYED_DATA data;
316 
317         data.cbSize = sizeof(data);
318         if (FindActCtxSectionGuid( 0, NULL, ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION, guid, &data ))
319         {
320             struct tlibredirect_data *tlib = (struct tlibredirect_data*)data.lpData;
321             WCHAR *nameW;
322             DWORD len;
323 
324             if ((wMaj != 0xffff || wMin != 0xffff) && (tlib->major_version != wMaj || tlib->minor_version < wMin))
325                 return TYPE_E_LIBNOTREGISTERED;
326 
327             nameW = (WCHAR*)((BYTE*)data.lpSectionBase + tlib->name_offset);
328             len = SearchPathW( NULL, nameW, NULL, ARRAY_SIZE( Path ), Path, NULL );
329             if (!len) return TYPE_E_LIBNOTREGISTERED;
330 
331             TRACE_(typelib)("got path from context %s\n", debugstr_w(Path));
332             *path = SysAllocString( Path );
333             return S_OK;
334         }
335     }
336 
337     if (!find_typelib_key( guid, &wMaj, &wMin )) return TYPE_E_LIBNOTREGISTERED;
338     get_typelib_key( guid, wMaj, wMin, buffer );
339 
340     res = RegOpenKeyExW( HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hkey );
341     if (res == ERROR_FILE_NOT_FOUND)
342     {
343         TRACE_(typelib)("%s not found\n", debugstr_w(buffer));
344         return TYPE_E_LIBNOTREGISTERED;
345     }
346     else if (res != ERROR_SUCCESS)
347     {
348         TRACE_(typelib)("failed to open %s for read access\n", debugstr_w(buffer));
349         return TYPE_E_REGISTRYACCESS;
350     }
351 
352     while (hr != S_OK)
353     {
354         LONG dwPathLen = sizeof(Path);
355 
356         get_lcid_subkey( myLCID, syskind, buffer );
357 
358         if (RegQueryValueW(hkey, buffer, Path, &dwPathLen))
359         {
360             if (!lcid)
361                 break;
362             else if (myLCID == lcid)
363             {
364                 /* try with sub-langid */
365                 myLCID = SUBLANGID(lcid);
366             }
367             else if ((myLCID == SUBLANGID(lcid)) && myLCID)
368             {
369                 /* try with system langid */
370                 myLCID = 0;
371             }
372             else
373             {
374                 break;
375             }
376         }
377         else
378         {
379             *path = SysAllocString( Path );
380             hr = S_OK;
381         }
382     }
383     RegCloseKey( hkey );
384     TRACE_(typelib)("-- 0x%08x\n", hr);
385     return hr;
386 }
387 
388 /****************************************************************************
389  *		QueryPathOfRegTypeLib	[OLEAUT32.164]
390  *
391  * Gets the path to a registered type library.
392  *
393  * PARAMS
394  *  guid [I] referenced guid
395  *  wMaj [I] major version
396  *  wMin [I] minor version
397  *  lcid [I] locale id
398  *  path [O] path of typelib
399  *
400  * RETURNS
401  *  Success: S_OK.
402  *  Failure: If the type library is not registered then TYPE_E_LIBNOTREGISTERED
403  *  or TYPE_E_REGISTRYACCESS if the type library registration key couldn't be
404  *  opened.
405  */
406 HRESULT WINAPI QueryPathOfRegTypeLib( REFGUID guid, WORD wMaj, WORD wMin, LCID lcid, LPBSTR path )
407 {
408     BOOL redir = TRUE;
409 #ifdef _WIN64
410     HRESULT hres = query_typelib_path( guid, wMaj, wMin, SYS_WIN64, lcid, path, TRUE );
411     if(SUCCEEDED(hres))
412         return hres;
413     redir = FALSE;
414 #endif
415     return query_typelib_path( guid, wMaj, wMin, SYS_WIN32, lcid, path, redir );
416 }
417 
418 /******************************************************************************
419  * CreateTypeLib [OLEAUT32.160]  creates a typelib
420  *
421  * RETURNS
422  *    Success: S_OK
423  *    Failure: Status
424  */
425 HRESULT WINAPI CreateTypeLib(SYSKIND syskind, LPCOLESTR file, ICreateTypeLib **ctlib)
426 {
427     ICreateTypeLib2 *typelib2;
428     HRESULT hres;
429 
430     FIXME("(%d, %s, %p): forwarding to CreateTypeLib2\n", syskind, debugstr_w(file), ctlib);
431 
432     hres = CreateTypeLib2(syskind, file, &typelib2);
433     if(SUCCEEDED(hres))
434     {
435         hres = ICreateTypeLib2_QueryInterface(typelib2, &IID_ICreateTypeLib, (void **)&ctlib);
436         ICreateTypeLib2_Release(typelib2);
437     }
438 
439     return hres;
440 }
441 
442 /******************************************************************************
443  *		LoadTypeLib	[OLEAUT32.161]
444  *
445  * Loads a type library
446  *
447  * PARAMS
448  *  szFile [I] Name of file to load from.
449  *  pptLib [O] Pointer that receives ITypeLib object on success.
450  *
451  * RETURNS
452  *    Success: S_OK
453  *    Failure: Status
454  *
455  * SEE
456  *  LoadTypeLibEx, LoadRegTypeLib, CreateTypeLib.
457  */
458 HRESULT WINAPI LoadTypeLib(const OLECHAR *szFile, ITypeLib * *pptLib)
459 {
460     TRACE("(%s,%p)\n",debugstr_w(szFile), pptLib);
461     return LoadTypeLibEx(szFile, REGKIND_DEFAULT, pptLib);
462 }
463 
464 /******************************************************************************
465  *		LoadTypeLibEx	[OLEAUT32.183]
466  *
467  * Loads and optionally registers a type library
468  *
469  * RETURNS
470  *    Success: S_OK
471  *    Failure: Status
472  */
473 HRESULT WINAPI LoadTypeLibEx(
474     LPCOLESTR szFile,  /* [in] Name of file to load from */
475     REGKIND  regkind,  /* [in] Specify kind of registration */
476     ITypeLib **pptLib) /* [out] Pointer to pointer to loaded type library */
477 {
478     WCHAR szPath[MAX_PATH+1];
479     HRESULT res;
480 
481     TRACE("(%s,%d,%p)\n",debugstr_w(szFile), regkind, pptLib);
482 
483     if (!szFile || !pptLib)
484         return E_INVALIDARG;
485 
486     *pptLib = NULL;
487 
488     res = TLB_ReadTypeLib(szFile, szPath, MAX_PATH + 1, (ITypeLib2**)pptLib);
489 
490     if (SUCCEEDED(res))
491         switch(regkind)
492         {
493             case REGKIND_DEFAULT:
494                 /* don't register typelibs supplied with full path. Experimentation confirms the following */
495                 if (((szFile[0] == '\\') && (szFile[1] == '\\')) ||
496                     (szFile[0] && (szFile[1] == ':'))) break;
497                 /* else fall-through */
498 
499             case REGKIND_REGISTER:
500                 if (FAILED(res = RegisterTypeLib(*pptLib, szPath, NULL)))
501                 {
502                     ITypeLib_Release(*pptLib);
503                     *pptLib = 0;
504                 }
505                 break;
506             case REGKIND_NONE:
507                 break;
508         }
509 
510     TRACE(" returns %08x\n",res);
511     return res;
512 }
513 
514 /******************************************************************************
515  *		LoadRegTypeLib	[OLEAUT32.162]
516  *
517  * Loads a registered type library.
518  *
519  * PARAMS
520  *  rguid     [I] GUID of the registered type library.
521  *  wVerMajor [I] major version.
522  *  wVerMinor [I] minor version.
523  *  lcid      [I] locale ID.
524  *  ppTLib    [O] pointer that receives an ITypeLib object on success.
525  *
526  * RETURNS
527  *  Success: S_OK.
528  *  Failure: Any HRESULT code returned from QueryPathOfRegTypeLib or
529  *  LoadTypeLib.
530  */
531 HRESULT WINAPI LoadRegTypeLib(
532 	REFGUID rguid,
533 	WORD wVerMajor,
534 	WORD wVerMinor,
535 	LCID lcid,
536 	ITypeLib **ppTLib)
537 {
538     BSTR bstr=NULL;
539     HRESULT res;
540 
541     *ppTLib = NULL;
542 
543     res = QueryPathOfRegTypeLib( rguid, wVerMajor, wVerMinor, lcid, &bstr);
544 
545     if(SUCCEEDED(res))
546     {
547         res= LoadTypeLib(bstr, ppTLib);
548         SysFreeString(bstr);
549 
550         if ((wVerMajor!=0xffff || wVerMinor!=0xffff) && *ppTLib)
551         {
552             TLIBATTR *attr;
553 
554             res = ITypeLib_GetLibAttr(*ppTLib, &attr);
555             if (res == S_OK)
556             {
557                 BOOL mismatch = attr->wMajorVerNum != wVerMajor || attr->wMinorVerNum < wVerMinor;
558                 ITypeLib_ReleaseTLibAttr(*ppTLib, attr);
559 
560                 if (mismatch)
561                 {
562                     ITypeLib_Release(*ppTLib);
563                     *ppTLib = NULL;
564                     res = TYPE_E_LIBNOTREGISTERED;
565                 }
566             }
567         }
568     }
569 
570     TRACE("(IID: %s) load %s (%p)\n",debugstr_guid(rguid), SUCCEEDED(res)? "SUCCESS":"FAILED", *ppTLib);
571 
572     return res;
573 }
574 
575 
576 /* some string constants shared between RegisterTypeLib and UnRegisterTypeLib */
577 static const WCHAR TypeLibW[] = {'T','y','p','e','L','i','b',0};
578 static const WCHAR FLAGSW[] = {'F','L','A','G','S',0};
579 static const WCHAR HELPDIRW[] = {'H','E','L','P','D','I','R',0};
580 static const WCHAR ProxyStubClsidW[] = {'P','r','o','x','y','S','t','u','b','C','l','s','i','d',0};
581 static const WCHAR ProxyStubClsid32W[] = {'P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
582 
583 static void TLB_register_interface(TLIBATTR *libattr, LPOLESTR name, TYPEATTR *tattr, DWORD flag)
584 {
585     WCHAR keyName[60];
586     HKEY key, subKey;
587 
588     static const WCHAR typelib_proxy_clsid[] = {'{','0','0','0','2','0','4','2','4','-',
589             '0','0','0','0','-','0','0','0','0','-','C','0','0','0','-',
590             '0','0','0','0','0','0','0','0','0','0','4','6','}',0};
591     static const WCHAR dispatch_proxy_clsid[] = {'{','0','0','0','2','0','4','2','0','-',
592             '0','0','0','0','-','0','0','0','0','-','C','0','0','0','-',
593             '0','0','0','0','0','0','0','0','0','0','4','6','}',0};
594 
595     get_interface_key( &tattr->guid, keyName );
596     if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0,
597                         KEY_WRITE | flag, NULL, &key, NULL) == ERROR_SUCCESS)
598     {
599         const WCHAR *proxy_clsid;
600 
601         if (tattr->typekind == TKIND_INTERFACE || (tattr->wTypeFlags & TYPEFLAG_FDUAL))
602             proxy_clsid = typelib_proxy_clsid;
603         else
604             proxy_clsid = dispatch_proxy_clsid;
605 
606         if (name)
607             RegSetValueExW(key, NULL, 0, REG_SZ,
608                            (BYTE *)name, (lstrlenW(name)+1) * sizeof(OLECHAR));
609 
610         if (RegCreateKeyExW(key, ProxyStubClsidW, 0, NULL, 0,
611             KEY_WRITE | flag, NULL, &subKey, NULL) == ERROR_SUCCESS) {
612             RegSetValueExW(subKey, NULL, 0, REG_SZ,
613                            (const BYTE *)proxy_clsid, sizeof(typelib_proxy_clsid));
614             RegCloseKey(subKey);
615         }
616 
617         if (RegCreateKeyExW(key, ProxyStubClsid32W, 0, NULL, 0,
618             KEY_WRITE | flag, NULL, &subKey, NULL) == ERROR_SUCCESS) {
619             RegSetValueExW(subKey, NULL, 0, REG_SZ,
620                            (const BYTE *)proxy_clsid, sizeof(typelib_proxy_clsid));
621             RegCloseKey(subKey);
622         }
623 
624         if (RegCreateKeyExW(key, TypeLibW, 0, NULL, 0,
625             KEY_WRITE | flag, NULL, &subKey, NULL) == ERROR_SUCCESS)
626         {
627             WCHAR buffer[40];
628             static const WCHAR fmtver[] = {'%','x','.','%','x',0 };
629             static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
630 
631             StringFromGUID2(&libattr->guid, buffer, 40);
632             RegSetValueExW(subKey, NULL, 0, REG_SZ,
633                            (BYTE *)buffer, (lstrlenW(buffer)+1) * sizeof(WCHAR));
634             swprintf(buffer, fmtver, libattr->wMajorVerNum, libattr->wMinorVerNum);
635             RegSetValueExW(subKey, VersionW, 0, REG_SZ,
636                            (BYTE*)buffer, (lstrlenW(buffer)+1) * sizeof(WCHAR));
637             RegCloseKey(subKey);
638         }
639 
640         RegCloseKey(key);
641     }
642 }
643 
644 /******************************************************************************
645  *		RegisterTypeLib	[OLEAUT32.163]
646  * Adds information about a type library to the System Registry
647  * NOTES
648  *    Docs: ITypeLib FAR * ptlib
649  *    Docs: OLECHAR FAR* szFullPath
650  *    Docs: OLECHAR FAR* szHelpDir
651  *
652  * RETURNS
653  *    Success: S_OK
654  *    Failure: Status
655  */
656 HRESULT WINAPI RegisterTypeLib(ITypeLib *ptlib, const WCHAR *szFullPath, const WCHAR *szHelpDir)
657 {
658     HRESULT res;
659     TLIBATTR *attr;
660     WCHAR keyName[60];
661     WCHAR tmp[16];
662     HKEY key, subKey;
663     UINT types, tidx;
664     TYPEKIND kind;
665     DWORD disposition;
666 
667     if (ptlib == NULL || szFullPath == NULL)
668         return E_INVALIDARG;
669 
670     if (FAILED(ITypeLib_GetLibAttr(ptlib, &attr)))
671         return E_FAIL;
672 
673 #ifndef _WIN64
674     if (attr->syskind == SYS_WIN64) return TYPE_E_BADMODULEKIND;
675 #endif
676 
677     get_typelib_key( &attr->guid, attr->wMajorVerNum, attr->wMinorVerNum, keyName );
678 
679     res = S_OK;
680     if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0,
681         KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS)
682     {
683         LPOLESTR doc;
684 
685         /* Set the human-readable name of the typelib */
686         if (FAILED(ITypeLib_GetDocumentation(ptlib, -1, NULL, &doc, NULL, NULL)))
687             res = E_FAIL;
688         else if (doc)
689         {
690             if (RegSetValueExW(key, NULL, 0, REG_SZ,
691                 (BYTE *)doc, (lstrlenW(doc)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS)
692                 res = E_FAIL;
693 
694             SysFreeString(doc);
695         }
696 
697         /* Make up the name of the typelib path subkey */
698         if (!get_lcid_subkey( attr->lcid, attr->syskind, tmp )) res = E_FAIL;
699 
700         /* Create the typelib path subkey */
701         if (res == S_OK && RegCreateKeyExW(key, tmp, 0, NULL, 0,
702             KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
703         {
704             if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
705                 (BYTE *)szFullPath, (lstrlenW(szFullPath)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS)
706                 res = E_FAIL;
707 
708             RegCloseKey(subKey);
709         }
710         else
711             res = E_FAIL;
712 
713         /* Create the flags subkey */
714         if (res == S_OK && RegCreateKeyExW(key, FLAGSW, 0, NULL, 0,
715             KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
716         {
717             /* FIXME: is %u correct? */
718             static const WCHAR formatW[] = {'%','u',0};
719             WCHAR buf[20];
720             swprintf(buf, formatW, attr->wLibFlags);
721             if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
722                                (BYTE *)buf, (lstrlenW(buf) + 1)*sizeof(WCHAR) ) != ERROR_SUCCESS)
723                 res = E_FAIL;
724 
725             RegCloseKey(subKey);
726         }
727         else
728             res = E_FAIL;
729 
730         /* create the helpdir subkey */
731         if (res == S_OK && RegCreateKeyExW(key, HELPDIRW, 0, NULL, 0,
732             KEY_WRITE, NULL, &subKey, &disposition) == ERROR_SUCCESS)
733         {
734             BSTR freeHelpDir = NULL;
735             OLECHAR* pIndexStr;
736 
737             /* if we created a new key, and helpDir was null, set the helpdir
738                to the directory which contains the typelib. However,
739                if we just opened an existing key, we leave the helpdir alone */
740             if ((disposition == REG_CREATED_NEW_KEY) && (szHelpDir == NULL)) {
741                 szHelpDir = freeHelpDir = SysAllocString(szFullPath);
742                 pIndexStr = wcsrchr(szHelpDir, '\\');
743                 if (pIndexStr) {
744                     *pIndexStr = 0;
745                 }
746             }
747 
748             /* if we have an szHelpDir, set it! */
749             if (szHelpDir != NULL) {
750                 if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
751                     (BYTE *)szHelpDir, (lstrlenW(szHelpDir)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS) {
752                     res = E_FAIL;
753                 }
754             }
755 
756             SysFreeString(freeHelpDir);
757             RegCloseKey(subKey);
758         } else {
759             res = E_FAIL;
760         }
761 
762         RegCloseKey(key);
763     }
764     else
765         res = E_FAIL;
766 
767     /* register OLE Automation-compatible interfaces for this typelib */
768     types = ITypeLib_GetTypeInfoCount(ptlib);
769     for (tidx=0; tidx<types; tidx++) {
770 	if (SUCCEEDED(ITypeLib_GetTypeInfoType(ptlib, tidx, &kind))) {
771 	    LPOLESTR name = NULL;
772 	    ITypeInfo *tinfo = NULL;
773 
774 	    ITypeLib_GetDocumentation(ptlib, tidx, &name, NULL, NULL, NULL);
775 
776 	    switch (kind) {
777 	    case TKIND_INTERFACE:
778 		TRACE_(typelib)("%d: interface %s\n", tidx, debugstr_w(name));
779 		ITypeLib_GetTypeInfo(ptlib, tidx, &tinfo);
780 		break;
781 
782 	    case TKIND_DISPATCH:
783 		TRACE_(typelib)("%d: dispinterface %s\n", tidx, debugstr_w(name));
784                 ITypeLib_GetTypeInfo(ptlib, tidx, &tinfo);
785 		break;
786 
787 	    default:
788 		TRACE_(typelib)("%d: %s\n", tidx, debugstr_w(name));
789 		break;
790 	    }
791 
792 	    if (tinfo) {
793 		TYPEATTR *tattr = NULL;
794 		ITypeInfo_GetTypeAttr(tinfo, &tattr);
795 
796 		if (tattr) {
797 		    TRACE_(typelib)("guid=%s, flags=%04x (",
798 				    debugstr_guid(&tattr->guid),
799 				    tattr->wTypeFlags);
800 
801 		    if (TRACE_ON(typelib)) {
802 #define XX(x) if (TYPEFLAG_##x & tattr->wTypeFlags) MESSAGE(#x"|");
803 			XX(FAPPOBJECT);
804 			XX(FCANCREATE);
805 			XX(FLICENSED);
806 			XX(FPREDECLID);
807 			XX(FHIDDEN);
808 			XX(FCONTROL);
809 			XX(FDUAL);
810 			XX(FNONEXTENSIBLE);
811 			XX(FOLEAUTOMATION);
812 			XX(FRESTRICTED);
813 			XX(FAGGREGATABLE);
814 			XX(FREPLACEABLE);
815 			XX(FDISPATCHABLE);
816 			XX(FREVERSEBIND);
817 			XX(FPROXY);
818 #undef XX
819 			MESSAGE("\n");
820 		    }
821 
822                     /* Register all dispinterfaces (which includes dual interfaces) and
823                        oleautomation interfaces */
824 		    if ((kind == TKIND_INTERFACE && (tattr->wTypeFlags & TYPEFLAG_FOLEAUTOMATION)) ||
825                         kind == TKIND_DISPATCH)
826 		    {
827                         BOOL is_wow64;
828                         DWORD opposite = (sizeof(void*) == 8 ? KEY_WOW64_32KEY : KEY_WOW64_64KEY);
829 
830                         /* register interface<->typelib coupling */
831                         TLB_register_interface(attr, name, tattr, 0);
832 
833                         /* register TLBs into the opposite registry view, too */
834                         if(opposite == KEY_WOW64_32KEY ||
835                                  (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64))
836                             TLB_register_interface(attr, name, tattr, opposite);
837 		    }
838 
839 		    ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
840 		}
841 
842 		ITypeInfo_Release(tinfo);
843 	    }
844 
845 	    SysFreeString(name);
846 	}
847     }
848 
849     ITypeLib_ReleaseTLibAttr(ptlib, attr);
850 
851     return res;
852 }
853 
854 static void TLB_unregister_interface(GUID *guid, REGSAM flag)
855 {
856     WCHAR subKeyName[50];
857     HKEY subKey;
858 
859     /* the path to the type */
860     get_interface_key( guid, subKeyName );
861 
862     /* Delete its bits */
863     if (RegOpenKeyExW(HKEY_CLASSES_ROOT, subKeyName, 0, KEY_WRITE | flag, &subKey) != ERROR_SUCCESS)
864         return;
865 
866     RegDeleteKeyW(subKey, ProxyStubClsidW);
867     RegDeleteKeyW(subKey, ProxyStubClsid32W);
868     RegDeleteKeyW(subKey, TypeLibW);
869     RegCloseKey(subKey);
870     RegDeleteKeyExW(HKEY_CLASSES_ROOT, subKeyName, flag, 0);
871 }
872 
873 /******************************************************************************
874  *	UnRegisterTypeLib	[OLEAUT32.186]
875  * Removes information about a type library from the System Registry
876  * NOTES
877  *
878  * RETURNS
879  *    Success: S_OK
880  *    Failure: Status
881  */
882 HRESULT WINAPI UnRegisterTypeLib(
883     REFGUID libid,	/* [in] Guid of the library */
884 	WORD wVerMajor,	/* [in] major version */
885 	WORD wVerMinor,	/* [in] minor version */
886 	LCID lcid,	/* [in] locale id */
887 	SYSKIND syskind)
888 {
889     BSTR tlibPath = NULL;
890     DWORD tmpLength;
891     WCHAR keyName[60];
892     WCHAR subKeyName[50];
893     int result = S_OK;
894     DWORD i = 0;
895     BOOL deleteOtherStuff;
896     HKEY key = NULL;
897     TYPEATTR* typeAttr = NULL;
898     TYPEKIND kind;
899     ITypeInfo* typeInfo = NULL;
900     ITypeLib* typeLib = NULL;
901     int numTypes;
902 
903     TRACE("(IID: %s)\n",debugstr_guid(libid));
904 
905     /* Create the path to the key */
906     get_typelib_key( libid, wVerMajor, wVerMinor, keyName );
907 
908     if (syskind != SYS_WIN16 && syskind != SYS_WIN32 && syskind != SYS_WIN64)
909     {
910         TRACE("Unsupported syskind %i\n", syskind);
911         result = E_INVALIDARG;
912         goto end;
913     }
914 
915     /* get the path to the typelib on disk */
916     if (query_typelib_path(libid, wVerMajor, wVerMinor, syskind, lcid, &tlibPath, FALSE) != S_OK) {
917         result = E_INVALIDARG;
918         goto end;
919     }
920 
921     /* Try and open the key to the type library. */
922     if (RegOpenKeyExW(HKEY_CLASSES_ROOT, keyName, 0, KEY_READ | KEY_WRITE, &key) != ERROR_SUCCESS) {
923         result = E_INVALIDARG;
924         goto end;
925     }
926 
927     /* Try and load the type library */
928     if (LoadTypeLibEx(tlibPath, REGKIND_NONE, &typeLib) != S_OK) {
929         result = TYPE_E_INVALIDSTATE;
930         goto end;
931     }
932 
933     /* remove any types registered with this typelib */
934     numTypes = ITypeLib_GetTypeInfoCount(typeLib);
935     for (i=0; i<numTypes; i++) {
936         /* get the kind of type */
937         if (ITypeLib_GetTypeInfoType(typeLib, i, &kind) != S_OK) {
938             goto enddeleteloop;
939         }
940 
941         /* skip non-interfaces, and get type info for the type */
942         if ((kind != TKIND_INTERFACE) && (kind != TKIND_DISPATCH)) {
943             goto enddeleteloop;
944         }
945         if (ITypeLib_GetTypeInfo(typeLib, i, &typeInfo) != S_OK) {
946             goto enddeleteloop;
947         }
948         if (ITypeInfo_GetTypeAttr(typeInfo, &typeAttr) != S_OK) {
949             goto enddeleteloop;
950         }
951 
952         if ((kind == TKIND_INTERFACE && (typeAttr->wTypeFlags & TYPEFLAG_FOLEAUTOMATION)) ||
953             kind == TKIND_DISPATCH)
954         {
955             BOOL is_wow64;
956             REGSAM opposite = (sizeof(void*) == 8 ? KEY_WOW64_32KEY : KEY_WOW64_64KEY);
957 
958             TLB_unregister_interface(&typeAttr->guid, 0);
959 
960             /* unregister TLBs into the opposite registry view, too */
961             if(opposite == KEY_WOW64_32KEY ||
962                (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)) {
963                 TLB_unregister_interface(&typeAttr->guid, opposite);
964             }
965         }
966 
967 enddeleteloop:
968         if (typeAttr) ITypeInfo_ReleaseTypeAttr(typeInfo, typeAttr);
969         typeAttr = NULL;
970         if (typeInfo) ITypeInfo_Release(typeInfo);
971         typeInfo = NULL;
972     }
973 
974     /* Now, delete the type library path subkey */
975     get_lcid_subkey( lcid, syskind, subKeyName );
976     RegDeleteKeyW(key, subKeyName);
977     *wcsrchr( subKeyName, '\\' ) = 0;  /* remove last path component */
978     RegDeleteKeyW(key, subKeyName);
979 
980     /* check if there is anything besides the FLAGS/HELPDIR keys.
981        If there is, we don't delete them */
982     tmpLength = ARRAY_SIZE(subKeyName);
983     deleteOtherStuff = TRUE;
984     i = 0;
985     while(RegEnumKeyExW(key, i++, subKeyName, &tmpLength, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
986         tmpLength = ARRAY_SIZE(subKeyName);
987 
988         /* if its not FLAGS or HELPDIR, then we must keep the rest of the key */
989         if (!wcscmp(subKeyName, FLAGSW)) continue;
990         if (!wcscmp(subKeyName, HELPDIRW)) continue;
991         deleteOtherStuff = FALSE;
992         break;
993     }
994 
995     /* only delete the other parts of the key if we're absolutely sure */
996     if (deleteOtherStuff) {
997         RegDeleteKeyW(key, FLAGSW);
998         RegDeleteKeyW(key, HELPDIRW);
999         RegCloseKey(key);
1000         key = NULL;
1001 
1002         RegDeleteKeyW(HKEY_CLASSES_ROOT, keyName);
1003         *wcsrchr( keyName, '\\' ) = 0;  /* remove last path component */
1004         RegDeleteKeyW(HKEY_CLASSES_ROOT, keyName);
1005     }
1006 
1007 end:
1008     SysFreeString(tlibPath);
1009     if (typeLib) ITypeLib_Release(typeLib);
1010     if (key) RegCloseKey(key);
1011     return result;
1012 }
1013 
1014 /******************************************************************************
1015  *		RegisterTypeLibForUser	[OLEAUT32.442]
1016  * Adds information about a type library to the user registry
1017  * NOTES
1018  *    Docs: ITypeLib FAR * ptlib
1019  *    Docs: OLECHAR FAR* szFullPath
1020  *    Docs: OLECHAR FAR* szHelpDir
1021  *
1022  * RETURNS
1023  *    Success: S_OK
1024  *    Failure: Status
1025  */
1026 HRESULT WINAPI RegisterTypeLibForUser(
1027      ITypeLib * ptlib,     /* [in] Pointer to the library*/
1028      OLECHAR * szFullPath, /* [in] full Path of the library*/
1029      OLECHAR * szHelpDir)  /* [in] dir to the helpfile for the library,
1030 							 may be NULL*/
1031 {
1032     FIXME("(%p, %s, %s) registering the typelib system-wide\n", ptlib,
1033           debugstr_w(szFullPath), debugstr_w(szHelpDir));
1034     return RegisterTypeLib(ptlib, szFullPath, szHelpDir);
1035 }
1036 
1037 /******************************************************************************
1038  *	UnRegisterTypeLibForUser	[OLEAUT32.443]
1039  * Removes information about a type library from the user registry
1040  *
1041  * RETURNS
1042  *    Success: S_OK
1043  *    Failure: Status
1044  */
1045 HRESULT WINAPI UnRegisterTypeLibForUser(
1046     REFGUID libid,	/* [in] GUID of the library */
1047     WORD wVerMajor,	/* [in] major version */
1048     WORD wVerMinor,	/* [in] minor version */
1049     LCID lcid,	/* [in] locale id */
1050     SYSKIND syskind)
1051 {
1052     FIXME("(%s, %u, %u, %u, %u) unregistering the typelib system-wide\n",
1053           debugstr_guid(libid), wVerMajor, wVerMinor, lcid, syskind);
1054     return UnRegisterTypeLib(libid, wVerMajor, wVerMinor, lcid, syskind);
1055 }
1056 
1057 /*======================= ITypeLib implementation =======================*/
1058 
1059 typedef struct tagTLBGuid {
1060     GUID guid;
1061     INT hreftype;
1062     UINT offset;
1063     struct list entry;
1064 } TLBGuid;
1065 
1066 typedef struct tagTLBCustData
1067 {
1068     TLBGuid *guid;
1069     VARIANT data;
1070     struct list entry;
1071 } TLBCustData;
1072 
1073 /* data structure for import typelibs */
1074 typedef struct tagTLBImpLib
1075 {
1076     int offset;                 /* offset in the file (MSFT)
1077 				   offset in nametable (SLTG)
1078 				   just used to identify library while reading
1079 				   data from file */
1080     TLBGuid *guid;                  /* libid */
1081     BSTR name;                  /* name */
1082 
1083     LCID lcid;                  /* lcid of imported typelib */
1084 
1085     WORD wVersionMajor;         /* major version number */
1086     WORD wVersionMinor;         /* minor version number */
1087 
1088     struct tagITypeLibImpl *pImpTypeLib; /* pointer to loaded typelib, or
1089 					    NULL if not yet loaded */
1090     struct list entry;
1091 } TLBImpLib;
1092 
1093 typedef struct tagTLBString {
1094     BSTR str;
1095     UINT offset;
1096     struct list entry;
1097 } TLBString;
1098 
1099 /* internal ITypeLib data */
1100 typedef struct tagITypeLibImpl
1101 {
1102     ITypeLib2 ITypeLib2_iface;
1103     ITypeComp ITypeComp_iface;
1104     ICreateTypeLib2 ICreateTypeLib2_iface;
1105     LONG ref;
1106     TLBGuid *guid;
1107     LCID lcid;
1108     SYSKIND syskind;
1109     int ptr_size;
1110     WORD ver_major;
1111     WORD ver_minor;
1112     WORD libflags;
1113     LCID set_lcid;
1114 
1115     /* strings can be stored in tlb as multibyte strings BUT they are *always*
1116      * exported to the application as a UNICODE string.
1117      */
1118     struct list string_list;
1119     struct list name_list;
1120     struct list guid_list;
1121 
1122     const TLBString *Name;
1123     const TLBString *DocString;
1124     const TLBString *HelpFile;
1125     const TLBString *HelpStringDll;
1126     DWORD dwHelpContext;
1127     int TypeInfoCount;          /* nr of typeinfo's in librarry */
1128     struct tagITypeInfoImpl **typeinfos;
1129     struct list custdata_list;
1130     struct list implib_list;
1131     int ctTypeDesc;             /* number of items in type desc array */
1132     TYPEDESC * pTypeDesc;       /* array of TypeDescriptions found in the
1133 				   library. Only used while reading MSFT
1134 				   typelibs */
1135     struct list ref_list;       /* list of ref types in this typelib */
1136     HREFTYPE dispatch_href;     /* reference to IDispatch, -1 if unused */
1137 
1138 
1139     /* typelibs are cached, keyed by path and index, so store the linked list info within them */
1140     struct list entry;
1141     WCHAR *path;
1142     INT index;
1143 } ITypeLibImpl;
1144 
1145 static const ITypeLib2Vtbl tlbvt;
1146 static const ITypeCompVtbl tlbtcvt;
1147 static const ICreateTypeLib2Vtbl CreateTypeLib2Vtbl;
1148 
1149 static inline ITypeLibImpl *impl_from_ITypeLib2(ITypeLib2 *iface)
1150 {
1151     return CONTAINING_RECORD(iface, ITypeLibImpl, ITypeLib2_iface);
1152 }
1153 
1154 static inline ITypeLibImpl *impl_from_ITypeLib(ITypeLib *iface)
1155 {
1156     return impl_from_ITypeLib2((ITypeLib2*)iface);
1157 }
1158 
1159 static inline ITypeLibImpl *impl_from_ITypeComp( ITypeComp *iface )
1160 {
1161     return CONTAINING_RECORD(iface, ITypeLibImpl, ITypeComp_iface);
1162 }
1163 
1164 static inline ITypeLibImpl *impl_from_ICreateTypeLib2( ICreateTypeLib2 *iface )
1165 {
1166     return CONTAINING_RECORD(iface, ITypeLibImpl, ICreateTypeLib2_iface);
1167 }
1168 
1169 /* ITypeLib methods */
1170 static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength);
1171 static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength);
1172 
1173 /*======================= ITypeInfo implementation =======================*/
1174 
1175 /* data for referenced types */
1176 typedef struct tagTLBRefType
1177 {
1178     INT index;              /* Type index for internal ref or for external ref
1179 			       it the format is SLTG.  -2 indicates to
1180 			       use guid */
1181 
1182     TYPEKIND tkind;
1183     TLBGuid *guid;              /* guid of the referenced type */
1184                             /* if index == TLB_REF_USE_GUID */
1185 
1186     HREFTYPE reference;     /* The href of this ref */
1187     TLBImpLib *pImpTLInfo;  /* If ref is external ptr to library data
1188 			       TLB_REF_INTERNAL for internal refs
1189 			       TLB_REF_NOT_FOUND for broken refs */
1190 
1191     struct list entry;
1192 } TLBRefType;
1193 
1194 #define TLB_REF_USE_GUID -2
1195 
1196 #define TLB_REF_INTERNAL (void*)-2
1197 #define TLB_REF_NOT_FOUND (void*)-1
1198 
1199 /* internal Parameter data */
1200 typedef struct tagTLBParDesc
1201 {
1202     const TLBString *Name;
1203     struct list custdata_list;
1204 } TLBParDesc;
1205 
1206 /* internal Function data */
1207 typedef struct tagTLBFuncDesc
1208 {
1209     FUNCDESC funcdesc;      /* lots of info on the function and its attributes. */
1210     const TLBString *Name;             /* the name of this function */
1211     TLBParDesc *pParamDesc; /* array with param names and custom data */
1212     int helpcontext;
1213     int HelpStringContext;
1214     const TLBString *HelpString;
1215     const TLBString *Entry;            /* if IS_INTRESOURCE true, it's numeric; if -1 it isn't present */
1216     struct list custdata_list;
1217 } TLBFuncDesc;
1218 
1219 /* internal Variable data */
1220 typedef struct tagTLBVarDesc
1221 {
1222     VARDESC vardesc;                /* lots of info on the variable and its attributes. */
1223     VARDESC *vardesc_create;        /* additional data needed for storing VARDESC */
1224     const TLBString *Name;          /* the name of this variable */
1225     int HelpContext;
1226     int HelpStringContext;
1227     const TLBString *HelpString;
1228     struct list custdata_list;
1229 } TLBVarDesc;
1230 
1231 /* internal implemented interface data */
1232 typedef struct tagTLBImplType
1233 {
1234     HREFTYPE hRef;          /* hRef of interface */
1235     int implflags;          /* IMPLFLAG_*s */
1236     struct list custdata_list;
1237 } TLBImplType;
1238 
1239 /* internal TypeInfo data */
1240 typedef struct tagITypeInfoImpl
1241 {
1242     ITypeInfo2 ITypeInfo2_iface;
1243     ITypeComp ITypeComp_iface;
1244     ICreateTypeInfo2 ICreateTypeInfo2_iface;
1245     LONG ref;
1246     BOOL not_attached_to_typelib;
1247     BOOL needs_layout;
1248 
1249     TLBGuid *guid;
1250     TYPEATTR typeattr;
1251     TYPEDESC *tdescAlias;
1252 
1253     ITypeLibImpl * pTypeLib;        /* back pointer to typelib */
1254     int index;                  /* index in this typelib; */
1255     HREFTYPE hreftype;          /* hreftype for app object binding */
1256     /* type libs seem to store the doc strings in ascii
1257      * so why should we do it in unicode?
1258      */
1259     const TLBString *Name;
1260     const TLBString *DocString;
1261     const TLBString *DllName;
1262     const TLBString *Schema;
1263     DWORD dwHelpContext;
1264     DWORD dwHelpStringContext;
1265 
1266     /* functions  */
1267     TLBFuncDesc *funcdescs;
1268 
1269     /* variables  */
1270     TLBVarDesc *vardescs;
1271 
1272     /* Implemented Interfaces  */
1273     TLBImplType *impltypes;
1274 
1275     struct list *pcustdata_list;
1276     struct list custdata_list;
1277 } ITypeInfoImpl;
1278 
1279 static inline ITypeInfoImpl *info_impl_from_ITypeComp( ITypeComp *iface )
1280 {
1281     return CONTAINING_RECORD(iface, ITypeInfoImpl, ITypeComp_iface);
1282 }
1283 
1284 static inline ITypeInfoImpl *impl_from_ITypeInfo2( ITypeInfo2 *iface )
1285 {
1286     return CONTAINING_RECORD(iface, ITypeInfoImpl, ITypeInfo2_iface);
1287 }
1288 
1289 static inline ITypeInfoImpl *impl_from_ITypeInfo( ITypeInfo *iface )
1290 {
1291     return impl_from_ITypeInfo2((ITypeInfo2*)iface);
1292 }
1293 
1294 static inline ITypeInfoImpl *info_impl_from_ICreateTypeInfo2( ICreateTypeInfo2 *iface )
1295 {
1296     return CONTAINING_RECORD(iface, ITypeInfoImpl, ICreateTypeInfo2_iface);
1297 }
1298 
1299 static const ITypeInfo2Vtbl tinfvt;
1300 static const ITypeCompVtbl  tcompvt;
1301 static const ICreateTypeInfo2Vtbl CreateTypeInfo2Vtbl;
1302 
1303 static ITypeInfoImpl* ITypeInfoImpl_Constructor(void);
1304 static void ITypeInfoImpl_Destroy(ITypeInfoImpl *This);
1305 
1306 typedef struct tagTLBContext
1307 {
1308 	unsigned int oStart;  /* start of TLB in file */
1309 	unsigned int pos;     /* current pos */
1310 	unsigned int length;  /* total length */
1311 	void *mapping;        /* memory mapping */
1312 	MSFT_SegDir * pTblDir;
1313 	ITypeLibImpl* pLibInfo;
1314 } TLBContext;
1315 
1316 
1317 static inline BSTR TLB_get_bstr(const TLBString *str)
1318 {
1319     return str != NULL ? str->str : NULL;
1320 }
1321 
1322 static inline int TLB_str_memcmp(void *left, const TLBString *str, DWORD len)
1323 {
1324     if(!str)
1325         return 1;
1326     return memcmp(left, str->str, len);
1327 }
1328 
1329 static inline const GUID *TLB_get_guidref(const TLBGuid *guid)
1330 {
1331     return guid != NULL ? &guid->guid : NULL;
1332 }
1333 
1334 static inline const GUID *TLB_get_guid_null(const TLBGuid *guid)
1335 {
1336     return guid != NULL ? &guid->guid : &GUID_NULL;
1337 }
1338 
1339 static int get_ptr_size(SYSKIND syskind)
1340 {
1341     switch(syskind){
1342     case SYS_WIN64:
1343         return 8;
1344     case SYS_WIN32:
1345     case SYS_MAC:
1346     case SYS_WIN16:
1347         return 4;
1348     }
1349     WARN("Unhandled syskind: 0x%x\n", syskind);
1350     return 4;
1351 }
1352 
1353 /*
1354  debug
1355 */
1356 static void dump_TypeDesc(const TYPEDESC *pTD,char *szVarType) {
1357     if (pTD->vt & VT_RESERVED)
1358 	szVarType += strlen(strcpy(szVarType, "reserved | "));
1359     if (pTD->vt & VT_BYREF)
1360 	szVarType += strlen(strcpy(szVarType, "ref to "));
1361     if (pTD->vt & VT_ARRAY)
1362 	szVarType += strlen(strcpy(szVarType, "array of "));
1363     if (pTD->vt & VT_VECTOR)
1364 	szVarType += strlen(strcpy(szVarType, "vector of "));
1365     switch(pTD->vt & VT_TYPEMASK) {
1366     case VT_UI1: sprintf(szVarType, "VT_UI1"); break;
1367     case VT_I2: sprintf(szVarType, "VT_I2"); break;
1368     case VT_I4: sprintf(szVarType, "VT_I4"); break;
1369     case VT_R4: sprintf(szVarType, "VT_R4"); break;
1370     case VT_R8: sprintf(szVarType, "VT_R8"); break;
1371     case VT_BOOL: sprintf(szVarType, "VT_BOOL"); break;
1372     case VT_ERROR: sprintf(szVarType, "VT_ERROR"); break;
1373     case VT_CY: sprintf(szVarType, "VT_CY"); break;
1374     case VT_DATE: sprintf(szVarType, "VT_DATE"); break;
1375     case VT_BSTR: sprintf(szVarType, "VT_BSTR"); break;
1376     case VT_UNKNOWN: sprintf(szVarType, "VT_UNKNOWN"); break;
1377     case VT_DISPATCH: sprintf(szVarType, "VT_DISPATCH"); break;
1378     case VT_I1: sprintf(szVarType, "VT_I1"); break;
1379     case VT_UI2: sprintf(szVarType, "VT_UI2"); break;
1380     case VT_UI4: sprintf(szVarType, "VT_UI4"); break;
1381     case VT_INT: sprintf(szVarType, "VT_INT"); break;
1382     case VT_UINT: sprintf(szVarType, "VT_UINT"); break;
1383     case VT_VARIANT: sprintf(szVarType, "VT_VARIANT"); break;
1384     case VT_VOID: sprintf(szVarType, "VT_VOID"); break;
1385     case VT_HRESULT: sprintf(szVarType, "VT_HRESULT"); break;
1386     case VT_USERDEFINED: sprintf(szVarType, "VT_USERDEFINED ref = %x",
1387 				 pTD->u.hreftype); break;
1388     case VT_LPSTR: sprintf(szVarType, "VT_LPSTR"); break;
1389     case VT_LPWSTR: sprintf(szVarType, "VT_LPWSTR"); break;
1390     case VT_PTR: sprintf(szVarType, "ptr to ");
1391       dump_TypeDesc(pTD->u.lptdesc, szVarType + 7);
1392       break;
1393     case VT_SAFEARRAY: sprintf(szVarType, "safearray of ");
1394       dump_TypeDesc(pTD->u.lptdesc, szVarType + 13);
1395       break;
1396     case VT_CARRAY: sprintf(szVarType, "%d dim array of ",
1397 			    pTD->u.lpadesc->cDims); /* FIXME print out sizes */
1398       dump_TypeDesc(&pTD->u.lpadesc->tdescElem, szVarType + strlen(szVarType));
1399       break;
1400 
1401     default: sprintf(szVarType, "unknown(%d)", pTD->vt & VT_TYPEMASK); break;
1402     }
1403 }
1404 
1405 static void dump_ELEMDESC(const ELEMDESC *edesc) {
1406   char buf[200];
1407   USHORT flags = edesc->u.paramdesc.wParamFlags;
1408   dump_TypeDesc(&edesc->tdesc,buf);
1409   MESSAGE("\t\ttdesc.vartype %d (%s)\n",edesc->tdesc.vt,buf);
1410   MESSAGE("\t\tu.paramdesc.wParamFlags");
1411   if (!flags) MESSAGE(" PARAMFLAGS_NONE");
1412   if (flags & PARAMFLAG_FIN) MESSAGE(" PARAMFLAG_FIN");
1413   if (flags & PARAMFLAG_FOUT) MESSAGE(" PARAMFLAG_FOUT");
1414   if (flags & PARAMFLAG_FLCID) MESSAGE(" PARAMFLAG_FLCID");
1415   if (flags & PARAMFLAG_FRETVAL) MESSAGE(" PARAMFLAG_FRETVAL");
1416   if (flags & PARAMFLAG_FOPT) MESSAGE(" PARAMFLAG_FOPT");
1417   if (flags & PARAMFLAG_FHASDEFAULT) MESSAGE(" PARAMFLAG_FHASDEFAULT");
1418   if (flags & PARAMFLAG_FHASCUSTDATA) MESSAGE(" PARAMFLAG_FHASCUSTDATA");
1419   MESSAGE("\n\t\tu.paramdesc.lpex %p\n",edesc->u.paramdesc.pparamdescex);
1420 }
1421 static void dump_FUNCDESC(const FUNCDESC *funcdesc) {
1422   int i;
1423   MESSAGE("memid is %08x\n",funcdesc->memid);
1424   for (i=0;i<funcdesc->cParams;i++) {
1425       MESSAGE("Param %d:\n",i);
1426       dump_ELEMDESC(funcdesc->lprgelemdescParam+i);
1427   }
1428   MESSAGE("\tfunckind: %d (",funcdesc->funckind);
1429   switch (funcdesc->funckind) {
1430   case FUNC_VIRTUAL: MESSAGE("virtual");break;
1431   case FUNC_PUREVIRTUAL: MESSAGE("pure virtual");break;
1432   case FUNC_NONVIRTUAL: MESSAGE("nonvirtual");break;
1433   case FUNC_STATIC: MESSAGE("static");break;
1434   case FUNC_DISPATCH: MESSAGE("dispatch");break;
1435   default: MESSAGE("unknown");break;
1436   }
1437   MESSAGE(")\n\tinvkind: %d (",funcdesc->invkind);
1438   switch (funcdesc->invkind) {
1439   case INVOKE_FUNC: MESSAGE("func");break;
1440   case INVOKE_PROPERTYGET: MESSAGE("property get");break;
1441   case INVOKE_PROPERTYPUT: MESSAGE("property put");break;
1442   case INVOKE_PROPERTYPUTREF: MESSAGE("property put ref");break;
1443   }
1444   MESSAGE(")\n\tcallconv: %d (",funcdesc->callconv);
1445   switch (funcdesc->callconv) {
1446   case CC_CDECL: MESSAGE("cdecl");break;
1447   case CC_PASCAL: MESSAGE("pascal");break;
1448   case CC_STDCALL: MESSAGE("stdcall");break;
1449   case CC_SYSCALL: MESSAGE("syscall");break;
1450   default:break;
1451   }
1452   MESSAGE(")\n\toVft: %d\n", funcdesc->oVft);
1453   MESSAGE("\tcParamsOpt: %d\n", funcdesc->cParamsOpt);
1454   MESSAGE("\twFlags: %x\n", funcdesc->wFuncFlags);
1455 
1456   MESSAGE("\telemdescFunc (return value type):\n");
1457   dump_ELEMDESC(&funcdesc->elemdescFunc);
1458 }
1459 
1460 static const char * const typekind_desc[] =
1461 {
1462 	"TKIND_ENUM",
1463 	"TKIND_RECORD",
1464 	"TKIND_MODULE",
1465 	"TKIND_INTERFACE",
1466 	"TKIND_DISPATCH",
1467 	"TKIND_COCLASS",
1468 	"TKIND_ALIAS",
1469 	"TKIND_UNION",
1470 	"TKIND_MAX"
1471 };
1472 
1473 static void dump_TLBFuncDescOne(const TLBFuncDesc * pfd)
1474 {
1475   int i;
1476   MESSAGE("%s(%u)\n", debugstr_w(TLB_get_bstr(pfd->Name)), pfd->funcdesc.cParams);
1477   for (i=0;i<pfd->funcdesc.cParams;i++)
1478       MESSAGE("\tparm%d: %s\n",i,debugstr_w(TLB_get_bstr(pfd->pParamDesc[i].Name)));
1479 
1480 
1481   dump_FUNCDESC(&(pfd->funcdesc));
1482 
1483   MESSAGE("\thelpstring: %s\n", debugstr_w(TLB_get_bstr(pfd->HelpString)));
1484   if(pfd->Entry == NULL)
1485       MESSAGE("\tentry: (null)\n");
1486   else if(pfd->Entry == (void*)-1)
1487       MESSAGE("\tentry: invalid\n");
1488   else if(IS_INTRESOURCE(pfd->Entry))
1489       MESSAGE("\tentry: %p\n", pfd->Entry);
1490   else
1491       MESSAGE("\tentry: %s\n", debugstr_w(TLB_get_bstr(pfd->Entry)));
1492 }
1493 static void dump_TLBFuncDesc(const TLBFuncDesc * pfd, UINT n)
1494 {
1495 	while (n)
1496 	{
1497 	  dump_TLBFuncDescOne(pfd);
1498 	  ++pfd;
1499 	  --n;
1500 	}
1501 }
1502 static void dump_TLBVarDesc(const TLBVarDesc * pvd, UINT n)
1503 {
1504 	while (n)
1505 	{
1506 	  TRACE_(typelib)("%s\n", debugstr_w(TLB_get_bstr(pvd->Name)));
1507 	  ++pvd;
1508 	  --n;
1509 	}
1510 }
1511 
1512 static void dump_TLBImpLib(const TLBImpLib *import)
1513 {
1514     TRACE_(typelib)("%s %s\n", debugstr_guid(TLB_get_guidref(import->guid)),
1515 		    debugstr_w(import->name));
1516     TRACE_(typelib)("v%d.%d lcid=%x offset=%x\n", import->wVersionMajor,
1517 		    import->wVersionMinor, import->lcid, import->offset);
1518 }
1519 
1520 static void dump_TLBRefType(const ITypeLibImpl *pTL)
1521 {
1522     TLBRefType *ref;
1523 
1524     LIST_FOR_EACH_ENTRY(ref, &pTL->ref_list, TLBRefType, entry)
1525     {
1526         TRACE_(typelib)("href:0x%08x\n", ref->reference);
1527         if(ref->index == -1)
1528 	    TRACE_(typelib)("%s\n", debugstr_guid(TLB_get_guidref(ref->guid)));
1529         else
1530 	    TRACE_(typelib)("type no: %d\n", ref->index);
1531 
1532         if(ref->pImpTLInfo != TLB_REF_INTERNAL && ref->pImpTLInfo != TLB_REF_NOT_FOUND)
1533         {
1534             TRACE_(typelib)("in lib\n");
1535             dump_TLBImpLib(ref->pImpTLInfo);
1536         }
1537     }
1538 }
1539 
1540 static void dump_TLBImplType(const TLBImplType * impl, UINT n)
1541 {
1542     if(!impl)
1543         return;
1544     while (n) {
1545         TRACE_(typelib)("implementing/inheriting interface hRef = %x implflags %x\n",
1546             impl->hRef, impl->implflags);
1547         ++impl;
1548         --n;
1549     }
1550 }
1551 
1552 static void dump_DispParms(const DISPPARAMS * pdp)
1553 {
1554     unsigned int index;
1555 
1556     TRACE("args=%u named args=%u\n", pdp->cArgs, pdp->cNamedArgs);
1557 
1558     if (pdp->cNamedArgs && pdp->rgdispidNamedArgs)
1559     {
1560         TRACE("named args:\n");
1561         for (index = 0; index < pdp->cNamedArgs; index++)
1562             TRACE( "\t0x%x\n", pdp->rgdispidNamedArgs[index] );
1563     }
1564 
1565     if (pdp->cArgs && pdp->rgvarg)
1566     {
1567         TRACE("args:\n");
1568         for (index = 0; index < pdp->cArgs; index++)
1569             TRACE("  [%d] %s\n", index, debugstr_variant(pdp->rgvarg+index));
1570     }
1571 }
1572 
1573 static void dump_TypeInfo(const ITypeInfoImpl * pty)
1574 {
1575     TRACE("%p ref=%u\n", pty, pty->ref);
1576     TRACE("%s %s\n", debugstr_w(TLB_get_bstr(pty->Name)), debugstr_w(TLB_get_bstr(pty->DocString)));
1577     TRACE("attr:%s\n", debugstr_guid(TLB_get_guidref(pty->guid)));
1578     TRACE("kind:%s\n", typekind_desc[pty->typeattr.typekind]);
1579     TRACE("fct:%u var:%u impl:%u\n", pty->typeattr.cFuncs, pty->typeattr.cVars, pty->typeattr.cImplTypes);
1580     TRACE("wTypeFlags: 0x%04x\n", pty->typeattr.wTypeFlags);
1581     TRACE("parent tlb:%p index in TLB:%u\n",pty->pTypeLib, pty->index);
1582     if (pty->typeattr.typekind == TKIND_MODULE) TRACE("dllname:%s\n", debugstr_w(TLB_get_bstr(pty->DllName)));
1583     if (TRACE_ON(ole))
1584         dump_TLBFuncDesc(pty->funcdescs, pty->typeattr.cFuncs);
1585     dump_TLBVarDesc(pty->vardescs, pty->typeattr.cVars);
1586     dump_TLBImplType(pty->impltypes, pty->typeattr.cImplTypes);
1587 }
1588 
1589 static void dump_VARDESC(const VARDESC *v)
1590 {
1591     MESSAGE("memid %d\n",v->memid);
1592     MESSAGE("lpstrSchema %s\n",debugstr_w(v->lpstrSchema));
1593     MESSAGE("oInst %d\n",v->u.oInst);
1594     dump_ELEMDESC(&(v->elemdescVar));
1595     MESSAGE("wVarFlags %x\n",v->wVarFlags);
1596     MESSAGE("varkind %d\n",v->varkind);
1597 }
1598 
1599 static TYPEDESC std_typedesc[VT_LPWSTR+1] =
1600 {
1601     /* VT_LPWSTR is largest type that, may appear in type description */
1602     {{0}, VT_EMPTY},  {{0}, VT_NULL},        {{0}, VT_I2},      {{0}, VT_I4},
1603     {{0}, VT_R4},     {{0}, VT_R8},          {{0}, VT_CY},      {{0}, VT_DATE},
1604     {{0}, VT_BSTR},   {{0}, VT_DISPATCH},    {{0}, VT_ERROR},   {{0}, VT_BOOL},
1605     {{0}, VT_VARIANT},{{0}, VT_UNKNOWN},     {{0}, VT_DECIMAL}, {{0}, 15}, /* unused in VARENUM */
1606     {{0}, VT_I1},     {{0}, VT_UI1},         {{0}, VT_UI2},     {{0}, VT_UI4},
1607     {{0}, VT_I8},     {{0}, VT_UI8},         {{0}, VT_INT},     {{0}, VT_UINT},
1608     {{0}, VT_VOID},   {{0}, VT_HRESULT},     {{0}, VT_PTR},     {{0}, VT_SAFEARRAY},
1609     {{0}, VT_CARRAY}, {{0}, VT_USERDEFINED}, {{0}, VT_LPSTR},   {{0}, VT_LPWSTR}
1610 };
1611 
1612 static void TLB_abort(void)
1613 {
1614     DebugBreak();
1615 }
1616 
1617 /* returns the size required for a deep copy of a typedesc into a
1618  * flat buffer */
1619 static SIZE_T TLB_SizeTypeDesc( const TYPEDESC *tdesc, BOOL alloc_initial_space )
1620 {
1621     SIZE_T size = 0;
1622 
1623     if (alloc_initial_space)
1624         size += sizeof(TYPEDESC);
1625 
1626     switch (tdesc->vt)
1627     {
1628     case VT_PTR:
1629     case VT_SAFEARRAY:
1630         size += TLB_SizeTypeDesc(tdesc->u.lptdesc, TRUE);
1631         break;
1632     case VT_CARRAY:
1633         size += FIELD_OFFSET(ARRAYDESC, rgbounds[tdesc->u.lpadesc->cDims]);
1634         size += TLB_SizeTypeDesc(&tdesc->u.lpadesc->tdescElem, FALSE);
1635         break;
1636     }
1637     return size;
1638 }
1639 
1640 /* deep copy a typedesc into a flat buffer */
1641 static void *TLB_CopyTypeDesc( TYPEDESC *dest, const TYPEDESC *src, void *buffer )
1642 {
1643     if (!dest)
1644     {
1645         dest = buffer;
1646         buffer = (char *)buffer + sizeof(TYPEDESC);
1647     }
1648 
1649     *dest = *src;
1650 
1651     switch (src->vt)
1652     {
1653     case VT_PTR:
1654     case VT_SAFEARRAY:
1655         dest->u.lptdesc = buffer;
1656         buffer = TLB_CopyTypeDesc(NULL, src->u.lptdesc, buffer);
1657         break;
1658     case VT_CARRAY:
1659         dest->u.lpadesc = buffer;
1660         memcpy(dest->u.lpadesc, src->u.lpadesc, FIELD_OFFSET(ARRAYDESC, rgbounds[src->u.lpadesc->cDims]));
1661         buffer = (char *)buffer + FIELD_OFFSET(ARRAYDESC, rgbounds[src->u.lpadesc->cDims]);
1662         buffer = TLB_CopyTypeDesc(&dest->u.lpadesc->tdescElem, &src->u.lpadesc->tdescElem, buffer);
1663         break;
1664     }
1665     return buffer;
1666 }
1667 
1668 /* free custom data allocated by MSFT_CustData */
1669 static inline void TLB_FreeCustData(struct list *custdata_list)
1670 {
1671     TLBCustData *cd, *cdn;
1672     LIST_FOR_EACH_ENTRY_SAFE(cd, cdn, custdata_list, TLBCustData, entry)
1673     {
1674         list_remove(&cd->entry);
1675         VariantClear(&cd->data);
1676         heap_free(cd);
1677     }
1678 }
1679 
1680 static BSTR TLB_MultiByteToBSTR(const char *ptr)
1681 {
1682     DWORD len;
1683     BSTR ret;
1684 
1685     len = MultiByteToWideChar(CP_ACP, 0, ptr, -1, NULL, 0);
1686     ret = SysAllocStringLen(NULL, len - 1);
1687     if (!ret) return ret;
1688     MultiByteToWideChar(CP_ACP, 0, ptr, -1, ret, len);
1689     return ret;
1690 }
1691 
1692 static inline TLBFuncDesc *TLB_get_funcdesc_by_memberid(TLBFuncDesc *funcdescs,
1693         UINT n, MEMBERID memid)
1694 {
1695     while(n){
1696         if(funcdescs->funcdesc.memid == memid)
1697             return funcdescs;
1698         ++funcdescs;
1699         --n;
1700     }
1701     return NULL;
1702 }
1703 
1704 static inline TLBVarDesc *TLB_get_vardesc_by_memberid(TLBVarDesc *vardescs,
1705         UINT n, MEMBERID memid)
1706 {
1707     while(n){
1708         if(vardescs->vardesc.memid == memid)
1709             return vardescs;
1710         ++vardescs;
1711         --n;
1712     }
1713     return NULL;
1714 }
1715 
1716 static inline TLBVarDesc *TLB_get_vardesc_by_name(TLBVarDesc *vardescs,
1717         UINT n, const OLECHAR *name)
1718 {
1719     while(n){
1720         if(!lstrcmpiW(TLB_get_bstr(vardescs->Name), name))
1721             return vardescs;
1722         ++vardescs;
1723         --n;
1724     }
1725     return NULL;
1726 }
1727 
1728 static inline TLBCustData *TLB_get_custdata_by_guid(struct list *custdata_list, REFGUID guid)
1729 {
1730     TLBCustData *cust_data;
1731     LIST_FOR_EACH_ENTRY(cust_data, custdata_list, TLBCustData, entry)
1732         if(IsEqualIID(TLB_get_guid_null(cust_data->guid), guid))
1733             return cust_data;
1734     return NULL;
1735 }
1736 
1737 static inline ITypeInfoImpl *TLB_get_typeinfo_by_name(ITypeInfoImpl **typeinfos,
1738         UINT n, const OLECHAR *name)
1739 {
1740     while(n){
1741         if(!lstrcmpiW(TLB_get_bstr((*typeinfos)->Name), name))
1742             return *typeinfos;
1743         ++typeinfos;
1744         --n;
1745     }
1746     return NULL;
1747 }
1748 
1749 static void TLBVarDesc_Constructor(TLBVarDesc *var_desc)
1750 {
1751     list_init(&var_desc->custdata_list);
1752 }
1753 
1754 static TLBVarDesc *TLBVarDesc_Alloc(UINT n)
1755 {
1756     TLBVarDesc *ret;
1757 
1758     ret = heap_alloc_zero(sizeof(TLBVarDesc) * n);
1759     if(!ret)
1760         return NULL;
1761 
1762     while(n){
1763         TLBVarDesc_Constructor(&ret[n-1]);
1764         --n;
1765     }
1766 
1767     return ret;
1768 }
1769 
1770 static TLBParDesc *TLBParDesc_Constructor(UINT n)
1771 {
1772     TLBParDesc *ret;
1773 
1774     ret = heap_alloc_zero(sizeof(TLBParDesc) * n);
1775     if(!ret)
1776         return NULL;
1777 
1778     while(n){
1779         list_init(&ret[n-1].custdata_list);
1780         --n;
1781     }
1782 
1783     return ret;
1784 }
1785 
1786 static void TLBFuncDesc_Constructor(TLBFuncDesc *func_desc)
1787 {
1788     list_init(&func_desc->custdata_list);
1789 }
1790 
1791 static TLBFuncDesc *TLBFuncDesc_Alloc(UINT n)
1792 {
1793     TLBFuncDesc *ret;
1794 
1795     ret = heap_alloc_zero(sizeof(TLBFuncDesc) * n);
1796     if(!ret)
1797         return NULL;
1798 
1799     while(n){
1800         TLBFuncDesc_Constructor(&ret[n-1]);
1801         --n;
1802     }
1803 
1804     return ret;
1805 }
1806 
1807 static void TLBImplType_Constructor(TLBImplType *impl)
1808 {
1809     list_init(&impl->custdata_list);
1810 }
1811 
1812 static TLBImplType *TLBImplType_Alloc(UINT n)
1813 {
1814     TLBImplType *ret;
1815 
1816     ret = heap_alloc_zero(sizeof(TLBImplType) * n);
1817     if(!ret)
1818         return NULL;
1819 
1820     while(n){
1821         TLBImplType_Constructor(&ret[n-1]);
1822         --n;
1823     }
1824 
1825     return ret;
1826 }
1827 
1828 static TLBGuid *TLB_append_guid(struct list *guid_list,
1829         const GUID *new_guid, HREFTYPE hreftype)
1830 {
1831     TLBGuid *guid;
1832 
1833     LIST_FOR_EACH_ENTRY(guid, guid_list, TLBGuid, entry) {
1834         if (IsEqualGUID(&guid->guid, new_guid))
1835             return guid;
1836     }
1837 
1838     guid = heap_alloc(sizeof(TLBGuid));
1839     if (!guid)
1840         return NULL;
1841 
1842     memcpy(&guid->guid, new_guid, sizeof(GUID));
1843     guid->hreftype = hreftype;
1844 
1845     list_add_tail(guid_list, &guid->entry);
1846 
1847     return guid;
1848 }
1849 
1850 static HRESULT TLB_set_custdata(struct list *custdata_list, TLBGuid *tlbguid, VARIANT *var)
1851 {
1852     TLBCustData *cust_data;
1853 
1854     switch(V_VT(var)){
1855     case VT_I4:
1856     case VT_R4:
1857     case VT_UI4:
1858     case VT_INT:
1859     case VT_UINT:
1860     case VT_HRESULT:
1861     case VT_BSTR:
1862         break;
1863     default:
1864         return DISP_E_BADVARTYPE;
1865     }
1866 
1867     cust_data = TLB_get_custdata_by_guid(custdata_list, TLB_get_guid_null(tlbguid));
1868 
1869     if (!cust_data) {
1870         cust_data = heap_alloc(sizeof(TLBCustData));
1871         if (!cust_data)
1872             return E_OUTOFMEMORY;
1873 
1874         cust_data->guid = tlbguid;
1875         VariantInit(&cust_data->data);
1876 
1877         list_add_tail(custdata_list, &cust_data->entry);
1878     }else
1879         VariantClear(&cust_data->data);
1880 
1881     return VariantCopy(&cust_data->data, var);
1882 }
1883 
1884 static TLBString *TLB_append_str(struct list *string_list, BSTR new_str)
1885 {
1886     TLBString *str;
1887 
1888     if(!new_str)
1889         return NULL;
1890 
1891     LIST_FOR_EACH_ENTRY(str, string_list, TLBString, entry) {
1892         if (wcscmp(str->str, new_str) == 0)
1893             return str;
1894     }
1895 
1896     str = heap_alloc(sizeof(TLBString));
1897     if (!str)
1898         return NULL;
1899 
1900     str->str = SysAllocString(new_str);
1901     if (!str->str) {
1902         heap_free(str);
1903         return NULL;
1904     }
1905 
1906     list_add_tail(string_list, &str->entry);
1907 
1908     return str;
1909 }
1910 
1911 static HRESULT TLB_get_size_from_hreftype(ITypeInfoImpl *info, HREFTYPE href,
1912         ULONG *size, WORD *align)
1913 {
1914     ITypeInfo *other;
1915     TYPEATTR *attr;
1916     HRESULT hr;
1917 
1918     hr = ITypeInfo2_GetRefTypeInfo(&info->ITypeInfo2_iface, href, &other);
1919     if(FAILED(hr))
1920         return hr;
1921 
1922     hr = ITypeInfo_GetTypeAttr(other, &attr);
1923     if(FAILED(hr)){
1924         ITypeInfo_Release(other);
1925         return hr;
1926     }
1927 
1928     if(size)
1929         *size = attr->cbSizeInstance;
1930     if(align)
1931         *align = attr->cbAlignment;
1932 
1933     ITypeInfo_ReleaseTypeAttr(other, attr);
1934     ITypeInfo_Release(other);
1935 
1936     return S_OK;
1937 }
1938 
1939 static HRESULT TLB_size_instance(ITypeInfoImpl *info, SYSKIND sys,
1940         TYPEDESC *tdesc, ULONG *size, WORD *align)
1941 {
1942     ULONG i, sub, ptr_size;
1943     HRESULT hr;
1944 
1945     ptr_size = get_ptr_size(sys);
1946 
1947     switch(tdesc->vt){
1948     case VT_VOID:
1949         *size = 0;
1950         break;
1951     case VT_I1:
1952     case VT_UI1:
1953         *size = 1;
1954         break;
1955     case VT_I2:
1956     case VT_BOOL:
1957     case VT_UI2:
1958         *size = 2;
1959         break;
1960     case VT_I4:
1961     case VT_R4:
1962     case VT_ERROR:
1963     case VT_UI4:
1964     case VT_INT:
1965     case VT_UINT:
1966     case VT_HRESULT:
1967         *size = 4;
1968         break;
1969     case VT_R8:
1970     case VT_I8:
1971     case VT_UI8:
1972         *size = 8;
1973         break;
1974     case VT_BSTR:
1975     case VT_DISPATCH:
1976     case VT_UNKNOWN:
1977     case VT_PTR:
1978     case VT_SAFEARRAY:
1979     case VT_LPSTR:
1980     case VT_LPWSTR:
1981         *size = ptr_size;
1982         break;
1983     case VT_DATE:
1984         *size = sizeof(DATE);
1985         break;
1986     case VT_VARIANT:
1987         *size = sizeof(VARIANT);
1988 #ifdef _WIN64
1989         if(sys == SYS_WIN32)
1990             *size -= 8; /* 32-bit VARIANT is 8 bytes smaller than 64-bit VARIANT */
1991 #endif
1992         break;
1993     case VT_DECIMAL:
1994         *size = sizeof(DECIMAL);
1995         break;
1996     case VT_CY:
1997         *size = sizeof(CY);
1998         break;
1999     case VT_CARRAY:
2000         *size = 0;
2001         for(i = 0; i < tdesc->u.lpadesc->cDims; ++i)
2002             *size += tdesc->u.lpadesc->rgbounds[i].cElements;
2003         hr = TLB_size_instance(info, sys, &tdesc->u.lpadesc->tdescElem, &sub, align);
2004         if(FAILED(hr))
2005             return hr;
2006         *size *= sub;
2007         return S_OK;
2008     case VT_USERDEFINED:
2009         return TLB_get_size_from_hreftype(info, tdesc->u.hreftype, size, align);
2010     default:
2011         FIXME("Unsized VT: 0x%x\n", tdesc->vt);
2012         return E_FAIL;
2013     }
2014 
2015     if(align){
2016         if(*size < 4)
2017             *align = *size;
2018         else
2019             *align = 4;
2020     }
2021 
2022     return S_OK;
2023 }
2024 
2025 /**********************************************************************
2026  *
2027  *  Functions for reading MSFT typelibs (those created by CreateTypeLib2)
2028  */
2029 
2030 static inline void MSFT_Seek(TLBContext *pcx, LONG where)
2031 {
2032     if (where != DO_NOT_SEEK)
2033     {
2034         where += pcx->oStart;
2035         if (where > pcx->length)
2036         {
2037             /* FIXME */
2038             ERR("seek beyond end (%d/%d)\n", where, pcx->length );
2039             TLB_abort();
2040         }
2041         pcx->pos = where;
2042     }
2043 }
2044 
2045 /* read function */
2046 static DWORD MSFT_Read(void *buffer,  DWORD count, TLBContext *pcx, LONG where )
2047 {
2048     TRACE_(typelib)("pos=0x%08x len=0x%08x 0x%08x 0x%08x 0x%08x\n",
2049        pcx->pos, count, pcx->oStart, pcx->length, where);
2050 
2051     MSFT_Seek(pcx, where);
2052     if (pcx->pos + count > pcx->length) count = pcx->length - pcx->pos;
2053     memcpy( buffer, (char *)pcx->mapping + pcx->pos, count );
2054     pcx->pos += count;
2055     return count;
2056 }
2057 
2058 static DWORD MSFT_ReadLEDWords(void *buffer,  DWORD count, TLBContext *pcx,
2059                                LONG where )
2060 {
2061   DWORD ret;
2062 
2063   ret = MSFT_Read(buffer, count, pcx, where);
2064   FromLEDWords(buffer, ret);
2065 
2066   return ret;
2067 }
2068 
2069 static DWORD MSFT_ReadLEWords(void *buffer,  DWORD count, TLBContext *pcx,
2070                               LONG where )
2071 {
2072   DWORD ret;
2073 
2074   ret = MSFT_Read(buffer, count, pcx, where);
2075   FromLEWords(buffer, ret);
2076 
2077   return ret;
2078 }
2079 
2080 static HRESULT MSFT_ReadAllGuids(TLBContext *pcx)
2081 {
2082     TLBGuid *guid;
2083     MSFT_GuidEntry entry;
2084     int offs = 0;
2085 
2086     MSFT_Seek(pcx, pcx->pTblDir->pGuidTab.offset);
2087     while (1) {
2088         if (offs >= pcx->pTblDir->pGuidTab.length)
2089             return S_OK;
2090 
2091         MSFT_ReadLEWords(&entry, sizeof(MSFT_GuidEntry), pcx, DO_NOT_SEEK);
2092 
2093         guid = heap_alloc(sizeof(TLBGuid));
2094 
2095         guid->offset = offs;
2096         guid->guid = entry.guid;
2097         guid->hreftype = entry.hreftype;
2098 
2099         list_add_tail(&pcx->pLibInfo->guid_list, &guid->entry);
2100 
2101         offs += sizeof(MSFT_GuidEntry);
2102     }
2103 }
2104 
2105 static TLBGuid *MSFT_ReadGuid( int offset, TLBContext *pcx)
2106 {
2107     TLBGuid *ret;
2108 
2109     LIST_FOR_EACH_ENTRY(ret, &pcx->pLibInfo->guid_list, TLBGuid, entry){
2110         if(ret->offset == offset){
2111             TRACE_(typelib)("%s\n", debugstr_guid(&ret->guid));
2112             return ret;
2113         }
2114     }
2115 
2116     return NULL;
2117 }
2118 
2119 static HREFTYPE MSFT_ReadHreftype( TLBContext *pcx, int offset )
2120 {
2121     MSFT_NameIntro niName;
2122 
2123     if (offset < 0)
2124     {
2125         ERR_(typelib)("bad offset %d\n", offset);
2126         return -1;
2127     }
2128 
2129     MSFT_ReadLEDWords(&niName, sizeof(niName), pcx,
2130 		      pcx->pTblDir->pNametab.offset+offset);
2131 
2132     return niName.hreftype;
2133 }
2134 
2135 static HRESULT MSFT_ReadAllNames(TLBContext *pcx)
2136 {
2137     char *string;
2138     MSFT_NameIntro intro;
2139     INT16 len_piece;
2140     int offs = 0, lengthInChars;
2141 
2142     MSFT_Seek(pcx, pcx->pTblDir->pNametab.offset);
2143     while (1) {
2144         TLBString *tlbstr;
2145 
2146         if (offs >= pcx->pTblDir->pNametab.length)
2147             return S_OK;
2148 
2149         MSFT_ReadLEWords(&intro, sizeof(MSFT_NameIntro), pcx, DO_NOT_SEEK);
2150         intro.namelen &= 0xFF;
2151         len_piece = intro.namelen + sizeof(MSFT_NameIntro);
2152         if(len_piece % 4)
2153             len_piece = (len_piece + 4) & ~0x3;
2154         if(len_piece < 8)
2155             len_piece = 8;
2156 
2157         string = heap_alloc(len_piece + 1);
2158         MSFT_Read(string, len_piece - sizeof(MSFT_NameIntro), pcx, DO_NOT_SEEK);
2159         string[intro.namelen] = '\0';
2160 
2161         lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
2162                                             string, -1, NULL, 0);
2163         if (!lengthInChars) {
2164             heap_free(string);
2165             return E_UNEXPECTED;
2166         }
2167 
2168         tlbstr = heap_alloc(sizeof(TLBString));
2169 
2170         tlbstr->offset = offs;
2171         tlbstr->str = SysAllocStringByteLen(NULL, lengthInChars * sizeof(WCHAR));
2172         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, string, -1, tlbstr->str, lengthInChars);
2173 
2174         heap_free(string);
2175 
2176         list_add_tail(&pcx->pLibInfo->name_list, &tlbstr->entry);
2177 
2178         offs += len_piece;
2179     }
2180 }
2181 
2182 static TLBString *MSFT_ReadName( TLBContext *pcx, int offset)
2183 {
2184     TLBString *tlbstr;
2185 
2186     LIST_FOR_EACH_ENTRY(tlbstr, &pcx->pLibInfo->name_list, TLBString, entry) {
2187         if (tlbstr->offset == offset) {
2188             TRACE_(typelib)("%s\n", debugstr_w(tlbstr->str));
2189             return tlbstr;
2190         }
2191     }
2192 
2193     return NULL;
2194 }
2195 
2196 static TLBString *MSFT_ReadString( TLBContext *pcx, int offset)
2197 {
2198     TLBString *tlbstr;
2199 
2200     LIST_FOR_EACH_ENTRY(tlbstr, &pcx->pLibInfo->string_list, TLBString, entry) {
2201         if (tlbstr->offset == offset) {
2202             TRACE_(typelib)("%s\n", debugstr_w(tlbstr->str));
2203             return tlbstr;
2204         }
2205     }
2206 
2207     return NULL;
2208 }
2209 
2210 /*
2211  * read a value and fill a VARIANT structure
2212  */
2213 static void MSFT_ReadValue( VARIANT * pVar, int offset, TLBContext *pcx )
2214 {
2215     int size;
2216 
2217     TRACE_(typelib)("\n");
2218 
2219     if(offset <0) { /* data are packed in here */
2220         V_VT(pVar) = (offset & 0x7c000000 )>> 26;
2221         V_I4(pVar) = offset & 0x3ffffff;
2222         return;
2223     }
2224     MSFT_ReadLEWords(&(V_VT(pVar)), sizeof(VARTYPE), pcx,
2225                      pcx->pTblDir->pCustData.offset + offset );
2226     TRACE_(typelib)("Vartype = %x\n", V_VT(pVar));
2227     switch (V_VT(pVar)){
2228         case VT_EMPTY:  /* FIXME: is this right? */
2229         case VT_NULL:   /* FIXME: is this right? */
2230         case VT_I2  :   /* this should not happen */
2231         case VT_I4  :
2232         case VT_R4  :
2233         case VT_ERROR   :
2234         case VT_BOOL    :
2235         case VT_I1  :
2236         case VT_UI1 :
2237         case VT_UI2 :
2238         case VT_UI4 :
2239         case VT_INT :
2240         case VT_UINT    :
2241         case VT_VOID    : /* FIXME: is this right? */
2242         case VT_HRESULT :
2243             size=4; break;
2244         case VT_R8  :
2245         case VT_CY  :
2246         case VT_DATE    :
2247         case VT_I8  :
2248         case VT_UI8 :
2249         case VT_DECIMAL :  /* FIXME: is this right? */
2250         case VT_FILETIME :
2251             size=8;break;
2252             /* pointer types with known behaviour */
2253         case VT_BSTR    :{
2254             char * ptr;
2255             MSFT_ReadLEDWords(&size, sizeof(INT), pcx, DO_NOT_SEEK );
2256             if(size == -1){
2257                 V_BSTR(pVar) = NULL;
2258             }else{
2259                 ptr = heap_alloc_zero(size);
2260                 MSFT_Read(ptr, size, pcx, DO_NOT_SEEK);
2261                 V_BSTR(pVar)=SysAllocStringLen(NULL,size);
2262                 /* FIXME: do we need a AtoW conversion here? */
2263                 V_UNION(pVar, bstrVal[size])='\0';
2264                 while(size--) V_UNION(pVar, bstrVal[size])=ptr[size];
2265                 heap_free(ptr);
2266             }
2267 	}
2268 	size=-4; break;
2269     /* FIXME: this will not work AT ALL when the variant contains a pointer */
2270         case VT_DISPATCH :
2271         case VT_VARIANT :
2272         case VT_UNKNOWN :
2273         case VT_PTR :
2274         case VT_SAFEARRAY :
2275         case VT_CARRAY  :
2276         case VT_USERDEFINED :
2277         case VT_LPSTR   :
2278         case VT_LPWSTR  :
2279         case VT_BLOB    :
2280         case VT_STREAM  :
2281         case VT_STORAGE :
2282         case VT_STREAMED_OBJECT :
2283         case VT_STORED_OBJECT   :
2284         case VT_BLOB_OBJECT :
2285         case VT_CF  :
2286         case VT_CLSID   :
2287         default:
2288             size=0;
2289             FIXME("VARTYPE %d is not supported, setting pointer to NULL\n",
2290                 V_VT(pVar));
2291     }
2292 
2293     if(size>0) /* (big|small) endian correct? */
2294         MSFT_Read(&(V_I2(pVar)), size, pcx, DO_NOT_SEEK );
2295     return;
2296 }
2297 /*
2298  * create a linked list with custom data
2299  */
2300 static int MSFT_CustData( TLBContext *pcx, int offset, struct list *custdata_list)
2301 {
2302     MSFT_CDGuid entry;
2303     TLBCustData* pNew;
2304     int count=0;
2305 
2306     TRACE_(typelib)("\n");
2307 
2308     if (pcx->pTblDir->pCDGuids.offset < 0) return 0;
2309 
2310     while(offset >=0){
2311         count++;
2312         pNew=heap_alloc_zero(sizeof(TLBCustData));
2313         MSFT_ReadLEDWords(&entry, sizeof(entry), pcx, pcx->pTblDir->pCDGuids.offset+offset);
2314         pNew->guid = MSFT_ReadGuid(entry.GuidOffset, pcx);
2315         MSFT_ReadValue(&(pNew->data), entry.DataOffset, pcx);
2316         list_add_head(custdata_list, &pNew->entry);
2317         offset = entry.next;
2318     }
2319     return count;
2320 }
2321 
2322 static void MSFT_GetTdesc(TLBContext *pcx, INT type, TYPEDESC *pTd)
2323 {
2324     if(type <0)
2325         pTd->vt=type & VT_TYPEMASK;
2326     else
2327         *pTd=pcx->pLibInfo->pTypeDesc[type/(2*sizeof(INT))];
2328 
2329     TRACE_(typelib)("vt type = %X\n", pTd->vt);
2330 }
2331 
2332 static BOOL TLB_is_propgetput(INVOKEKIND invkind)
2333 {
2334     return (invkind == INVOKE_PROPERTYGET ||
2335         invkind == INVOKE_PROPERTYPUT ||
2336         invkind == INVOKE_PROPERTYPUTREF);
2337 }
2338 
2339 static void
2340 MSFT_DoFuncs(TLBContext*     pcx,
2341 	    ITypeInfoImpl*  pTI,
2342             int             cFuncs,
2343             int             cVars,
2344             int             offset,
2345             TLBFuncDesc**   pptfd)
2346 {
2347     /*
2348      * member information is stored in a data structure at offset
2349      * indicated by the memoffset field of the typeinfo structure
2350      * There are several distinctive parts.
2351      * The first part starts with a field that holds the total length
2352      * of this (first) part excluding this field. Then follow the records,
2353      * for each member there is one record.
2354      *
2355      * The first entry is always the length of the record (including this
2356      * length word).
2357      * The rest of the record depends on the type of the member. If there is
2358      * a field indicating the member type (function, variable, interface, etc)
2359      * I have not found it yet. At this time we depend on the information
2360      * in the type info and the usual order how things are stored.
2361      *
2362      * Second follows an array sized nrMEM*sizeof(INT) with a member id
2363      * for each member;
2364      *
2365      * Third is an equal sized array with file offsets to the name entry
2366      * of each member.
2367      *
2368      * The fourth and last (?) part is an array with offsets to the records
2369      * in the first part of this file segment.
2370      */
2371 
2372     int infolen, nameoffset, reclength, i;
2373     int recoffset = offset + sizeof(INT);
2374 
2375     char *recbuf = heap_alloc(0xffff);
2376     MSFT_FuncRecord *pFuncRec = (MSFT_FuncRecord*)recbuf;
2377     TLBFuncDesc *ptfd_prev = NULL, *ptfd;
2378 
2379     TRACE_(typelib)("\n");
2380 
2381     MSFT_ReadLEDWords(&infolen, sizeof(INT), pcx, offset);
2382 
2383     *pptfd = TLBFuncDesc_Alloc(cFuncs);
2384     ptfd = *pptfd;
2385     for ( i = 0; i < cFuncs ; i++ )
2386     {
2387         int optional;
2388 
2389         /* name, eventually add to a hash table */
2390         MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx,
2391                           offset + infolen + (cFuncs + cVars + i + 1) * sizeof(INT));
2392 
2393         /* read the function information record */
2394         MSFT_ReadLEDWords(&reclength, sizeof(pFuncRec->Info), pcx, recoffset);
2395 
2396         reclength &= 0xffff;
2397 
2398         MSFT_ReadLEDWords(&pFuncRec->DataType, reclength - FIELD_OFFSET(MSFT_FuncRecord, DataType), pcx, DO_NOT_SEEK);
2399 
2400         /* size without argument data */
2401         optional = reclength - pFuncRec->nrargs*sizeof(MSFT_ParameterInfo);
2402         if (pFuncRec->FKCCIC & 0x1000)
2403             optional -= pFuncRec->nrargs * sizeof(INT);
2404 
2405         if (optional > FIELD_OFFSET(MSFT_FuncRecord, HelpContext))
2406             ptfd->helpcontext = pFuncRec->HelpContext;
2407 
2408         if (optional > FIELD_OFFSET(MSFT_FuncRecord, oHelpString))
2409             ptfd->HelpString = MSFT_ReadString(pcx, pFuncRec->oHelpString);
2410 
2411         if (optional > FIELD_OFFSET(MSFT_FuncRecord, oEntry))
2412         {
2413             if (pFuncRec->FKCCIC & 0x2000 )
2414             {
2415                 if (!IS_INTRESOURCE(pFuncRec->oEntry))
2416                     ERR("ordinal 0x%08x invalid, IS_INTRESOURCE is false\n", pFuncRec->oEntry);
2417                 ptfd->Entry = (TLBString*)(DWORD_PTR)LOWORD(pFuncRec->oEntry);
2418             }
2419             else
2420                 ptfd->Entry = MSFT_ReadString(pcx, pFuncRec->oEntry);
2421         }
2422         else
2423             ptfd->Entry = (TLBString*)-1;
2424 
2425         if (optional > FIELD_OFFSET(MSFT_FuncRecord, HelpStringContext))
2426             ptfd->HelpStringContext = pFuncRec->HelpStringContext;
2427 
2428         if (optional > FIELD_OFFSET(MSFT_FuncRecord, oCustData) && pFuncRec->FKCCIC & 0x80)
2429             MSFT_CustData(pcx, pFuncRec->oCustData, &ptfd->custdata_list);
2430 
2431         /* fill the FuncDesc Structure */
2432         MSFT_ReadLEDWords( & ptfd->funcdesc.memid, sizeof(INT), pcx,
2433                            offset + infolen + ( i + 1) * sizeof(INT));
2434 
2435         ptfd->funcdesc.funckind   =  (pFuncRec->FKCCIC)      & 0x7;
2436         ptfd->funcdesc.invkind    =  (pFuncRec->FKCCIC) >> 3 & 0xF;
2437         ptfd->funcdesc.callconv   =  (pFuncRec->FKCCIC) >> 8 & 0xF;
2438         ptfd->funcdesc.cParams    =   pFuncRec->nrargs  ;
2439         ptfd->funcdesc.cParamsOpt =   pFuncRec->nroargs ;
2440         ptfd->funcdesc.oVft       =   (pFuncRec->VtableOffset & ~1) * sizeof(void *) / pTI->pTypeLib->ptr_size;
2441         ptfd->funcdesc.wFuncFlags =   LOWORD(pFuncRec->Flags) ;
2442 
2443         /* nameoffset is sometimes -1 on the second half of a propget/propput
2444          * pair of functions */
2445         if ((nameoffset == -1) && (i > 0) &&
2446                 TLB_is_propgetput(ptfd_prev->funcdesc.invkind) &&
2447                 TLB_is_propgetput(ptfd->funcdesc.invkind))
2448             ptfd->Name = ptfd_prev->Name;
2449         else
2450             ptfd->Name = MSFT_ReadName(pcx, nameoffset);
2451 
2452         MSFT_GetTdesc(pcx,
2453 		      pFuncRec->DataType,
2454 		      &ptfd->funcdesc.elemdescFunc.tdesc);
2455 
2456         /* do the parameters/arguments */
2457         if(pFuncRec->nrargs)
2458         {
2459             int j = 0;
2460             MSFT_ParameterInfo paraminfo;
2461 
2462             ptfd->funcdesc.lprgelemdescParam =
2463                 heap_alloc_zero(pFuncRec->nrargs * (sizeof(ELEMDESC) + sizeof(PARAMDESCEX)));
2464 
2465             ptfd->pParamDesc = TLBParDesc_Constructor(pFuncRec->nrargs);
2466 
2467             MSFT_ReadLEDWords(&paraminfo, sizeof(paraminfo), pcx,
2468                               recoffset + reclength - pFuncRec->nrargs * sizeof(MSFT_ParameterInfo));
2469 
2470             for ( j = 0 ; j < pFuncRec->nrargs ; j++ )
2471             {
2472                 ELEMDESC *elemdesc = &ptfd->funcdesc.lprgelemdescParam[j];
2473 
2474                 MSFT_GetTdesc(pcx,
2475 			      paraminfo.DataType,
2476 			      &elemdesc->tdesc);
2477 
2478                 elemdesc->u.paramdesc.wParamFlags = paraminfo.Flags;
2479 
2480                 /* name */
2481                 if (paraminfo.oName != -1)
2482                     ptfd->pParamDesc[j].Name =
2483                         MSFT_ReadName( pcx, paraminfo.oName );
2484                 TRACE_(typelib)("param[%d] = %s\n", j, debugstr_w(TLB_get_bstr(ptfd->pParamDesc[j].Name)));
2485 
2486                 /* default value */
2487                 if ( (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) &&
2488                      (pFuncRec->FKCCIC & 0x1000) )
2489                 {
2490                     INT* pInt = (INT *)((char *)pFuncRec +
2491                                    reclength -
2492                                    (pFuncRec->nrargs * 4) * sizeof(INT) );
2493 
2494                     PARAMDESC* pParamDesc = &elemdesc->u.paramdesc;
2495 
2496                     pParamDesc->pparamdescex = (PARAMDESCEX*)(ptfd->funcdesc.lprgelemdescParam+pFuncRec->nrargs)+j;
2497                     pParamDesc->pparamdescex->cBytes = sizeof(PARAMDESCEX);
2498 
2499 		    MSFT_ReadValue(&(pParamDesc->pparamdescex->varDefaultValue),
2500                         pInt[j], pcx);
2501                 }
2502                 else
2503                     elemdesc->u.paramdesc.pparamdescex = NULL;
2504 
2505                 /* custom info */
2506                 if (optional > (FIELD_OFFSET(MSFT_FuncRecord, oArgCustData) +
2507                                 j*sizeof(pFuncRec->oArgCustData[0])) &&
2508                     pFuncRec->FKCCIC & 0x80 )
2509                 {
2510                     MSFT_CustData(pcx,
2511 				  pFuncRec->oArgCustData[j],
2512 				  &ptfd->pParamDesc[j].custdata_list);
2513                 }
2514 
2515                 /* SEEK value = jump to offset,
2516                  * from there jump to the end of record,
2517                  * go back by (j-1) arguments
2518                  */
2519                 MSFT_ReadLEDWords( &paraminfo ,
2520 			   sizeof(MSFT_ParameterInfo), pcx,
2521 			   recoffset + reclength - ((pFuncRec->nrargs - j - 1)
2522 					       * sizeof(MSFT_ParameterInfo)));
2523             }
2524         }
2525 
2526         /* scode is not used: archaic win16 stuff FIXME: right? */
2527         ptfd->funcdesc.cScodes   = 0 ;
2528         ptfd->funcdesc.lprgscode = NULL ;
2529 
2530         ptfd_prev = ptfd;
2531         ++ptfd;
2532         recoffset += reclength;
2533     }
2534     heap_free(recbuf);
2535 }
2536 
2537 static void MSFT_DoVars(TLBContext *pcx, ITypeInfoImpl *pTI, int cFuncs,
2538 		       int cVars, int offset, TLBVarDesc ** pptvd)
2539 {
2540     int infolen, nameoffset, reclength;
2541     char recbuf[256];
2542     MSFT_VarRecord *pVarRec = (MSFT_VarRecord*)recbuf;
2543     TLBVarDesc *ptvd;
2544     int i;
2545     int recoffset;
2546 
2547     TRACE_(typelib)("\n");
2548 
2549     ptvd = *pptvd = TLBVarDesc_Alloc(cVars);
2550     MSFT_ReadLEDWords(&infolen,sizeof(INT), pcx, offset);
2551     MSFT_ReadLEDWords(&recoffset,sizeof(INT), pcx, offset + infolen +
2552                       ((cFuncs+cVars)*2+cFuncs + 1)*sizeof(INT));
2553     recoffset += offset+sizeof(INT);
2554     for(i=0;i<cVars;i++, ++ptvd){
2555     /* name, eventually add to a hash table */
2556         MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx,
2557                           offset + infolen + (2*cFuncs + cVars + i + 1) * sizeof(INT));
2558         ptvd->Name=MSFT_ReadName(pcx, nameoffset);
2559     /* read the variable information record */
2560         MSFT_ReadLEDWords(&reclength, sizeof(pVarRec->Info), pcx, recoffset);
2561         reclength &= 0xff;
2562         MSFT_ReadLEDWords(&pVarRec->DataType, reclength - FIELD_OFFSET(MSFT_VarRecord, DataType), pcx, DO_NOT_SEEK);
2563 
2564         /* optional data */
2565         if(reclength > FIELD_OFFSET(MSFT_VarRecord, HelpContext))
2566             ptvd->HelpContext = pVarRec->HelpContext;
2567 
2568         if(reclength > FIELD_OFFSET(MSFT_VarRecord, HelpString))
2569             ptvd->HelpString = MSFT_ReadString(pcx, pVarRec->HelpString);
2570 
2571         if(reclength > FIELD_OFFSET(MSFT_VarRecord, HelpStringContext))
2572             ptvd->HelpStringContext = pVarRec->HelpStringContext;
2573 
2574     /* fill the VarDesc Structure */
2575         MSFT_ReadLEDWords(&ptvd->vardesc.memid, sizeof(INT), pcx,
2576                           offset + infolen + (cFuncs + i + 1) * sizeof(INT));
2577         ptvd->vardesc.varkind = pVarRec->VarKind;
2578         ptvd->vardesc.wVarFlags = pVarRec->Flags;
2579         MSFT_GetTdesc(pcx, pVarRec->DataType,
2580             &ptvd->vardesc.elemdescVar.tdesc);
2581 /*   ptvd->vardesc.lpstrSchema; is reserved (SDK) FIXME?? */
2582         if(pVarRec->VarKind == VAR_CONST ){
2583             ptvd->vardesc.u.lpvarValue = heap_alloc_zero(sizeof(VARIANT));
2584             MSFT_ReadValue(ptvd->vardesc.u.lpvarValue,
2585                 pVarRec->OffsValue, pcx);
2586         } else
2587             ptvd->vardesc.u.oInst=pVarRec->OffsValue;
2588         recoffset += reclength;
2589     }
2590 }
2591 
2592 /* process Implemented Interfaces of a com class */
2593 static void MSFT_DoImplTypes(TLBContext *pcx, ITypeInfoImpl *pTI, int count,
2594 			    int offset)
2595 {
2596     int i;
2597     MSFT_RefRecord refrec;
2598     TLBImplType *pImpl;
2599 
2600     TRACE_(typelib)("\n");
2601 
2602     pTI->impltypes = TLBImplType_Alloc(count);
2603     pImpl = pTI->impltypes;
2604     for(i=0;i<count;i++){
2605         if(offset<0) break; /* paranoia */
2606         MSFT_ReadLEDWords(&refrec,sizeof(refrec),pcx,offset+pcx->pTblDir->pRefTab.offset);
2607         pImpl->hRef = refrec.reftype;
2608         pImpl->implflags=refrec.flags;
2609         MSFT_CustData(pcx, refrec.oCustData, &pImpl->custdata_list);
2610         offset=refrec.onext;
2611         ++pImpl;
2612     }
2613 }
2614 
2615 #ifdef _WIN64
2616 /* when a 32-bit typelib is loaded in 64-bit mode, we need to resize pointers
2617  * and some structures, and fix the alignment */
2618 static void TLB_fix_32on64_typeinfo(ITypeInfoImpl *info)
2619 {
2620     if(info->typeattr.typekind == TKIND_ALIAS){
2621         switch(info->tdescAlias->vt){
2622         case VT_BSTR:
2623         case VT_DISPATCH:
2624         case VT_UNKNOWN:
2625         case VT_PTR:
2626         case VT_SAFEARRAY:
2627         case VT_LPSTR:
2628         case VT_LPWSTR:
2629             info->typeattr.cbSizeInstance = sizeof(void*);
2630             info->typeattr.cbAlignment = sizeof(void*);
2631             break;
2632         case VT_CARRAY:
2633         case VT_USERDEFINED:
2634             TLB_size_instance(info, SYS_WIN64, info->tdescAlias, &info->typeattr.cbSizeInstance, &info->typeattr.cbAlignment);
2635             break;
2636         case VT_VARIANT:
2637             info->typeattr.cbSizeInstance = sizeof(VARIANT);
2638             info->typeattr.cbAlignment = 8;
2639         default:
2640             if(info->typeattr.cbSizeInstance < sizeof(void*))
2641                 info->typeattr.cbAlignment = info->typeattr.cbSizeInstance;
2642             else
2643                 info->typeattr.cbAlignment = sizeof(void*);
2644             break;
2645         }
2646     }else if(info->typeattr.typekind == TKIND_INTERFACE ||
2647             info->typeattr.typekind == TKIND_DISPATCH ||
2648             info->typeattr.typekind == TKIND_COCLASS){
2649         info->typeattr.cbSizeInstance = sizeof(void*);
2650         info->typeattr.cbAlignment = sizeof(void*);
2651     }
2652 }
2653 #endif
2654 
2655 /*
2656  * process a typeinfo record
2657  */
2658 static ITypeInfoImpl * MSFT_DoTypeInfo(
2659     TLBContext *pcx,
2660     int count,
2661     ITypeLibImpl * pLibInfo)
2662 {
2663     MSFT_TypeInfoBase tiBase;
2664     ITypeInfoImpl *ptiRet;
2665 
2666     TRACE_(typelib)("count=%u\n", count);
2667 
2668     ptiRet = ITypeInfoImpl_Constructor();
2669     MSFT_ReadLEDWords(&tiBase, sizeof(tiBase) ,pcx ,
2670                       pcx->pTblDir->pTypeInfoTab.offset+count*sizeof(tiBase));
2671 
2672 /* this is where we are coming from */
2673     ptiRet->pTypeLib = pLibInfo;
2674     ptiRet->index=count;
2675 
2676     ptiRet->guid = MSFT_ReadGuid(tiBase.posguid, pcx);
2677     ptiRet->typeattr.lcid = pLibInfo->set_lcid;   /* FIXME: correct? */
2678     ptiRet->typeattr.lpstrSchema = NULL;              /* reserved */
2679     ptiRet->typeattr.cbSizeInstance = tiBase.size;
2680     ptiRet->typeattr.typekind = tiBase.typekind & 0xF;
2681     ptiRet->typeattr.cFuncs = LOWORD(tiBase.cElement);
2682     ptiRet->typeattr.cVars = HIWORD(tiBase.cElement);
2683     ptiRet->typeattr.cbAlignment = (tiBase.typekind >> 11 )& 0x1F; /* there are more flags there */
2684     ptiRet->typeattr.wTypeFlags = tiBase.flags;
2685     ptiRet->typeattr.wMajorVerNum = LOWORD(tiBase.version);
2686     ptiRet->typeattr.wMinorVerNum = HIWORD(tiBase.version);
2687     ptiRet->typeattr.cImplTypes = tiBase.cImplTypes;
2688     ptiRet->typeattr.cbSizeVft = tiBase.cbSizeVft;
2689     if (ptiRet->typeattr.typekind == TKIND_ALIAS) {
2690         TYPEDESC tmp;
2691         MSFT_GetTdesc(pcx, tiBase.datatype1, &tmp);
2692         ptiRet->tdescAlias = heap_alloc(TLB_SizeTypeDesc(&tmp, TRUE));
2693         TLB_CopyTypeDesc(NULL, &tmp, ptiRet->tdescAlias);
2694     }
2695 
2696 /*  FIXME: */
2697 /*    IDLDESC  idldescType; *//* never saw this one != zero  */
2698 
2699 /* name, eventually add to a hash table */
2700     ptiRet->Name=MSFT_ReadName(pcx, tiBase.NameOffset);
2701     ptiRet->hreftype = MSFT_ReadHreftype(pcx, tiBase.NameOffset);
2702     TRACE_(typelib)("reading %s\n", debugstr_w(TLB_get_bstr(ptiRet->Name)));
2703     /* help info */
2704     ptiRet->DocString=MSFT_ReadString(pcx, tiBase.docstringoffs);
2705     ptiRet->dwHelpStringContext=tiBase.helpstringcontext;
2706     ptiRet->dwHelpContext=tiBase.helpcontext;
2707 
2708     if (ptiRet->typeattr.typekind == TKIND_MODULE)
2709         ptiRet->DllName = MSFT_ReadString(pcx, tiBase.datatype1);
2710 
2711 /* note: InfoType's Help file and HelpStringDll come from the containing
2712  * library. Further HelpString and Docstring appear to be the same thing :(
2713  */
2714     /* functions */
2715     if(ptiRet->typeattr.cFuncs >0 )
2716         MSFT_DoFuncs(pcx, ptiRet, ptiRet->typeattr.cFuncs,
2717 		    ptiRet->typeattr.cVars,
2718 		    tiBase.memoffset, &ptiRet->funcdescs);
2719     /* variables */
2720     if(ptiRet->typeattr.cVars >0 )
2721         MSFT_DoVars(pcx, ptiRet, ptiRet->typeattr.cFuncs,
2722 		   ptiRet->typeattr.cVars,
2723 		   tiBase.memoffset, &ptiRet->vardescs);
2724     if(ptiRet->typeattr.cImplTypes >0 ) {
2725         switch(ptiRet->typeattr.typekind)
2726         {
2727         case TKIND_COCLASS:
2728             MSFT_DoImplTypes(pcx, ptiRet, ptiRet->typeattr.cImplTypes,
2729                 tiBase.datatype1);
2730             break;
2731         case TKIND_DISPATCH:
2732             /* This is not -1 when the interface is a non-base dual interface or
2733                when a dispinterface wraps an interface, i.e., the idl 'dispinterface x {interface y;};'.
2734                Note however that GetRefTypeOfImplType(0) always returns a ref to IDispatch and
2735                not this interface.
2736             */
2737 
2738             if (tiBase.datatype1 != -1)
2739             {
2740                 ptiRet->impltypes = TLBImplType_Alloc(1);
2741                 ptiRet->impltypes[0].hRef = tiBase.datatype1;
2742             }
2743             break;
2744         default:
2745             ptiRet->impltypes = TLBImplType_Alloc(1);
2746             ptiRet->impltypes[0].hRef = tiBase.datatype1;
2747             break;
2748        }
2749     }
2750     MSFT_CustData(pcx, tiBase.oCustData, ptiRet->pcustdata_list);
2751 
2752     TRACE_(typelib)("%s guid: %s kind:%s\n",
2753        debugstr_w(TLB_get_bstr(ptiRet->Name)),
2754        debugstr_guid(TLB_get_guidref(ptiRet->guid)),
2755        typekind_desc[ptiRet->typeattr.typekind]);
2756     if (TRACE_ON(typelib))
2757       dump_TypeInfo(ptiRet);
2758 
2759     return ptiRet;
2760 }
2761 
2762 static HRESULT MSFT_ReadAllStrings(TLBContext *pcx)
2763 {
2764     char *string;
2765     INT16 len_str, len_piece;
2766     int offs = 0, lengthInChars;
2767 
2768     MSFT_Seek(pcx, pcx->pTblDir->pStringtab.offset);
2769     while (1) {
2770         TLBString *tlbstr;
2771 
2772         if (offs >= pcx->pTblDir->pStringtab.length)
2773             return S_OK;
2774 
2775         MSFT_ReadLEWords(&len_str, sizeof(INT16), pcx, DO_NOT_SEEK);
2776         len_piece = len_str + sizeof(INT16);
2777         if(len_piece % 4)
2778             len_piece = (len_piece + 4) & ~0x3;
2779         if(len_piece < 8)
2780             len_piece = 8;
2781 
2782         string = heap_alloc(len_piece + 1);
2783         MSFT_Read(string, len_piece - sizeof(INT16), pcx, DO_NOT_SEEK);
2784         string[len_str] = '\0';
2785 
2786         lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
2787                                             string, -1, NULL, 0);
2788         if (!lengthInChars) {
2789             heap_free(string);
2790             return E_UNEXPECTED;
2791         }
2792 
2793         tlbstr = heap_alloc(sizeof(TLBString));
2794 
2795         tlbstr->offset = offs;
2796         tlbstr->str = SysAllocStringByteLen(NULL, lengthInChars * sizeof(WCHAR));
2797         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, string, -1, tlbstr->str, lengthInChars);
2798 
2799         heap_free(string);
2800 
2801         list_add_tail(&pcx->pLibInfo->string_list, &tlbstr->entry);
2802 
2803         offs += len_piece;
2804     }
2805 }
2806 
2807 static HRESULT MSFT_ReadAllRefs(TLBContext *pcx)
2808 {
2809     TLBRefType *ref;
2810     int offs = 0;
2811 
2812     MSFT_Seek(pcx, pcx->pTblDir->pImpInfo.offset);
2813     while (offs < pcx->pTblDir->pImpInfo.length) {
2814         MSFT_ImpInfo impinfo;
2815         TLBImpLib *pImpLib;
2816 
2817         MSFT_ReadLEDWords(&impinfo, sizeof(impinfo), pcx, DO_NOT_SEEK);
2818 
2819         ref = heap_alloc_zero(sizeof(TLBRefType));
2820         list_add_tail(&pcx->pLibInfo->ref_list, &ref->entry);
2821 
2822         LIST_FOR_EACH_ENTRY(pImpLib, &pcx->pLibInfo->implib_list, TLBImpLib, entry)
2823             if(pImpLib->offset==impinfo.oImpFile)
2824                 break;
2825 
2826         if(&pImpLib->entry != &pcx->pLibInfo->implib_list){
2827             ref->reference = offs;
2828             ref->pImpTLInfo = pImpLib;
2829             if(impinfo.flags & MSFT_IMPINFO_OFFSET_IS_GUID) {
2830                 ref->guid = MSFT_ReadGuid(impinfo.oGuid, pcx);
2831                 TRACE("importing by guid %s\n", debugstr_guid(TLB_get_guidref(ref->guid)));
2832                 ref->index = TLB_REF_USE_GUID;
2833             } else
2834                 ref->index = impinfo.oGuid;
2835         }else{
2836             ERR("Cannot find a reference\n");
2837             ref->reference = -1;
2838             ref->pImpTLInfo = TLB_REF_NOT_FOUND;
2839         }
2840 
2841         offs += sizeof(impinfo);
2842     }
2843 
2844     return S_OK;
2845 }
2846 
2847 /* Because type library parsing has some degree of overhead, and some apps repeatedly load the same
2848  * typelibs over and over, we cache them here. According to MSDN Microsoft have a similar scheme in
2849  * place. This will cause a deliberate memory leak, but generally losing RAM for cycles is an acceptable
2850  * tradeoff here.
2851  */
2852 static struct list tlb_cache = LIST_INIT(tlb_cache);
2853 static CRITICAL_SECTION cache_section;
2854 static CRITICAL_SECTION_DEBUG cache_section_debug =
2855 {
2856     0, 0, &cache_section,
2857     { &cache_section_debug.ProcessLocksList, &cache_section_debug.ProcessLocksList },
2858       0, 0, { (DWORD_PTR)(__FILE__ ": typelib loader cache") }
2859 };
2860 static CRITICAL_SECTION cache_section = { &cache_section_debug, -1, 0, 0, 0, 0 };
2861 
2862 
2863 typedef struct TLB_PEFile
2864 {
2865     IUnknown IUnknown_iface;
2866     LONG refs;
2867     HMODULE dll;
2868     HRSRC typelib_resource;
2869     HGLOBAL typelib_global;
2870     LPVOID typelib_base;
2871 } TLB_PEFile;
2872 
2873 static inline TLB_PEFile *pefile_impl_from_IUnknown(IUnknown *iface)
2874 {
2875     return CONTAINING_RECORD(iface, TLB_PEFile, IUnknown_iface);
2876 }
2877 
2878 static HRESULT WINAPI TLB_PEFile_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2879 {
2880     if (IsEqualIID(riid, &IID_IUnknown))
2881     {
2882         *ppv = iface;
2883         IUnknown_AddRef(iface);
2884         return S_OK;
2885     }
2886     *ppv = NULL;
2887     return E_NOINTERFACE;
2888 }
2889 
2890 static ULONG WINAPI TLB_PEFile_AddRef(IUnknown *iface)
2891 {
2892     TLB_PEFile *This = pefile_impl_from_IUnknown(iface);
2893     return InterlockedIncrement(&This->refs);
2894 }
2895 
2896 static ULONG WINAPI TLB_PEFile_Release(IUnknown *iface)
2897 {
2898     TLB_PEFile *This = pefile_impl_from_IUnknown(iface);
2899     ULONG refs = InterlockedDecrement(&This->refs);
2900     if (!refs)
2901     {
2902         if (This->typelib_global)
2903             FreeResource(This->typelib_global);
2904         if (This->dll)
2905             FreeLibrary(This->dll);
2906         heap_free(This);
2907     }
2908     return refs;
2909 }
2910 
2911 static const IUnknownVtbl TLB_PEFile_Vtable =
2912 {
2913     TLB_PEFile_QueryInterface,
2914     TLB_PEFile_AddRef,
2915     TLB_PEFile_Release
2916 };
2917 
2918 static HRESULT TLB_PEFile_Open(LPCWSTR path, INT index, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile)
2919 {
2920     TLB_PEFile *This;
2921     HRESULT hr = TYPE_E_CANTLOADLIBRARY;
2922 
2923     This = heap_alloc(sizeof(TLB_PEFile));
2924     if (!This)
2925         return E_OUTOFMEMORY;
2926 
2927     This->IUnknown_iface.lpVtbl = &TLB_PEFile_Vtable;
2928     This->refs = 1;
2929     This->dll = NULL;
2930     This->typelib_resource = NULL;
2931     This->typelib_global = NULL;
2932     This->typelib_base = NULL;
2933 
2934     This->dll = LoadLibraryExW(path, 0, DONT_RESOLVE_DLL_REFERENCES |
2935                     LOAD_LIBRARY_AS_DATAFILE | LOAD_WITH_ALTERED_SEARCH_PATH);
2936 
2937     if (This->dll)
2938     {
2939         static const WCHAR TYPELIBW[] = {'T','Y','P','E','L','I','B',0};
2940         This->typelib_resource = FindResourceW(This->dll, MAKEINTRESOURCEW(index), TYPELIBW);
2941         if (This->typelib_resource)
2942         {
2943             This->typelib_global = LoadResource(This->dll, This->typelib_resource);
2944             if (This->typelib_global)
2945             {
2946                 This->typelib_base = LockResource(This->typelib_global);
2947 
2948                 if (This->typelib_base)
2949                 {
2950                     *pdwTLBLength = SizeofResource(This->dll, This->typelib_resource);
2951                     *ppBase = This->typelib_base;
2952                     *ppFile = &This->IUnknown_iface;
2953                     return S_OK;
2954                 }
2955             }
2956         }
2957 
2958         TRACE("No TYPELIB resource found\n");
2959         hr = E_FAIL;
2960     }
2961 
2962     TLB_PEFile_Release(&This->IUnknown_iface);
2963     return hr;
2964 }
2965 
2966 typedef struct TLB_NEFile
2967 {
2968     IUnknown IUnknown_iface;
2969     LONG refs;
2970     LPVOID typelib_base;
2971 } TLB_NEFile;
2972 
2973 static inline TLB_NEFile *nefile_impl_from_IUnknown(IUnknown *iface)
2974 {
2975     return CONTAINING_RECORD(iface, TLB_NEFile, IUnknown_iface);
2976 }
2977 
2978 static HRESULT WINAPI TLB_NEFile_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2979 {
2980     if (IsEqualIID(riid, &IID_IUnknown))
2981     {
2982         *ppv = iface;
2983         IUnknown_AddRef(iface);
2984         return S_OK;
2985     }
2986     *ppv = NULL;
2987     return E_NOINTERFACE;
2988 }
2989 
2990 static ULONG WINAPI TLB_NEFile_AddRef(IUnknown *iface)
2991 {
2992     TLB_NEFile *This = nefile_impl_from_IUnknown(iface);
2993     return InterlockedIncrement(&This->refs);
2994 }
2995 
2996 static ULONG WINAPI TLB_NEFile_Release(IUnknown *iface)
2997 {
2998     TLB_NEFile *This = nefile_impl_from_IUnknown(iface);
2999     ULONG refs = InterlockedDecrement(&This->refs);
3000     if (!refs)
3001     {
3002         heap_free(This->typelib_base);
3003         heap_free(This);
3004     }
3005     return refs;
3006 }
3007 
3008 static const IUnknownVtbl TLB_NEFile_Vtable =
3009 {
3010     TLB_NEFile_QueryInterface,
3011     TLB_NEFile_AddRef,
3012     TLB_NEFile_Release
3013 };
3014 
3015 /***********************************************************************
3016  *           read_xx_header         [internal]
3017  */
3018 static int read_xx_header( HFILE lzfd )
3019 {
3020     IMAGE_DOS_HEADER mzh;
3021     char magic[3];
3022 
3023     LZSeek( lzfd, 0, SEEK_SET );
3024     if ( sizeof(mzh) != LZRead( lzfd, (LPSTR)&mzh, sizeof(mzh) ) )
3025         return 0;
3026     if ( mzh.e_magic != IMAGE_DOS_SIGNATURE )
3027         return 0;
3028 
3029     LZSeek( lzfd, mzh.e_lfanew, SEEK_SET );
3030     if ( 2 != LZRead( lzfd, magic, 2 ) )
3031         return 0;
3032 
3033     LZSeek( lzfd, mzh.e_lfanew, SEEK_SET );
3034 
3035     if ( magic[0] == 'N' && magic[1] == 'E' )
3036         return IMAGE_OS2_SIGNATURE;
3037     if ( magic[0] == 'P' && magic[1] == 'E' )
3038         return IMAGE_NT_SIGNATURE;
3039 
3040     magic[2] = '\0';
3041     WARN("Can't handle %s files.\n", magic );
3042     return 0;
3043 }
3044 
3045 
3046 /***********************************************************************
3047  *           find_ne_resource         [internal]
3048  */
3049 static BOOL find_ne_resource( HFILE lzfd, LPCSTR typeid, LPCSTR resid,
3050                                 DWORD *resLen, DWORD *resOff )
3051 {
3052     IMAGE_OS2_HEADER nehd;
3053     NE_TYPEINFO *typeInfo;
3054     NE_NAMEINFO *nameInfo;
3055     DWORD nehdoffset;
3056     LPBYTE resTab;
3057     DWORD resTabSize;
3058     int count;
3059 
3060     /* Read in NE header */
3061     nehdoffset = LZSeek( lzfd, 0, SEEK_CUR );
3062     if ( sizeof(nehd) != LZRead( lzfd, (LPSTR)&nehd, sizeof(nehd) ) ) return FALSE;
3063 
3064     resTabSize = nehd.ne_restab - nehd.ne_rsrctab;
3065     if ( !resTabSize )
3066     {
3067         TRACE("No resources in NE dll\n" );
3068         return FALSE;
3069     }
3070 
3071     /* Read in resource table */
3072     resTab = heap_alloc( resTabSize );
3073     if ( !resTab ) return FALSE;
3074 
3075     LZSeek( lzfd, nehd.ne_rsrctab + nehdoffset, SEEK_SET );
3076     if ( resTabSize != LZRead( lzfd, (char*)resTab, resTabSize ) )
3077     {
3078         heap_free( resTab );
3079         return FALSE;
3080     }
3081 
3082     /* Find resource */
3083     typeInfo = (NE_TYPEINFO *)(resTab + 2);
3084 
3085     if (!IS_INTRESOURCE(typeid))  /* named type */
3086     {
3087         BYTE len = strlen( typeid );
3088         while (typeInfo->type_id)
3089         {
3090             if (!(typeInfo->type_id & 0x8000))
3091             {
3092                 BYTE *p = resTab + typeInfo->type_id;
3093                 if ((*p == len) && !_strnicmp( (char*)p+1, typeid, len )) goto found_type;
3094             }
3095             typeInfo = (NE_TYPEINFO *)((char *)(typeInfo + 1) +
3096                                        typeInfo->count * sizeof(NE_NAMEINFO));
3097         }
3098     }
3099     else  /* numeric type id */
3100     {
3101         WORD id = LOWORD(typeid) | 0x8000;
3102         while (typeInfo->type_id)
3103         {
3104             if (typeInfo->type_id == id) goto found_type;
3105             typeInfo = (NE_TYPEINFO *)((char *)(typeInfo + 1) +
3106                                        typeInfo->count * sizeof(NE_NAMEINFO));
3107         }
3108     }
3109     TRACE("No typeid entry found for %p\n", typeid );
3110     heap_free( resTab );
3111     return FALSE;
3112 
3113  found_type:
3114     nameInfo = (NE_NAMEINFO *)(typeInfo + 1);
3115 
3116     if (!IS_INTRESOURCE(resid))  /* named resource */
3117     {
3118         BYTE len = strlen( resid );
3119         for (count = typeInfo->count; count > 0; count--, nameInfo++)
3120         {
3121             BYTE *p = resTab + nameInfo->id;
3122             if (nameInfo->id & 0x8000) continue;
3123             if ((*p == len) && !_strnicmp( (char*)p+1, resid, len )) goto found_name;
3124         }
3125     }
3126     else  /* numeric resource id */
3127     {
3128         WORD id = LOWORD(resid) | 0x8000;
3129         for (count = typeInfo->count; count > 0; count--, nameInfo++)
3130             if (nameInfo->id == id) goto found_name;
3131     }
3132     TRACE("No resid entry found for %p\n", typeid );
3133     heap_free( resTab );
3134     return FALSE;
3135 
3136  found_name:
3137     /* Return resource data */
3138     if ( resLen ) *resLen = nameInfo->length << *(WORD *)resTab;
3139     if ( resOff ) *resOff = nameInfo->offset << *(WORD *)resTab;
3140 
3141     heap_free( resTab );
3142     return TRUE;
3143 }
3144 
3145 static HRESULT TLB_NEFile_Open(LPCWSTR path, INT index, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile){
3146 
3147     HFILE lzfd = -1;
3148     OFSTRUCT ofs;
3149     HRESULT hr = TYPE_E_CANTLOADLIBRARY;
3150     TLB_NEFile *This;
3151 
3152     This = heap_alloc(sizeof(TLB_NEFile));
3153     if (!This) return E_OUTOFMEMORY;
3154 
3155     This->IUnknown_iface.lpVtbl = &TLB_NEFile_Vtable;
3156     This->refs = 1;
3157     This->typelib_base = NULL;
3158 
3159     lzfd = LZOpenFileW( (LPWSTR)path, &ofs, OF_READ );
3160     if ( lzfd >= 0 && read_xx_header( lzfd ) == IMAGE_OS2_SIGNATURE )
3161     {
3162         DWORD reslen, offset;
3163         if( find_ne_resource( lzfd, "TYPELIB", MAKEINTRESOURCEA(index), &reslen, &offset ) )
3164         {
3165             This->typelib_base = heap_alloc(reslen);
3166             if( !This->typelib_base )
3167                 hr = E_OUTOFMEMORY;
3168             else
3169             {
3170                 LZSeek( lzfd, offset, SEEK_SET );
3171                 reslen = LZRead( lzfd, This->typelib_base, reslen );
3172                 LZClose( lzfd );
3173                 *ppBase = This->typelib_base;
3174                 *pdwTLBLength = reslen;
3175                 *ppFile = &This->IUnknown_iface;
3176                 return S_OK;
3177             }
3178         }
3179     }
3180 
3181     if( lzfd >= 0) LZClose( lzfd );
3182     TLB_NEFile_Release(&This->IUnknown_iface);
3183     return hr;
3184 }
3185 
3186 typedef struct TLB_Mapping
3187 {
3188     IUnknown IUnknown_iface;
3189     LONG refs;
3190     HANDLE file;
3191     HANDLE mapping;
3192     LPVOID typelib_base;
3193 } TLB_Mapping;
3194 
3195 static inline TLB_Mapping *mapping_impl_from_IUnknown(IUnknown *iface)
3196 {
3197     return CONTAINING_RECORD(iface, TLB_Mapping, IUnknown_iface);
3198 }
3199 
3200 static HRESULT WINAPI TLB_Mapping_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
3201 {
3202     if (IsEqualIID(riid, &IID_IUnknown))
3203     {
3204         *ppv = iface;
3205         IUnknown_AddRef(iface);
3206         return S_OK;
3207     }
3208     *ppv = NULL;
3209     return E_NOINTERFACE;
3210 }
3211 
3212 static ULONG WINAPI TLB_Mapping_AddRef(IUnknown *iface)
3213 {
3214     TLB_Mapping *This = mapping_impl_from_IUnknown(iface);
3215     return InterlockedIncrement(&This->refs);
3216 }
3217 
3218 static ULONG WINAPI TLB_Mapping_Release(IUnknown *iface)
3219 {
3220     TLB_Mapping *This = mapping_impl_from_IUnknown(iface);
3221     ULONG refs = InterlockedDecrement(&This->refs);
3222     if (!refs)
3223     {
3224         if (This->typelib_base)
3225             UnmapViewOfFile(This->typelib_base);
3226         if (This->mapping)
3227             CloseHandle(This->mapping);
3228         if (This->file != INVALID_HANDLE_VALUE)
3229             CloseHandle(This->file);
3230         heap_free(This);
3231     }
3232     return refs;
3233 }
3234 
3235 static const IUnknownVtbl TLB_Mapping_Vtable =
3236 {
3237     TLB_Mapping_QueryInterface,
3238     TLB_Mapping_AddRef,
3239     TLB_Mapping_Release
3240 };
3241 
3242 static HRESULT TLB_Mapping_Open(LPCWSTR path, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile)
3243 {
3244     TLB_Mapping *This;
3245 
3246     This = heap_alloc(sizeof(TLB_Mapping));
3247     if (!This)
3248         return E_OUTOFMEMORY;
3249 
3250     This->IUnknown_iface.lpVtbl = &TLB_Mapping_Vtable;
3251     This->refs = 1;
3252     This->file = INVALID_HANDLE_VALUE;
3253     This->mapping = NULL;
3254     This->typelib_base = NULL;
3255 
3256     This->file = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
3257     if (INVALID_HANDLE_VALUE != This->file)
3258     {
3259         This->mapping = CreateFileMappingW(This->file, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL);
3260         if (This->mapping)
3261         {
3262             This->typelib_base = MapViewOfFile(This->mapping, FILE_MAP_READ, 0, 0, 0);
3263             if(This->typelib_base)
3264             {
3265                 /* retrieve file size */
3266                 *pdwTLBLength = GetFileSize(This->file, NULL);
3267                 *ppBase = This->typelib_base;
3268                 *ppFile = &This->IUnknown_iface;
3269                 return S_OK;
3270             }
3271         }
3272     }
3273 
3274     IUnknown_Release(&This->IUnknown_iface);
3275     return TYPE_E_CANTLOADLIBRARY;
3276 }
3277 
3278 /****************************************************************************
3279  *	TLB_ReadTypeLib
3280  *
3281  * find the type of the typelib file and map the typelib resource into
3282  * the memory
3283  */
3284 
3285 #define SLTG_SIGNATURE 0x47544c53 /* "SLTG" */
3286 static HRESULT TLB_ReadTypeLib(LPCWSTR pszFileName, LPWSTR pszPath, UINT cchPath, ITypeLib2 **ppTypeLib)
3287 {
3288     ITypeLibImpl *entry;
3289     HRESULT ret;
3290     INT index = 1;
3291     LPWSTR index_str, file = (LPWSTR)pszFileName;
3292     LPVOID pBase = NULL;
3293     DWORD dwTLBLength = 0;
3294     IUnknown *pFile = NULL;
3295     HANDLE h;
3296 
3297     *ppTypeLib = NULL;
3298 
3299     index_str = wcsrchr(pszFileName, '\\');
3300     if(index_str && *++index_str != '\0')
3301     {
3302         LPWSTR end_ptr;
3303         LONG idx = wcstol(index_str, &end_ptr, 10);
3304         if(*end_ptr == '\0')
3305         {
3306             int str_len = index_str - pszFileName - 1;
3307             index = idx;
3308             file = heap_alloc((str_len + 1) * sizeof(WCHAR));
3309             memcpy(file, pszFileName, str_len * sizeof(WCHAR));
3310             file[str_len] = 0;
3311         }
3312     }
3313 
3314     if(!SearchPathW(NULL, file, NULL, cchPath, pszPath, NULL))
3315     {
3316         if(wcschr(file, '\\'))
3317         {
3318             lstrcpyW(pszPath, file);
3319         }
3320         else
3321         {
3322             int len = GetSystemDirectoryW(pszPath, cchPath);
3323             pszPath[len] = '\\';
3324             memcpy(pszPath + len + 1, file, (lstrlenW(file) + 1) * sizeof(WCHAR));
3325         }
3326     }
3327 
3328     if(file != pszFileName) heap_free(file);
3329 
3330     h = CreateFileW(pszPath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3331     if(h != INVALID_HANDLE_VALUE){
3332         FILE_NAME_INFORMATION size_info;
3333         BOOL br;
3334 
3335         /* GetFileInformationByHandleEx returns the path of the file without
3336          * WOW64 redirection */
3337         br = GetFileInformationByHandleEx(h, FileNameInfo, &size_info, sizeof(size_info));
3338         if(br || GetLastError() == ERROR_MORE_DATA){
3339             FILE_NAME_INFORMATION *info;
3340             DWORD size = sizeof(*info) + size_info.FileNameLength + sizeof(WCHAR);
3341 
3342             info = HeapAlloc(GetProcessHeap(), 0, size);
3343 
3344             br = GetFileInformationByHandleEx(h, FileNameInfo, info, size);
3345             if(br){
3346                 info->FileName[info->FileNameLength / sizeof(WCHAR)] = 0;
3347                 lstrcpynW(pszPath + 2, info->FileName, cchPath - 2);
3348             }
3349 
3350             HeapFree(GetProcessHeap(), 0, info);
3351         }
3352 
3353         CloseHandle(h);
3354     }
3355 
3356     TRACE_(typelib)("File %s index %d\n", debugstr_w(pszPath), index);
3357 
3358     /* We look the path up in the typelib cache. If found, we just addref it, and return the pointer. */
3359     EnterCriticalSection(&cache_section);
3360     LIST_FOR_EACH_ENTRY(entry, &tlb_cache, ITypeLibImpl, entry)
3361     {
3362         if (!wcsicmp(entry->path, pszPath) && entry->index == index)
3363         {
3364             TRACE("cache hit\n");
3365             *ppTypeLib = &entry->ITypeLib2_iface;
3366             ITypeLib2_AddRef(*ppTypeLib);
3367             LeaveCriticalSection(&cache_section);
3368             return S_OK;
3369         }
3370     }
3371     LeaveCriticalSection(&cache_section);
3372 
3373     /* now actually load and parse the typelib */
3374 
3375     ret = TLB_PEFile_Open(pszPath, index, &pBase, &dwTLBLength, &pFile);
3376     if (ret == TYPE_E_CANTLOADLIBRARY)
3377         ret = TLB_NEFile_Open(pszPath, index, &pBase, &dwTLBLength, &pFile);
3378     if (ret == TYPE_E_CANTLOADLIBRARY)
3379         ret = TLB_Mapping_Open(pszPath, &pBase, &dwTLBLength, &pFile);
3380     if (SUCCEEDED(ret))
3381     {
3382         if (dwTLBLength >= 4)
3383         {
3384             DWORD dwSignature = FromLEDWord(*((DWORD*) pBase));
3385             if (dwSignature == MSFT_SIGNATURE)
3386                 *ppTypeLib = ITypeLib2_Constructor_MSFT(pBase, dwTLBLength);
3387             else if (dwSignature == SLTG_SIGNATURE)
3388                 *ppTypeLib = ITypeLib2_Constructor_SLTG(pBase, dwTLBLength);
3389             else
3390             {
3391                 FIXME("Header type magic 0x%08x not supported.\n",dwSignature);
3392                 ret = TYPE_E_CANTLOADLIBRARY;
3393             }
3394         }
3395         else
3396             ret = TYPE_E_CANTLOADLIBRARY;
3397         IUnknown_Release(pFile);
3398     }
3399 
3400     if(*ppTypeLib) {
3401 	ITypeLibImpl *impl = impl_from_ITypeLib2(*ppTypeLib);
3402 
3403 	TRACE("adding to cache\n");
3404 	impl->path = heap_alloc((lstrlenW(pszPath)+1) * sizeof(WCHAR));
3405 	lstrcpyW(impl->path, pszPath);
3406 	/* We should really canonicalise the path here. */
3407         impl->index = index;
3408 
3409         /* FIXME: check if it has added already in the meantime */
3410         EnterCriticalSection(&cache_section);
3411         list_add_head(&tlb_cache, &impl->entry);
3412         LeaveCriticalSection(&cache_section);
3413         ret = S_OK;
3414     }
3415     else
3416     {
3417         if(ret != E_FAIL)
3418             ERR("Loading of typelib %s failed with error %d\n", debugstr_w(pszFileName), GetLastError());
3419 
3420         ret = TYPE_E_CANTLOADLIBRARY;
3421     }
3422 
3423 
3424     return ret;
3425 }
3426 
3427 /*================== ITypeLib(2) Methods ===================================*/
3428 
3429 static ITypeLibImpl* TypeLibImpl_Constructor(void)
3430 {
3431     ITypeLibImpl* pTypeLibImpl;
3432 
3433     pTypeLibImpl = heap_alloc_zero(sizeof(ITypeLibImpl));
3434     if (!pTypeLibImpl) return NULL;
3435 
3436     pTypeLibImpl->ITypeLib2_iface.lpVtbl = &tlbvt;
3437     pTypeLibImpl->ITypeComp_iface.lpVtbl = &tlbtcvt;
3438     pTypeLibImpl->ICreateTypeLib2_iface.lpVtbl = &CreateTypeLib2Vtbl;
3439     pTypeLibImpl->ref = 1;
3440 
3441     list_init(&pTypeLibImpl->implib_list);
3442     list_init(&pTypeLibImpl->custdata_list);
3443     list_init(&pTypeLibImpl->name_list);
3444     list_init(&pTypeLibImpl->string_list);
3445     list_init(&pTypeLibImpl->guid_list);
3446     list_init(&pTypeLibImpl->ref_list);
3447     pTypeLibImpl->dispatch_href = -1;
3448 
3449     return pTypeLibImpl;
3450 }
3451 
3452 /****************************************************************************
3453  *	ITypeLib2_Constructor_MSFT
3454  *
3455  * loading an MSFT typelib from an in-memory image
3456  */
3457 static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength)
3458 {
3459     TLBContext cx;
3460     LONG lPSegDir;
3461     MSFT_Header tlbHeader;
3462     MSFT_SegDir tlbSegDir;
3463     ITypeLibImpl * pTypeLibImpl;
3464     int i;
3465 
3466     TRACE("%p, TLB length = %d\n", pLib, dwTLBLength);
3467 
3468     pTypeLibImpl = TypeLibImpl_Constructor();
3469     if (!pTypeLibImpl) return NULL;
3470 
3471     /* get pointer to beginning of typelib data */
3472     cx.pos = 0;
3473     cx.oStart=0;
3474     cx.mapping = pLib;
3475     cx.pLibInfo = pTypeLibImpl;
3476     cx.length = dwTLBLength;
3477 
3478     /* read header */
3479     MSFT_ReadLEDWords(&tlbHeader, sizeof(tlbHeader), &cx, 0);
3480     TRACE_(typelib)("header:\n");
3481     TRACE_(typelib)("\tmagic1=0x%08x ,magic2=0x%08x\n",tlbHeader.magic1,tlbHeader.magic2 );
3482     if (tlbHeader.magic1 != MSFT_SIGNATURE) {
3483 	FIXME("Header type magic 0x%08x not supported.\n",tlbHeader.magic1);
3484 	return NULL;
3485     }
3486     TRACE_(typelib)("\tdispatchpos = 0x%x\n", tlbHeader.dispatchpos);
3487 
3488     /* there is a small amount of information here until the next important
3489      * part:
3490      * the segment directory . Try to calculate the amount of data */
3491     lPSegDir = sizeof(tlbHeader) + (tlbHeader.nrtypeinfos)*4 + ((tlbHeader.varflags & HELPDLLFLAG)? 4 :0);
3492 
3493     /* now read the segment directory */
3494     TRACE("read segment directory (at %d)\n",lPSegDir);
3495     MSFT_ReadLEDWords(&tlbSegDir, sizeof(tlbSegDir), &cx, lPSegDir);
3496     cx.pTblDir = &tlbSegDir;
3497 
3498     /* just check two entries */
3499     if ( tlbSegDir.pTypeInfoTab.res0c != 0x0F || tlbSegDir.pImpInfo.res0c != 0x0F)
3500     {
3501         ERR("cannot find the table directory, ptr=0x%x\n",lPSegDir);
3502 	heap_free(pTypeLibImpl);
3503 	return NULL;
3504     }
3505 
3506     MSFT_ReadAllNames(&cx);
3507     MSFT_ReadAllStrings(&cx);
3508     MSFT_ReadAllGuids(&cx);
3509 
3510     /* now fill our internal data */
3511     /* TLIBATTR fields */
3512     pTypeLibImpl->guid = MSFT_ReadGuid(tlbHeader.posguid, &cx);
3513 
3514     pTypeLibImpl->syskind = tlbHeader.varflags & 0x0f; /* check the mask */
3515     pTypeLibImpl->ptr_size = get_ptr_size(pTypeLibImpl->syskind);
3516     pTypeLibImpl->ver_major = LOWORD(tlbHeader.version);
3517     pTypeLibImpl->ver_minor = HIWORD(tlbHeader.version);
3518     pTypeLibImpl->libflags = ((WORD) tlbHeader.flags & 0xffff) /* check mask */ | LIBFLAG_FHASDISKIMAGE;
3519 
3520     pTypeLibImpl->set_lcid = tlbHeader.lcid2;
3521     pTypeLibImpl->lcid = tlbHeader.lcid;
3522 
3523     /* name, eventually add to a hash table */
3524     pTypeLibImpl->Name = MSFT_ReadName(&cx, tlbHeader.NameOffset);
3525 
3526     /* help info */
3527     pTypeLibImpl->DocString = MSFT_ReadString(&cx, tlbHeader.helpstring);
3528     pTypeLibImpl->HelpFile = MSFT_ReadString(&cx, tlbHeader.helpfile);
3529 
3530     if( tlbHeader.varflags & HELPDLLFLAG)
3531     {
3532             int offset;
3533             MSFT_ReadLEDWords(&offset, sizeof(offset), &cx, sizeof(tlbHeader));
3534             pTypeLibImpl->HelpStringDll = MSFT_ReadString(&cx, offset);
3535     }
3536 
3537     pTypeLibImpl->dwHelpContext = tlbHeader.helpstringcontext;
3538 
3539     /* custom data */
3540     if(tlbHeader.CustomDataOffset >= 0)
3541     {
3542         MSFT_CustData(&cx, tlbHeader.CustomDataOffset, &pTypeLibImpl->custdata_list);
3543     }
3544 
3545     /* fill in type descriptions */
3546     if(tlbSegDir.pTypdescTab.length > 0)
3547     {
3548         int i, j, cTD = tlbSegDir.pTypdescTab.length / (2*sizeof(INT));
3549         INT16 td[4];
3550         pTypeLibImpl->ctTypeDesc = cTD;
3551         pTypeLibImpl->pTypeDesc = heap_alloc_zero( cTD * sizeof(TYPEDESC));
3552         MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pTypdescTab.offset);
3553         for(i=0; i<cTD; )
3554 	{
3555             /* FIXME: add several sanity checks here */
3556             pTypeLibImpl->pTypeDesc[i].vt = td[0] & VT_TYPEMASK;
3557             if(td[0] == VT_PTR || td[0] == VT_SAFEARRAY)
3558 	    {
3559 	        /* FIXME: check safearray */
3560                 if(td[3] < 0)
3561                     pTypeLibImpl->pTypeDesc[i].u.lptdesc = &std_typedesc[td[2]];
3562                 else
3563                     pTypeLibImpl->pTypeDesc[i].u.lptdesc = &pTypeLibImpl->pTypeDesc[td[2]/8];
3564             }
3565 	    else if(td[0] == VT_CARRAY)
3566             {
3567 	        /* array descr table here */
3568 	        pTypeLibImpl->pTypeDesc[i].u.lpadesc = (void *)(INT_PTR)td[2];  /* temp store offset in*/
3569             }
3570             else if(td[0] == VT_USERDEFINED)
3571 	    {
3572                 pTypeLibImpl->pTypeDesc[i].u.hreftype = MAKELONG(td[2],td[3]);
3573             }
3574 	    if(++i<cTD) MSFT_ReadLEWords(td, sizeof(td), &cx, DO_NOT_SEEK);
3575         }
3576 
3577         /* second time around to fill the array subscript info */
3578         for(i=0;i<cTD;i++)
3579 	{
3580             if(pTypeLibImpl->pTypeDesc[i].vt != VT_CARRAY) continue;
3581             if(tlbSegDir.pArrayDescriptions.offset>0)
3582 	    {
3583                 MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pArrayDescriptions.offset + (INT_PTR)pTypeLibImpl->pTypeDesc[i].u.lpadesc);
3584                 pTypeLibImpl->pTypeDesc[i].u.lpadesc = heap_alloc_zero(sizeof(ARRAYDESC)+sizeof(SAFEARRAYBOUND)*(td[3]-1));
3585 
3586                 if(td[1]<0)
3587                     pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem.vt = td[0] & VT_TYPEMASK;
3588                 else
3589                     pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem = cx.pLibInfo->pTypeDesc[td[0]/(2*sizeof(INT))];
3590 
3591                 pTypeLibImpl->pTypeDesc[i].u.lpadesc->cDims = td[2];
3592 
3593                 for(j = 0; j<td[2]; j++)
3594 		{
3595                     MSFT_ReadLEDWords(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].cElements,
3596                                       sizeof(INT), &cx, DO_NOT_SEEK);
3597                     MSFT_ReadLEDWords(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].lLbound,
3598                                       sizeof(INT), &cx, DO_NOT_SEEK);
3599                 }
3600             }
3601 	    else
3602 	    {
3603                 pTypeLibImpl->pTypeDesc[i].u.lpadesc = NULL;
3604                 ERR("didn't find array description data\n");
3605             }
3606         }
3607     }
3608 
3609     /* imported type libs */
3610     if(tlbSegDir.pImpFiles.offset>0)
3611     {
3612         TLBImpLib *pImpLib;
3613         int oGuid, offset = tlbSegDir.pImpFiles.offset;
3614         UINT16 size;
3615 
3616         while(offset < tlbSegDir.pImpFiles.offset +tlbSegDir.pImpFiles.length)
3617 	{
3618             char *name;
3619 
3620             pImpLib = heap_alloc_zero(sizeof(TLBImpLib));
3621             pImpLib->offset = offset - tlbSegDir.pImpFiles.offset;
3622             MSFT_ReadLEDWords(&oGuid, sizeof(INT), &cx, offset);
3623 
3624             MSFT_ReadLEDWords(&pImpLib->lcid,         sizeof(LCID),   &cx, DO_NOT_SEEK);
3625             MSFT_ReadLEWords(&pImpLib->wVersionMajor, sizeof(WORD),   &cx, DO_NOT_SEEK);
3626             MSFT_ReadLEWords(&pImpLib->wVersionMinor, sizeof(WORD),   &cx, DO_NOT_SEEK);
3627             MSFT_ReadLEWords(& size,                      sizeof(UINT16), &cx, DO_NOT_SEEK);
3628 
3629             size >>= 2;
3630             name = heap_alloc_zero(size+1);
3631             MSFT_Read(name, size, &cx, DO_NOT_SEEK);
3632             pImpLib->name = TLB_MultiByteToBSTR(name);
3633             heap_free(name);
3634 
3635             pImpLib->guid = MSFT_ReadGuid(oGuid, &cx);
3636             offset = (offset + sizeof(INT) + sizeof(DWORD) + sizeof(LCID) + sizeof(UINT16) + size + 3) & ~3;
3637 
3638             list_add_tail(&pTypeLibImpl->implib_list, &pImpLib->entry);
3639         }
3640     }
3641 
3642     MSFT_ReadAllRefs(&cx);
3643 
3644     pTypeLibImpl->dispatch_href = tlbHeader.dispatchpos;
3645 
3646     /* type infos */
3647     if(tlbHeader.nrtypeinfos >= 0 )
3648     {
3649         ITypeInfoImpl **ppTI;
3650 
3651         ppTI = pTypeLibImpl->typeinfos = heap_alloc_zero(sizeof(ITypeInfoImpl*) * tlbHeader.nrtypeinfos);
3652 
3653         for(i = 0; i < tlbHeader.nrtypeinfos; i++)
3654         {
3655             *ppTI = MSFT_DoTypeInfo(&cx, i, pTypeLibImpl);
3656 
3657             ++ppTI;
3658             (pTypeLibImpl->TypeInfoCount)++;
3659         }
3660     }
3661 
3662 #ifdef _WIN64
3663     if(pTypeLibImpl->syskind == SYS_WIN32){
3664         for(i = 0; i < pTypeLibImpl->TypeInfoCount; ++i)
3665             TLB_fix_32on64_typeinfo(pTypeLibImpl->typeinfos[i]);
3666     }
3667 #endif
3668 
3669     TRACE("(%p)\n", pTypeLibImpl);
3670     return &pTypeLibImpl->ITypeLib2_iface;
3671 }
3672 
3673 
3674 static BOOL TLB_GUIDFromString(const char *str, GUID *guid)
3675 {
3676   char b[3];
3677   int i;
3678   short s;
3679 
3680   if(sscanf(str, "%x-%hx-%hx-%hx", &guid->Data1, &guid->Data2, &guid->Data3, &s) != 4) {
3681     FIXME("Can't parse guid %s\n", debugstr_guid(guid));
3682     return FALSE;
3683   }
3684 
3685   guid->Data4[0] = s >> 8;
3686   guid->Data4[1] = s & 0xff;
3687 
3688   b[2] = '\0';
3689   for(i = 0; i < 6; i++) {
3690     memcpy(b, str + 24 + 2 * i, 2);
3691     guid->Data4[i + 2] = strtol(b, NULL, 16);
3692   }
3693   return TRUE;
3694 }
3695 
3696 struct bitstream
3697 {
3698     const BYTE *buffer;
3699     DWORD       length;
3700     WORD        current;
3701 };
3702 
3703 static const char *lookup_code(const BYTE *table, DWORD table_size, struct bitstream *bits)
3704 {
3705     const BYTE *p = table;
3706 
3707     while (p < table + table_size && *p == 0x80)
3708     {
3709         if (p + 2 >= table + table_size) return NULL;
3710 
3711         if (!(bits->current & 0xff))
3712         {
3713             if (!bits->length) return NULL;
3714             bits->current = (*bits->buffer << 8) | 1;
3715             bits->buffer++;
3716             bits->length--;
3717         }
3718 
3719         if (bits->current & 0x8000)
3720         {
3721             p += 3;
3722         }
3723         else
3724         {
3725             p = table + (*(p + 2) | (*(p + 1) << 8));
3726         }
3727 
3728         bits->current <<= 1;
3729     }
3730 
3731     if (p + 1 < table + table_size && *(p + 1))
3732     {
3733         /* FIXME: Whats the meaning of *p? */
3734         const BYTE *q = p + 1;
3735         while (q < table + table_size && *q) q++;
3736         return (q < table + table_size) ? (const char *)(p + 1) : NULL;
3737     }
3738 
3739     return NULL;
3740 }
3741 
3742 static const TLBString *decode_string(const BYTE *table, const char *stream, DWORD stream_length, ITypeLibImpl *lib)
3743 {
3744     DWORD buf_size, table_size;
3745     const char *p;
3746     struct bitstream bits;
3747     BSTR buf;
3748     TLBString *tlbstr;
3749 
3750     if (!stream_length) return NULL;
3751 
3752     bits.buffer = (const BYTE *)stream;
3753     bits.length = stream_length;
3754     bits.current = 0;
3755 
3756     buf_size = *(const WORD *)table;
3757     table += sizeof(WORD);
3758     table_size = *(const DWORD *)table;
3759     table += sizeof(DWORD);
3760 
3761     buf = SysAllocStringLen(NULL, buf_size);
3762     buf[0] = 0;
3763 
3764     while ((p = lookup_code(table, table_size, &bits)))
3765     {
3766         static const WCHAR spaceW[] = { ' ',0 };
3767         if (buf[0]) lstrcatW(buf, spaceW);
3768         MultiByteToWideChar(CP_ACP, 0, p, -1, buf + lstrlenW(buf), buf_size - lstrlenW(buf));
3769     }
3770 
3771     tlbstr = TLB_append_str(&lib->string_list, buf);
3772     SysFreeString(buf);
3773 
3774     return tlbstr;
3775 }
3776 
3777 static WORD SLTG_ReadString(const char *ptr, const TLBString **pStr, ITypeLibImpl *lib)
3778 {
3779     WORD bytelen;
3780     DWORD len;
3781     BSTR tmp_str;
3782 
3783     *pStr = NULL;
3784     bytelen = *(const WORD*)ptr;
3785     if(bytelen == 0xffff) return 2;
3786 
3787     len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, NULL, 0);
3788     tmp_str = SysAllocStringLen(NULL, len);
3789     if (tmp_str) {
3790         MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, tmp_str, len);
3791         *pStr = TLB_append_str(&lib->string_list, tmp_str);
3792         SysFreeString(tmp_str);
3793     }
3794     return bytelen + 2;
3795 }
3796 
3797 static WORD SLTG_ReadStringA(const char *ptr, char **str)
3798 {
3799     WORD bytelen;
3800 
3801     *str = NULL;
3802     bytelen = *(const WORD*)ptr;
3803     if(bytelen == 0xffff) return 2;
3804     *str = heap_alloc(bytelen + 1);
3805     memcpy(*str, ptr + 2, bytelen);
3806     (*str)[bytelen] = '\0';
3807     return bytelen + 2;
3808 }
3809 
3810 static TLBString *SLTG_ReadName(const char *pNameTable, int offset, ITypeLibImpl *lib)
3811 {
3812     BSTR tmp_str;
3813     TLBString *tlbstr;
3814 
3815     LIST_FOR_EACH_ENTRY(tlbstr, &lib->name_list, TLBString, entry) {
3816         if (tlbstr->offset == offset)
3817             return tlbstr;
3818     }
3819 
3820     tmp_str = TLB_MultiByteToBSTR(pNameTable + offset);
3821     tlbstr = TLB_append_str(&lib->name_list, tmp_str);
3822     SysFreeString(tmp_str);
3823 
3824     return tlbstr;
3825 }
3826 
3827 static DWORD SLTG_ReadLibBlk(LPVOID pLibBlk, ITypeLibImpl *pTypeLibImpl)
3828 {
3829     char *ptr = pLibBlk;
3830     WORD w;
3831 
3832     if((w = *(WORD*)ptr) != SLTG_LIBBLK_MAGIC) {
3833         FIXME("libblk magic = %04x\n", w);
3834 	return 0;
3835     }
3836 
3837     ptr += 6;
3838     if((w = *(WORD*)ptr) != 0xffff) {
3839         FIXME("LibBlk.res06 = %04x. Assumung string and skipping\n", w);
3840         ptr += w;
3841     }
3842     ptr += 2;
3843 
3844     ptr += SLTG_ReadString(ptr, &pTypeLibImpl->DocString, pTypeLibImpl);
3845 
3846     ptr += SLTG_ReadString(ptr, &pTypeLibImpl->HelpFile, pTypeLibImpl);
3847 
3848     pTypeLibImpl->dwHelpContext = *(DWORD*)ptr;
3849     ptr += 4;
3850 
3851     pTypeLibImpl->syskind = *(WORD*)ptr;
3852     pTypeLibImpl->ptr_size = get_ptr_size(pTypeLibImpl->syskind);
3853     ptr += 2;
3854 
3855     if(SUBLANGID(*(WORD*)ptr) == SUBLANG_NEUTRAL)
3856         pTypeLibImpl->lcid = pTypeLibImpl->set_lcid = MAKELCID(MAKELANGID(PRIMARYLANGID(*(WORD*)ptr),0),0);
3857     else
3858         pTypeLibImpl->lcid = pTypeLibImpl->set_lcid = 0;
3859     ptr += 2;
3860 
3861     ptr += 4; /* skip res12 */
3862 
3863     pTypeLibImpl->libflags = *(WORD*)ptr;
3864     ptr += 2;
3865 
3866     pTypeLibImpl->ver_major = *(WORD*)ptr;
3867     ptr += 2;
3868 
3869     pTypeLibImpl->ver_minor = *(WORD*)ptr;
3870     ptr += 2;
3871 
3872     pTypeLibImpl->guid = TLB_append_guid(&pTypeLibImpl->guid_list, (GUID*)ptr, -2);
3873     ptr += sizeof(GUID);
3874 
3875     return ptr - (char*)pLibBlk;
3876 }
3877 
3878 /* stores a mapping between the sltg typeinfo's references and the typelib's HREFTYPEs */
3879 typedef struct
3880 {
3881     unsigned int num;
3882     HREFTYPE refs[1];
3883 } sltg_ref_lookup_t;
3884 
3885 static HRESULT sltg_get_typelib_ref(const sltg_ref_lookup_t *table, DWORD typeinfo_ref,
3886 				    HREFTYPE *typelib_ref)
3887 {
3888     if(table && typeinfo_ref < table->num)
3889     {
3890         *typelib_ref = table->refs[typeinfo_ref];
3891         return S_OK;
3892     }
3893 
3894     ERR_(typelib)("Unable to find reference\n");
3895     *typelib_ref = -1;
3896     return E_FAIL;
3897 }
3898 
3899 static WORD *SLTG_DoType(WORD *pType, char *pBlk, TYPEDESC *pTD, const sltg_ref_lookup_t *ref_lookup)
3900 {
3901     BOOL done = FALSE;
3902 
3903     while(!done) {
3904         if((*pType & 0xe00) == 0xe00) {
3905 	    pTD->vt = VT_PTR;
3906 	    pTD->u.lptdesc = heap_alloc_zero(sizeof(TYPEDESC));
3907 	    pTD = pTD->u.lptdesc;
3908 	}
3909 	switch(*pType & 0x3f) {
3910 	case VT_PTR:
3911 	    pTD->vt = VT_PTR;
3912 	    pTD->u.lptdesc = heap_alloc_zero(sizeof(TYPEDESC));
3913 	    pTD = pTD->u.lptdesc;
3914 	    break;
3915 
3916 	case VT_USERDEFINED:
3917 	    pTD->vt = VT_USERDEFINED;
3918             sltg_get_typelib_ref(ref_lookup, *(++pType) / 4, &pTD->u.hreftype);
3919 	    done = TRUE;
3920 	    break;
3921 
3922 	case VT_CARRAY:
3923 	  {
3924 	    /* *(pType+1) is offset to a SAFEARRAY, *(pType+2) is type of
3925 	       array */
3926 
3927 	    SAFEARRAY *pSA = (SAFEARRAY *)(pBlk + *(++pType));
3928 
3929 	    pTD->vt = VT_CARRAY;
3930 	    pTD->u.lpadesc = heap_alloc_zero(sizeof(ARRAYDESC) + (pSA->cDims - 1) * sizeof(SAFEARRAYBOUND));
3931 	    pTD->u.lpadesc->cDims = pSA->cDims;
3932 	    memcpy(pTD->u.lpadesc->rgbounds, pSA->rgsabound,
3933 		   pSA->cDims * sizeof(SAFEARRAYBOUND));
3934 
3935 	    pTD = &pTD->u.lpadesc->tdescElem;
3936 	    break;
3937 	  }
3938 
3939 	case VT_SAFEARRAY:
3940 	  {
3941 	    /* FIXME: *(pType+1) gives an offset to SAFEARRAY, is this
3942 	       useful? */
3943 
3944 	    pType++;
3945 	    pTD->vt = VT_SAFEARRAY;
3946 	    pTD->u.lptdesc = heap_alloc_zero(sizeof(TYPEDESC));
3947 	    pTD = pTD->u.lptdesc;
3948 	    break;
3949 	  }
3950 	default:
3951 	    pTD->vt = *pType & 0x3f;
3952 	    done = TRUE;
3953 	    break;
3954 	}
3955 	pType++;
3956     }
3957     return pType;
3958 }
3959 
3960 static WORD *SLTG_DoElem(WORD *pType, char *pBlk,
3961 			 ELEMDESC *pElem, const sltg_ref_lookup_t *ref_lookup)
3962 {
3963     /* Handle [in/out] first */
3964     if((*pType & 0xc000) == 0xc000)
3965         pElem->u.paramdesc.wParamFlags = PARAMFLAG_NONE;
3966     else if(*pType & 0x8000)
3967         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN | PARAMFLAG_FOUT;
3968     else if(*pType & 0x4000)
3969         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FOUT;
3970     else
3971         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN;
3972 
3973     if(*pType & 0x2000)
3974         pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FLCID;
3975 
3976     if(*pType & 0x80)
3977         pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FRETVAL;
3978 
3979     return SLTG_DoType(pType, pBlk, &pElem->tdesc, ref_lookup);
3980 }
3981 
3982 
3983 static sltg_ref_lookup_t *SLTG_DoRefs(SLTG_RefInfo *pRef, ITypeLibImpl *pTL,
3984 			char *pNameTable)
3985 {
3986     unsigned int ref;
3987     char *name;
3988     TLBRefType *ref_type;
3989     sltg_ref_lookup_t *table;
3990     HREFTYPE typelib_ref;
3991 
3992     if(pRef->magic != SLTG_REF_MAGIC) {
3993         FIXME("Ref magic = %x\n", pRef->magic);
3994 	return NULL;
3995     }
3996     name = ( (char*)pRef->names + pRef->number);
3997 
3998     table = heap_alloc(sizeof(*table) + ((pRef->number >> 3) - 1) * sizeof(table->refs[0]));
3999     table->num = pRef->number >> 3;
4000 
4001     /* FIXME should scan the existing list and reuse matching refs added by previous typeinfos */
4002 
4003     /* We don't want the first href to be 0 */
4004     typelib_ref = (list_count(&pTL->ref_list) + 1) << 2;
4005 
4006     for(ref = 0; ref < pRef->number >> 3; ref++) {
4007         char *refname;
4008 	unsigned int lib_offs, type_num;
4009 
4010 	ref_type = heap_alloc_zero(sizeof(TLBRefType));
4011 
4012 	name += SLTG_ReadStringA(name, &refname);
4013 	if(sscanf(refname, "*\\R%x*#%x", &lib_offs, &type_num) != 2)
4014 	    FIXME_(typelib)("Can't sscanf ref\n");
4015 	if(lib_offs != 0xffff) {
4016 	    TLBImpLib *import;
4017 
4018             LIST_FOR_EACH_ENTRY(import, &pTL->implib_list, TLBImpLib, entry)
4019                 if(import->offset == lib_offs)
4020                     break;
4021 
4022             if(&import->entry == &pTL->implib_list) {
4023 	        char fname[MAX_PATH+1];
4024 		int len;
4025                 GUID tmpguid;
4026 
4027 		import = heap_alloc_zero(sizeof(*import));
4028 		import->offset = lib_offs;
4029 		TLB_GUIDFromString( pNameTable + lib_offs + 4, &tmpguid);
4030                 import->guid = TLB_append_guid(&pTL->guid_list, &tmpguid, 2);
4031 		if(sscanf(pNameTable + lib_offs + 40, "}#%hd.%hd#%x#%s",
4032 			  &import->wVersionMajor,
4033 			  &import->wVersionMinor,
4034 			  &import->lcid, fname) != 4) {
4035 		  FIXME_(typelib)("can't sscanf ref %s\n",
4036 			pNameTable + lib_offs + 40);
4037 		}
4038 		len = strlen(fname);
4039 		if(fname[len-1] != '#')
4040 		    FIXME("fname = %s\n", fname);
4041 		fname[len-1] = '\0';
4042 		import->name = TLB_MultiByteToBSTR(fname);
4043 		list_add_tail(&pTL->implib_list, &import->entry);
4044 	    }
4045 	    ref_type->pImpTLInfo = import;
4046 
4047             /* Store a reference to IDispatch */
4048             if(pTL->dispatch_href == -1 && IsEqualGUID(&import->guid->guid, &IID_StdOle) && type_num == 4)
4049                 pTL->dispatch_href = typelib_ref;
4050 
4051 	} else { /* internal ref */
4052 	  ref_type->pImpTLInfo = TLB_REF_INTERNAL;
4053 	}
4054 	ref_type->reference = typelib_ref;
4055 	ref_type->index = type_num;
4056 
4057 	heap_free(refname);
4058         list_add_tail(&pTL->ref_list, &ref_type->entry);
4059 
4060         table->refs[ref] = typelib_ref;
4061         typelib_ref += 4;
4062     }
4063     if((BYTE)*name != SLTG_REF_MAGIC)
4064       FIXME_(typelib)("End of ref block magic = %x\n", *name);
4065     dump_TLBRefType(pTL);
4066     return table;
4067 }
4068 
4069 static char *SLTG_DoImpls(char *pBlk, ITypeInfoImpl *pTI,
4070 			  BOOL OneOnly, const sltg_ref_lookup_t *ref_lookup)
4071 {
4072     SLTG_ImplInfo *info;
4073     TLBImplType *pImplType;
4074     /* I don't really get this structure, usually it's 0x16 bytes
4075        long, but iuser.tlb contains some that are 0x18 bytes long.
4076        That's ok because we can use the next ptr to jump to the next
4077        one. But how do we know the length of the last one?  The WORD
4078        at offs 0x8 might be the clue.  For now I'm just assuming that
4079        the last one is the regular 0x16 bytes. */
4080 
4081     info = (SLTG_ImplInfo*)pBlk;
4082     while(1){
4083         pTI->typeattr.cImplTypes++;
4084         if(info->next == 0xffff)
4085             break;
4086         info = (SLTG_ImplInfo*)(pBlk + info->next);
4087     }
4088 
4089     info = (SLTG_ImplInfo*)pBlk;
4090     pTI->impltypes = TLBImplType_Alloc(pTI->typeattr.cImplTypes);
4091     pImplType = pTI->impltypes;
4092     while(1) {
4093 	sltg_get_typelib_ref(ref_lookup, info->ref, &pImplType->hRef);
4094 	pImplType->implflags = info->impltypeflags;
4095 	++pImplType;
4096 
4097 	if(info->next == 0xffff)
4098 	    break;
4099 	if(OneOnly)
4100 	    FIXME_(typelib)("Interface inheriting more than one interface\n");
4101 	info = (SLTG_ImplInfo*)(pBlk + info->next);
4102     }
4103     info++; /* see comment at top of function */
4104     return (char*)info;
4105 }
4106 
4107 static void SLTG_DoVars(char *pBlk, char *pFirstItem, ITypeInfoImpl *pTI, unsigned short cVars,
4108 			const char *pNameTable, const sltg_ref_lookup_t *ref_lookup, const BYTE *hlp_strings)
4109 {
4110   TLBVarDesc *pVarDesc;
4111   const TLBString *prevName = NULL;
4112   SLTG_Variable *pItem;
4113   unsigned short i;
4114   WORD *pType;
4115 
4116   pVarDesc = pTI->vardescs = TLBVarDesc_Alloc(cVars);
4117 
4118   for(pItem = (SLTG_Variable *)pFirstItem, i = 0; i < cVars;
4119       pItem = (SLTG_Variable *)(pBlk + pItem->next), i++, ++pVarDesc) {
4120 
4121       pVarDesc->vardesc.memid = pItem->memid;
4122 
4123       if (pItem->magic != SLTG_VAR_MAGIC &&
4124           pItem->magic != SLTG_VAR_WITH_FLAGS_MAGIC) {
4125 	  FIXME_(typelib)("var magic = %02x\n", pItem->magic);
4126 	  return;
4127       }
4128 
4129       if (pItem->name == 0xfffe)
4130         pVarDesc->Name = prevName;
4131       else
4132         pVarDesc->Name = SLTG_ReadName(pNameTable, pItem->name, pTI->pTypeLib);
4133 
4134       TRACE_(typelib)("name: %s\n", debugstr_w(TLB_get_bstr(pVarDesc->Name)));
4135       TRACE_(typelib)("byte_offs = 0x%x\n", pItem->byte_offs);
4136       TRACE_(typelib)("memid = 0x%x\n", pItem->memid);
4137 
4138       if (pItem->helpstring != 0xffff)
4139       {
4140           pVarDesc->HelpString = decode_string(hlp_strings, pBlk + pItem->helpstring, pNameTable - pBlk, pTI->pTypeLib);
4141           TRACE_(typelib)("helpstring = %s\n", debugstr_w(pVarDesc->HelpString->str));
4142       }
4143 
4144       if(pItem->flags & 0x02)
4145 	  pType = &pItem->type;
4146       else
4147 	  pType = (WORD*)(pBlk + pItem->type);
4148 
4149       if (pItem->flags & ~0xda)
4150         FIXME_(typelib)("unhandled flags = %02x\n", pItem->flags & ~0xda);
4151 
4152       SLTG_DoElem(pType, pBlk,
4153 		  &pVarDesc->vardesc.elemdescVar, ref_lookup);
4154 
4155       if (TRACE_ON(typelib)) {
4156           char buf[300];
4157           dump_TypeDesc(&pVarDesc->vardesc.elemdescVar.tdesc, buf);
4158           TRACE_(typelib)("elemdescVar: %s\n", buf);
4159       }
4160 
4161       if (pItem->flags & 0x40) {
4162         TRACE_(typelib)("VAR_DISPATCH\n");
4163         pVarDesc->vardesc.varkind = VAR_DISPATCH;
4164       }
4165       else if (pItem->flags & 0x10) {
4166         TRACE_(typelib)("VAR_CONST\n");
4167         pVarDesc->vardesc.varkind = VAR_CONST;
4168         pVarDesc->vardesc.u.lpvarValue = heap_alloc(sizeof(VARIANT));
4169         V_VT(pVarDesc->vardesc.u.lpvarValue) = VT_INT;
4170         if (pItem->flags & 0x08)
4171           V_INT(pVarDesc->vardesc.u.lpvarValue) = pItem->byte_offs;
4172         else {
4173           switch (pVarDesc->vardesc.elemdescVar.tdesc.vt)
4174           {
4175             case VT_LPSTR:
4176             case VT_LPWSTR:
4177             case VT_BSTR:
4178             {
4179               WORD len = *(WORD *)(pBlk + pItem->byte_offs);
4180               BSTR str;
4181               TRACE_(typelib)("len = %u\n", len);
4182               if (len == 0xffff) {
4183                 str = NULL;
4184               } else {
4185                 INT alloc_len = MultiByteToWideChar(CP_ACP, 0, pBlk + pItem->byte_offs + 2, len, NULL, 0);
4186                 str = SysAllocStringLen(NULL, alloc_len);
4187                 MultiByteToWideChar(CP_ACP, 0, pBlk + pItem->byte_offs + 2, len, str, alloc_len);
4188               }
4189               V_VT(pVarDesc->vardesc.u.lpvarValue) = VT_BSTR;
4190               V_BSTR(pVarDesc->vardesc.u.lpvarValue) = str;
4191               break;
4192             }
4193             case VT_I2:
4194             case VT_UI2:
4195             case VT_I4:
4196             case VT_UI4:
4197             case VT_INT:
4198             case VT_UINT:
4199               V_INT(pVarDesc->vardesc.u.lpvarValue) =
4200                 *(INT*)(pBlk + pItem->byte_offs);
4201               break;
4202             default:
4203               FIXME_(typelib)("VAR_CONST unimplemented for type %d\n", pVarDesc->vardesc.elemdescVar.tdesc.vt);
4204           }
4205         }
4206       }
4207       else {
4208         TRACE_(typelib)("VAR_PERINSTANCE\n");
4209         pVarDesc->vardesc.u.oInst = pItem->byte_offs;
4210         pVarDesc->vardesc.varkind = VAR_PERINSTANCE;
4211       }
4212 
4213       if (pItem->magic == SLTG_VAR_WITH_FLAGS_MAGIC)
4214         pVarDesc->vardesc.wVarFlags = pItem->varflags;
4215 
4216       if (pItem->flags & 0x80)
4217         pVarDesc->vardesc.wVarFlags |= VARFLAG_FREADONLY;
4218 
4219       prevName = pVarDesc->Name;
4220   }
4221   pTI->typeattr.cVars = cVars;
4222 }
4223 
4224 static void SLTG_DoFuncs(char *pBlk, char *pFirstItem, ITypeInfoImpl *pTI,
4225 			 unsigned short cFuncs, char *pNameTable, const sltg_ref_lookup_t *ref_lookup,
4226 			 const BYTE *hlp_strings)
4227 {
4228     SLTG_Function *pFunc;
4229     unsigned short i;
4230     TLBFuncDesc *pFuncDesc;
4231 
4232     pTI->funcdescs = TLBFuncDesc_Alloc(cFuncs);
4233 
4234     pFuncDesc = pTI->funcdescs;
4235     for(pFunc = (SLTG_Function*)pFirstItem, i = 0; i < cFuncs && pFunc != (SLTG_Function*)0xFFFF;
4236 	pFunc = (SLTG_Function*)(pBlk + pFunc->next), i++, ++pFuncDesc) {
4237 
4238         int param;
4239 	WORD *pType, *pArg;
4240 
4241         switch (pFunc->magic & ~SLTG_FUNCTION_FLAGS_PRESENT) {
4242         case SLTG_FUNCTION_MAGIC:
4243             pFuncDesc->funcdesc.funckind = FUNC_PUREVIRTUAL;
4244             break;
4245         case SLTG_DISPATCH_FUNCTION_MAGIC:
4246             pFuncDesc->funcdesc.funckind = FUNC_DISPATCH;
4247             break;
4248         case SLTG_STATIC_FUNCTION_MAGIC:
4249             pFuncDesc->funcdesc.funckind = FUNC_STATIC;
4250             break;
4251         default:
4252 	    FIXME("unimplemented func magic = %02x\n", pFunc->magic & ~SLTG_FUNCTION_FLAGS_PRESENT);
4253 	    continue;
4254 	}
4255 	pFuncDesc->Name = SLTG_ReadName(pNameTable, pFunc->name, pTI->pTypeLib);
4256 
4257 	pFuncDesc->funcdesc.memid = pFunc->dispid;
4258 	pFuncDesc->funcdesc.invkind = pFunc->inv >> 4;
4259 	pFuncDesc->funcdesc.callconv = pFunc->nacc & 0x7;
4260 	pFuncDesc->funcdesc.cParams = pFunc->nacc >> 3;
4261 	pFuncDesc->funcdesc.cParamsOpt = (pFunc->retnextopt & 0x7e) >> 1;
4262 	pFuncDesc->funcdesc.oVft = (pFunc->vtblpos & ~1) * sizeof(void *) / pTI->pTypeLib->ptr_size;
4263         if (pFunc->helpstring != 0xffff)
4264             pFuncDesc->HelpString = decode_string(hlp_strings, pBlk + pFunc->helpstring, pNameTable - pBlk, pTI->pTypeLib);
4265 
4266 	if(pFunc->magic & SLTG_FUNCTION_FLAGS_PRESENT)
4267 	    pFuncDesc->funcdesc.wFuncFlags = pFunc->funcflags;
4268 
4269 	if(pFunc->retnextopt & 0x80)
4270 	    pType = &pFunc->rettype;
4271 	else
4272 	    pType = (WORD*)(pBlk + pFunc->rettype);
4273 
4274 	SLTG_DoElem(pType, pBlk, &pFuncDesc->funcdesc.elemdescFunc, ref_lookup);
4275 
4276 	pFuncDesc->funcdesc.lprgelemdescParam =
4277 	  heap_alloc_zero(pFuncDesc->funcdesc.cParams * sizeof(ELEMDESC));
4278 	pFuncDesc->pParamDesc = TLBParDesc_Constructor(pFuncDesc->funcdesc.cParams);
4279 
4280 	pArg = (WORD*)(pBlk + pFunc->arg_off);
4281 
4282 	for(param = 0; param < pFuncDesc->funcdesc.cParams; param++) {
4283 	    char *paramName = pNameTable + (*pArg & ~1);
4284 	    BOOL HaveOffs;
4285 	    /* If arg type follows then paramName points to the 2nd
4286 	       letter of the name, else the next WORD is an offset to
4287 	       the arg type and paramName points to the first letter.
4288 	       So let's take one char off paramName and see if we're
4289 	       pointing at an alpha-numeric char.  However if *pArg is
4290 	       0xffff or 0xfffe then the param has no name, the former
4291 	       meaning that the next WORD is the type, the latter
4292 	       meaning that the next WORD is an offset to the type. */
4293 
4294 	    if(*pArg == 0xffff || *pArg == 0xfffe)
4295 	        paramName = NULL;
4296 
4297 	    HaveOffs = !(*pArg & 1);
4298 	    pArg++;
4299 
4300             TRACE_(typelib)("param %d: paramName %s, *pArg %#x\n",
4301                 param, debugstr_a(paramName), *pArg);
4302 
4303 	    if(HaveOffs) { /* the next word is an offset to type */
4304 	        pType = (WORD*)(pBlk + *pArg);
4305 		SLTG_DoElem(pType, pBlk,
4306 			    &pFuncDesc->funcdesc.lprgelemdescParam[param], ref_lookup);
4307 		pArg++;
4308 	    } else {
4309 		pArg = SLTG_DoElem(pArg, pBlk,
4310                                    &pFuncDesc->funcdesc.lprgelemdescParam[param], ref_lookup);
4311 	    }
4312 
4313 	    /* Are we an optional param ? */
4314 	    if(pFuncDesc->funcdesc.cParams - param <=
4315 	       pFuncDesc->funcdesc.cParamsOpt)
4316 	      pFuncDesc->funcdesc.lprgelemdescParam[param].u.paramdesc.wParamFlags |= PARAMFLAG_FOPT;
4317 
4318 	    if(paramName) {
4319 	        pFuncDesc->pParamDesc[param].Name = SLTG_ReadName(pNameTable,
4320 	                paramName - pNameTable, pTI->pTypeLib);
4321 	    } else {
4322 	        pFuncDesc->pParamDesc[param].Name = pFuncDesc->Name;
4323 	    }
4324 	}
4325     }
4326     pTI->typeattr.cFuncs = cFuncs;
4327 }
4328 
4329 static void SLTG_ProcessCoClass(char *pBlk, ITypeInfoImpl *pTI,
4330 				char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
4331 				SLTG_TypeInfoTail *pTITail)
4332 {
4333     char *pFirstItem;
4334     sltg_ref_lookup_t *ref_lookup = NULL;
4335 
4336     if(pTIHeader->href_table != 0xffffffff) {
4337         ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
4338 		    pNameTable);
4339     }
4340 
4341     pFirstItem = pBlk;
4342 
4343     if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
4344         SLTG_DoImpls(pFirstItem, pTI, FALSE, ref_lookup);
4345     }
4346     heap_free(ref_lookup);
4347 }
4348 
4349 
4350 static void SLTG_ProcessInterface(char *pBlk, ITypeInfoImpl *pTI,
4351 				  char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
4352 				  const SLTG_TypeInfoTail *pTITail, const BYTE *hlp_strings)
4353 {
4354     char *pFirstItem;
4355     sltg_ref_lookup_t *ref_lookup = NULL;
4356 
4357     if(pTIHeader->href_table != 0xffffffff) {
4358         ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
4359 		    pNameTable);
4360     }
4361 
4362     pFirstItem = pBlk;
4363 
4364     if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
4365         SLTG_DoImpls(pFirstItem, pTI, TRUE, ref_lookup);
4366     }
4367 
4368     if (pTITail->funcs_off != 0xffff)
4369         SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup, hlp_strings);
4370 
4371     heap_free(ref_lookup);
4372 
4373     if (TRACE_ON(typelib))
4374         dump_TLBFuncDesc(pTI->funcdescs, pTI->typeattr.cFuncs);
4375 }
4376 
4377 static void SLTG_ProcessRecord(char *pBlk, ITypeInfoImpl *pTI,
4378 			       const char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
4379 			       const SLTG_TypeInfoTail *pTITail, const BYTE *hlp_strings)
4380 {
4381   SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, NULL, hlp_strings);
4382 }
4383 
4384 static void SLTG_ProcessAlias(char *pBlk, ITypeInfoImpl *pTI,
4385 			      char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
4386 			      const SLTG_TypeInfoTail *pTITail)
4387 {
4388   WORD *pType;
4389   sltg_ref_lookup_t *ref_lookup = NULL;
4390 
4391   if (pTITail->simple_alias) {
4392       /* if simple alias, no more processing required */
4393       pTI->tdescAlias = heap_alloc_zero(sizeof(TYPEDESC));
4394       pTI->tdescAlias->vt = pTITail->tdescalias_vt;
4395       return;
4396   }
4397 
4398   if(pTIHeader->href_table != 0xffffffff) {
4399       ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
4400 		  pNameTable);
4401   }
4402 
4403   /* otherwise it is an offset to a type */
4404   pType = (WORD *)(pBlk + pTITail->tdescalias_vt);
4405 
4406   pTI->tdescAlias = heap_alloc(sizeof(TYPEDESC));
4407   SLTG_DoType(pType, pBlk, pTI->tdescAlias, ref_lookup);
4408 
4409   heap_free(ref_lookup);
4410 }
4411 
4412 static void SLTG_ProcessDispatch(char *pBlk, ITypeInfoImpl *pTI,
4413 				 char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
4414 				 const SLTG_TypeInfoTail *pTITail, const BYTE *hlp_strings)
4415 {
4416   sltg_ref_lookup_t *ref_lookup = NULL;
4417   if (pTIHeader->href_table != 0xffffffff)
4418       ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
4419                                   pNameTable);
4420 
4421   if (pTITail->vars_off != 0xffff)
4422     SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, ref_lookup, hlp_strings);
4423 
4424   if (pTITail->funcs_off != 0xffff)
4425     SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup, hlp_strings);
4426 
4427   if (pTITail->impls_off != 0xffff)
4428     SLTG_DoImpls(pBlk + pTITail->impls_off, pTI, FALSE, ref_lookup);
4429 
4430   /* this is necessary to cope with MSFT typelibs that set cFuncs to the number
4431    * of dispinterface functions including the IDispatch ones, so
4432    * ITypeInfo::GetFuncDesc takes the real value for cFuncs from cbSizeVft */
4433   pTI->typeattr.cbSizeVft = pTI->typeattr.cFuncs * pTI->pTypeLib->ptr_size;
4434 
4435   heap_free(ref_lookup);
4436   if (TRACE_ON(typelib))
4437       dump_TLBFuncDesc(pTI->funcdescs, pTI->typeattr.cFuncs);
4438 }
4439 
4440 static void SLTG_ProcessEnum(char *pBlk, ITypeInfoImpl *pTI,
4441 			     const char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
4442 			     const SLTG_TypeInfoTail *pTITail, const BYTE *hlp_strings)
4443 {
4444   SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, NULL, hlp_strings);
4445 }
4446 
4447 static void SLTG_ProcessModule(char *pBlk, ITypeInfoImpl *pTI,
4448 			       char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
4449 			       const SLTG_TypeInfoTail *pTITail, const BYTE *hlp_strings)
4450 {
4451   sltg_ref_lookup_t *ref_lookup = NULL;
4452   if (pTIHeader->href_table != 0xffffffff)
4453       ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
4454                                   pNameTable);
4455 
4456   if (pTITail->vars_off != 0xffff)
4457     SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, ref_lookup, hlp_strings);
4458 
4459   if (pTITail->funcs_off != 0xffff)
4460     SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup, hlp_strings);
4461   heap_free(ref_lookup);
4462   if (TRACE_ON(typelib))
4463     dump_TypeInfo(pTI);
4464 }
4465 
4466 /* Because SLTG_OtherTypeInfo is such a painful struct, we make a more
4467    manageable copy of it into this */
4468 typedef struct {
4469   char *index_name;
4470   char *other_name;
4471   WORD res1a;
4472   WORD name_offs;
4473   WORD hlpstr_len;
4474   char *extra;
4475   WORD res20;
4476   DWORD helpcontext;
4477   WORD res26;
4478   GUID uuid;
4479   WORD typekind;
4480 } SLTG_InternalOtherTypeInfo;
4481 
4482 /****************************************************************************
4483  *	ITypeLib2_Constructor_SLTG
4484  *
4485  * loading a SLTG typelib from an in-memory image
4486  */
4487 static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength)
4488 {
4489     ITypeLibImpl *pTypeLibImpl;
4490     SLTG_Header *pHeader;
4491     SLTG_BlkEntry *pBlkEntry;
4492     SLTG_Magic *pMagic;
4493     SLTG_Index *pIndex;
4494     SLTG_Pad9 *pPad9;
4495     LPVOID pBlk, pFirstBlk;
4496     SLTG_LibBlk *pLibBlk;
4497     SLTG_InternalOtherTypeInfo *pOtherTypeInfoBlks;
4498     char *pNameTable, *ptr;
4499     const BYTE *hlp_strings;
4500     int i;
4501     DWORD len, order;
4502     ITypeInfoImpl **ppTypeInfoImpl;
4503 
4504     TRACE_(typelib)("%p, TLB length = %d\n", pLib, dwTLBLength);
4505 
4506 
4507     pTypeLibImpl = TypeLibImpl_Constructor();
4508     if (!pTypeLibImpl) return NULL;
4509 
4510     pHeader = pLib;
4511 
4512     TRACE_(typelib)("header:\n");
4513     TRACE_(typelib)("\tmagic=0x%08x, file blocks = %d\n", pHeader->SLTG_magic,
4514 	  pHeader->nrOfFileBlks );
4515     if (pHeader->SLTG_magic != SLTG_SIGNATURE) {
4516 	FIXME_(typelib)("Header type magic 0x%08x not supported.\n",
4517 	      pHeader->SLTG_magic);
4518 	return NULL;
4519     }
4520 
4521     /* There are pHeader->nrOfFileBlks - 2 TypeInfo records in this typelib */
4522     pTypeLibImpl->TypeInfoCount = pHeader->nrOfFileBlks - 2;
4523 
4524     /* This points to pHeader->nrOfFileBlks - 1 of SLTG_BlkEntry */
4525     pBlkEntry = (SLTG_BlkEntry*)(pHeader + 1);
4526 
4527     /* Next we have a magic block */
4528     pMagic = (SLTG_Magic*)(pBlkEntry + pHeader->nrOfFileBlks - 1);
4529 
4530     /* Let's see if we're still in sync */
4531     if(memcmp(pMagic->CompObj_magic, SLTG_COMPOBJ_MAGIC,
4532 	      sizeof(SLTG_COMPOBJ_MAGIC))) {
4533         FIXME_(typelib)("CompObj magic = %s\n", pMagic->CompObj_magic);
4534 	return NULL;
4535     }
4536     if(memcmp(pMagic->dir_magic, SLTG_DIR_MAGIC,
4537 	      sizeof(SLTG_DIR_MAGIC))) {
4538         FIXME_(typelib)("dir magic = %s\n", pMagic->dir_magic);
4539 	return NULL;
4540     }
4541 
4542     pIndex = (SLTG_Index*)(pMagic+1);
4543 
4544     pPad9 = (SLTG_Pad9*)(pIndex + pTypeLibImpl->TypeInfoCount);
4545 
4546     pFirstBlk = pPad9 + 1;
4547 
4548     /* We'll set up a ptr to the main library block, which is the last one. */
4549 
4550     for(pBlk = pFirstBlk, order = pHeader->first_blk - 1;
4551 	  pBlkEntry[order].next != 0;
4552 	  order = pBlkEntry[order].next - 1) {
4553        pBlk = (char*)pBlk + pBlkEntry[order].len;
4554     }
4555     pLibBlk = pBlk;
4556 
4557     len = SLTG_ReadLibBlk(pLibBlk, pTypeLibImpl);
4558 
4559     /* Now there are 0x40 bytes of 0xffff with the numbers 0 to TypeInfoCount
4560        interspersed */
4561 
4562     len += 0x40;
4563 
4564     /* And now TypeInfoCount of SLTG_OtherTypeInfo */
4565     pTypeLibImpl->TypeInfoCount = *(WORD *)((char *)pLibBlk + len);
4566     len += sizeof(WORD);
4567 
4568     pOtherTypeInfoBlks = heap_alloc_zero(sizeof(*pOtherTypeInfoBlks) * pTypeLibImpl->TypeInfoCount);
4569 
4570     ptr = (char*)pLibBlk + len;
4571 
4572     for(i = 0; i < pTypeLibImpl->TypeInfoCount; i++) {
4573 	WORD w, extra;
4574 	len = 0;
4575 
4576 	w = *(WORD*)ptr;
4577 	if(w != 0xffff) {
4578 	    len += w;
4579 	    pOtherTypeInfoBlks[i].index_name = heap_alloc(w+1);
4580 	    memcpy(pOtherTypeInfoBlks[i].index_name, ptr + 2, w);
4581 	    pOtherTypeInfoBlks[i].index_name[w] = '\0';
4582 	}
4583 	w = *(WORD*)(ptr + 2 + len);
4584 	if(w != 0xffff) {
4585 	    TRACE_(typelib)("\twith %s\n", debugstr_an(ptr + 4 + len, w));
4586 	    pOtherTypeInfoBlks[i].other_name = heap_alloc(w+1);
4587 	    memcpy(pOtherTypeInfoBlks[i].other_name, ptr + 4 + len, w);
4588 	    pOtherTypeInfoBlks[i].other_name[w] = '\0';
4589 	    len += w;
4590 	}
4591 	pOtherTypeInfoBlks[i].res1a = *(WORD*)(ptr + 4 + len);
4592 	pOtherTypeInfoBlks[i].name_offs = *(WORD*)(ptr + 6 + len);
4593 	extra = pOtherTypeInfoBlks[i].hlpstr_len = *(WORD*)(ptr + 8 + len);
4594 	if(extra) {
4595 	    pOtherTypeInfoBlks[i].extra = heap_alloc(extra);
4596 	    memcpy(pOtherTypeInfoBlks[i].extra, ptr + 10 + len, extra);
4597 	    len += extra;
4598 	}
4599 	pOtherTypeInfoBlks[i].res20 = *(WORD*)(ptr + 10 + len);
4600 	pOtherTypeInfoBlks[i].helpcontext = *(DWORD*)(ptr + 12 + len);
4601 	pOtherTypeInfoBlks[i].res26 = *(WORD*)(ptr + 16 + len);
4602 	memcpy(&pOtherTypeInfoBlks[i].uuid, ptr + 18 + len, sizeof(GUID));
4603 	pOtherTypeInfoBlks[i].typekind = *(WORD*)(ptr + 18 + sizeof(GUID) + len);
4604 	len += sizeof(SLTG_OtherTypeInfo);
4605 	ptr += len;
4606     }
4607 
4608     /* Get the next DWORD */
4609     len = *(DWORD*)ptr;
4610 
4611     hlp_strings = (const BYTE *)ptr + sizeof(DWORD);
4612     TRACE("max help string length %#x, help strings length %#x\n",
4613         *(WORD *)hlp_strings, *(DWORD *)(hlp_strings + 2));
4614 
4615     /* Now add this to pLibBLk look at what we're pointing at and
4616        possibly add 0x20, then add 0x216, sprinkle a bit a magic
4617        dust and we should be pointing at the beginning of the name
4618        table */
4619 
4620     pNameTable = (char*)pLibBlk + len;
4621 
4622    switch(*(WORD*)pNameTable) {
4623    case 0xffff:
4624        break;
4625    case 0x0200:
4626        pNameTable += 0x20;
4627        break;
4628    default:
4629        FIXME_(typelib)("pNameTable jump = %x\n", *(WORD*)pNameTable);
4630        break;
4631    }
4632 
4633     pNameTable += 0x216;
4634 
4635     pNameTable += 2;
4636 
4637     TRACE_(typelib)("Library name is %s\n", pNameTable + pLibBlk->name);
4638 
4639     pTypeLibImpl->Name = SLTG_ReadName(pNameTable, pLibBlk->name, pTypeLibImpl);
4640 
4641 
4642     /* Hopefully we now have enough ptrs set up to actually read in
4643        some TypeInfos.  It's not clear which order to do them in, so
4644        I'll just follow the links along the BlkEntry chain and read
4645        them in the order in which they are in the file */
4646 
4647     pTypeLibImpl->typeinfos = heap_alloc_zero(pTypeLibImpl->TypeInfoCount * sizeof(ITypeInfoImpl*));
4648     ppTypeInfoImpl = pTypeLibImpl->typeinfos;
4649 
4650     for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0;
4651 	pBlkEntry[order].next != 0;
4652 	order = pBlkEntry[order].next - 1, i++) {
4653 
4654       SLTG_TypeInfoHeader *pTIHeader;
4655       SLTG_TypeInfoTail *pTITail;
4656       SLTG_MemberHeader *pMemHeader;
4657 
4658       if(strcmp(pBlkEntry[order].index_string + (char*)pMagic, pOtherTypeInfoBlks[i].index_name)) {
4659         FIXME_(typelib)("Index strings don't match\n");
4660         heap_free(pOtherTypeInfoBlks);
4661         return NULL;
4662       }
4663 
4664       pTIHeader = pBlk;
4665       if(pTIHeader->magic != SLTG_TIHEADER_MAGIC) {
4666 	FIXME_(typelib)("TypeInfoHeader magic = %04x\n", pTIHeader->magic);
4667        heap_free(pOtherTypeInfoBlks);
4668 	return NULL;
4669       }
4670       TRACE_(typelib)("pTIHeader->res06 = %x, pTIHeader->res0e = %x, "
4671         "pTIHeader->res16 = %x, pTIHeader->res1e = %x\n",
4672         pTIHeader->res06, pTIHeader->res0e, pTIHeader->res16, pTIHeader->res1e);
4673 
4674       *ppTypeInfoImpl = ITypeInfoImpl_Constructor();
4675       (*ppTypeInfoImpl)->pTypeLib = pTypeLibImpl;
4676       (*ppTypeInfoImpl)->index = i;
4677       (*ppTypeInfoImpl)->Name = SLTG_ReadName(pNameTable, pOtherTypeInfoBlks[i].name_offs, pTypeLibImpl);
4678       (*ppTypeInfoImpl)->dwHelpContext = pOtherTypeInfoBlks[i].helpcontext;
4679       (*ppTypeInfoImpl)->DocString = decode_string(hlp_strings, pOtherTypeInfoBlks[i].extra, pOtherTypeInfoBlks[i].hlpstr_len, pTypeLibImpl);
4680       (*ppTypeInfoImpl)->guid = TLB_append_guid(&pTypeLibImpl->guid_list, &pOtherTypeInfoBlks[i].uuid, 2);
4681       (*ppTypeInfoImpl)->typeattr.typekind = pTIHeader->typekind;
4682       (*ppTypeInfoImpl)->typeattr.wMajorVerNum = pTIHeader->major_version;
4683       (*ppTypeInfoImpl)->typeattr.wMinorVerNum = pTIHeader->minor_version;
4684       (*ppTypeInfoImpl)->typeattr.wTypeFlags =
4685 	(pTIHeader->typeflags1 >> 3) | (pTIHeader->typeflags2 << 5);
4686 
4687       if((*ppTypeInfoImpl)->typeattr.wTypeFlags & TYPEFLAG_FDUAL)
4688 	(*ppTypeInfoImpl)->typeattr.typekind = TKIND_DISPATCH;
4689 
4690       if((pTIHeader->typeflags1 & 7) != 2)
4691 	FIXME_(typelib)("typeflags1 = %02x\n", pTIHeader->typeflags1);
4692       if(pTIHeader->typeflags3 != 2)
4693 	FIXME_(typelib)("typeflags3 = %02x\n", pTIHeader->typeflags3);
4694 
4695       TRACE_(typelib)("TypeInfo %s of kind %s guid %s typeflags %04x\n",
4696 	    debugstr_w(TLB_get_bstr((*ppTypeInfoImpl)->Name)),
4697 	    typekind_desc[pTIHeader->typekind],
4698 	    debugstr_guid(TLB_get_guidref((*ppTypeInfoImpl)->guid)),
4699 	    (*ppTypeInfoImpl)->typeattr.wTypeFlags);
4700 
4701       pMemHeader = (SLTG_MemberHeader*)((char *)pBlk + pTIHeader->elem_table);
4702 
4703       pTITail = (SLTG_TypeInfoTail*)((char *)(pMemHeader + 1) + pMemHeader->cbExtra);
4704 
4705       (*ppTypeInfoImpl)->typeattr.cbAlignment = pTITail->cbAlignment;
4706       (*ppTypeInfoImpl)->typeattr.cbSizeInstance = pTITail->cbSizeInstance;
4707       (*ppTypeInfoImpl)->typeattr.cbSizeVft = pTITail->cbSizeVft;
4708 
4709       switch(pTIHeader->typekind) {
4710       case TKIND_ENUM:
4711 	SLTG_ProcessEnum((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
4712                          pTIHeader, pTITail, hlp_strings);
4713 	break;
4714 
4715       case TKIND_RECORD:
4716 	SLTG_ProcessRecord((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
4717                            pTIHeader, pTITail, hlp_strings);
4718 	break;
4719 
4720       case TKIND_INTERFACE:
4721 	SLTG_ProcessInterface((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
4722                               pTIHeader, pTITail, hlp_strings);
4723 	break;
4724 
4725       case TKIND_COCLASS:
4726 	SLTG_ProcessCoClass((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
4727                             pTIHeader, pTITail);
4728 	break;
4729 
4730       case TKIND_ALIAS:
4731 	SLTG_ProcessAlias((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
4732                           pTIHeader, pTITail);
4733 	break;
4734 
4735       case TKIND_DISPATCH:
4736 	SLTG_ProcessDispatch((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
4737                              pTIHeader, pTITail, hlp_strings);
4738 	break;
4739 
4740       case TKIND_MODULE:
4741 	SLTG_ProcessModule((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
4742                            pTIHeader, pTITail, hlp_strings);
4743 	break;
4744 
4745       default:
4746 	FIXME("Not processing typekind %d\n", pTIHeader->typekind);
4747 	break;
4748 
4749       }
4750 
4751       /* could get cFuncs, cVars and cImplTypes from here
4752 		       but we've already set those */
4753 #define X(x) TRACE_(typelib)("tt "#x": %x\n",pTITail->res##x);
4754       X(06);
4755       X(16);
4756       X(18);
4757       X(1a);
4758       X(1e);
4759       X(24);
4760       X(26);
4761       X(2a);
4762       X(2c);
4763       X(2e);
4764       X(30);
4765       X(32);
4766       X(34);
4767 #undef X
4768       ++ppTypeInfoImpl;
4769       pBlk = (char*)pBlk + pBlkEntry[order].len;
4770     }
4771 
4772     if(i != pTypeLibImpl->TypeInfoCount) {
4773       FIXME("Somehow processed %d TypeInfos\n", i);
4774       heap_free(pOtherTypeInfoBlks);
4775       return NULL;
4776     }
4777 
4778     heap_free(pOtherTypeInfoBlks);
4779     return &pTypeLibImpl->ITypeLib2_iface;
4780 }
4781 
4782 static HRESULT WINAPI ITypeLib2_fnQueryInterface(ITypeLib2 *iface, REFIID riid, void **ppv)
4783 {
4784     ITypeLibImpl *This = impl_from_ITypeLib2(iface);
4785 
4786     TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
4787 
4788     if(IsEqualIID(riid, &IID_IUnknown) ||
4789        IsEqualIID(riid,&IID_ITypeLib)||
4790        IsEqualIID(riid,&IID_ITypeLib2))
4791     {
4792         *ppv = &This->ITypeLib2_iface;
4793     }
4794     else if(IsEqualIID(riid, &IID_ICreateTypeLib) ||
4795              IsEqualIID(riid, &IID_ICreateTypeLib2))
4796     {
4797         *ppv = &This->ICreateTypeLib2_iface;
4798     }
4799     else
4800     {
4801         *ppv = NULL;
4802         TRACE("-- Interface: E_NOINTERFACE\n");
4803         return E_NOINTERFACE;
4804     }
4805 
4806     IUnknown_AddRef((IUnknown*)*ppv);
4807     return S_OK;
4808 }
4809 
4810 static ULONG WINAPI ITypeLib2_fnAddRef( ITypeLib2 *iface)
4811 {
4812     ITypeLibImpl *This = impl_from_ITypeLib2(iface);
4813     ULONG ref = InterlockedIncrement(&This->ref);
4814 
4815     TRACE("(%p) ref=%u\n", This, ref);
4816 
4817     return ref;
4818 }
4819 
4820 static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface)
4821 {
4822     ITypeLibImpl *This = impl_from_ITypeLib2(iface);
4823     ULONG ref = InterlockedDecrement(&This->ref);
4824 
4825     TRACE("(%p) ref=%u\n",This, ref);
4826 
4827     if (!ref)
4828     {
4829       TLBImpLib *pImpLib, *pImpLibNext;
4830       TLBRefType *ref_type, *ref_type_next;
4831       TLBString *tlbstr, *tlbstr_next;
4832       TLBGuid *tlbguid, *tlbguid_next;
4833       int i;
4834 
4835       /* remove cache entry */
4836       if(This->path)
4837       {
4838           TRACE("removing from cache list\n");
4839           EnterCriticalSection(&cache_section);
4840           if(This->entry.next)
4841               list_remove(&This->entry);
4842           LeaveCriticalSection(&cache_section);
4843           heap_free(This->path);
4844       }
4845       TRACE(" destroying ITypeLib(%p)\n",This);
4846 
4847       LIST_FOR_EACH_ENTRY_SAFE(tlbstr, tlbstr_next, &This->string_list, TLBString, entry) {
4848           list_remove(&tlbstr->entry);
4849           SysFreeString(tlbstr->str);
4850           heap_free(tlbstr);
4851       }
4852 
4853       LIST_FOR_EACH_ENTRY_SAFE(tlbstr, tlbstr_next, &This->name_list, TLBString, entry) {
4854           list_remove(&tlbstr->entry);
4855           SysFreeString(tlbstr->str);
4856           heap_free(tlbstr);
4857       }
4858 
4859       LIST_FOR_EACH_ENTRY_SAFE(tlbguid, tlbguid_next, &This->guid_list, TLBGuid, entry) {
4860           list_remove(&tlbguid->entry);
4861           heap_free(tlbguid);
4862       }
4863 
4864       TLB_FreeCustData(&This->custdata_list);
4865 
4866       for (i = 0; i < This->ctTypeDesc; i++)
4867           if (This->pTypeDesc[i].vt == VT_CARRAY)
4868               heap_free(This->pTypeDesc[i].u.lpadesc);
4869 
4870       heap_free(This->pTypeDesc);
4871 
4872       LIST_FOR_EACH_ENTRY_SAFE(pImpLib, pImpLibNext, &This->implib_list, TLBImpLib, entry)
4873       {
4874           if (pImpLib->pImpTypeLib)
4875               ITypeLib2_Release(&pImpLib->pImpTypeLib->ITypeLib2_iface);
4876           SysFreeString(pImpLib->name);
4877 
4878           list_remove(&pImpLib->entry);
4879           heap_free(pImpLib);
4880       }
4881 
4882       LIST_FOR_EACH_ENTRY_SAFE(ref_type, ref_type_next, &This->ref_list, TLBRefType, entry)
4883       {
4884           list_remove(&ref_type->entry);
4885           heap_free(ref_type);
4886       }
4887 
4888       for (i = 0; i < This->TypeInfoCount; ++i){
4889           heap_free(This->typeinfos[i]->tdescAlias);
4890           ITypeInfoImpl_Destroy(This->typeinfos[i]);
4891       }
4892       heap_free(This->typeinfos);
4893       heap_free(This);
4894       return 0;
4895     }
4896 
4897     return ref;
4898 }
4899 
4900 /* ITypeLib::GetTypeInfoCount
4901  *
4902  * Returns the number of type descriptions in the type library
4903  */
4904 static UINT WINAPI ITypeLib2_fnGetTypeInfoCount( ITypeLib2 *iface)
4905 {
4906     ITypeLibImpl *This = impl_from_ITypeLib2(iface);
4907     TRACE("(%p)->count is %d\n",This, This->TypeInfoCount);
4908     return This->TypeInfoCount;
4909 }
4910 
4911 /* ITypeLib::GetTypeInfo
4912  *
4913  * retrieves the specified type description in the library.
4914  */
4915 static HRESULT WINAPI ITypeLib2_fnGetTypeInfo(
4916     ITypeLib2 *iface,
4917     UINT index,
4918     ITypeInfo **ppTInfo)
4919 {
4920     ITypeLibImpl *This = impl_from_ITypeLib2(iface);
4921 
4922     TRACE("%p %u %p\n", This, index, ppTInfo);
4923 
4924     if(!ppTInfo)
4925         return E_INVALIDARG;
4926 
4927     if(index >= This->TypeInfoCount)
4928         return TYPE_E_ELEMENTNOTFOUND;
4929 
4930     *ppTInfo = (ITypeInfo *)&This->typeinfos[index]->ITypeInfo2_iface;
4931     ITypeInfo_AddRef(*ppTInfo);
4932 
4933     return S_OK;
4934 }
4935 
4936 
4937 /* ITypeLibs::GetTypeInfoType
4938  *
4939  * Retrieves the type of a type description.
4940  */
4941 static HRESULT WINAPI ITypeLib2_fnGetTypeInfoType(
4942     ITypeLib2 *iface,
4943     UINT index,
4944     TYPEKIND *pTKind)
4945 {
4946     ITypeLibImpl *This = impl_from_ITypeLib2(iface);
4947 
4948     TRACE("(%p, %d, %p)\n", This, index, pTKind);
4949 
4950     if(!pTKind)
4951         return E_INVALIDARG;
4952 
4953     if(index >= This->TypeInfoCount)
4954         return TYPE_E_ELEMENTNOTFOUND;
4955 
4956     *pTKind = This->typeinfos[index]->typeattr.typekind;
4957 
4958     return S_OK;
4959 }
4960 
4961 /* ITypeLib::GetTypeInfoOfGuid
4962  *
4963  * Retrieves the type description that corresponds to the specified GUID.
4964  *
4965  */
4966 static HRESULT WINAPI ITypeLib2_fnGetTypeInfoOfGuid(
4967     ITypeLib2 *iface,
4968     REFGUID guid,
4969     ITypeInfo **ppTInfo)
4970 {
4971     ITypeLibImpl *This = impl_from_ITypeLib2(iface);
4972     int i;
4973 
4974     TRACE("%p %s %p\n", This, debugstr_guid(guid), ppTInfo);
4975 
4976     for(i = 0; i < This->TypeInfoCount; ++i){
4977         if(IsEqualIID(TLB_get_guid_null(This->typeinfos[i]->guid), guid)){
4978             *ppTInfo = (ITypeInfo *)&This->typeinfos[i]->ITypeInfo2_iface;
4979             ITypeInfo_AddRef(*ppTInfo);
4980             return S_OK;
4981         }
4982     }
4983 
4984     return TYPE_E_ELEMENTNOTFOUND;
4985 }
4986 
4987 /* ITypeLib::GetLibAttr
4988  *
4989  * Retrieves the structure that contains the library's attributes.
4990  *
4991  */
4992 static HRESULT WINAPI ITypeLib2_fnGetLibAttr(
4993 	ITypeLib2 *iface,
4994 	LPTLIBATTR *attr)
4995 {
4996     ITypeLibImpl *This = impl_from_ITypeLib2(iface);
4997 
4998     TRACE("(%p, %p)\n", This, attr);
4999 
5000     if (!attr) return E_INVALIDARG;
5001 
5002     *attr = heap_alloc(sizeof(**attr));
5003     if (!*attr) return E_OUTOFMEMORY;
5004 
5005     (*attr)->guid = *TLB_get_guid_null(This->guid);
5006     (*attr)->lcid = This->set_lcid;
5007     (*attr)->syskind = This->syskind;
5008     (*attr)->wMajorVerNum = This->ver_major;
5009     (*attr)->wMinorVerNum = This->ver_minor;
5010     (*attr)->wLibFlags = This->libflags;
5011 
5012     return S_OK;
5013 }
5014 
5015 /* ITypeLib::GetTypeComp
5016  *
5017  * Enables a client compiler to bind to a library's types, variables,
5018  * constants, and global functions.
5019  *
5020  */
5021 static HRESULT WINAPI ITypeLib2_fnGetTypeComp(
5022 	ITypeLib2 *iface,
5023 	ITypeComp **ppTComp)
5024 {
5025     ITypeLibImpl *This = impl_from_ITypeLib2(iface);
5026 
5027     TRACE("(%p)->(%p)\n",This,ppTComp);
5028     *ppTComp = &This->ITypeComp_iface;
5029     ITypeComp_AddRef(*ppTComp);
5030 
5031     return S_OK;
5032 }
5033 
5034 /* ITypeLib::GetDocumentation
5035  *
5036  * Retrieves the library's documentation string, the complete Help file name
5037  * and path, and the context identifier for the library Help topic in the Help
5038  * file.
5039  *
5040  * On a successful return all non-null BSTR pointers will have been set,
5041  * possibly to NULL.
5042  */
5043 static HRESULT WINAPI ITypeLib2_fnGetDocumentation(
5044     ITypeLib2 *iface,
5045     INT index,
5046     BSTR *pBstrName,
5047     BSTR *pBstrDocString,
5048     DWORD *pdwHelpContext,
5049     BSTR *pBstrHelpFile)
5050 {
5051     ITypeLibImpl *This = impl_from_ITypeLib2(iface);
5052     HRESULT result = E_INVALIDARG;
5053     ITypeInfo *pTInfo;
5054 
5055     TRACE("(%p) index %d Name(%p) DocString(%p) HelpContext(%p) HelpFile(%p)\n",
5056         This, index,
5057         pBstrName, pBstrDocString,
5058         pdwHelpContext, pBstrHelpFile);
5059 
5060     if(index<0)
5061     {
5062         /* documentation for the typelib */
5063         if(pBstrName)
5064         {
5065             if (This->Name)
5066             {
5067                 if(!(*pBstrName = SysAllocString(TLB_get_bstr(This->Name))))
5068                     goto memerr1;
5069             }
5070             else
5071                 *pBstrName = NULL;
5072         }
5073         if(pBstrDocString)
5074         {
5075             if (This->DocString)
5076             {
5077                 if(!(*pBstrDocString = SysAllocString(TLB_get_bstr(This->DocString))))
5078                     goto memerr2;
5079             }
5080             else
5081                 *pBstrDocString = NULL;
5082         }
5083         if(pdwHelpContext)
5084         {
5085             *pdwHelpContext = This->dwHelpContext;
5086         }
5087         if(pBstrHelpFile)
5088         {
5089             if (This->HelpFile)
5090             {
5091                 if(!(*pBstrHelpFile = SysAllocString(TLB_get_bstr(This->HelpFile))))
5092                     goto memerr3;
5093             }
5094             else
5095                 *pBstrHelpFile = NULL;
5096         }
5097 
5098         result = S_OK;
5099     }
5100     else
5101     {
5102         /* for a typeinfo */
5103         result = ITypeLib2_fnGetTypeInfo(iface, index, &pTInfo);
5104 
5105         if(SUCCEEDED(result))
5106         {
5107             result = ITypeInfo_GetDocumentation(pTInfo,
5108                                           MEMBERID_NIL,
5109                                           pBstrName,
5110                                           pBstrDocString,
5111                                           pdwHelpContext, pBstrHelpFile);
5112 
5113             ITypeInfo_Release(pTInfo);
5114         }
5115     }
5116     return result;
5117 memerr3:
5118     if (pBstrDocString) SysFreeString (*pBstrDocString);
5119 memerr2:
5120     if (pBstrName) SysFreeString (*pBstrName);
5121 memerr1:
5122     return STG_E_INSUFFICIENTMEMORY;
5123 }
5124 
5125 /* ITypeLib::IsName
5126  *
5127  * Indicates whether a passed-in string contains the name of a type or member
5128  * described in the library.
5129  *
5130  */
5131 static HRESULT WINAPI ITypeLib2_fnIsName(
5132 	ITypeLib2 *iface,
5133 	LPOLESTR szNameBuf,
5134 	ULONG lHashVal,
5135 	BOOL *pfName)
5136 {
5137     ITypeLibImpl *This = impl_from_ITypeLib2(iface);
5138     int tic;
5139     UINT nNameBufLen = (lstrlenW(szNameBuf)+1)*sizeof(WCHAR), fdc, vrc;
5140 
5141     TRACE("(%p)->(%s,%08x,%p)\n", This, debugstr_w(szNameBuf), lHashVal,
5142 	  pfName);
5143 
5144     *pfName=TRUE;
5145     for(tic = 0; tic < This->TypeInfoCount; ++tic){
5146         ITypeInfoImpl *pTInfo = This->typeinfos[tic];
5147         if(!TLB_str_memcmp(szNameBuf, pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
5148         for(fdc = 0; fdc < pTInfo->typeattr.cFuncs; ++fdc) {
5149             TLBFuncDesc *pFInfo = &pTInfo->funcdescs[fdc];
5150             int pc;
5151             if(!TLB_str_memcmp(szNameBuf, pFInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
5152             for(pc=0; pc < pFInfo->funcdesc.cParams; pc++){
5153                 if(!TLB_str_memcmp(szNameBuf, pFInfo->pParamDesc[pc].Name, nNameBufLen))
5154                     goto ITypeLib2_fnIsName_exit;
5155             }
5156         }
5157         for(vrc = 0; vrc < pTInfo->typeattr.cVars; ++vrc){
5158             TLBVarDesc *pVInfo = &pTInfo->vardescs[vrc];
5159             if(!TLB_str_memcmp(szNameBuf, pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
5160         }
5161 
5162     }
5163     *pfName=FALSE;
5164 
5165 ITypeLib2_fnIsName_exit:
5166     TRACE("(%p)slow! search for %s: %sfound!\n", This,
5167           debugstr_w(szNameBuf), *pfName ? "" : "NOT ");
5168 
5169     return S_OK;
5170 }
5171 
5172 /* ITypeLib::FindName
5173  *
5174  * Finds occurrences of a type description in a type library. This may be used
5175  * to quickly verify that a name exists in a type library.
5176  *
5177  */
5178 static HRESULT WINAPI ITypeLib2_fnFindName(
5179 	ITypeLib2 *iface,
5180 	LPOLESTR name,
5181 	ULONG hash,
5182 	ITypeInfo **ppTInfo,
5183 	MEMBERID *memid,
5184 	UINT16 *found)
5185 {
5186     ITypeLibImpl *This = impl_from_ITypeLib2(iface);
5187     int tic;
5188     UINT count = 0;
5189     UINT len;
5190 
5191     TRACE("(%p)->(%s %u %p %p %p)\n", This, debugstr_w(name), hash, ppTInfo, memid, found);
5192 
5193     if ((!name && hash == 0) || !ppTInfo || !memid || !found)
5194         return E_INVALIDARG;
5195 
5196     len = (lstrlenW(name) + 1)*sizeof(WCHAR);
5197     for(tic = 0; count < *found && tic < This->TypeInfoCount; ++tic) {
5198         ITypeInfoImpl *pTInfo = This->typeinfos[tic];
5199         TLBVarDesc *var;
5200         UINT fdc;
5201 
5202         if(!TLB_str_memcmp(name, pTInfo->Name, len)) {
5203             memid[count] = MEMBERID_NIL;
5204             goto ITypeLib2_fnFindName_exit;
5205         }
5206 
5207         for(fdc = 0; fdc < pTInfo->typeattr.cFuncs; ++fdc) {
5208             TLBFuncDesc *func = &pTInfo->funcdescs[fdc];
5209 
5210             if(!TLB_str_memcmp(name, func->Name, len)) {
5211                 memid[count] = func->funcdesc.memid;
5212                 goto ITypeLib2_fnFindName_exit;
5213             }
5214         }
5215 
5216         var = TLB_get_vardesc_by_name(pTInfo->vardescs, pTInfo->typeattr.cVars, name);
5217         if (var) {
5218             memid[count] = var->vardesc.memid;
5219             goto ITypeLib2_fnFindName_exit;
5220         }
5221 
5222         continue;
5223 ITypeLib2_fnFindName_exit:
5224         ITypeInfo2_AddRef(&pTInfo->ITypeInfo2_iface);
5225         ppTInfo[count] = (ITypeInfo *)&pTInfo->ITypeInfo2_iface;
5226         count++;
5227     }
5228     TRACE("found %d typeinfos\n", count);
5229 
5230     *found = count;
5231 
5232     return S_OK;
5233 }
5234 
5235 /* ITypeLib::ReleaseTLibAttr
5236  *
5237  * Releases the TLIBATTR originally obtained from ITypeLib::GetLibAttr.
5238  *
5239  */
5240 static VOID WINAPI ITypeLib2_fnReleaseTLibAttr(
5241 	ITypeLib2 *iface,
5242 	TLIBATTR *pTLibAttr)
5243 {
5244     ITypeLibImpl *This = impl_from_ITypeLib2(iface);
5245     TRACE("(%p)->(%p)\n", This, pTLibAttr);
5246     heap_free(pTLibAttr);
5247 }
5248 
5249 /* ITypeLib2::GetCustData
5250  *
5251  * gets the custom data
5252  */
5253 static HRESULT WINAPI ITypeLib2_fnGetCustData(
5254 	ITypeLib2 * iface,
5255 	REFGUID guid,
5256         VARIANT *pVarVal)
5257 {
5258     ITypeLibImpl *This = impl_from_ITypeLib2(iface);
5259     TLBCustData *pCData;
5260 
5261     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(guid), pVarVal);
5262 
5263     pCData = TLB_get_custdata_by_guid(&This->custdata_list, guid);
5264     if(!pCData)
5265         return TYPE_E_ELEMENTNOTFOUND;
5266 
5267     VariantInit(pVarVal);
5268     VariantCopy(pVarVal, &pCData->data);
5269 
5270     return S_OK;
5271 }
5272 
5273 /* ITypeLib2::GetLibStatistics
5274  *
5275  * Returns statistics about a type library that are required for efficient
5276  * sizing of hash tables.
5277  *
5278  */
5279 static HRESULT WINAPI ITypeLib2_fnGetLibStatistics(
5280 	ITypeLib2 * iface,
5281         ULONG *pcUniqueNames,
5282 	ULONG *pcchUniqueNames)
5283 {
5284     ITypeLibImpl *This = impl_from_ITypeLib2(iface);
5285 
5286     FIXME("(%p): stub!\n", This);
5287 
5288     if(pcUniqueNames) *pcUniqueNames=1;
5289     if(pcchUniqueNames) *pcchUniqueNames=1;
5290     return S_OK;
5291 }
5292 
5293 /* ITypeLib2::GetDocumentation2
5294  *
5295  * Retrieves the library's documentation string, the complete Help file name
5296  * and path, the localization context to use, and the context ID for the
5297  * library Help topic in the Help file.
5298  *
5299  */
5300 static HRESULT WINAPI ITypeLib2_fnGetDocumentation2(
5301 	ITypeLib2 * iface,
5302         INT index,
5303 	LCID lcid,
5304 	BSTR *pbstrHelpString,
5305         DWORD *pdwHelpStringContext,
5306 	BSTR *pbstrHelpStringDll)
5307 {
5308     ITypeLibImpl *This = impl_from_ITypeLib2(iface);
5309     HRESULT result;
5310     ITypeInfo *pTInfo;
5311 
5312     FIXME("(%p) index %d lcid %d half implemented stub!\n", This, index, lcid);
5313 
5314     /* the help string should be obtained from the helpstringdll,
5315      * using the _DLLGetDocumentation function, based on the supplied
5316      * lcid. Nice to do sometime...
5317      */
5318     if(index<0)
5319     {
5320       /* documentation for the typelib */
5321       if(pbstrHelpString)
5322         *pbstrHelpString=SysAllocString(TLB_get_bstr(This->DocString));
5323       if(pdwHelpStringContext)
5324         *pdwHelpStringContext=This->dwHelpContext;
5325       if(pbstrHelpStringDll)
5326         *pbstrHelpStringDll=SysAllocString(TLB_get_bstr(This->HelpStringDll));
5327 
5328       result = S_OK;
5329     }
5330     else
5331     {
5332       /* for a typeinfo */
5333       result=ITypeLib2_GetTypeInfo(iface, index, &pTInfo);
5334 
5335       if(SUCCEEDED(result))
5336       {
5337         ITypeInfo2 * pTInfo2;
5338         result = ITypeInfo_QueryInterface(pTInfo,
5339                                           &IID_ITypeInfo2,
5340                                           (LPVOID*) &pTInfo2);
5341 
5342         if(SUCCEEDED(result))
5343         {
5344           result = ITypeInfo2_GetDocumentation2(pTInfo2,
5345                                            MEMBERID_NIL,
5346                                            lcid,
5347                                            pbstrHelpString,
5348                                            pdwHelpStringContext,
5349                                            pbstrHelpStringDll);
5350 
5351           ITypeInfo2_Release(pTInfo2);
5352         }
5353 
5354         ITypeInfo_Release(pTInfo);
5355       }
5356     }
5357     return result;
5358 }
5359 
5360 static HRESULT TLB_copy_all_custdata(struct list *custdata_list, CUSTDATA *pCustData)
5361 {
5362     TLBCustData *pCData;
5363     unsigned int ct;
5364     CUSTDATAITEM *cdi;
5365 
5366     ct = list_count(custdata_list);
5367 
5368     pCustData->prgCustData = CoTaskMemAlloc(ct * sizeof(CUSTDATAITEM));
5369     if(!pCustData->prgCustData)
5370         return E_OUTOFMEMORY;
5371 
5372     pCustData->cCustData = ct;
5373 
5374     cdi = pCustData->prgCustData;
5375     LIST_FOR_EACH_ENTRY(pCData, custdata_list, TLBCustData, entry){
5376         cdi->guid = *TLB_get_guid_null(pCData->guid);
5377         VariantCopy(&cdi->varValue, &pCData->data);
5378         ++cdi;
5379     }
5380 
5381     return S_OK;
5382 }
5383 
5384 
5385 /* ITypeLib2::GetAllCustData
5386  *
5387  * Gets all custom data items for the library.
5388  *
5389  */
5390 static HRESULT WINAPI ITypeLib2_fnGetAllCustData(
5391 	ITypeLib2 * iface,
5392         CUSTDATA *pCustData)
5393 {
5394     ITypeLibImpl *This = impl_from_ITypeLib2(iface);
5395     TRACE("(%p)->(%p)\n", This, pCustData);
5396     return TLB_copy_all_custdata(&This->custdata_list, pCustData);
5397 }
5398 
5399 static const ITypeLib2Vtbl tlbvt = {
5400     ITypeLib2_fnQueryInterface,
5401     ITypeLib2_fnAddRef,
5402     ITypeLib2_fnRelease,
5403     ITypeLib2_fnGetTypeInfoCount,
5404     ITypeLib2_fnGetTypeInfo,
5405     ITypeLib2_fnGetTypeInfoType,
5406     ITypeLib2_fnGetTypeInfoOfGuid,
5407     ITypeLib2_fnGetLibAttr,
5408     ITypeLib2_fnGetTypeComp,
5409     ITypeLib2_fnGetDocumentation,
5410     ITypeLib2_fnIsName,
5411     ITypeLib2_fnFindName,
5412     ITypeLib2_fnReleaseTLibAttr,
5413 
5414     ITypeLib2_fnGetCustData,
5415     ITypeLib2_fnGetLibStatistics,
5416     ITypeLib2_fnGetDocumentation2,
5417     ITypeLib2_fnGetAllCustData
5418  };
5419 
5420 
5421 static HRESULT WINAPI ITypeLibComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
5422 {
5423     ITypeLibImpl *This = impl_from_ITypeComp(iface);
5424 
5425     return ITypeLib2_QueryInterface(&This->ITypeLib2_iface, riid, ppv);
5426 }
5427 
5428 static ULONG WINAPI ITypeLibComp_fnAddRef(ITypeComp * iface)
5429 {
5430     ITypeLibImpl *This = impl_from_ITypeComp(iface);
5431 
5432     return ITypeLib2_AddRef(&This->ITypeLib2_iface);
5433 }
5434 
5435 static ULONG WINAPI ITypeLibComp_fnRelease(ITypeComp * iface)
5436 {
5437     ITypeLibImpl *This = impl_from_ITypeComp(iface);
5438 
5439     return ITypeLib2_Release(&This->ITypeLib2_iface);
5440 }
5441 
5442 static HRESULT WINAPI ITypeLibComp_fnBind(
5443     ITypeComp * iface,
5444     OLECHAR * szName,
5445     ULONG lHash,
5446     WORD wFlags,
5447     ITypeInfo ** ppTInfo,
5448     DESCKIND * pDescKind,
5449     BINDPTR * pBindPtr)
5450 {
5451     ITypeLibImpl *This = impl_from_ITypeComp(iface);
5452     BOOL typemismatch = FALSE;
5453     int i;
5454 
5455     TRACE("(%p)->(%s, 0x%x, 0x%x, %p, %p, %p)\n", This, debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
5456 
5457     *pDescKind = DESCKIND_NONE;
5458     pBindPtr->lptcomp = NULL;
5459     *ppTInfo = NULL;
5460 
5461     for(i = 0; i < This->TypeInfoCount; ++i){
5462         ITypeInfoImpl *pTypeInfo = This->typeinfos[i];
5463         TRACE("testing %s\n", debugstr_w(TLB_get_bstr(pTypeInfo->Name)));
5464 
5465         /* FIXME: check wFlags here? */
5466         /* FIXME: we should use a hash table to look this info up using lHash
5467          * instead of an O(n) search */
5468         if ((pTypeInfo->typeattr.typekind == TKIND_ENUM) ||
5469             (pTypeInfo->typeattr.typekind == TKIND_MODULE))
5470         {
5471             if (pTypeInfo->Name && !wcscmp(pTypeInfo->Name->str, szName))
5472             {
5473                 *pDescKind = DESCKIND_TYPECOMP;
5474                 pBindPtr->lptcomp = &pTypeInfo->ITypeComp_iface;
5475                 ITypeComp_AddRef(pBindPtr->lptcomp);
5476                 TRACE("module or enum: %s\n", debugstr_w(szName));
5477                 return S_OK;
5478             }
5479         }
5480 
5481         if ((pTypeInfo->typeattr.typekind == TKIND_MODULE) ||
5482             (pTypeInfo->typeattr.typekind == TKIND_ENUM))
5483         {
5484             ITypeComp *pSubTypeComp = &pTypeInfo->ITypeComp_iface;
5485             HRESULT hr;
5486 
5487             hr = ITypeComp_Bind(pSubTypeComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
5488             if (SUCCEEDED(hr) && (*pDescKind != DESCKIND_NONE))
5489             {
5490                 TRACE("found in module or in enum: %s\n", debugstr_w(szName));
5491                 return S_OK;
5492             }
5493             else if (hr == TYPE_E_TYPEMISMATCH)
5494                 typemismatch = TRUE;
5495         }
5496 
5497         if ((pTypeInfo->typeattr.typekind == TKIND_COCLASS) &&
5498             (pTypeInfo->typeattr.wTypeFlags & TYPEFLAG_FAPPOBJECT))
5499         {
5500             ITypeComp *pSubTypeComp = &pTypeInfo->ITypeComp_iface;
5501             HRESULT hr;
5502             ITypeInfo *subtypeinfo;
5503             BINDPTR subbindptr;
5504             DESCKIND subdesckind;
5505 
5506             hr = ITypeComp_Bind(pSubTypeComp, szName, lHash, wFlags,
5507                 &subtypeinfo, &subdesckind, &subbindptr);
5508             if (SUCCEEDED(hr) && (subdesckind != DESCKIND_NONE))
5509             {
5510                 TYPEDESC tdesc_appobject;
5511                 const VARDESC vardesc_appobject =
5512                 {
5513                     -2,         /* memid */
5514                     NULL,       /* lpstrSchema */
5515                     {
5516                         0       /* oInst */
5517                     },
5518                     {
5519                                 /* ELEMDESC */
5520                         {
5521                                 /* TYPEDESC */
5522                                 {
5523                                     &tdesc_appobject
5524                                 },
5525                                 VT_PTR
5526                         },
5527                     },
5528                     0,          /* wVarFlags */
5529                     VAR_STATIC  /* varkind */
5530                 };
5531 
5532                 tdesc_appobject.u.hreftype = pTypeInfo->hreftype;
5533                 tdesc_appobject.vt = VT_USERDEFINED;
5534 
5535                 TRACE("found in implicit app object: %s\n", debugstr_w(szName));
5536 
5537                 /* cleanup things filled in by Bind call so we can put our
5538                  * application object data in there instead */
5539                 switch (subdesckind)
5540                 {
5541                 case DESCKIND_FUNCDESC:
5542                     ITypeInfo_ReleaseFuncDesc(subtypeinfo, subbindptr.lpfuncdesc);
5543                     break;
5544                 case DESCKIND_VARDESC:
5545                     ITypeInfo_ReleaseVarDesc(subtypeinfo, subbindptr.lpvardesc);
5546                     break;
5547                 default:
5548                     break;
5549                 }
5550                 if (subtypeinfo) ITypeInfo_Release(subtypeinfo);
5551 
5552                 if (pTypeInfo->hreftype == -1)
5553                     FIXME("no hreftype for interface %p\n", pTypeInfo);
5554 
5555                 hr = TLB_AllocAndInitVarDesc(&vardesc_appobject, &pBindPtr->lpvardesc);
5556                 if (FAILED(hr))
5557                     return hr;
5558 
5559                 *pDescKind = DESCKIND_IMPLICITAPPOBJ;
5560                 *ppTInfo = (ITypeInfo *)&pTypeInfo->ITypeInfo2_iface;
5561                 ITypeInfo_AddRef(*ppTInfo);
5562                 return S_OK;
5563             }
5564             else if (hr == TYPE_E_TYPEMISMATCH)
5565                 typemismatch = TRUE;
5566         }
5567     }
5568 
5569     if (typemismatch)
5570     {
5571         TRACE("type mismatch %s\n", debugstr_w(szName));
5572         return TYPE_E_TYPEMISMATCH;
5573     }
5574     else
5575     {
5576         TRACE("name not found %s\n", debugstr_w(szName));
5577         return S_OK;
5578     }
5579 }
5580 
5581 static HRESULT WINAPI ITypeLibComp_fnBindType(
5582     ITypeComp * iface,
5583     OLECHAR * szName,
5584     ULONG lHash,
5585     ITypeInfo ** ppTInfo,
5586     ITypeComp ** ppTComp)
5587 {
5588     ITypeLibImpl *This = impl_from_ITypeComp(iface);
5589     ITypeInfoImpl *info;
5590 
5591     TRACE("(%s, %x, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
5592 
5593     if(!szName || !ppTInfo || !ppTComp)
5594         return E_INVALIDARG;
5595 
5596     info = TLB_get_typeinfo_by_name(This->typeinfos, This->TypeInfoCount, szName);
5597     if(!info){
5598         *ppTInfo = NULL;
5599         *ppTComp = NULL;
5600         return S_OK;
5601     }
5602 
5603     *ppTInfo = (ITypeInfo *)&info->ITypeInfo2_iface;
5604     ITypeInfo_AddRef(*ppTInfo);
5605     *ppTComp = &info->ITypeComp_iface;
5606     ITypeComp_AddRef(*ppTComp);
5607 
5608     return S_OK;
5609 }
5610 
5611 static const ITypeCompVtbl tlbtcvt =
5612 {
5613 
5614     ITypeLibComp_fnQueryInterface,
5615     ITypeLibComp_fnAddRef,
5616     ITypeLibComp_fnRelease,
5617 
5618     ITypeLibComp_fnBind,
5619     ITypeLibComp_fnBindType
5620 };
5621 
5622 /*================== ITypeInfo(2) Methods ===================================*/
5623 static ITypeInfoImpl* ITypeInfoImpl_Constructor(void)
5624 {
5625     ITypeInfoImpl *pTypeInfoImpl;
5626 
5627     pTypeInfoImpl = heap_alloc_zero(sizeof(ITypeInfoImpl));
5628     if (pTypeInfoImpl)
5629     {
5630       pTypeInfoImpl->ITypeInfo2_iface.lpVtbl = &tinfvt;
5631       pTypeInfoImpl->ITypeComp_iface.lpVtbl = &tcompvt;
5632       pTypeInfoImpl->ICreateTypeInfo2_iface.lpVtbl = &CreateTypeInfo2Vtbl;
5633       pTypeInfoImpl->ref = 0;
5634       pTypeInfoImpl->hreftype = -1;
5635       pTypeInfoImpl->typeattr.memidConstructor = MEMBERID_NIL;
5636       pTypeInfoImpl->typeattr.memidDestructor = MEMBERID_NIL;
5637       pTypeInfoImpl->pcustdata_list = &pTypeInfoImpl->custdata_list;
5638       list_init(pTypeInfoImpl->pcustdata_list);
5639     }
5640     TRACE("(%p)\n", pTypeInfoImpl);
5641     return pTypeInfoImpl;
5642 }
5643 
5644 /* ITypeInfo::QueryInterface
5645  */
5646 static HRESULT WINAPI ITypeInfo_fnQueryInterface(
5647 	ITypeInfo2 *iface,
5648 	REFIID riid,
5649 	VOID **ppvObject)
5650 {
5651     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
5652 
5653     TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
5654 
5655     *ppvObject=NULL;
5656     if(IsEqualIID(riid, &IID_IUnknown) ||
5657             IsEqualIID(riid,&IID_ITypeInfo)||
5658             IsEqualIID(riid,&IID_ITypeInfo2))
5659         *ppvObject = &This->ITypeInfo2_iface;
5660     else if(IsEqualIID(riid, &IID_ICreateTypeInfo) ||
5661              IsEqualIID(riid, &IID_ICreateTypeInfo2))
5662         *ppvObject = &This->ICreateTypeInfo2_iface;
5663     else if(IsEqualIID(riid, &IID_ITypeComp))
5664         *ppvObject = &This->ITypeComp_iface;
5665 
5666     if(*ppvObject){
5667         IUnknown_AddRef((IUnknown*)*ppvObject);
5668         TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
5669         return S_OK;
5670     }
5671     TRACE("-- Interface: E_NOINTERFACE\n");
5672     return E_NOINTERFACE;
5673 }
5674 
5675 /* ITypeInfo::AddRef
5676  */
5677 static ULONG WINAPI ITypeInfo_fnAddRef( ITypeInfo2 *iface)
5678 {
5679     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
5680     ULONG ref = InterlockedIncrement(&This->ref);
5681 
5682     TRACE("(%p)->ref is %u\n",This, ref);
5683 
5684     if (ref == 1 /* incremented from 0 */)
5685         ITypeLib2_AddRef(&This->pTypeLib->ITypeLib2_iface);
5686 
5687     return ref;
5688 }
5689 
5690 static void ITypeInfoImpl_Destroy(ITypeInfoImpl *This)
5691 {
5692     UINT i;
5693 
5694     TRACE("destroying ITypeInfo(%p)\n",This);
5695 
5696     for (i = 0; i < This->typeattr.cFuncs; ++i)
5697     {
5698         int j;
5699         TLBFuncDesc *pFInfo = &This->funcdescs[i];
5700         for(j = 0; j < pFInfo->funcdesc.cParams; j++)
5701         {
5702             ELEMDESC *elemdesc = &pFInfo->funcdesc.lprgelemdescParam[j];
5703             if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
5704                 VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue);
5705             TLB_FreeCustData(&pFInfo->pParamDesc[j].custdata_list);
5706         }
5707         heap_free(pFInfo->funcdesc.lprgelemdescParam);
5708         heap_free(pFInfo->pParamDesc);
5709         TLB_FreeCustData(&pFInfo->custdata_list);
5710     }
5711     heap_free(This->funcdescs);
5712 
5713     for(i = 0; i < This->typeattr.cVars; ++i)
5714     {
5715         TLBVarDesc *pVInfo = &This->vardescs[i];
5716         if (pVInfo->vardesc_create) {
5717             TLB_FreeVarDesc(pVInfo->vardesc_create);
5718         } else if (pVInfo->vardesc.varkind == VAR_CONST) {
5719             VariantClear(pVInfo->vardesc.u.lpvarValue);
5720             heap_free(pVInfo->vardesc.u.lpvarValue);
5721         }
5722         TLB_FreeCustData(&pVInfo->custdata_list);
5723     }
5724     heap_free(This->vardescs);
5725 
5726     if(This->impltypes){
5727         for (i = 0; i < This->typeattr.cImplTypes; ++i){
5728             TLBImplType *pImpl = &This->impltypes[i];
5729             TLB_FreeCustData(&pImpl->custdata_list);
5730         }
5731         heap_free(This->impltypes);
5732     }
5733 
5734     TLB_FreeCustData(&This->custdata_list);
5735 
5736     heap_free(This);
5737 }
5738 
5739 /* ITypeInfo::Release
5740  */
5741 static ULONG WINAPI ITypeInfo_fnRelease(ITypeInfo2 *iface)
5742 {
5743     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
5744     ULONG ref = InterlockedDecrement(&This->ref);
5745 
5746     TRACE("(%p)->(%u)\n",This, ref);
5747 
5748     if (!ref)
5749     {
5750         BOOL not_attached_to_typelib = This->not_attached_to_typelib;
5751         ITypeLib2_Release(&This->pTypeLib->ITypeLib2_iface);
5752         if (not_attached_to_typelib)
5753             heap_free(This);
5754         /* otherwise This will be freed when typelib is freed */
5755     }
5756 
5757     return ref;
5758 }
5759 
5760 /* ITypeInfo::GetTypeAttr
5761  *
5762  * Retrieves a TYPEATTR structure that contains the attributes of the type
5763  * description.
5764  *
5765  */
5766 static HRESULT WINAPI ITypeInfo_fnGetTypeAttr( ITypeInfo2 *iface,
5767         LPTYPEATTR  *ppTypeAttr)
5768 {
5769     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
5770     SIZE_T size;
5771 
5772     TRACE("(%p)\n",This);
5773 
5774     size = sizeof(**ppTypeAttr);
5775     if (This->typeattr.typekind == TKIND_ALIAS && This->tdescAlias)
5776         size += TLB_SizeTypeDesc(This->tdescAlias, FALSE);
5777 
5778     *ppTypeAttr = heap_alloc(size);
5779     if (!*ppTypeAttr)
5780         return E_OUTOFMEMORY;
5781 
5782     **ppTypeAttr = This->typeattr;
5783     (*ppTypeAttr)->guid = *TLB_get_guid_null(This->guid);
5784 
5785     if (This->tdescAlias)
5786         TLB_CopyTypeDesc(&(*ppTypeAttr)->tdescAlias, This->tdescAlias, *ppTypeAttr + 1);
5787 
5788     if((*ppTypeAttr)->typekind == TKIND_DISPATCH) {
5789         /* This should include all the inherited funcs */
5790         (*ppTypeAttr)->cFuncs = (*ppTypeAttr)->cbSizeVft / This->pTypeLib->ptr_size;
5791         /* This is always the size of IDispatch's vtbl */
5792         (*ppTypeAttr)->cbSizeVft = sizeof(IDispatchVtbl);
5793         (*ppTypeAttr)->wTypeFlags &= ~TYPEFLAG_FOLEAUTOMATION;
5794     }
5795     return S_OK;
5796 }
5797 
5798 /* ITypeInfo::GetTypeComp
5799  *
5800  * Retrieves the ITypeComp interface for the type description, which enables a
5801  * client compiler to bind to the type description's members.
5802  *
5803  */
5804 static HRESULT WINAPI ITypeInfo_fnGetTypeComp( ITypeInfo2 *iface,
5805         ITypeComp  * *ppTComp)
5806 {
5807     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
5808 
5809     TRACE("(%p)->(%p)\n", This, ppTComp);
5810 
5811     *ppTComp = &This->ITypeComp_iface;
5812     ITypeComp_AddRef(*ppTComp);
5813     return S_OK;
5814 }
5815 
5816 static SIZE_T TLB_SizeElemDesc( const ELEMDESC *elemdesc )
5817 {
5818     SIZE_T size = TLB_SizeTypeDesc(&elemdesc->tdesc, FALSE);
5819     if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
5820         size += sizeof(*elemdesc->u.paramdesc.pparamdescex);
5821     return size;
5822 }
5823 
5824 static HRESULT TLB_CopyElemDesc( const ELEMDESC *src, ELEMDESC *dest, char **buffer )
5825 {
5826     *dest = *src;
5827     *buffer = TLB_CopyTypeDesc(&dest->tdesc, &src->tdesc, *buffer);
5828     if (src->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
5829     {
5830         const PARAMDESCEX *pparamdescex_src = src->u.paramdesc.pparamdescex;
5831         PARAMDESCEX *pparamdescex_dest = dest->u.paramdesc.pparamdescex = (PARAMDESCEX *)*buffer;
5832         *buffer += sizeof(PARAMDESCEX);
5833         *pparamdescex_dest = *pparamdescex_src;
5834         pparamdescex_dest->cBytes = sizeof(PARAMDESCEX);
5835         VariantInit(&pparamdescex_dest->varDefaultValue);
5836         return VariantCopy(&pparamdescex_dest->varDefaultValue,
5837                            (VARIANTARG *)&pparamdescex_src->varDefaultValue);
5838     }
5839     else
5840         dest->u.paramdesc.pparamdescex = NULL;
5841     return S_OK;
5842 }
5843 
5844 static HRESULT TLB_SanitizeBSTR(BSTR str)
5845 {
5846     UINT len = SysStringLen(str), i;
5847     for (i = 0; i < len; ++i)
5848         if (str[i] > 0x7f)
5849             str[i] = '?';
5850     return S_OK;
5851 }
5852 
5853 static HRESULT TLB_SanitizeVariant(VARIANT *var)
5854 {
5855     if (V_VT(var) == VT_INT)
5856         return VariantChangeType(var, var, 0, VT_I4);
5857     else if (V_VT(var) == VT_UINT)
5858         return VariantChangeType(var, var, 0, VT_UI4);
5859     else if (V_VT(var) == VT_BSTR)
5860         return TLB_SanitizeBSTR(V_BSTR(var));
5861 
5862     return S_OK;
5863 }
5864 
5865 static void TLB_FreeElemDesc( ELEMDESC *elemdesc )
5866 {
5867     if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
5868         VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue);
5869 }
5870 
5871 static HRESULT TLB_AllocAndInitFuncDesc( const FUNCDESC *src, FUNCDESC **dest_ptr, BOOL dispinterface )
5872 {
5873     FUNCDESC *dest;
5874     char *buffer;
5875     SIZE_T size = sizeof(*src);
5876     SHORT i;
5877     HRESULT hr;
5878 
5879     size += sizeof(*src->lprgscode) * src->cScodes;
5880     size += TLB_SizeElemDesc(&src->elemdescFunc);
5881     for (i = 0; i < src->cParams; i++)
5882     {
5883         size += sizeof(ELEMDESC);
5884         size += TLB_SizeElemDesc(&src->lprgelemdescParam[i]);
5885     }
5886 
5887     dest = (FUNCDESC *)SysAllocStringByteLen(NULL, size);
5888     if (!dest) return E_OUTOFMEMORY;
5889 
5890     *dest = *src;
5891     if (dispinterface)    /* overwrite funckind */
5892         dest->funckind = FUNC_DISPATCH;
5893     buffer = (char *)(dest + 1);
5894 
5895     dest->oVft = dest->oVft & 0xFFFC;
5896 
5897     if (dest->cScodes) {
5898         dest->lprgscode = (SCODE *)buffer;
5899         memcpy(dest->lprgscode, src->lprgscode, sizeof(*src->lprgscode) * src->cScodes);
5900         buffer += sizeof(*src->lprgscode) * src->cScodes;
5901     } else
5902         dest->lprgscode = NULL;
5903 
5904     hr = TLB_CopyElemDesc(&src->elemdescFunc, &dest->elemdescFunc, &buffer);
5905     if (FAILED(hr))
5906     {
5907         SysFreeString((BSTR)dest);
5908         return hr;
5909     }
5910 
5911     if (dest->cParams) {
5912         dest->lprgelemdescParam = (ELEMDESC *)buffer;
5913         buffer += sizeof(ELEMDESC) * src->cParams;
5914         for (i = 0; i < src->cParams; i++)
5915         {
5916             hr = TLB_CopyElemDesc(&src->lprgelemdescParam[i], &dest->lprgelemdescParam[i], &buffer);
5917             if (FAILED(hr))
5918                 break;
5919         }
5920         if (FAILED(hr))
5921         {
5922             /* undo the above actions */
5923             for (i = i - 1; i >= 0; i--)
5924                 TLB_FreeElemDesc(&dest->lprgelemdescParam[i]);
5925             TLB_FreeElemDesc(&dest->elemdescFunc);
5926             SysFreeString((BSTR)dest);
5927             return hr;
5928         }
5929     } else
5930         dest->lprgelemdescParam = NULL;
5931 
5932     /* special treatment for dispinterfaces: this makes functions appear
5933      * to return their [retval] value when it is really returning an
5934      * HRESULT */
5935     if (dispinterface && dest->elemdescFunc.tdesc.vt == VT_HRESULT)
5936     {
5937         if (dest->cParams &&
5938             (dest->lprgelemdescParam[dest->cParams - 1].u.paramdesc.wParamFlags & PARAMFLAG_FRETVAL))
5939         {
5940             ELEMDESC *elemdesc = &dest->lprgelemdescParam[dest->cParams - 1];
5941             if (elemdesc->tdesc.vt != VT_PTR)
5942             {
5943                 ERR("elemdesc should have started with VT_PTR instead of:\n");
5944                 if (ERR_ON(ole))
5945                     dump_ELEMDESC(elemdesc);
5946                 return E_UNEXPECTED;
5947             }
5948 
5949             /* copy last parameter to the return value. we are using a flat
5950              * buffer so there is no danger of leaking memory in
5951              * elemdescFunc */
5952             dest->elemdescFunc.tdesc = *elemdesc->tdesc.u.lptdesc;
5953 
5954             /* remove the last parameter */
5955             dest->cParams--;
5956         }
5957         else
5958             /* otherwise this function is made to appear to have no return
5959              * value */
5960             dest->elemdescFunc.tdesc.vt = VT_VOID;
5961 
5962     }
5963 
5964     *dest_ptr = dest;
5965     return S_OK;
5966 }
5967 
5968 static void TLB_FreeVarDesc(VARDESC *var_desc)
5969 {
5970     TLB_FreeElemDesc(&var_desc->elemdescVar);
5971     if (var_desc->varkind == VAR_CONST)
5972         VariantClear(var_desc->u.lpvarValue);
5973     SysFreeString((BSTR)var_desc);
5974 }
5975 
5976 HRESULT ITypeInfoImpl_GetInternalFuncDesc( ITypeInfo *iface, UINT index, const FUNCDESC **ppFuncDesc )
5977 {
5978     ITypeInfoImpl *This = impl_from_ITypeInfo(iface);
5979 
5980     if (index >= This->typeattr.cFuncs)
5981         return TYPE_E_ELEMENTNOTFOUND;
5982 
5983     *ppFuncDesc = &This->funcdescs[index].funcdesc;
5984     return S_OK;
5985 }
5986 
5987 /* internal function to make the inherited interfaces' methods appear
5988  * part of the interface */
5989 static HRESULT ITypeInfoImpl_GetInternalDispatchFuncDesc( ITypeInfo *iface,
5990     UINT index, const FUNCDESC **ppFuncDesc, UINT *funcs, UINT *hrefoffset)
5991 {
5992     ITypeInfoImpl *This = impl_from_ITypeInfo(iface);
5993     HRESULT hr;
5994     UINT implemented_funcs = 0;
5995 
5996     if (funcs)
5997         *funcs = 0;
5998     else
5999         *hrefoffset = DISPATCH_HREF_OFFSET;
6000 
6001     if(This->impltypes)
6002     {
6003         ITypeInfo *pSubTypeInfo;
6004         UINT sub_funcs;
6005 
6006         hr = ITypeInfo_GetRefTypeInfo(iface, This->impltypes[0].hRef, &pSubTypeInfo);
6007         if (FAILED(hr))
6008             return hr;
6009 
6010         hr = ITypeInfoImpl_GetInternalDispatchFuncDesc(pSubTypeInfo,
6011                                                        index,
6012                                                        ppFuncDesc,
6013                                                        &sub_funcs, hrefoffset);
6014         implemented_funcs += sub_funcs;
6015         ITypeInfo_Release(pSubTypeInfo);
6016         if (SUCCEEDED(hr))
6017             return hr;
6018         *hrefoffset += DISPATCH_HREF_OFFSET;
6019     }
6020 
6021     if (funcs)
6022         *funcs = implemented_funcs + This->typeattr.cFuncs;
6023     else
6024         *hrefoffset = 0;
6025 
6026     if (index < implemented_funcs)
6027         return E_INVALIDARG;
6028     return ITypeInfoImpl_GetInternalFuncDesc(iface, index - implemented_funcs,
6029                                              ppFuncDesc);
6030 }
6031 
6032 static inline void ITypeInfoImpl_ElemDescAddHrefOffset( LPELEMDESC pElemDesc, UINT hrefoffset)
6033 {
6034     TYPEDESC *pTypeDesc = &pElemDesc->tdesc;
6035     while (TRUE)
6036     {
6037         switch (pTypeDesc->vt)
6038         {
6039         case VT_USERDEFINED:
6040             pTypeDesc->u.hreftype += hrefoffset;
6041             return;
6042         case VT_PTR:
6043         case VT_SAFEARRAY:
6044             pTypeDesc = pTypeDesc->u.lptdesc;
6045             break;
6046         case VT_CARRAY:
6047             pTypeDesc = &pTypeDesc->u.lpadesc->tdescElem;
6048             break;
6049         default:
6050             return;
6051         }
6052     }
6053 }
6054 
6055 static inline void ITypeInfoImpl_FuncDescAddHrefOffset( LPFUNCDESC pFuncDesc, UINT hrefoffset)
6056 {
6057     SHORT i;
6058     for (i = 0; i < pFuncDesc->cParams; i++)
6059         ITypeInfoImpl_ElemDescAddHrefOffset(&pFuncDesc->lprgelemdescParam[i], hrefoffset);
6060     ITypeInfoImpl_ElemDescAddHrefOffset(&pFuncDesc->elemdescFunc, hrefoffset);
6061 }
6062 
6063 /* ITypeInfo::GetFuncDesc
6064  *
6065  * Retrieves the FUNCDESC structure that contains information about a
6066  * specified function.
6067  *
6068  */
6069 static HRESULT WINAPI ITypeInfo_fnGetFuncDesc( ITypeInfo2 *iface, UINT index,
6070         LPFUNCDESC  *ppFuncDesc)
6071 {
6072     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
6073     const FUNCDESC *internal_funcdesc;
6074     HRESULT hr;
6075     UINT hrefoffset = 0;
6076 
6077     TRACE("(%p) index %d\n", This, index);
6078 
6079     if (!ppFuncDesc)
6080         return E_INVALIDARG;
6081 
6082     if (This->needs_layout)
6083         ICreateTypeInfo2_LayOut(&This->ICreateTypeInfo2_iface);
6084 
6085     if (This->typeattr.typekind == TKIND_DISPATCH)
6086         hr = ITypeInfoImpl_GetInternalDispatchFuncDesc((ITypeInfo *)iface, index,
6087                                                        &internal_funcdesc, NULL,
6088                                                        &hrefoffset);
6089     else
6090         hr = ITypeInfoImpl_GetInternalFuncDesc((ITypeInfo *)iface, index,
6091                                                &internal_funcdesc);
6092     if (FAILED(hr))
6093     {
6094         WARN("description for function %d not found\n", index);
6095         return hr;
6096     }
6097 
6098     hr = TLB_AllocAndInitFuncDesc(
6099         internal_funcdesc,
6100         ppFuncDesc,
6101         This->typeattr.typekind == TKIND_DISPATCH);
6102 
6103     if ((This->typeattr.typekind == TKIND_DISPATCH) && hrefoffset)
6104         ITypeInfoImpl_FuncDescAddHrefOffset(*ppFuncDesc, hrefoffset);
6105 
6106     TRACE("-- 0x%08x\n", hr);
6107     return hr;
6108 }
6109 
6110 static HRESULT TLB_AllocAndInitVarDesc( const VARDESC *src, VARDESC **dest_ptr )
6111 {
6112     VARDESC *dest;
6113     char *buffer;
6114     SIZE_T size = sizeof(*src);
6115     HRESULT hr;
6116 
6117     if (src->lpstrSchema) size += (lstrlenW(src->lpstrSchema) + 1) * sizeof(WCHAR);
6118     if (src->varkind == VAR_CONST)
6119         size += sizeof(VARIANT);
6120     size += TLB_SizeElemDesc(&src->elemdescVar);
6121 
6122     dest = (VARDESC *)SysAllocStringByteLen(NULL, size);
6123     if (!dest) return E_OUTOFMEMORY;
6124 
6125     *dest = *src;
6126     buffer = (char *)(dest + 1);
6127     if (src->lpstrSchema)
6128     {
6129         int len;
6130         dest->lpstrSchema = (LPOLESTR)buffer;
6131         len = lstrlenW(src->lpstrSchema);
6132         memcpy(dest->lpstrSchema, src->lpstrSchema, (len + 1) * sizeof(WCHAR));
6133         buffer += (len + 1) * sizeof(WCHAR);
6134     }
6135 
6136     if (src->varkind == VAR_CONST)
6137     {
6138         HRESULT hr;
6139 
6140         dest->u.lpvarValue = (VARIANT *)buffer;
6141         *dest->u.lpvarValue = *src->u.lpvarValue;
6142         buffer += sizeof(VARIANT);
6143         VariantInit(dest->u.lpvarValue);
6144         hr = VariantCopy(dest->u.lpvarValue, src->u.lpvarValue);
6145         if (FAILED(hr))
6146         {
6147             SysFreeString((BSTR)dest);
6148             return hr;
6149         }
6150     }
6151     hr = TLB_CopyElemDesc(&src->elemdescVar, &dest->elemdescVar, &buffer);
6152     if (FAILED(hr))
6153     {
6154         if (src->varkind == VAR_CONST)
6155             VariantClear(dest->u.lpvarValue);
6156         SysFreeString((BSTR)dest);
6157         return hr;
6158     }
6159     *dest_ptr = dest;
6160     return S_OK;
6161 }
6162 
6163 /* ITypeInfo::GetVarDesc
6164  *
6165  * Retrieves a VARDESC structure that describes the specified variable.
6166  *
6167  */
6168 static HRESULT WINAPI ITypeInfo_fnGetVarDesc( ITypeInfo2 *iface, UINT index,
6169         LPVARDESC  *ppVarDesc)
6170 {
6171     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
6172     const TLBVarDesc *pVDesc = &This->vardescs[index];
6173 
6174     TRACE("(%p) index %d\n", This, index);
6175 
6176     if(index >= This->typeattr.cVars)
6177         return TYPE_E_ELEMENTNOTFOUND;
6178 
6179     if (This->needs_layout)
6180         ICreateTypeInfo2_LayOut(&This->ICreateTypeInfo2_iface);
6181 
6182     return TLB_AllocAndInitVarDesc(&pVDesc->vardesc, ppVarDesc);
6183 }
6184 
6185 /* ITypeInfo_GetNames
6186  *
6187  * Retrieves the variable with the specified member ID (or the name of the
6188  * property or method and its parameters) that correspond to the specified
6189  * function ID.
6190  */
6191 static HRESULT WINAPI ITypeInfo_fnGetNames( ITypeInfo2 *iface, MEMBERID memid,
6192         BSTR  *rgBstrNames, UINT cMaxNames, UINT  *pcNames)
6193 {
6194     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
6195     const TLBFuncDesc *pFDesc;
6196     const TLBVarDesc *pVDesc;
6197     int i;
6198     TRACE("(%p) memid=0x%08x Maxname=%d\n", This, memid, cMaxNames);
6199 
6200     if(!rgBstrNames)
6201         return E_INVALIDARG;
6202 
6203     *pcNames = 0;
6204 
6205     pFDesc = TLB_get_funcdesc_by_memberid(This->funcdescs, This->typeattr.cFuncs, memid);
6206     if(pFDesc)
6207     {
6208         if(!cMaxNames || !pFDesc->Name)
6209             return S_OK;
6210 
6211         *rgBstrNames = SysAllocString(TLB_get_bstr(pFDesc->Name));
6212         ++(*pcNames);
6213 
6214         for(i = 0; i < pFDesc->funcdesc.cParams; ++i){
6215             if(*pcNames >= cMaxNames || !pFDesc->pParamDesc[i].Name)
6216                 return S_OK;
6217             rgBstrNames[*pcNames] = SysAllocString(TLB_get_bstr(pFDesc->pParamDesc[i].Name));
6218             ++(*pcNames);
6219         }
6220         return S_OK;
6221     }
6222 
6223     pVDesc = TLB_get_vardesc_by_memberid(This->vardescs, This->typeattr.cVars, memid);
6224     if(pVDesc)
6225     {
6226       *rgBstrNames=SysAllocString(TLB_get_bstr(pVDesc->Name));
6227       *pcNames=1;
6228     }
6229     else
6230     {
6231         if(This->impltypes &&
6232 	   (This->typeattr.typekind == TKIND_INTERFACE || This->typeattr.typekind == TKIND_DISPATCH)) {
6233           /* recursive search */
6234           ITypeInfo *pTInfo;
6235           HRESULT result;
6236           result = ITypeInfo2_GetRefTypeInfo(iface, This->impltypes[0].hRef, &pTInfo);
6237           if(SUCCEEDED(result))
6238 	  {
6239             result=ITypeInfo_GetNames(pTInfo, memid, rgBstrNames, cMaxNames, pcNames);
6240             ITypeInfo_Release(pTInfo);
6241             return result;
6242           }
6243           WARN("Could not search inherited interface!\n");
6244         }
6245         else
6246 	{
6247           WARN("no names found\n");
6248 	}
6249         *pcNames=0;
6250         return TYPE_E_ELEMENTNOTFOUND;
6251     }
6252     return S_OK;
6253 }
6254 
6255 
6256 /* ITypeInfo::GetRefTypeOfImplType
6257  *
6258  * If a type description describes a COM class, it retrieves the type
6259  * description of the implemented interface types. For an interface,
6260  * GetRefTypeOfImplType returns the type information for inherited interfaces,
6261  * if any exist.
6262  *
6263  */
6264 static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType(
6265 	ITypeInfo2 *iface,
6266         UINT index,
6267 	HREFTYPE  *pRefType)
6268 {
6269     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
6270     HRESULT hr = S_OK;
6271 
6272     TRACE("(%p) index %d\n", This, index);
6273     if (TRACE_ON(ole)) dump_TypeInfo(This);
6274 
6275     if(index==(UINT)-1)
6276     {
6277       /* only valid on dual interfaces;
6278          retrieve the associated TKIND_INTERFACE handle for the current TKIND_DISPATCH
6279       */
6280 
6281       if (This->typeattr.wTypeFlags & TYPEFLAG_FDUAL)
6282       {
6283           *pRefType = -2;
6284       }
6285       else
6286       {
6287         hr = TYPE_E_ELEMENTNOTFOUND;
6288       }
6289     }
6290     else if(index == 0 && This->typeattr.typekind == TKIND_DISPATCH)
6291     {
6292       /* All TKIND_DISPATCHs are made to look like they inherit from IDispatch */
6293       *pRefType = This->pTypeLib->dispatch_href;
6294     }
6295     else
6296     {
6297         if(index >= This->typeattr.cImplTypes)
6298             hr = TYPE_E_ELEMENTNOTFOUND;
6299         else{
6300             *pRefType = This->impltypes[index].hRef;
6301             if (This->typeattr.typekind == TKIND_INTERFACE)
6302                 *pRefType |= 0x2;
6303         }
6304     }
6305 
6306     if(TRACE_ON(ole))
6307     {
6308         if(SUCCEEDED(hr))
6309             TRACE("SUCCESS -- hRef = 0x%08x\n", *pRefType );
6310         else
6311             TRACE("FAILURE -- hresult = 0x%08x\n", hr);
6312     }
6313 
6314     return hr;
6315 }
6316 
6317 /* ITypeInfo::GetImplTypeFlags
6318  *
6319  * Retrieves the IMPLTYPEFLAGS enumeration for one implemented interface
6320  * or base interface in a type description.
6321  */
6322 static HRESULT WINAPI ITypeInfo_fnGetImplTypeFlags( ITypeInfo2 *iface,
6323         UINT index, INT  *pImplTypeFlags)
6324 {
6325     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
6326 
6327     TRACE("(%p) index %d\n", This, index);
6328 
6329     if(!pImplTypeFlags)
6330         return E_INVALIDARG;
6331 
6332     if(This->typeattr.typekind == TKIND_DISPATCH && index == 0){
6333         *pImplTypeFlags = 0;
6334         return S_OK;
6335     }
6336 
6337     if(index >= This->typeattr.cImplTypes)
6338         return TYPE_E_ELEMENTNOTFOUND;
6339 
6340     *pImplTypeFlags = This->impltypes[index].implflags;
6341 
6342     return S_OK;
6343 }
6344 
6345 /* GetIDsOfNames
6346  * Maps between member names and member IDs, and parameter names and
6347  * parameter IDs.
6348  */
6349 static HRESULT WINAPI ITypeInfo_fnGetIDsOfNames( ITypeInfo2 *iface,
6350         LPOLESTR  *rgszNames, UINT cNames, MEMBERID  *pMemId)
6351 {
6352     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
6353     const TLBVarDesc *pVDesc;
6354     HRESULT ret=S_OK;
6355     UINT i, fdc;
6356 
6357     TRACE("(%p) Name %s cNames %d\n", This, debugstr_w(*rgszNames),
6358             cNames);
6359 
6360     /* init out parameters in case of failure */
6361     for (i = 0; i < cNames; i++)
6362         pMemId[i] = MEMBERID_NIL;
6363 
6364     for (fdc = 0; fdc < This->typeattr.cFuncs; ++fdc) {
6365         int j;
6366         const TLBFuncDesc *pFDesc = &This->funcdescs[fdc];
6367         if(!lstrcmpiW(*rgszNames, TLB_get_bstr(pFDesc->Name))) {
6368             if(cNames) *pMemId=pFDesc->funcdesc.memid;
6369             for(i=1; i < cNames; i++){
6370                 for(j=0; j<pFDesc->funcdesc.cParams; j++)
6371                     if(!lstrcmpiW(rgszNames[i],TLB_get_bstr(pFDesc->pParamDesc[j].Name)))
6372                             break;
6373                 if( j<pFDesc->funcdesc.cParams)
6374                     pMemId[i]=j;
6375                 else
6376                    ret=DISP_E_UNKNOWNNAME;
6377             };
6378             TRACE("-- 0x%08x\n", ret);
6379             return ret;
6380         }
6381     }
6382     pVDesc = TLB_get_vardesc_by_name(This->vardescs, This->typeattr.cVars, *rgszNames);
6383     if(pVDesc){
6384         if(cNames)
6385             *pMemId = pVDesc->vardesc.memid;
6386         return ret;
6387     }
6388     /* not found, see if it can be found in an inherited interface */
6389     if(This->impltypes) {
6390         /* recursive search */
6391         ITypeInfo *pTInfo;
6392         ret = ITypeInfo2_GetRefTypeInfo(iface, This->impltypes[0].hRef, &pTInfo);
6393         if(SUCCEEDED(ret)){
6394             ret=ITypeInfo_GetIDsOfNames(pTInfo, rgszNames, cNames, pMemId );
6395             ITypeInfo_Release(pTInfo);
6396             return ret;
6397         }
6398         WARN("Could not search inherited interface!\n");
6399     } else
6400         WARN("no names found\n");
6401     return DISP_E_UNKNOWNNAME;
6402 }
6403 
6404 
6405 #ifdef __i386__
6406 
6407 extern LONGLONG call_method( void *func, int nb_args, const DWORD *args, int *stack_offset );
6408 extern double call_double_method( void *func, int nb_args, const DWORD *args, int *stack_offset );
6409 __ASM_GLOBAL_FUNC( call_method,
6410                    "pushl %ebp\n\t"
6411                    __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
6412                    __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
6413                    "movl %esp,%ebp\n\t"
6414                    __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
6415                    "pushl %esi\n\t"
6416                   __ASM_CFI(".cfi_rel_offset %esi,-4\n\t")
6417                    "pushl %edi\n\t"
6418                   __ASM_CFI(".cfi_rel_offset %edi,-8\n\t")
6419                    "movl 12(%ebp),%edx\n\t"
6420                    "movl %esp,%edi\n\t"
6421                    "shll $2,%edx\n\t"
6422                    "jz 1f\n\t"
6423                    "subl %edx,%edi\n\t"
6424                    "andl $~15,%edi\n\t"
6425                    "movl %edi,%esp\n\t"
6426                    "movl 12(%ebp),%ecx\n\t"
6427                    "movl 16(%ebp),%esi\n\t"
6428                    "cld\n\t"
6429                    "rep; movsl\n"
6430                    "1:\tcall *8(%ebp)\n\t"
6431                    "subl %esp,%edi\n\t"
6432                    "movl 20(%ebp),%ecx\n\t"
6433                    "movl %edi,(%ecx)\n\t"
6434                    "leal -8(%ebp),%esp\n\t"
6435                    "popl %edi\n\t"
6436                    __ASM_CFI(".cfi_same_value %edi\n\t")
6437                    "popl %esi\n\t"
6438                    __ASM_CFI(".cfi_same_value %esi\n\t")
6439                    "popl %ebp\n\t"
6440                    __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
6441                    __ASM_CFI(".cfi_same_value %ebp\n\t")
6442                    "ret" )
6443 __ASM_GLOBAL_FUNC( call_double_method,
6444                    "jmp " __ASM_NAME("call_method") )
6445 
6446 HRESULT WINAPI DispCallFunc( void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn,
6447                              UINT cActuals, VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult )
6448 {
6449     int argspos = 0, stack_offset;
6450     void *func;
6451     UINT i;
6452     DWORD *args;
6453 
6454     TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
6455         pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
6456         pvargResult, V_VT(pvargResult));
6457 
6458     if (cc != CC_STDCALL && cc != CC_CDECL)
6459     {
6460         FIXME("unsupported calling convention %d\n",cc);
6461         return E_INVALIDARG;
6462     }
6463 
6464     /* maximum size for an argument is sizeof(VARIANT) */
6465     args = heap_alloc(sizeof(VARIANT) * cActuals + sizeof(DWORD) * 2 );
6466 
6467     if (pvInstance)
6468     {
6469         const FARPROC *vtable = *(FARPROC **)pvInstance;
6470         func = vtable[oVft/sizeof(void *)];
6471         args[argspos++] = (DWORD)pvInstance; /* the This pointer is always the first parameter */
6472     }
6473     else func = (void *)oVft;
6474 
6475     switch (vtReturn)
6476     {
6477     case VT_DECIMAL:
6478     case VT_VARIANT:
6479         args[argspos++] = (DWORD)pvargResult;  /* arg 0 is a pointer to the result */
6480         break;
6481     case VT_HRESULT:
6482         WARN("invalid return type %u\n", vtReturn);
6483         heap_free( args );
6484         return E_INVALIDARG;
6485     default:
6486         break;
6487     }
6488 
6489     for (i = 0; i < cActuals; i++)
6490     {
6491         VARIANT *arg = prgpvarg[i];
6492 
6493         switch (prgvt[i])
6494         {
6495         case VT_EMPTY:
6496             break;
6497         case VT_I8:
6498         case VT_UI8:
6499         case VT_R8:
6500         case VT_DATE:
6501         case VT_CY:
6502             memcpy( &args[argspos], &V_I8(arg), sizeof(V_I8(arg)) );
6503             argspos += sizeof(V_I8(arg)) / sizeof(DWORD);
6504             break;
6505         case VT_DECIMAL:
6506         case VT_VARIANT:
6507             memcpy( &args[argspos], arg, sizeof(*arg) );
6508             argspos += sizeof(*arg) / sizeof(DWORD);
6509             break;
6510         case VT_BOOL:  /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
6511             args[argspos++] = V_BOOL(arg);
6512             break;
6513         default:
6514             args[argspos++] = V_UI4(arg);
6515             break;
6516         }
6517         TRACE("arg %u: type %s %s\n", i, debugstr_vt(prgvt[i]), debugstr_variant(arg));
6518     }
6519 
6520     switch (vtReturn)
6521     {
6522     case VT_EMPTY:
6523     case VT_DECIMAL:
6524     case VT_VARIANT:
6525         call_method( func, argspos, args, &stack_offset );
6526         break;
6527     case VT_R4:
6528         V_R4(pvargResult) = call_double_method( func, argspos, args, &stack_offset );
6529         break;
6530     case VT_R8:
6531     case VT_DATE:
6532         V_R8(pvargResult) = call_double_method( func, argspos, args, &stack_offset );
6533         break;
6534     case VT_I8:
6535     case VT_UI8:
6536     case VT_CY:
6537         V_UI8(pvargResult) = call_method( func, argspos, args, &stack_offset );
6538         break;
6539     default:
6540         V_UI4(pvargResult) = call_method( func, argspos, args, &stack_offset );
6541         break;
6542     }
6543     heap_free( args );
6544     if (stack_offset && cc == CC_STDCALL)
6545     {
6546         WARN( "stack pointer off by %d\n", stack_offset );
6547         return DISP_E_BADCALLEE;
6548     }
6549     if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
6550     TRACE("retval: %s\n", debugstr_variant(pvargResult));
6551     return S_OK;
6552 }
6553 
6554 #elif defined(__x86_64__)
6555 
6556 extern DWORD_PTR CDECL call_method( void *func, int nb_args, const DWORD_PTR *args );
6557 extern double CDECL call_double_method( void *func, int nb_args, const DWORD_PTR *args );
6558 __ASM_GLOBAL_FUNC( call_method,
6559                    "pushq %rbp\n\t"
6560                    __ASM_SEH(".seh_pushreg %rbp\n\t")
6561                    __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t")
6562                    __ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
6563                    "movq %rsp,%rbp\n\t"
6564                    __ASM_SEH(".seh_setframe %rbp,0\n\t")
6565                    __ASM_CFI(".cfi_def_cfa_register %rbp\n\t")
6566                    "pushq %rsi\n\t"
6567                    __ASM_SEH(".seh_pushreg %rsi\n\t")
6568                    __ASM_CFI(".cfi_rel_offset %rsi,-8\n\t")
6569                    "pushq %rdi\n\t"
6570                    __ASM_SEH(".seh_pushreg %rdi\n\t")
6571                    __ASM_CFI(".cfi_rel_offset %rdi,-16\n\t")
6572                    __ASM_SEH(".seh_endprologue\n\t")
6573                    "movq %rcx,%rax\n\t"
6574                    "movq $4,%rcx\n\t"
6575                    "cmp %rcx,%rdx\n\t"
6576                    "cmovgq %rdx,%rcx\n\t"
6577                    "leaq 0(,%rcx,8),%rdx\n\t"
6578                    "subq %rdx,%rsp\n\t"
6579                    "andq $~15,%rsp\n\t"
6580                    "movq %rsp,%rdi\n\t"
6581                    "movq %r8,%rsi\n\t"
6582                    "rep; movsq\n\t"
6583                    "movq 0(%rsp),%rcx\n\t"
6584                    "movq 8(%rsp),%rdx\n\t"
6585                    "movq 16(%rsp),%r8\n\t"
6586                    "movq 24(%rsp),%r9\n\t"
6587                    "movq 0(%rsp),%xmm0\n\t"
6588                    "movq 8(%rsp),%xmm1\n\t"
6589                    "movq 16(%rsp),%xmm2\n\t"
6590                    "movq 24(%rsp),%xmm3\n\t"
6591                    "callq *%rax\n\t"
6592                    "leaq -16(%rbp),%rsp\n\t"
6593                    "popq %rdi\n\t"
6594                    __ASM_CFI(".cfi_same_value %rdi\n\t")
6595                    "popq %rsi\n\t"
6596                    __ASM_CFI(".cfi_same_value %rsi\n\t")
6597                    __ASM_CFI(".cfi_def_cfa_register %rsp\n\t")
6598                    "popq %rbp\n\t"
6599                    __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t")
6600                    __ASM_CFI(".cfi_same_value %rbp\n\t")
6601                    "ret")
6602 __ASM_GLOBAL_FUNC( call_double_method,
6603                    "jmp " __ASM_NAME("call_method") )
6604 
6605 HRESULT WINAPI DispCallFunc( void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn,
6606                              UINT cActuals, VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult )
6607 {
6608     int argspos = 0;
6609     UINT i;
6610     DWORD_PTR *args;
6611     void *func;
6612 
6613     TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
6614           pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
6615           pvargResult, V_VT(pvargResult));
6616 
6617     if (cc != CC_STDCALL && cc != CC_CDECL)
6618     {
6619 	FIXME("unsupported calling convention %d\n",cc);
6620         return E_INVALIDARG;
6621     }
6622 
6623     /* maximum size for an argument is sizeof(DWORD_PTR) */
6624     args = heap_alloc( sizeof(DWORD_PTR) * (cActuals + 2) );
6625 
6626     if (pvInstance)
6627     {
6628         const FARPROC *vtable = *(FARPROC **)pvInstance;
6629         func = vtable[oVft/sizeof(void *)];
6630         args[argspos++] = (DWORD_PTR)pvInstance; /* the This pointer is always the first parameter */
6631     }
6632     else func = (void *)oVft;
6633 
6634     switch (vtReturn)
6635     {
6636     case VT_DECIMAL:
6637     case VT_VARIANT:
6638         args[argspos++] = (DWORD_PTR)pvargResult;  /* arg 0 is a pointer to the result */
6639         break;
6640     case VT_HRESULT:
6641         WARN("invalid return type %u\n", vtReturn);
6642         heap_free( args );
6643         return E_INVALIDARG;
6644     default:
6645         break;
6646     }
6647 
6648     for (i = 0; i < cActuals; i++)
6649     {
6650         VARIANT *arg = prgpvarg[i];
6651 
6652         switch (prgvt[i])
6653         {
6654         case VT_DECIMAL:
6655         case VT_VARIANT:
6656             args[argspos++] = (ULONG_PTR)arg;
6657             break;
6658         case VT_BOOL:  /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
6659             args[argspos++] = V_BOOL(arg);
6660             break;
6661         default:
6662             args[argspos++] = V_UI8(arg);
6663             break;
6664         }
6665         TRACE("arg %u: type %s %s\n", i, debugstr_vt(prgvt[i]), debugstr_variant(arg));
6666     }
6667 
6668     switch (vtReturn)
6669     {
6670     case VT_R4:
6671         V_R4(pvargResult) = call_double_method( func, argspos, args );
6672         break;
6673     case VT_R8:
6674     case VT_DATE:
6675         V_R8(pvargResult) = call_double_method( func, argspos, args );
6676         break;
6677     case VT_DECIMAL:
6678     case VT_VARIANT:
6679         call_method( func, argspos, args );
6680         break;
6681     default:
6682         V_UI8(pvargResult) = call_method( func, argspos, args );
6683         break;
6684     }
6685     heap_free( args );
6686     if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
6687     TRACE("retval: %s\n", debugstr_variant(pvargResult));
6688     return S_OK;
6689 }
6690 
6691 #elif defined(__arm__)
6692 
6693 extern LONGLONG CDECL call_method( void *func, int nb_stk_args, const DWORD *stk_args, const DWORD *reg_args );
6694 extern float CDECL call_float_method( void *func, int nb_stk_args, const DWORD *stk_args, const DWORD *reg_args );
6695 extern double CDECL call_double_method( void *func, int nb_stk_args, const DWORD *stk_args, const DWORD *reg_args );
6696 __ASM_GLOBAL_FUNC( call_method,
6697                     /* r0 = *func
6698                      * r1 = nb_stk_args
6699                      * r2 = *stk_args (pointer to 'nb_stk_args' DWORD values to push on stack)
6700                      * r3 = *reg_args (pointer to 8, 64-bit d0-d7 (double) values OR as 16, 32-bit s0-s15 (float) values, followed by 4, 32-bit (DWORD) r0-r3 values)
6701                      */
6702 
6703                     "push {fp, lr}\n\t"             /* Save frame pointer and return address (stack still aligned to 8 bytes) */
6704                     "mov fp, sp\n\t"                /* Save stack pointer as our frame for cleaning the stack on return */
6705 
6706                     "lsls r1, r1, #2\n\t"           /* r1 = nb_stk_args * sizeof(DWORD) */
6707                     "beq 1f\n\t"                    /* Skip allocation if no stack args */
6708                     "add r2, r2, r1\n"              /* Calculate ending address of incoming stack data */
6709                     "2:\tldr ip, [r2, #-4]!\n\t"    /* Get next value */
6710                     "str ip, [sp, #-4]!\n\t"        /* Push it on the stack */
6711                     "subs r1, r1, #4\n\t"           /* Decrement count */
6712                     "bgt 2b\n\t"                    /* Loop till done */
6713 
6714                     "1:\n\t"
6715 #ifndef __SOFTFP__
6716                     "vldm r3!, {s0-s15}\n\t"        /* Load the s0-s15/d0-d7 arguments */
6717 #endif
6718                     "mov ip, r0\n\t"                /* Save the function call address to ip before we nuke r0 with arguments to pass */
6719                     "ldm r3, {r0-r3}\n\t"           /* Load the r0-r3 arguments */
6720 
6721                     "blx ip\n\t"                    /* Call the target function */
6722 
6723                     "mov sp, fp\n\t"                /* Clean the stack using fp */
6724                     "pop {fp, pc}\n\t"              /* Restore fp and return */
6725                 )
6726 __ASM_GLOBAL_FUNC( call_float_method,
6727                    "b " __ASM_NAME("call_method") )
6728 __ASM_GLOBAL_FUNC( call_double_method,
6729                    "b " __ASM_NAME("call_method") )
6730 
6731 HRESULT WINAPI DispCallFunc( void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn,
6732                              UINT cActuals, VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult )
6733 {
6734     int argspos;
6735     void *func;
6736     UINT i;
6737     DWORD *args;
6738     struct {
6739 #ifndef __SOFTFP__
6740         union {
6741             float s[16];
6742             double d[8];
6743         } sd;
6744 #endif
6745         DWORD r[4];
6746     } regs;
6747     int rcount;     /* 32-bit register index count */
6748 #ifndef __SOFTFP__
6749     int scount = 0; /* single-precision float register index count */
6750     int dcount = 0; /* double-precision float register index count */
6751 #endif
6752 
6753     TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
6754         pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg, pvargResult, V_VT(pvargResult));
6755 
6756     if (cc != CC_STDCALL && cc != CC_CDECL)
6757     {
6758         FIXME("unsupported calling convention %d\n",cc);
6759         return E_INVALIDARG;
6760     }
6761 
6762     argspos = 0;
6763     rcount = 0;
6764 
6765     if (pvInstance)
6766     {
6767         const FARPROC *vtable = *(FARPROC **)pvInstance;
6768         func = vtable[oVft/sizeof(void *)];
6769         regs.r[rcount++] = (DWORD)pvInstance; /* the This pointer is always the first parameter */
6770     }
6771     else func = (void *)oVft;
6772 
6773     /* Determine if we need to pass a pointer for the return value as arg 0.  If so, do that */
6774     /*  first as it will need to be in the 'r' registers:                                    */
6775     switch (vtReturn)
6776     {
6777     case VT_DECIMAL:
6778     case VT_VARIANT:
6779         regs.r[rcount++] = (DWORD)pvargResult;  /* arg 0 is a pointer to the result */
6780         break;
6781     case VT_HRESULT:
6782         WARN("invalid return type %u\n", vtReturn);
6783         return E_INVALIDARG;
6784     default:                    /* And all others are in 'r', 's', or 'd' registers or have no return value */
6785         break;
6786     }
6787 
6788     /* maximum size for an argument is sizeof(VARIANT).  Also allow for return pointer and stack alignment. */
6789     args = heap_alloc( sizeof(VARIANT) * cActuals + sizeof(DWORD) * 4 );
6790 
6791     for (i = 0; i < cActuals; i++)
6792     {
6793         VARIANT *arg = prgpvarg[i];
6794         DWORD *pdwarg = (DWORD *)(arg);     /* a reinterpret_cast of the variant, used for copying structures when they are split between registers and stack */
6795         int ntemp;              /* Used for counting words split between registers and stack */
6796 
6797         switch (prgvt[i])
6798         {
6799         case VT_EMPTY:
6800             break;
6801         case VT_R8:             /* these must be 8-byte aligned, and put in 'd' regs or stack, as they are double-floats */
6802         case VT_DATE:
6803 #ifndef __SOFTFP__
6804             dcount = max( (scount + 1) / 2, dcount );
6805             if (dcount < 8)
6806             {
6807                 regs.sd.d[dcount++] = V_R8(arg);
6808             }
6809             else
6810             {
6811                 argspos += (argspos % 2);   /* align argspos to 8-bytes */
6812                 memcpy( &args[argspos], &V_R8(arg), sizeof(V_R8(arg)) );
6813                 argspos += sizeof(V_R8(arg)) / sizeof(DWORD);
6814             }
6815             break;
6816 #endif
6817         case VT_I8:             /* these must be 8-byte aligned, and put in 'r' regs or stack, as they are long-longs */
6818         case VT_UI8:
6819         case VT_CY:
6820             if (rcount < 3)
6821             {
6822                 rcount += (rcount % 2);     /* align rcount to 8-byte register pair */
6823                 memcpy( &regs.r[rcount], &V_UI8(arg), sizeof(V_UI8(arg)) );
6824                 rcount += sizeof(V_UI8(arg)) / sizeof(DWORD);
6825             }
6826             else
6827             {
6828                 rcount = 4;                 /* Make sure we flag that all 'r' regs are full */
6829                 argspos += (argspos % 2);   /* align argspos to 8-bytes */
6830                 memcpy( &args[argspos], &V_UI8(arg), sizeof(V_UI8(arg)) );
6831                 argspos += sizeof(V_UI8(arg)) / sizeof(DWORD);
6832             }
6833             break;
6834         case VT_DECIMAL:        /* these structures are 8-byte aligned, and put in 'r' regs or stack, can be split between the two */
6835         case VT_VARIANT:
6836             /* 8-byte align 'r' and/or stack: */
6837             if (rcount < 3)
6838                 rcount += (rcount % 2);
6839             else
6840             {
6841                 rcount = 4;
6842                 argspos += (argspos % 2);
6843             }
6844             ntemp = sizeof(*arg) / sizeof(DWORD);
6845             while (ntemp > 0)
6846             {
6847                 if (rcount < 4)
6848                     regs.r[rcount++] = *pdwarg++;
6849                 else
6850                     args[argspos++] = *pdwarg++;
6851                 --ntemp;
6852             }
6853             break;
6854         case VT_BOOL:  /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
6855             if (rcount < 4)
6856                 regs.r[rcount++] = V_BOOL(arg);
6857             else
6858                 args[argspos++] = V_BOOL(arg);
6859             break;
6860         case VT_R4:             /* these must be 4-byte aligned, and put in 's' regs or stack, as they are single-floats */
6861 #ifndef __SOFTFP__
6862             if (!(scount % 2)) scount = max( scount, dcount * 2 );
6863             if (scount < 16)
6864                 regs.sd.s[scount++] = V_R4(arg);
6865             else
6866                 args[argspos++] = V_UI4(arg);
6867             break;
6868 #endif
6869         default:
6870             if (rcount < 4)
6871                 regs.r[rcount++] = V_UI4(arg);
6872             else
6873                 args[argspos++] = V_UI4(arg);
6874             break;
6875         }
6876         TRACE("arg %u: type %s %s\n", i, debugstr_vt(prgvt[i]), debugstr_variant(arg));
6877     }
6878 
6879     argspos += (argspos % 2);   /* Make sure stack function alignment is 8-byte */
6880 
6881     switch (vtReturn)
6882     {
6883     case VT_EMPTY:      /* EMPTY = no return value */
6884     case VT_DECIMAL:    /* DECIMAL and VARIANT already have a pointer argument passed (see above) */
6885     case VT_VARIANT:
6886         call_method( func, argspos, args, (DWORD*)&regs );
6887         break;
6888     case VT_R4:
6889         V_R4(pvargResult) = call_float_method( func, argspos, args, (DWORD*)&regs );
6890         break;
6891     case VT_R8:
6892     case VT_DATE:
6893         V_R8(pvargResult) = call_double_method( func, argspos, args, (DWORD*)&regs );
6894         break;
6895     case VT_I8:
6896     case VT_UI8:
6897     case VT_CY:
6898         V_UI8(pvargResult) = call_method( func, argspos, args, (DWORD*)&regs );
6899         break;
6900     default:
6901         V_UI4(pvargResult) = call_method( func, argspos, args, (DWORD*)&regs );
6902         break;
6903     }
6904     heap_free( args );
6905     if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
6906     TRACE("retval: %s\n", debugstr_variant(pvargResult));
6907     return S_OK;
6908 }
6909 
6910 #elif defined(__aarch64__)
6911 
6912 extern DWORD_PTR CDECL call_method( void *func, int nb_stk_args, const DWORD_PTR *stk_args, const DWORD_PTR *reg_args );
6913 extern float CDECL call_float_method( void *func, int nb_stk_args, const DWORD_PTR *stk_args, const DWORD_PTR *reg_args );
6914 extern double CDECL call_double_method( void *func, int nb_stk_args, const DWORD_PTR *stk_args, const DWORD_PTR *reg_args );
6915 __ASM_GLOBAL_FUNC( call_method,
6916                    "stp x29, x30, [sp, #-16]!\n\t"
6917                    "mov x29, sp\n\t"
6918                    "sub sp, sp, x1, lsl #3\n\t"
6919                    "cbz x1, 2f\n"
6920                    "1:\tsub x1, x1, #1\n\t"
6921                    "ldr x4, [x2, x1, lsl #3]\n\t"
6922                    "str x4, [sp, x1, lsl #3]\n\t"
6923                    "cbnz x1, 1b\n"
6924                    "2:\tmov x16, x0\n\t"
6925                    "mov x9, x3\n\t"
6926                    "ldp d0, d1, [x9]\n\t"
6927                    "ldp d2, d3, [x9, #0x10]\n\t"
6928                    "ldp d4, d5, [x9, #0x20]\n\t"
6929                    "ldp d6, d7, [x9, #0x30]\n\t"
6930                    "ldp x0, x1, [x9, #0x40]\n\t"
6931                    "ldp x2, x3, [x9, #0x50]\n\t"
6932                    "ldp x4, x5, [x9, #0x60]\n\t"
6933                    "ldp x6, x7, [x9, #0x70]\n\t"
6934                    "ldr x8, [x9, #0x80]\n\t"
6935                    "blr x16\n\t"
6936                    "mov sp, x29\n\t"
6937                    "ldp x29, x30, [sp], #16\n\t"
6938                    "ret" )
6939 __ASM_GLOBAL_FUNC( call_float_method,
6940                    "b " __ASM_NAME("call_method") )
6941 __ASM_GLOBAL_FUNC( call_double_method,
6942                    "b " __ASM_NAME("call_method") )
6943 
6944 HRESULT WINAPI DispCallFunc( void *instance, ULONG_PTR offset, CALLCONV cc, VARTYPE ret_type, UINT count,
6945                              VARTYPE *types, VARIANTARG **vargs, VARIANT *result )
6946 {
6947     int argspos;
6948     void *func;
6949     UINT i;
6950     DWORD_PTR *args;
6951     struct
6952     {
6953         union
6954         {
6955             float f;
6956             double d;
6957         } fp[8];
6958         DWORD_PTR x[9];
6959     } regs;
6960     int rcount;      /* 64-bit register index count */
6961     int fpcount = 0; /* float register index count */
6962 
6963     TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
6964           instance, offset, cc, ret_type, count, types, vargs, result, V_VT(result));
6965 
6966     if (cc != CC_STDCALL && cc != CC_CDECL)
6967     {
6968         FIXME("unsupported calling convention %d\n",cc);
6969         return E_INVALIDARG;
6970     }
6971 
6972     argspos = 0;
6973     rcount = 0;
6974 
6975     if (instance)
6976     {
6977         const FARPROC *vtable = *(FARPROC **)instance;
6978         func = vtable[offset/sizeof(void *)];
6979         regs.x[rcount++] = (DWORD_PTR)instance; /* the This pointer is always the first parameter */
6980     }
6981     else func = (void *)offset;
6982 
6983     /* Determine if we need to pass a pointer for the return value as arg 0.  If so, do that */
6984     /*  first as it will need to be in the 'x' registers:                                    */
6985     switch (ret_type)
6986     {
6987     case VT_DECIMAL:
6988     case VT_VARIANT:
6989         regs.x[8] = (DWORD_PTR)result;  /* x8 is a pointer to the result */
6990         break;
6991     case VT_HRESULT:
6992         WARN("invalid return type %u\n", ret_type);
6993         return E_INVALIDARG;
6994     default:
6995         break;
6996     }
6997 
6998     /* maximum size for an argument is sizeof(VARIANT).  Also allow for return pointer and stack alignment. */
6999     args = heap_alloc( sizeof(VARIANT) * count + sizeof(DWORD_PTR) * 4 );
7000 
7001     for (i = 0; i < count; i++)
7002     {
7003         VARIANT *arg = vargs[i];
7004 
7005         switch (types[i])
7006         {
7007         case VT_EMPTY:
7008             break;
7009         case VT_R4:
7010             if (fpcount < 8) regs.fp[fpcount++].f = V_R4(arg);
7011             else *(float *)&args[argspos++] = V_R4(arg);
7012             break;
7013         case VT_R8:
7014         case VT_DATE:
7015             if (fpcount < 8) regs.fp[fpcount++].d = V_R8(arg);
7016             else *(double *)&args[argspos++] = V_R8(arg);
7017             break;
7018         case VT_DECIMAL:
7019         case VT_VARIANT:
7020             if (rcount < 7)
7021             {
7022                 memcpy( &regs.x[rcount], arg, sizeof(*arg) );
7023                 rcount += 2;
7024             }
7025             else
7026             {
7027                 memcpy( &args[argspos], arg, sizeof(*arg) );
7028                 argspos += 2;
7029             }
7030             break;
7031         case VT_BOOL:  /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
7032             if (rcount < 8) regs.x[rcount++] = V_BOOL(arg);
7033             else args[argspos++] = V_BOOL(arg);
7034             break;
7035         default:
7036             if (rcount < 8) regs.x[rcount++] = V_UI8(arg);
7037             else args[argspos++] = V_UI8(arg);
7038             break;
7039         }
7040         TRACE("arg %u: type %s %s\n", i, debugstr_vt(types[i]), debugstr_variant(arg));
7041     }
7042 
7043     argspos += (argspos % 2);   /* Make sure stack function alignment is 16-byte */
7044 
7045     switch (ret_type)
7046     {
7047     case VT_EMPTY:      /* EMPTY = no return value */
7048     case VT_DECIMAL:    /* DECIMAL and VARIANT already have a pointer argument passed (see above) */
7049     case VT_VARIANT:
7050         call_method( func, argspos, args, (DWORD_PTR *)&regs );
7051         break;
7052     case VT_R4:
7053         V_R4(result) = call_float_method( func, argspos, args, (DWORD_PTR *)&regs );
7054         break;
7055     case VT_R8:
7056     case VT_DATE:
7057         V_R8(result) = call_double_method( func, argspos, args, (DWORD_PTR *)&regs );
7058         break;
7059     default:
7060         V_UI8(result) = call_method( func, argspos, args, (DWORD_PTR *)&regs );
7061         break;
7062     }
7063     heap_free( args );
7064     if (ret_type != VT_VARIANT) V_VT(result) = ret_type;
7065     TRACE("retval: %s\n", debugstr_variant(result));
7066     return S_OK;
7067 }
7068 
7069 #else  /* __aarch64__ */
7070 
7071 HRESULT WINAPI DispCallFunc( void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn,
7072                              UINT cActuals, VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult )
7073 {
7074     FIXME( "(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d)): not implemented for this CPU\n",
7075            pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg, pvargResult, V_VT(pvargResult));
7076     return E_NOTIMPL;
7077 }
7078 
7079 #endif
7080 
7081 static HRESULT userdefined_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
7082 {
7083     HRESULT hr = S_OK;
7084     ITypeInfo *tinfo2 = NULL;
7085     TYPEATTR *tattr = NULL;
7086 
7087     hr = ITypeInfo_GetRefTypeInfo(tinfo, tdesc->u.hreftype, &tinfo2);
7088     if (hr)
7089     {
7090         ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED, "
7091             "hr = 0x%08x\n",
7092               tdesc->u.hreftype, hr);
7093         return hr;
7094     }
7095     hr = ITypeInfo_GetTypeAttr(tinfo2, &tattr);
7096     if (hr)
7097     {
7098         ERR("ITypeInfo_GetTypeAttr failed, hr = 0x%08x\n", hr);
7099         ITypeInfo_Release(tinfo2);
7100         return hr;
7101     }
7102 
7103     switch (tattr->typekind)
7104     {
7105     case TKIND_ENUM:
7106         *vt |= VT_I4;
7107         break;
7108 
7109     case TKIND_ALIAS:
7110         hr = typedescvt_to_variantvt(tinfo2, &tattr->tdescAlias, vt);
7111         break;
7112 
7113     case TKIND_INTERFACE:
7114         if (tattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE)
7115            *vt |= VT_DISPATCH;
7116         else
7117            *vt |= VT_UNKNOWN;
7118         break;
7119 
7120     case TKIND_DISPATCH:
7121         *vt |= VT_DISPATCH;
7122         break;
7123 
7124     case TKIND_COCLASS:
7125         *vt |= VT_DISPATCH;
7126         break;
7127 
7128     case TKIND_RECORD:
7129         FIXME("TKIND_RECORD unhandled.\n");
7130         hr = E_NOTIMPL;
7131         break;
7132 
7133     case TKIND_UNION:
7134         FIXME("TKIND_UNION unhandled.\n");
7135         hr = E_NOTIMPL;
7136         break;
7137 
7138     default:
7139         FIXME("TKIND %d unhandled.\n",tattr->typekind);
7140         hr = E_NOTIMPL;
7141         break;
7142     }
7143     ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
7144     ITypeInfo_Release(tinfo2);
7145     return hr;
7146 }
7147 
7148 static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
7149 {
7150     HRESULT hr = S_OK;
7151 
7152     /* enforce only one level of pointer indirection */
7153     if (!(*vt & VT_BYREF) && !(*vt & VT_ARRAY) && (tdesc->vt == VT_PTR))
7154     {
7155         tdesc = tdesc->u.lptdesc;
7156 
7157         /* munch VT_PTR -> VT_USERDEFINED(interface) into VT_UNKNOWN or
7158          * VT_DISPATCH and VT_PTR -> VT_PTR -> VT_USERDEFINED(interface) into
7159          * VT_BYREF|VT_DISPATCH or VT_BYREF|VT_UNKNOWN */
7160         if ((tdesc->vt == VT_USERDEFINED) ||
7161             ((tdesc->vt == VT_PTR) && (tdesc->u.lptdesc->vt == VT_USERDEFINED)))
7162         {
7163             VARTYPE vt_userdefined = 0;
7164             const TYPEDESC *tdesc_userdefined = tdesc;
7165             if (tdesc->vt == VT_PTR)
7166             {
7167                 vt_userdefined = VT_BYREF;
7168                 tdesc_userdefined = tdesc->u.lptdesc;
7169             }
7170             hr = userdefined_to_variantvt(tinfo, tdesc_userdefined, &vt_userdefined);
7171             if ((hr == S_OK) &&
7172                 (((vt_userdefined & VT_TYPEMASK) == VT_UNKNOWN) ||
7173                  ((vt_userdefined & VT_TYPEMASK) == VT_DISPATCH)))
7174             {
7175                 *vt |= vt_userdefined;
7176                 return S_OK;
7177             }
7178         }
7179         *vt = VT_BYREF;
7180     }
7181 
7182     switch (tdesc->vt)
7183     {
7184     case VT_HRESULT:
7185         *vt |= VT_ERROR;
7186         break;
7187     case VT_USERDEFINED:
7188         hr = userdefined_to_variantvt(tinfo, tdesc, vt);
7189         break;
7190     case VT_VOID:
7191     case VT_CARRAY:
7192     case VT_PTR:
7193     case VT_LPSTR:
7194     case VT_LPWSTR:
7195         ERR("cannot convert type %d into variant VT\n", tdesc->vt);
7196         hr = DISP_E_BADVARTYPE;
7197         break;
7198     case VT_SAFEARRAY:
7199         *vt |= VT_ARRAY;
7200         hr = typedescvt_to_variantvt(tinfo, tdesc->u.lptdesc, vt);
7201         break;
7202     case VT_INT:
7203         *vt |= VT_I4;
7204         break;
7205     case VT_UINT:
7206         *vt |= VT_UI4;
7207         break;
7208     default:
7209         *vt |= tdesc->vt;
7210         break;
7211     }
7212     return hr;
7213 }
7214 
7215 static HRESULT get_iface_guid(ITypeInfo *tinfo, HREFTYPE href, GUID *guid)
7216 {
7217     ITypeInfo *tinfo2;
7218     TYPEATTR *tattr;
7219     HRESULT hres;
7220     int flags, i;
7221 
7222     hres = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2);
7223     if(FAILED(hres))
7224         return hres;
7225 
7226     hres = ITypeInfo_GetTypeAttr(tinfo2, &tattr);
7227     if(FAILED(hres)) {
7228         ITypeInfo_Release(tinfo2);
7229         return hres;
7230     }
7231 
7232     switch(tattr->typekind) {
7233     case TKIND_ALIAS:
7234         hres = get_iface_guid(tinfo2, tattr->tdescAlias.u.hreftype, guid);
7235         break;
7236 
7237     case TKIND_INTERFACE:
7238     case TKIND_DISPATCH:
7239         *guid = tattr->guid;
7240         break;
7241 
7242     case TKIND_COCLASS:
7243         for (i = 0; i < tattr->cImplTypes; i++)
7244         {
7245             ITypeInfo_GetImplTypeFlags(tinfo2, i, &flags);
7246             if (flags & IMPLTYPEFLAG_FDEFAULT)
7247                 break;
7248         }
7249 
7250         if (i == tattr->cImplTypes)
7251             i = 0;
7252 
7253         hres = ITypeInfo_GetRefTypeOfImplType(tinfo2, i, &href);
7254         if (SUCCEEDED(hres))
7255             hres = get_iface_guid(tinfo2, href, guid);
7256         break;
7257 
7258     default:
7259         ERR("Unexpected typekind %d\n", tattr->typekind);
7260         hres = E_UNEXPECTED;
7261     }
7262 
7263     ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
7264     ITypeInfo_Release(tinfo2);
7265     return hres;
7266 }
7267 
7268 static inline BOOL func_restricted( const FUNCDESC *desc )
7269 {
7270     return (desc->wFuncFlags & FUNCFLAG_FRESTRICTED) && (desc->memid >= 0);
7271 }
7272 
7273 #define INVBUF_ELEMENT_SIZE \
7274     (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *) + sizeof(VARTYPE))
7275 #define INVBUF_GET_ARG_ARRAY(buffer, params) (buffer)
7276 #define INVBUF_GET_MISSING_ARG_ARRAY(buffer, params) \
7277     ((VARIANTARG *)((char *)(buffer) + sizeof(VARIANTARG) * (params)))
7278 #define INVBUF_GET_ARG_PTR_ARRAY(buffer, params) \
7279     ((VARIANTARG **)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG)) * (params)))
7280 #define INVBUF_GET_ARG_TYPE_ARRAY(buffer, params) \
7281     ((VARTYPE *)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *)) * (params)))
7282 
7283 static HRESULT WINAPI ITypeInfo_fnInvoke(
7284     ITypeInfo2 *iface,
7285     VOID  *pIUnk,
7286     MEMBERID memid,
7287     UINT16 wFlags,
7288     DISPPARAMS  *pDispParams,
7289     VARIANT  *pVarResult,
7290     EXCEPINFO  *pExcepInfo,
7291     UINT  *pArgErr)
7292 {
7293     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
7294     int i;
7295     unsigned int var_index;
7296     TYPEKIND type_kind;
7297     HRESULT hres;
7298     const TLBFuncDesc *pFuncInfo;
7299     UINT fdc;
7300 
7301     TRACE("(%p)(%p,id=%d,flags=0x%08x,%p,%p,%p,%p)\n",
7302       This,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr
7303     );
7304 
7305     if( This->typeattr.wTypeFlags & TYPEFLAG_FRESTRICTED )
7306         return DISP_E_MEMBERNOTFOUND;
7307 
7308     if (!pDispParams)
7309     {
7310         ERR("NULL pDispParams not allowed\n");
7311         return E_INVALIDARG;
7312     }
7313 
7314     dump_DispParms(pDispParams);
7315 
7316     if (pDispParams->cNamedArgs > pDispParams->cArgs)
7317     {
7318         ERR("named argument array cannot be bigger than argument array (%d/%d)\n",
7319             pDispParams->cNamedArgs, pDispParams->cArgs);
7320         return E_INVALIDARG;
7321     }
7322 
7323     /* we do this instead of using GetFuncDesc since it will return a fake
7324      * FUNCDESC for dispinterfaces and we want the real function description */
7325     for (fdc = 0; fdc < This->typeattr.cFuncs; ++fdc){
7326         pFuncInfo = &This->funcdescs[fdc];
7327         if ((memid == pFuncInfo->funcdesc.memid) &&
7328             (wFlags & pFuncInfo->funcdesc.invkind) &&
7329             !func_restricted( &pFuncInfo->funcdesc ))
7330             break;
7331     }
7332 
7333     if (fdc < This->typeattr.cFuncs) {
7334         const FUNCDESC *func_desc = &pFuncInfo->funcdesc;
7335 
7336         if (TRACE_ON(ole))
7337         {
7338             TRACE("invoking:\n");
7339             dump_TLBFuncDescOne(pFuncInfo);
7340         }
7341 
7342 	switch (func_desc->funckind) {
7343 	case FUNC_PUREVIRTUAL:
7344 	case FUNC_VIRTUAL: {
7345             void *buffer = heap_alloc_zero(INVBUF_ELEMENT_SIZE * func_desc->cParams);
7346             VARIANT varresult;
7347             VARIANT retval; /* pointer for storing byref retvals in */
7348             VARIANTARG **prgpvarg = INVBUF_GET_ARG_PTR_ARRAY(buffer, func_desc->cParams);
7349             VARIANTARG *rgvarg = INVBUF_GET_ARG_ARRAY(buffer, func_desc->cParams);
7350             VARTYPE *rgvt = INVBUF_GET_ARG_TYPE_ARRAY(buffer, func_desc->cParams);
7351             UINT cNamedArgs = pDispParams->cNamedArgs;
7352             DISPID *rgdispidNamedArgs = pDispParams->rgdispidNamedArgs;
7353             UINT vargs_converted=0;
7354 
7355             hres = S_OK;
7356 
7357             if (func_desc->invkind & (INVOKE_PROPERTYPUT|INVOKE_PROPERTYPUTREF))
7358             {
7359                 if (!cNamedArgs || (rgdispidNamedArgs[0] != DISPID_PROPERTYPUT))
7360                 {
7361                     ERR("first named arg for property put invocation must be DISPID_PROPERTYPUT\n");
7362                     hres = DISP_E_PARAMNOTFOUND;
7363                     goto func_fail;
7364                 }
7365             }
7366 
7367             if (func_desc->cParamsOpt < 0 && cNamedArgs)
7368             {
7369                 ERR("functions with the vararg attribute do not support named arguments\n");
7370                 hres = DISP_E_NONAMEDARGS;
7371                 goto func_fail;
7372             }
7373 
7374             for (i = 0; i < func_desc->cParams; i++)
7375             {
7376                 TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc;
7377                 hres = typedescvt_to_variantvt((ITypeInfo *)iface, tdesc, &rgvt[i]);
7378                 if (FAILED(hres))
7379                     goto func_fail;
7380             }
7381 
7382             TRACE("changing args\n");
7383             for (i = 0; i < func_desc->cParams; i++)
7384             {
7385                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
7386                 TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc;
7387                 VARIANTARG *src_arg;
7388 
7389                 if (wParamFlags & PARAMFLAG_FLCID)
7390                 {
7391                     VARIANTARG *arg;
7392                     arg = prgpvarg[i] = &rgvarg[i];
7393                     V_VT(arg) = VT_I4;
7394                     V_I4(arg) = This->pTypeLib->lcid;
7395                     continue;
7396                 }
7397 
7398                 src_arg = NULL;
7399 
7400                 if (cNamedArgs)
7401                 {
7402                     USHORT j;
7403                     for (j = 0; j < cNamedArgs; j++)
7404                         if (rgdispidNamedArgs[j] == i || (i == func_desc->cParams-1 && rgdispidNamedArgs[j] == DISPID_PROPERTYPUT))
7405                         {
7406                             src_arg = &pDispParams->rgvarg[j];
7407                             break;
7408                         }
7409                 }
7410 
7411                 if (!src_arg && vargs_converted + cNamedArgs < pDispParams->cArgs)
7412                 {
7413                     src_arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted];
7414                     vargs_converted++;
7415                 }
7416 
7417                 if (wParamFlags & PARAMFLAG_FRETVAL)
7418                 {
7419                     /* under most conditions the caller is not allowed to
7420                      * pass in a dispparam arg in the index of what would be
7421                      * the retval parameter. however, there is an exception
7422                      * where the extra parameter is used in an extra
7423                      * IDispatch::Invoke below */
7424                     if ((i < pDispParams->cArgs) &&
7425                         ((func_desc->cParams != 1) || !pVarResult ||
7426                          !(func_desc->invkind & INVOKE_PROPERTYGET)))
7427                     {
7428                         hres = DISP_E_BADPARAMCOUNT;
7429                         break;
7430                     }
7431 
7432                     /* note: this check is placed so that if the caller passes
7433                      * in a VARIANTARG for the retval we just ignore it, like
7434                      * native does */
7435                     if (i == func_desc->cParams - 1)
7436                     {
7437                         VARIANTARG *arg;
7438                         arg = prgpvarg[i] = &rgvarg[i];
7439                         memset(arg, 0, sizeof(*arg));
7440                         V_VT(arg) = rgvt[i];
7441                         memset(&retval, 0, sizeof(retval));
7442                         V_BYREF(arg) = &retval;
7443                     }
7444                     else
7445                     {
7446                         ERR("[retval] parameter must be the last parameter of the method (%d/%d)\n", i, func_desc->cParams);
7447                         hres = E_UNEXPECTED;
7448                         break;
7449                     }
7450                 }
7451                 else if (src_arg && !((wParamFlags & PARAMFLAG_FOPT) &&
7452                          V_VT(src_arg) == VT_ERROR && V_ERROR(src_arg) == DISP_E_PARAMNOTFOUND))
7453                 {
7454                     TRACE("%s\n", debugstr_variant(src_arg));
7455 
7456                     if(rgvt[i]!=V_VT(src_arg))
7457                     {
7458                         if (rgvt[i] == VT_VARIANT)
7459                             hres = VariantCopy(&rgvarg[i], src_arg);
7460                         else if (rgvt[i] == (VT_VARIANT | VT_BYREF))
7461                         {
7462                             if (rgvt[i] == V_VT(src_arg))
7463                                 V_VARIANTREF(&rgvarg[i]) = V_VARIANTREF(src_arg);
7464                             else
7465                             {
7466                                 VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
7467                                 if (wParamFlags & PARAMFLAG_FIN)
7468                                     hres = VariantCopy(&missing_arg[i], src_arg);
7469                                 V_VARIANTREF(&rgvarg[i]) = &missing_arg[i];
7470                             }
7471                             V_VT(&rgvarg[i]) = rgvt[i];
7472                         }
7473                         else if ((rgvt[i] == (VT_VARIANT | VT_ARRAY) || rgvt[i] == (VT_VARIANT | VT_ARRAY | VT_BYREF)) && func_desc->cParamsOpt < 0)
7474                         {
7475                             SAFEARRAY *a;
7476                             SAFEARRAYBOUND bound;
7477                             VARIANT *v;
7478                             LONG j;
7479                             bound.lLbound = 0;
7480                             bound.cElements = pDispParams->cArgs-i;
7481                             if (!(a = SafeArrayCreate(VT_VARIANT, 1, &bound)))
7482                             {
7483                                 ERR("SafeArrayCreate failed\n");
7484                                 break;
7485                             }
7486                             hres = SafeArrayAccessData(a, (LPVOID)&v);
7487                             if (hres != S_OK)
7488                             {
7489                                 ERR("SafeArrayAccessData failed with %x\n", hres);
7490                                 SafeArrayDestroy(a);
7491                                 break;
7492                             }
7493                             for (j = 0; j < bound.cElements; j++)
7494                                 VariantCopy(&v[j], &pDispParams->rgvarg[pDispParams->cArgs - 1 - i - j]);
7495                             hres = SafeArrayUnaccessData(a);
7496                             if (hres != S_OK)
7497                             {
7498                                 ERR("SafeArrayUnaccessData failed with %x\n", hres);
7499                                 SafeArrayDestroy(a);
7500                                 break;
7501                             }
7502                             if (rgvt[i] & VT_BYREF)
7503                                 V_BYREF(&rgvarg[i]) = &a;
7504                             else
7505                                 V_ARRAY(&rgvarg[i]) = a;
7506                             V_VT(&rgvarg[i]) = rgvt[i];
7507                         }
7508                         else if ((rgvt[i] & VT_BYREF) && !V_ISBYREF(src_arg))
7509                         {
7510                             VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
7511                             if (wParamFlags & PARAMFLAG_FIN)
7512                                 hres = VariantChangeType(&missing_arg[i], src_arg, 0, rgvt[i] & ~VT_BYREF);
7513                             else
7514                                 V_VT(&missing_arg[i]) = rgvt[i] & ~VT_BYREF;
7515                             V_BYREF(&rgvarg[i]) = &V_NONE(&missing_arg[i]);
7516                             V_VT(&rgvarg[i]) = rgvt[i];
7517                         }
7518                         else if ((rgvt[i] & VT_BYREF) && (rgvt[i] == V_VT(src_arg)))
7519                         {
7520                             V_BYREF(&rgvarg[i]) = V_BYREF(src_arg);
7521                             V_VT(&rgvarg[i]) = rgvt[i];
7522                         }
7523                         else
7524                         {
7525                             /* FIXME: this doesn't work for VT_BYREF arguments if
7526                              * they are not the same type as in the paramdesc */
7527                             V_VT(&rgvarg[i]) = V_VT(src_arg);
7528                             hres = VariantChangeType(&rgvarg[i], src_arg, 0, rgvt[i]);
7529                             V_VT(&rgvarg[i]) = rgvt[i];
7530                         }
7531 
7532                         if (FAILED(hres))
7533                         {
7534                             ERR("failed to convert param %d to %s from %s\n", i,
7535                                 debugstr_vt(rgvt[i]), debugstr_variant(src_arg));
7536                             break;
7537                         }
7538                         prgpvarg[i] = &rgvarg[i];
7539                     }
7540                     else
7541                     {
7542                         prgpvarg[i] = src_arg;
7543                     }
7544 
7545                     if((tdesc->vt == VT_USERDEFINED || (tdesc->vt == VT_PTR && tdesc->u.lptdesc->vt == VT_USERDEFINED))
7546                        && (V_VT(prgpvarg[i]) == VT_DISPATCH || V_VT(prgpvarg[i]) == VT_UNKNOWN)
7547                        && V_UNKNOWN(prgpvarg[i])) {
7548                         IUnknown *userdefined_iface;
7549                         GUID guid;
7550 
7551                         if (tdesc->vt == VT_PTR)
7552                             tdesc = tdesc->u.lptdesc;
7553 
7554                         hres = get_iface_guid((ITypeInfo*)iface, tdesc->u.hreftype, &guid);
7555                         if(FAILED(hres))
7556                             break;
7557 
7558                         hres = IUnknown_QueryInterface(V_UNKNOWN(prgpvarg[i]), &guid, (void**)&userdefined_iface);
7559                         if(FAILED(hres)) {
7560                             ERR("argument does not support %s interface\n", debugstr_guid(&guid));
7561                             break;
7562                         }
7563 
7564                         IUnknown_Release(V_UNKNOWN(prgpvarg[i]));
7565                         V_UNKNOWN(prgpvarg[i]) = userdefined_iface;
7566                     }
7567                 }
7568                 else if (wParamFlags & PARAMFLAG_FOPT)
7569                 {
7570                     VARIANTARG *arg;
7571                     arg = prgpvarg[i] = &rgvarg[i];
7572                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
7573                     {
7574                         hres = VariantCopy(arg, &func_desc->lprgelemdescParam[i].u.paramdesc.pparamdescex->varDefaultValue);
7575                         if (FAILED(hres))
7576                             break;
7577                     }
7578                     else
7579                     {
7580                         VARIANTARG *missing_arg;
7581                         /* if the function wants a pointer to a variant then
7582                          * set that up, otherwise just pass the VT_ERROR in
7583                          * the argument by value */
7584                         if (rgvt[i] & VT_BYREF)
7585                         {
7586                             missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams) + i;
7587                             V_VT(arg) = VT_VARIANT | VT_BYREF;
7588                             V_VARIANTREF(arg) = missing_arg;
7589                         }
7590                         else
7591                             missing_arg = arg;
7592                         V_VT(missing_arg) = VT_ERROR;
7593                         V_ERROR(missing_arg) = DISP_E_PARAMNOTFOUND;
7594                     }
7595                 }
7596                 else
7597                 {
7598                     hres = DISP_E_BADPARAMCOUNT;
7599                     break;
7600                 }
7601             }
7602             if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
7603 
7604             /* VT_VOID is a special case for return types, so it is not
7605              * handled in the general function */
7606             if (func_desc->elemdescFunc.tdesc.vt == VT_VOID)
7607                 V_VT(&varresult) = VT_EMPTY;
7608             else
7609             {
7610                 V_VT(&varresult) = 0;
7611                 hres = typedescvt_to_variantvt((ITypeInfo *)iface, &func_desc->elemdescFunc.tdesc, &V_VT(&varresult));
7612                 if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
7613             }
7614 
7615             hres = DispCallFunc(pIUnk, func_desc->oVft & 0xFFFC, func_desc->callconv,
7616                                 V_VT(&varresult), func_desc->cParams, rgvt,
7617                                 prgpvarg, &varresult);
7618 
7619             vargs_converted = 0;
7620 
7621             for (i = 0; i < func_desc->cParams; i++)
7622             {
7623                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
7624                 VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
7625 
7626                 if (wParamFlags & PARAMFLAG_FLCID)
7627                     continue;
7628                 else if (wParamFlags & PARAMFLAG_FRETVAL)
7629                 {
7630                     TRACE("[retval] value: %s\n", debugstr_variant(prgpvarg[i]));
7631 
7632                     if (pVarResult)
7633                     {
7634                         VariantInit(pVarResult);
7635                         /* deref return value */
7636                         hres = VariantCopyInd(pVarResult, prgpvarg[i]);
7637                     }
7638 
7639                     VARIANT_ClearInd(prgpvarg[i]);
7640                 }
7641                 else if (vargs_converted < pDispParams->cArgs)
7642                 {
7643                     VARIANTARG *arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted];
7644                     if (wParamFlags & PARAMFLAG_FOUT)
7645                     {
7646                         if ((rgvt[i] & VT_BYREF) && !(V_VT(arg) & VT_BYREF))
7647                         {
7648                             hres = VariantChangeType(arg, &rgvarg[i], 0, V_VT(arg));
7649 
7650                             if (FAILED(hres))
7651                             {
7652                                 ERR("failed to convert param %d to vt %d\n", i,
7653                                     V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted]));
7654                                 break;
7655                             }
7656                         }
7657                     }
7658                     else if (V_VT(prgpvarg[i]) == (VT_VARIANT | VT_ARRAY) &&
7659                              func_desc->cParamsOpt < 0 &&
7660                              i == func_desc->cParams-1)
7661                     {
7662                         SAFEARRAY *a = V_ARRAY(prgpvarg[i]);
7663                         LONG j, ubound;
7664                         VARIANT *v;
7665                         hres = SafeArrayGetUBound(a, 1, &ubound);
7666                         if (hres != S_OK)
7667                         {
7668                             ERR("SafeArrayGetUBound failed with %x\n", hres);
7669                             break;
7670                         }
7671                         hres = SafeArrayAccessData(a, (LPVOID)&v);
7672                         if (hres != S_OK)
7673                         {
7674                             ERR("SafeArrayAccessData failed with %x\n", hres);
7675                             break;
7676                         }
7677                         for (j = 0; j <= ubound; j++)
7678                             VariantClear(&v[j]);
7679                         hres = SafeArrayUnaccessData(a);
7680                         if (hres != S_OK)
7681                         {
7682                             ERR("SafeArrayUnaccessData failed with %x\n", hres);
7683                             break;
7684                         }
7685                     }
7686                     VariantClear(&rgvarg[i]);
7687                     vargs_converted++;
7688                 }
7689                 else if (wParamFlags & PARAMFLAG_FOPT)
7690                 {
7691                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
7692                         VariantClear(&rgvarg[i]);
7693                 }
7694 
7695                 VariantClear(&missing_arg[i]);
7696             }
7697 
7698             if ((V_VT(&varresult) == VT_ERROR) && FAILED(V_ERROR(&varresult)))
7699             {
7700                 WARN("invoked function failed with error 0x%08x\n", V_ERROR(&varresult));
7701                 hres = DISP_E_EXCEPTION;
7702                 if (pExcepInfo)
7703                 {
7704                     IErrorInfo *pErrorInfo;
7705                     pExcepInfo->scode = V_ERROR(&varresult);
7706                     if (GetErrorInfo(0, &pErrorInfo) == S_OK)
7707                     {
7708                         IErrorInfo_GetDescription(pErrorInfo, &pExcepInfo->bstrDescription);
7709                         IErrorInfo_GetHelpFile(pErrorInfo, &pExcepInfo->bstrHelpFile);
7710                         IErrorInfo_GetSource(pErrorInfo, &pExcepInfo->bstrSource);
7711                         IErrorInfo_GetHelpContext(pErrorInfo, &pExcepInfo->dwHelpContext);
7712 
7713                         IErrorInfo_Release(pErrorInfo);
7714                     }
7715                 }
7716             }
7717             if (V_VT(&varresult) != VT_ERROR)
7718             {
7719                 TRACE("varresult value: %s\n", debugstr_variant(&varresult));
7720 
7721                 if (pVarResult)
7722                 {
7723                     VariantClear(pVarResult);
7724                     *pVarResult = varresult;
7725                 }
7726                 else
7727                     VariantClear(&varresult);
7728             }
7729 
7730             if (SUCCEEDED(hres) && pVarResult && (func_desc->cParams == 1) &&
7731                 (func_desc->invkind & INVOKE_PROPERTYGET) &&
7732                 (func_desc->lprgelemdescParam[0].u.paramdesc.wParamFlags & PARAMFLAG_FRETVAL) &&
7733                 (pDispParams->cArgs != 0))
7734             {
7735                 if (V_VT(pVarResult) == VT_DISPATCH)
7736                 {
7737                     IDispatch *pDispatch = V_DISPATCH(pVarResult);
7738                     /* Note: not VariantClear; we still need the dispatch
7739                      * pointer to be valid */
7740                     VariantInit(pVarResult);
7741                     hres = IDispatch_Invoke(pDispatch, DISPID_VALUE, &IID_NULL,
7742                         GetSystemDefaultLCID(), wFlags,
7743                         pDispParams, pVarResult, pExcepInfo, pArgErr);
7744                     IDispatch_Release(pDispatch);
7745                 }
7746                 else
7747                 {
7748                     VariantClear(pVarResult);
7749                     hres = DISP_E_NOTACOLLECTION;
7750                 }
7751             }
7752 
7753 func_fail:
7754             heap_free(buffer);
7755             break;
7756         }
7757 	case FUNC_DISPATCH:  {
7758 	   IDispatch *disp;
7759 
7760 	   hres = IUnknown_QueryInterface((LPUNKNOWN)pIUnk,&IID_IDispatch,(LPVOID*)&disp);
7761 	   if (SUCCEEDED(hres)) {
7762                FIXME("Calling Invoke in IDispatch iface. untested!\n");
7763                hres = IDispatch_Invoke(
7764                                      disp,memid,&IID_NULL,LOCALE_USER_DEFAULT,wFlags,pDispParams,
7765                                      pVarResult,pExcepInfo,pArgErr
7766                                      );
7767                if (FAILED(hres))
7768                    FIXME("IDispatch::Invoke failed with %08x. (Could be not a real error?)\n", hres);
7769                IDispatch_Release(disp);
7770            } else
7771 	       FIXME("FUNC_DISPATCH used on object without IDispatch iface?\n");
7772            break;
7773 	}
7774 	default:
7775             FIXME("Unknown function invocation type %d\n", func_desc->funckind);
7776             hres = E_FAIL;
7777             break;
7778         }
7779 
7780         TRACE("-- 0x%08x\n", hres);
7781         return hres;
7782 
7783     } else if(SUCCEEDED(hres = ITypeInfo2_GetVarIndexOfMemId(iface, memid, &var_index))) {
7784         VARDESC *var_desc;
7785 
7786         hres = ITypeInfo2_GetVarDesc(iface, var_index, &var_desc);
7787         if(FAILED(hres)) return hres;
7788 
7789         FIXME("varseek: Found memid, but variable-based invoking not supported\n");
7790         dump_VARDESC(var_desc);
7791         ITypeInfo2_ReleaseVarDesc(iface, var_desc);
7792         return E_NOTIMPL;
7793     }
7794 
7795     /* not found, look for it in inherited interfaces */
7796     ITypeInfo2_GetTypeKind(iface, &type_kind);
7797     if(type_kind == TKIND_INTERFACE || type_kind == TKIND_DISPATCH) {
7798         if(This->impltypes) {
7799             /* recursive search */
7800             ITypeInfo *pTInfo;
7801             hres = ITypeInfo2_GetRefTypeInfo(iface, This->impltypes[0].hRef, &pTInfo);
7802             if(SUCCEEDED(hres)){
7803                 hres = ITypeInfo_Invoke(pTInfo,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr);
7804                 ITypeInfo_Release(pTInfo);
7805                 return hres;
7806             }
7807             WARN("Could not search inherited interface!\n");
7808         }
7809     }
7810     WARN("did not find member id %d, flags 0x%x!\n", memid, wFlags);
7811     return DISP_E_MEMBERNOTFOUND;
7812 }
7813 
7814 /* ITypeInfo::GetDocumentation
7815  *
7816  * Retrieves the documentation string, the complete Help file name and path,
7817  * and the context ID for the Help topic for a specified type description.
7818  *
7819  * (Can be tested by the Visual Basic Editor in Word for instance.)
7820  */
7821 static HRESULT WINAPI ITypeInfo_fnGetDocumentation( ITypeInfo2 *iface,
7822         MEMBERID memid, BSTR  *pBstrName, BSTR  *pBstrDocString,
7823         DWORD  *pdwHelpContext, BSTR  *pBstrHelpFile)
7824 {
7825     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
7826     const TLBFuncDesc *pFDesc;
7827     const TLBVarDesc *pVDesc;
7828     TRACE("(%p) memid %d Name(%p) DocString(%p)"
7829           " HelpContext(%p) HelpFile(%p)\n",
7830         This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
7831     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
7832         if(pBstrName)
7833             *pBstrName=SysAllocString(TLB_get_bstr(This->Name));
7834         if(pBstrDocString)
7835             *pBstrDocString=SysAllocString(TLB_get_bstr(This->DocString));
7836         if(pdwHelpContext)
7837             *pdwHelpContext=This->dwHelpContext;
7838         if(pBstrHelpFile)
7839             *pBstrHelpFile=SysAllocString(TLB_get_bstr(This->pTypeLib->HelpFile));
7840         return S_OK;
7841     }else {/* for a member */
7842         pFDesc = TLB_get_funcdesc_by_memberid(This->funcdescs, This->typeattr.cFuncs, memid);
7843         if(pFDesc){
7844             if(pBstrName)
7845               *pBstrName = SysAllocString(TLB_get_bstr(pFDesc->Name));
7846             if(pBstrDocString)
7847               *pBstrDocString=SysAllocString(TLB_get_bstr(pFDesc->HelpString));
7848             if(pdwHelpContext)
7849               *pdwHelpContext=pFDesc->helpcontext;
7850             if(pBstrHelpFile)
7851               *pBstrHelpFile = SysAllocString(TLB_get_bstr(This->pTypeLib->HelpFile));
7852             return S_OK;
7853         }
7854         pVDesc = TLB_get_vardesc_by_memberid(This->vardescs, This->typeattr.cVars, memid);
7855         if(pVDesc){
7856             if(pBstrName)
7857               *pBstrName = SysAllocString(TLB_get_bstr(pVDesc->Name));
7858             if(pBstrDocString)
7859               *pBstrDocString=SysAllocString(TLB_get_bstr(pVDesc->HelpString));
7860             if(pdwHelpContext)
7861               *pdwHelpContext=pVDesc->HelpContext;
7862             if(pBstrHelpFile)
7863               *pBstrHelpFile = SysAllocString(TLB_get_bstr(This->pTypeLib->HelpFile));
7864             return S_OK;
7865         }
7866     }
7867 
7868     if(This->impltypes &&
7869        (This->typeattr.typekind == TKIND_INTERFACE || This->typeattr.typekind == TKIND_DISPATCH)) {
7870         /* recursive search */
7871         ITypeInfo *pTInfo;
7872         HRESULT result;
7873         result = ITypeInfo2_GetRefTypeInfo(iface, This->impltypes[0].hRef, &pTInfo);
7874         if(SUCCEEDED(result)) {
7875             result = ITypeInfo_GetDocumentation(pTInfo, memid, pBstrName,
7876                 pBstrDocString, pdwHelpContext, pBstrHelpFile);
7877             ITypeInfo_Release(pTInfo);
7878             return result;
7879         }
7880         WARN("Could not search inherited interface!\n");
7881     }
7882 
7883     WARN("member %d not found\n", memid);
7884     return TYPE_E_ELEMENTNOTFOUND;
7885 }
7886 
7887 /*  ITypeInfo::GetDllEntry
7888  *
7889  * Retrieves a description or specification of an entry point for a function
7890  * in a DLL.
7891  */
7892 static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid,
7893         INVOKEKIND invKind, BSTR  *pBstrDllName, BSTR  *pBstrName,
7894         WORD  *pwOrdinal)
7895 {
7896     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
7897     const TLBFuncDesc *pFDesc;
7898 
7899     TRACE("(%p)->(memid %x, %d, %p, %p, %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
7900 
7901     if (pBstrDllName) *pBstrDllName = NULL;
7902     if (pBstrName) *pBstrName = NULL;
7903     if (pwOrdinal) *pwOrdinal = 0;
7904 
7905     if (This->typeattr.typekind != TKIND_MODULE)
7906         return TYPE_E_BADMODULEKIND;
7907 
7908     pFDesc = TLB_get_funcdesc_by_memberid(This->funcdescs, This->typeattr.cFuncs, memid);
7909     if(pFDesc){
7910 	    dump_TypeInfo(This);
7911 	    if (TRACE_ON(ole))
7912 		dump_TLBFuncDescOne(pFDesc);
7913 
7914 	    if (pBstrDllName)
7915 		*pBstrDllName = SysAllocString(TLB_get_bstr(This->DllName));
7916 
7917             if (!IS_INTRESOURCE(pFDesc->Entry) && (pFDesc->Entry != (void*)-1)) {
7918 		if (pBstrName)
7919 		    *pBstrName = SysAllocString(TLB_get_bstr(pFDesc->Entry));
7920 		if (pwOrdinal)
7921 		    *pwOrdinal = -1;
7922 		return S_OK;
7923 	    }
7924 	    if (pBstrName)
7925 		*pBstrName = NULL;
7926 	    if (pwOrdinal)
7927 		*pwOrdinal = LOWORD(pFDesc->Entry);
7928 	    return S_OK;
7929         }
7930     return TYPE_E_ELEMENTNOTFOUND;
7931 }
7932 
7933 /* internal function to make the inherited interfaces' methods appear
7934  * part of the interface */
7935 static HRESULT ITypeInfoImpl_GetDispatchRefTypeInfo( ITypeInfo *iface,
7936     HREFTYPE *hRefType, ITypeInfo  **ppTInfo)
7937 {
7938     ITypeInfoImpl *This = impl_from_ITypeInfo(iface);
7939     HRESULT hr;
7940 
7941     TRACE("%p, 0x%x\n", iface, *hRefType);
7942 
7943     if (This->impltypes && (*hRefType & DISPATCH_HREF_MASK))
7944     {
7945         ITypeInfo *pSubTypeInfo;
7946 
7947         hr = ITypeInfo_GetRefTypeInfo(iface, This->impltypes[0].hRef, &pSubTypeInfo);
7948         if (FAILED(hr))
7949             return hr;
7950 
7951         hr = ITypeInfoImpl_GetDispatchRefTypeInfo(pSubTypeInfo,
7952                                                   hRefType, ppTInfo);
7953         ITypeInfo_Release(pSubTypeInfo);
7954         if (SUCCEEDED(hr))
7955             return hr;
7956     }
7957     *hRefType -= DISPATCH_HREF_OFFSET;
7958 
7959     if (!(*hRefType & DISPATCH_HREF_MASK))
7960         return ITypeInfo_GetRefTypeInfo(iface, *hRefType, ppTInfo);
7961     else
7962         return E_FAIL;
7963 }
7964 
7965 struct search_res_tlb_params
7966 {
7967     const GUID *guid;
7968     ITypeLib *pTLib;
7969 };
7970 
7971 static BOOL CALLBACK search_res_tlb(HMODULE hModule, LPCWSTR lpszType, LPWSTR lpszName, LONG_PTR lParam)
7972 {
7973     struct search_res_tlb_params *params = (LPVOID)lParam;
7974     static const WCHAR formatW[] = {'\\','%','d',0};
7975     WCHAR szPath[MAX_PATH+1];
7976     ITypeLib *pTLib = NULL;
7977     HRESULT ret;
7978     DWORD len;
7979 
7980     if (IS_INTRESOURCE(lpszName) == FALSE)
7981         return TRUE;
7982 
7983     if (!(len = GetModuleFileNameW(hModule, szPath, MAX_PATH)))
7984         return TRUE;
7985 
7986     if (swprintf(szPath + len, formatW, LOWORD(lpszName)) < 0)
7987         return TRUE;
7988 
7989     ret = LoadTypeLibEx(szPath, REGKIND_NONE, &pTLib);
7990     if (SUCCEEDED(ret))
7991     {
7992         ITypeLibImpl *impl = impl_from_ITypeLib(pTLib);
7993         if (IsEqualGUID(params->guid, impl->guid))
7994         {
7995             params->pTLib = pTLib;
7996             return FALSE; /* stop enumeration */
7997         }
7998         ITypeLib_Release(pTLib);
7999     }
8000 
8001     return TRUE;
8002 }
8003 
8004 /* ITypeInfo::GetRefTypeInfo
8005  *
8006  * If a type description references other type descriptions, it retrieves
8007  * the referenced type descriptions.
8008  */
8009 static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo(
8010 	ITypeInfo2 *iface,
8011         HREFTYPE hRefType,
8012 	ITypeInfo  **ppTInfo)
8013 {
8014     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8015     HRESULT result = E_FAIL;
8016 
8017     if(!ppTInfo)
8018         return E_INVALIDARG;
8019 
8020     if ((INT)hRefType < 0) {
8021         ITypeInfoImpl *pTypeInfoImpl;
8022 
8023         if (!(This->typeattr.wTypeFlags & TYPEFLAG_FDUAL) ||
8024                 !(This->typeattr.typekind == TKIND_INTERFACE ||
8025                     This->typeattr.typekind == TKIND_DISPATCH))
8026             return TYPE_E_ELEMENTNOTFOUND;
8027 
8028         /* when we meet a DUAL typeinfo, we must create the alternate
8029         * version of it.
8030         */
8031         pTypeInfoImpl = ITypeInfoImpl_Constructor();
8032 
8033         *pTypeInfoImpl = *This;
8034         pTypeInfoImpl->ref = 0;
8035         list_init(&pTypeInfoImpl->custdata_list);
8036 
8037         if (This->typeattr.typekind == TKIND_INTERFACE)
8038             pTypeInfoImpl->typeattr.typekind = TKIND_DISPATCH;
8039         else
8040             pTypeInfoImpl->typeattr.typekind = TKIND_INTERFACE;
8041 
8042         *ppTInfo = (ITypeInfo *)&pTypeInfoImpl->ITypeInfo2_iface;
8043         /* the AddRef implicitly adds a reference to the parent typelib, which
8044          * stops the copied data from being destroyed until the new typeinfo's
8045          * refcount goes to zero, but we need to signal to the new instance to
8046          * not free its data structures when it is destroyed */
8047         pTypeInfoImpl->not_attached_to_typelib = TRUE;
8048 
8049         ITypeInfo_AddRef(*ppTInfo);
8050 
8051         result = S_OK;
8052     } else if ((hRefType & DISPATCH_HREF_MASK) &&
8053         (This->typeattr.typekind == TKIND_DISPATCH))
8054     {
8055         HREFTYPE href_dispatch = hRefType;
8056         result = ITypeInfoImpl_GetDispatchRefTypeInfo((ITypeInfo *)iface, &href_dispatch, ppTInfo);
8057     } else {
8058         TLBRefType *ref_type;
8059         ITypeLib *pTLib = NULL;
8060         UINT i;
8061 
8062         if(!(hRefType & 0x1)){
8063             for(i = 0; i < This->pTypeLib->TypeInfoCount; ++i)
8064             {
8065                 if (This->pTypeLib->typeinfos[i]->hreftype == (hRefType&(~0x3)))
8066                 {
8067                     result = S_OK;
8068                     *ppTInfo = (ITypeInfo*)&This->pTypeLib->typeinfos[i]->ITypeInfo2_iface;
8069                     ITypeInfo_AddRef(*ppTInfo);
8070                     goto end;
8071                 }
8072             }
8073         }
8074 
8075         LIST_FOR_EACH_ENTRY(ref_type, &This->pTypeLib->ref_list, TLBRefType, entry)
8076         {
8077             if(ref_type->reference == (hRefType & (~0x3)))
8078                 break;
8079         }
8080         if(&ref_type->entry == &This->pTypeLib->ref_list)
8081         {
8082             FIXME("Can't find pRefType for ref %x\n", hRefType);
8083             goto end;
8084         }
8085 
8086         if(ref_type->pImpTLInfo == TLB_REF_INTERNAL) {
8087             UINT Index;
8088             TRACE("internal reference\n");
8089             result = ITypeInfo2_GetContainingTypeLib(iface, &pTLib, &Index);
8090         } else {
8091             if(ref_type->pImpTLInfo->pImpTypeLib) {
8092                 TRACE("typeinfo in imported typelib that is already loaded\n");
8093                 pTLib = (ITypeLib*)&ref_type->pImpTLInfo->pImpTypeLib->ITypeLib2_iface;
8094                 ITypeLib_AddRef(pTLib);
8095                 result = S_OK;
8096             } else {
8097                 static const WCHAR TYPELIBW[] = {'T','Y','P','E','L','I','B',0};
8098                 struct search_res_tlb_params params;
8099                 BSTR libnam;
8100 
8101                 TRACE("typeinfo in imported typelib that isn't already loaded\n");
8102 
8103                 /* Search in resource table */
8104                 params.guid  = TLB_get_guid_null(ref_type->pImpTLInfo->guid);
8105                 params.pTLib = NULL;
8106                 EnumResourceNamesW(NULL, TYPELIBW, search_res_tlb, (LONG_PTR)&params);
8107                 pTLib  = params.pTLib;
8108                 result = S_OK;
8109 
8110                 if (!pTLib)
8111                 {
8112                     /* Search on disk */
8113                     result = query_typelib_path(TLB_get_guid_null(ref_type->pImpTLInfo->guid),
8114                             ref_type->pImpTLInfo->wVersionMajor,
8115                             ref_type->pImpTLInfo->wVersionMinor,
8116                             This->pTypeLib->syskind,
8117                             ref_type->pImpTLInfo->lcid, &libnam, TRUE);
8118                     if (FAILED(result))
8119                         libnam = SysAllocString(ref_type->pImpTLInfo->name);
8120 
8121                     result = LoadTypeLib(libnam, &pTLib);
8122                     SysFreeString(libnam);
8123                 }
8124 
8125                 if(SUCCEEDED(result)) {
8126                     ref_type->pImpTLInfo->pImpTypeLib = impl_from_ITypeLib(pTLib);
8127                     ITypeLib_AddRef(pTLib);
8128                 }
8129             }
8130         }
8131         if(SUCCEEDED(result)) {
8132             if(ref_type->index == TLB_REF_USE_GUID)
8133                 result = ITypeLib_GetTypeInfoOfGuid(pTLib, TLB_get_guid_null(ref_type->guid), ppTInfo);
8134             else
8135                 result = ITypeLib_GetTypeInfo(pTLib, ref_type->index, ppTInfo);
8136         }
8137         if (pTLib != NULL)
8138             ITypeLib_Release(pTLib);
8139     }
8140 
8141 end:
8142     TRACE("(%p) hreftype 0x%04x loaded %s (%p)\n", This, hRefType,
8143           SUCCEEDED(result)? "SUCCESS":"FAILURE", *ppTInfo);
8144     return result;
8145 }
8146 
8147 /* ITypeInfo::AddressOfMember
8148  *
8149  * Retrieves the addresses of static functions or variables, such as those
8150  * defined in a DLL.
8151  */
8152 static HRESULT WINAPI ITypeInfo_fnAddressOfMember( ITypeInfo2 *iface,
8153         MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
8154 {
8155     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8156     HRESULT hr;
8157     BSTR dll, entry;
8158     WORD ordinal;
8159     HMODULE module;
8160 
8161     TRACE("(%p)->(0x%x, 0x%x, %p)\n", This, memid, invKind, ppv);
8162 
8163     hr = ITypeInfo2_GetDllEntry(iface, memid, invKind, &dll, &entry, &ordinal);
8164     if (FAILED(hr))
8165         return hr;
8166 
8167     module = LoadLibraryW(dll);
8168     if (!module)
8169     {
8170         ERR("couldn't load %s\n", debugstr_w(dll));
8171         SysFreeString(dll);
8172         SysFreeString(entry);
8173         return STG_E_FILENOTFOUND;
8174     }
8175     /* FIXME: store library somewhere where we can free it */
8176 
8177     if (entry)
8178     {
8179         LPSTR entryA;
8180         INT len = WideCharToMultiByte(CP_ACP, 0, entry, -1, NULL, 0, NULL, NULL);
8181         entryA = heap_alloc(len);
8182         WideCharToMultiByte(CP_ACP, 0, entry, -1, entryA, len, NULL, NULL);
8183 
8184         *ppv = GetProcAddress(module, entryA);
8185         if (!*ppv)
8186             ERR("function not found %s\n", debugstr_a(entryA));
8187 
8188         heap_free(entryA);
8189     }
8190     else
8191     {
8192         *ppv = GetProcAddress(module, MAKEINTRESOURCEA(ordinal));
8193         if (!*ppv)
8194             ERR("function not found %d\n", ordinal);
8195     }
8196 
8197     SysFreeString(dll);
8198     SysFreeString(entry);
8199 
8200     if (!*ppv)
8201         return TYPE_E_DLLFUNCTIONNOTFOUND;
8202 
8203     return S_OK;
8204 }
8205 
8206 /* ITypeInfo::CreateInstance
8207  *
8208  * Creates a new instance of a type that describes a component object class
8209  * (coclass).
8210  */
8211 static HRESULT WINAPI ITypeInfo_fnCreateInstance( ITypeInfo2 *iface,
8212         IUnknown *pOuterUnk, REFIID riid, VOID  **ppvObj)
8213 {
8214     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8215     HRESULT hr;
8216     TYPEATTR *pTA;
8217 
8218     TRACE("(%p)->(%p, %s, %p)\n", This, pOuterUnk, debugstr_guid(riid), ppvObj);
8219 
8220     *ppvObj = NULL;
8221 
8222     if(pOuterUnk)
8223     {
8224         WARN("Not able to aggregate\n");
8225         return CLASS_E_NOAGGREGATION;
8226     }
8227 
8228     hr = ITypeInfo2_GetTypeAttr(iface, &pTA);
8229     if(FAILED(hr)) return hr;
8230 
8231     if(pTA->typekind != TKIND_COCLASS)
8232     {
8233         WARN("CreateInstance on typeinfo of type %x\n", pTA->typekind);
8234         hr = E_INVALIDARG;
8235         goto end;
8236     }
8237 
8238     hr = S_FALSE;
8239     if(pTA->wTypeFlags & TYPEFLAG_FAPPOBJECT)
8240     {
8241         IUnknown *pUnk;
8242         hr = GetActiveObject(&pTA->guid, NULL, &pUnk);
8243         TRACE("GetActiveObject rets %08x\n", hr);
8244         if(hr == S_OK)
8245         {
8246             hr = IUnknown_QueryInterface(pUnk, riid, ppvObj);
8247             IUnknown_Release(pUnk);
8248         }
8249     }
8250 
8251     if(hr != S_OK)
8252         hr = CoCreateInstance(&pTA->guid, NULL,
8253                               CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
8254                               riid, ppvObj);
8255 
8256 end:
8257     ITypeInfo2_ReleaseTypeAttr(iface, pTA);
8258     return hr;
8259 }
8260 
8261 /* ITypeInfo::GetMops
8262  *
8263  * Retrieves marshalling information.
8264  */
8265 static HRESULT WINAPI ITypeInfo_fnGetMops( ITypeInfo2 *iface, MEMBERID memid,
8266 				BSTR  *pBstrMops)
8267 {
8268     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8269     FIXME("(%p %d) stub!\n", This, memid);
8270     *pBstrMops = NULL;
8271     return S_OK;
8272 }
8273 
8274 /* ITypeInfo::GetContainingTypeLib
8275  *
8276  * Retrieves the containing type library and the index of the type description
8277  * within that type library.
8278  */
8279 static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( ITypeInfo2 *iface,
8280         ITypeLib  * *ppTLib, UINT  *pIndex)
8281 {
8282     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8283 
8284     /* If a pointer is null, we simply ignore it, the ATL in particular passes pIndex as 0 */
8285     if (pIndex) {
8286       *pIndex=This->index;
8287       TRACE("returning pIndex=%d\n", *pIndex);
8288     }
8289 
8290     if (ppTLib) {
8291       *ppTLib = (ITypeLib *)&This->pTypeLib->ITypeLib2_iface;
8292       ITypeLib_AddRef(*ppTLib);
8293       TRACE("returning ppTLib=%p\n", *ppTLib);
8294     }
8295 
8296     return S_OK;
8297 }
8298 
8299 /* ITypeInfo::ReleaseTypeAttr
8300  *
8301  * Releases a TYPEATTR previously returned by Get
8302  *
8303  */
8304 static void WINAPI ITypeInfo_fnReleaseTypeAttr( ITypeInfo2 *iface,
8305         TYPEATTR* pTypeAttr)
8306 {
8307     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8308     TRACE("(%p)->(%p)\n", This, pTypeAttr);
8309     heap_free(pTypeAttr);
8310 }
8311 
8312 /* ITypeInfo::ReleaseFuncDesc
8313  *
8314  * Releases a FUNCDESC previously returned by GetFuncDesc. *
8315  */
8316 static void WINAPI ITypeInfo_fnReleaseFuncDesc(
8317 	ITypeInfo2 *iface,
8318         FUNCDESC *pFuncDesc)
8319 {
8320     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8321     SHORT i;
8322 
8323     TRACE("(%p)->(%p)\n", This, pFuncDesc);
8324 
8325     for (i = 0; i < pFuncDesc->cParams; i++)
8326         TLB_FreeElemDesc(&pFuncDesc->lprgelemdescParam[i]);
8327     TLB_FreeElemDesc(&pFuncDesc->elemdescFunc);
8328 
8329     SysFreeString((BSTR)pFuncDesc);
8330 }
8331 
8332 /* ITypeInfo::ReleaseVarDesc
8333  *
8334  * Releases a VARDESC previously returned by GetVarDesc.
8335  */
8336 static void WINAPI ITypeInfo_fnReleaseVarDesc( ITypeInfo2 *iface,
8337         VARDESC *pVarDesc)
8338 {
8339     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8340     TRACE("(%p)->(%p)\n", This, pVarDesc);
8341 
8342     TLB_FreeVarDesc(pVarDesc);
8343 }
8344 
8345 /* ITypeInfo2::GetTypeKind
8346  *
8347  * Returns the TYPEKIND enumeration quickly, without doing any allocations.
8348  *
8349  */
8350 static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo2 * iface,
8351     TYPEKIND *pTypeKind)
8352 {
8353     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8354     *pTypeKind = This->typeattr.typekind;
8355     TRACE("(%p) type 0x%0x\n", This,*pTypeKind);
8356     return S_OK;
8357 }
8358 
8359 /* ITypeInfo2::GetTypeFlags
8360  *
8361  * Returns the type flags without any allocations. This returns a DWORD type
8362  * flag, which expands the type flags without growing the TYPEATTR (type
8363  * attribute).
8364  *
8365  */
8366 static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo2 *iface, ULONG *pTypeFlags)
8367 {
8368     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8369     *pTypeFlags=This->typeattr.wTypeFlags;
8370     TRACE("(%p) flags 0x%x\n", This,*pTypeFlags);
8371     return S_OK;
8372 }
8373 
8374 /* ITypeInfo2::GetFuncIndexOfMemId
8375  * Binds to a specific member based on a known DISPID, where the member name
8376  * is not known (for example, when binding to a default member).
8377  *
8378  */
8379 static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo2 * iface,
8380     MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex)
8381 {
8382     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8383     UINT fdc;
8384     HRESULT result;
8385 
8386     for (fdc = 0; fdc < This->typeattr.cFuncs; ++fdc){
8387         const TLBFuncDesc *pFuncInfo = &This->funcdescs[fdc];
8388         if(memid == pFuncInfo->funcdesc.memid && (invKind & pFuncInfo->funcdesc.invkind))
8389             break;
8390     }
8391     if(fdc < This->typeattr.cFuncs) {
8392         *pFuncIndex = fdc;
8393         result = S_OK;
8394     } else
8395         result = TYPE_E_ELEMENTNOTFOUND;
8396 
8397     TRACE("(%p) memid 0x%08x invKind 0x%04x -> %s\n", This,
8398           memid, invKind, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
8399     return result;
8400 }
8401 
8402 /* TypeInfo2::GetVarIndexOfMemId
8403  *
8404  * Binds to a specific member based on a known DISPID, where the member name
8405  * is not known (for example, when binding to a default member).
8406  *
8407  */
8408 static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( ITypeInfo2 * iface,
8409     MEMBERID memid, UINT *pVarIndex)
8410 {
8411     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8412     TLBVarDesc *pVarInfo;
8413 
8414     TRACE("%p %d %p\n", iface, memid, pVarIndex);
8415 
8416     pVarInfo = TLB_get_vardesc_by_memberid(This->vardescs, This->typeattr.cVars, memid);
8417     if(!pVarInfo)
8418         return TYPE_E_ELEMENTNOTFOUND;
8419 
8420     *pVarIndex = (pVarInfo - This->vardescs);
8421 
8422     return S_OK;
8423 }
8424 
8425 /* ITypeInfo2::GetCustData
8426  *
8427  * Gets the custom data
8428  */
8429 static HRESULT WINAPI ITypeInfo2_fnGetCustData(
8430 	ITypeInfo2 * iface,
8431 	REFGUID guid,
8432 	VARIANT *pVarVal)
8433 {
8434     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8435     TLBCustData *pCData;
8436 
8437     TRACE("%p %s %p\n", This, debugstr_guid(guid), pVarVal);
8438 
8439     if(!guid || !pVarVal)
8440         return E_INVALIDARG;
8441 
8442     pCData = TLB_get_custdata_by_guid(This->pcustdata_list, guid);
8443 
8444     VariantInit( pVarVal);
8445     if (pCData)
8446         VariantCopy( pVarVal, &pCData->data);
8447     else
8448         VariantClear( pVarVal );
8449     return S_OK;
8450 }
8451 
8452 /* ITypeInfo2::GetFuncCustData
8453  *
8454  * Gets the custom data
8455  */
8456 static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData(
8457 	ITypeInfo2 * iface,
8458 	UINT index,
8459 	REFGUID guid,
8460 	VARIANT *pVarVal)
8461 {
8462     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8463     TLBCustData *pCData;
8464     TLBFuncDesc *pFDesc = &This->funcdescs[index];
8465 
8466     TRACE("%p %u %s %p\n", This, index, debugstr_guid(guid), pVarVal);
8467 
8468     if(index >= This->typeattr.cFuncs)
8469         return TYPE_E_ELEMENTNOTFOUND;
8470 
8471     pCData = TLB_get_custdata_by_guid(&pFDesc->custdata_list, guid);
8472     if(!pCData)
8473         return TYPE_E_ELEMENTNOTFOUND;
8474 
8475     VariantInit(pVarVal);
8476     VariantCopy(pVarVal, &pCData->data);
8477 
8478     return S_OK;
8479 }
8480 
8481 /* ITypeInfo2::GetParamCustData
8482  *
8483  * Gets the custom data
8484  */
8485 static HRESULT WINAPI ITypeInfo2_fnGetParamCustData(
8486 	ITypeInfo2 * iface,
8487 	UINT indexFunc,
8488 	UINT indexParam,
8489 	REFGUID guid,
8490 	VARIANT *pVarVal)
8491 {
8492     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8493     TLBCustData *pCData;
8494     TLBFuncDesc *pFDesc = &This->funcdescs[indexFunc];
8495 
8496     TRACE("%p %u %u %s %p\n", This, indexFunc, indexParam,
8497             debugstr_guid(guid), pVarVal);
8498 
8499     if(indexFunc >= This->typeattr.cFuncs)
8500         return TYPE_E_ELEMENTNOTFOUND;
8501 
8502     if(indexParam >= pFDesc->funcdesc.cParams)
8503         return TYPE_E_ELEMENTNOTFOUND;
8504 
8505     pCData = TLB_get_custdata_by_guid(&pFDesc->pParamDesc[indexParam].custdata_list, guid);
8506     if(!pCData)
8507         return TYPE_E_ELEMENTNOTFOUND;
8508 
8509     VariantInit(pVarVal);
8510     VariantCopy(pVarVal, &pCData->data);
8511 
8512     return S_OK;
8513 }
8514 
8515 /* ITypeInfo2::GetVarCustData
8516  *
8517  * Gets the custom data
8518  */
8519 static HRESULT WINAPI ITypeInfo2_fnGetVarCustData(
8520 	ITypeInfo2 * iface,
8521 	UINT index,
8522 	REFGUID guid,
8523 	VARIANT *pVarVal)
8524 {
8525     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8526     TLBCustData *pCData;
8527     TLBVarDesc *pVDesc = &This->vardescs[index];
8528 
8529     TRACE("%p %s %p\n", This, debugstr_guid(guid), pVarVal);
8530 
8531     if(index >= This->typeattr.cVars)
8532         return TYPE_E_ELEMENTNOTFOUND;
8533 
8534     pCData = TLB_get_custdata_by_guid(&pVDesc->custdata_list, guid);
8535     if(!pCData)
8536         return TYPE_E_ELEMENTNOTFOUND;
8537 
8538     VariantInit(pVarVal);
8539     VariantCopy(pVarVal, &pCData->data);
8540 
8541     return S_OK;
8542 }
8543 
8544 /* ITypeInfo2::GetImplCustData
8545  *
8546  * Gets the custom data
8547  */
8548 static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData(
8549 	ITypeInfo2 * iface,
8550 	UINT index,
8551 	REFGUID guid,
8552 	VARIANT *pVarVal)
8553 {
8554     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8555     TLBCustData *pCData;
8556     TLBImplType *pRDesc = &This->impltypes[index];
8557 
8558     TRACE("%p %u %s %p\n", This, index, debugstr_guid(guid), pVarVal);
8559 
8560     if(index >= This->typeattr.cImplTypes)
8561         return TYPE_E_ELEMENTNOTFOUND;
8562 
8563     pCData = TLB_get_custdata_by_guid(&pRDesc->custdata_list, guid);
8564     if(!pCData)
8565         return TYPE_E_ELEMENTNOTFOUND;
8566 
8567     VariantInit(pVarVal);
8568     VariantCopy(pVarVal, &pCData->data);
8569 
8570     return S_OK;
8571 }
8572 
8573 /* ITypeInfo2::GetDocumentation2
8574  *
8575  * Retrieves the documentation string, the complete Help file name and path,
8576  * the localization context to use, and the context ID for the library Help
8577  * topic in the Help file.
8578  *
8579  */
8580 static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2(
8581 	ITypeInfo2 * iface,
8582 	MEMBERID memid,
8583 	LCID lcid,
8584 	BSTR *pbstrHelpString,
8585 	DWORD *pdwHelpStringContext,
8586 	BSTR *pbstrHelpStringDll)
8587 {
8588     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8589     const TLBFuncDesc *pFDesc;
8590     const TLBVarDesc *pVDesc;
8591     TRACE("(%p) memid %d lcid(0x%x)  HelpString(%p) "
8592           "HelpStringContext(%p) HelpStringDll(%p)\n",
8593           This, memid, lcid, pbstrHelpString, pdwHelpStringContext,
8594           pbstrHelpStringDll );
8595     /* the help string should be obtained from the helpstringdll,
8596      * using the _DLLGetDocumentation function, based on the supplied
8597      * lcid. Nice to do sometime...
8598      */
8599     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
8600         if(pbstrHelpString)
8601             *pbstrHelpString=SysAllocString(TLB_get_bstr(This->Name));
8602         if(pdwHelpStringContext)
8603             *pdwHelpStringContext=This->dwHelpStringContext;
8604         if(pbstrHelpStringDll)
8605             *pbstrHelpStringDll=
8606                 SysAllocString(TLB_get_bstr(This->pTypeLib->HelpStringDll));/* FIXME */
8607         return S_OK;
8608     }else {/* for a member */
8609         pFDesc = TLB_get_funcdesc_by_memberid(This->funcdescs, This->typeattr.cFuncs, memid);
8610         if(pFDesc){
8611             if(pbstrHelpString)
8612                 *pbstrHelpString=SysAllocString(TLB_get_bstr(pFDesc->HelpString));
8613             if(pdwHelpStringContext)
8614                 *pdwHelpStringContext=pFDesc->HelpStringContext;
8615             if(pbstrHelpStringDll)
8616                 *pbstrHelpStringDll=
8617                     SysAllocString(TLB_get_bstr(This->pTypeLib->HelpStringDll));/* FIXME */
8618             return S_OK;
8619         }
8620         pVDesc = TLB_get_vardesc_by_memberid(This->vardescs, This->typeattr.cVars, memid);
8621         if(pVDesc){
8622             if(pbstrHelpString)
8623                 *pbstrHelpString=SysAllocString(TLB_get_bstr(pVDesc->HelpString));
8624             if(pdwHelpStringContext)
8625                 *pdwHelpStringContext=pVDesc->HelpStringContext;
8626             if(pbstrHelpStringDll)
8627                 *pbstrHelpStringDll=
8628                     SysAllocString(TLB_get_bstr(This->pTypeLib->HelpStringDll));/* FIXME */
8629             return S_OK;
8630         }
8631     }
8632     return TYPE_E_ELEMENTNOTFOUND;
8633 }
8634 
8635 /* ITypeInfo2::GetAllCustData
8636  *
8637  * Gets all custom data items for the Type info.
8638  *
8639  */
8640 static HRESULT WINAPI ITypeInfo2_fnGetAllCustData(
8641 	ITypeInfo2 * iface,
8642 	CUSTDATA *pCustData)
8643 {
8644     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8645 
8646     TRACE("%p %p\n", This, pCustData);
8647 
8648     return TLB_copy_all_custdata(This->pcustdata_list, pCustData);
8649 }
8650 
8651 /* ITypeInfo2::GetAllFuncCustData
8652  *
8653  * Gets all custom data items for the specified Function
8654  *
8655  */
8656 static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData(
8657 	ITypeInfo2 * iface,
8658 	UINT index,
8659 	CUSTDATA *pCustData)
8660 {
8661     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8662     TLBFuncDesc *pFDesc = &This->funcdescs[index];
8663 
8664     TRACE("%p %u %p\n", This, index, pCustData);
8665 
8666     if(index >= This->typeattr.cFuncs)
8667         return TYPE_E_ELEMENTNOTFOUND;
8668 
8669     return TLB_copy_all_custdata(&pFDesc->custdata_list, pCustData);
8670 }
8671 
8672 /* ITypeInfo2::GetAllParamCustData
8673  *
8674  * Gets all custom data items for the Functions
8675  *
8676  */
8677 static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo2 * iface,
8678     UINT indexFunc, UINT indexParam, CUSTDATA *pCustData)
8679 {
8680     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8681     TLBFuncDesc *pFDesc = &This->funcdescs[indexFunc];
8682 
8683     TRACE("%p %u %u %p\n", This, indexFunc, indexParam, pCustData);
8684 
8685     if(indexFunc >= This->typeattr.cFuncs)
8686         return TYPE_E_ELEMENTNOTFOUND;
8687 
8688     if(indexParam >= pFDesc->funcdesc.cParams)
8689         return TYPE_E_ELEMENTNOTFOUND;
8690 
8691     return TLB_copy_all_custdata(&pFDesc->pParamDesc[indexParam].custdata_list, pCustData);
8692 }
8693 
8694 /* ITypeInfo2::GetAllVarCustData
8695  *
8696  * Gets all custom data items for the specified Variable
8697  *
8698  */
8699 static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo2 * iface,
8700     UINT index, CUSTDATA *pCustData)
8701 {
8702     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8703     TLBVarDesc * pVDesc = &This->vardescs[index];
8704 
8705     TRACE("%p %u %p\n", This, index, pCustData);
8706 
8707     if(index >= This->typeattr.cVars)
8708         return TYPE_E_ELEMENTNOTFOUND;
8709 
8710     return TLB_copy_all_custdata(&pVDesc->custdata_list, pCustData);
8711 }
8712 
8713 /* ITypeInfo2::GetAllImplCustData
8714  *
8715  * Gets all custom data items for the specified implementation type
8716  *
8717  */
8718 static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData(
8719 	ITypeInfo2 * iface,
8720 	UINT index,
8721 	CUSTDATA *pCustData)
8722 {
8723     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8724     TLBImplType *pRDesc = &This->impltypes[index];
8725 
8726     TRACE("%p %u %p\n", This, index, pCustData);
8727 
8728     if(index >= This->typeattr.cImplTypes)
8729         return TYPE_E_ELEMENTNOTFOUND;
8730 
8731     return TLB_copy_all_custdata(&pRDesc->custdata_list, pCustData);
8732 }
8733 
8734 static const ITypeInfo2Vtbl tinfvt =
8735 {
8736 
8737     ITypeInfo_fnQueryInterface,
8738     ITypeInfo_fnAddRef,
8739     ITypeInfo_fnRelease,
8740 
8741     ITypeInfo_fnGetTypeAttr,
8742     ITypeInfo_fnGetTypeComp,
8743     ITypeInfo_fnGetFuncDesc,
8744     ITypeInfo_fnGetVarDesc,
8745     ITypeInfo_fnGetNames,
8746     ITypeInfo_fnGetRefTypeOfImplType,
8747     ITypeInfo_fnGetImplTypeFlags,
8748     ITypeInfo_fnGetIDsOfNames,
8749     ITypeInfo_fnInvoke,
8750     ITypeInfo_fnGetDocumentation,
8751     ITypeInfo_fnGetDllEntry,
8752     ITypeInfo_fnGetRefTypeInfo,
8753     ITypeInfo_fnAddressOfMember,
8754     ITypeInfo_fnCreateInstance,
8755     ITypeInfo_fnGetMops,
8756     ITypeInfo_fnGetContainingTypeLib,
8757     ITypeInfo_fnReleaseTypeAttr,
8758     ITypeInfo_fnReleaseFuncDesc,
8759     ITypeInfo_fnReleaseVarDesc,
8760 
8761     ITypeInfo2_fnGetTypeKind,
8762     ITypeInfo2_fnGetTypeFlags,
8763     ITypeInfo2_fnGetFuncIndexOfMemId,
8764     ITypeInfo2_fnGetVarIndexOfMemId,
8765     ITypeInfo2_fnGetCustData,
8766     ITypeInfo2_fnGetFuncCustData,
8767     ITypeInfo2_fnGetParamCustData,
8768     ITypeInfo2_fnGetVarCustData,
8769     ITypeInfo2_fnGetImplTypeCustData,
8770     ITypeInfo2_fnGetDocumentation2,
8771     ITypeInfo2_fnGetAllCustData,
8772     ITypeInfo2_fnGetAllFuncCustData,
8773     ITypeInfo2_fnGetAllParamCustData,
8774     ITypeInfo2_fnGetAllVarCustData,
8775     ITypeInfo2_fnGetAllImplTypeCustData,
8776 };
8777 
8778 /******************************************************************************
8779  * CreateDispTypeInfo [OLEAUT32.31]
8780  *
8781  * Build type information for an object so it can be called through an
8782  * IDispatch interface.
8783  *
8784  * RETURNS
8785  *  Success: S_OK. pptinfo contains the created ITypeInfo object.
8786  *  Failure: E_INVALIDARG, if one or more arguments is invalid.
8787  *
8788  * NOTES
8789  *  This call allows an objects methods to be accessed through IDispatch, by
8790  *  building an ITypeInfo object that IDispatch can use to call through.
8791  */
8792 HRESULT WINAPI CreateDispTypeInfo(
8793 	INTERFACEDATA *pidata, /* [I] Description of the interface to build type info for */
8794 	LCID lcid, /* [I] Locale Id */
8795 	ITypeInfo **pptinfo) /* [O] Destination for created ITypeInfo object */
8796 {
8797     ITypeInfoImpl *pTIClass, *pTIIface;
8798     ITypeLibImpl *pTypeLibImpl;
8799     unsigned int param, func;
8800     TLBFuncDesc *pFuncDesc;
8801     TLBRefType *ref;
8802 
8803     TRACE("\n");
8804     pTypeLibImpl = TypeLibImpl_Constructor();
8805     if (!pTypeLibImpl) return E_FAIL;
8806 
8807     pTypeLibImpl->TypeInfoCount = 2;
8808     pTypeLibImpl->typeinfos = heap_alloc_zero(pTypeLibImpl->TypeInfoCount * sizeof(ITypeInfoImpl*));
8809 
8810     pTIIface = pTypeLibImpl->typeinfos[0] = ITypeInfoImpl_Constructor();
8811     pTIIface->pTypeLib = pTypeLibImpl;
8812     pTIIface->index = 0;
8813     pTIIface->Name = NULL;
8814     pTIIface->dwHelpContext = -1;
8815     pTIIface->guid = NULL;
8816     pTIIface->typeattr.lcid = lcid;
8817     pTIIface->typeattr.typekind = TKIND_INTERFACE;
8818     pTIIface->typeattr.wMajorVerNum = 0;
8819     pTIIface->typeattr.wMinorVerNum = 0;
8820     pTIIface->typeattr.cbAlignment = 2;
8821     pTIIface->typeattr.cbSizeInstance = -1;
8822     pTIIface->typeattr.cbSizeVft = -1;
8823     pTIIface->typeattr.cFuncs = 0;
8824     pTIIface->typeattr.cImplTypes = 0;
8825     pTIIface->typeattr.cVars = 0;
8826     pTIIface->typeattr.wTypeFlags = 0;
8827     pTIIface->hreftype = 0;
8828 
8829     pTIIface->funcdescs = TLBFuncDesc_Alloc(pidata->cMembers);
8830     pFuncDesc = pTIIface->funcdescs;
8831     for(func = 0; func < pidata->cMembers; func++) {
8832         METHODDATA *md = pidata->pmethdata + func;
8833         pFuncDesc->Name = TLB_append_str(&pTypeLibImpl->name_list, md->szName);
8834         pFuncDesc->funcdesc.memid = md->dispid;
8835         pFuncDesc->funcdesc.lprgscode = NULL;
8836         pFuncDesc->funcdesc.funckind = FUNC_VIRTUAL;
8837         pFuncDesc->funcdesc.invkind = md->wFlags;
8838         pFuncDesc->funcdesc.callconv = md->cc;
8839         pFuncDesc->funcdesc.cParams = md->cArgs;
8840         pFuncDesc->funcdesc.cParamsOpt = 0;
8841         pFuncDesc->funcdesc.oVft = md->iMeth * sizeof(void *);
8842         pFuncDesc->funcdesc.cScodes = 0;
8843         pFuncDesc->funcdesc.wFuncFlags = 0;
8844         pFuncDesc->funcdesc.elemdescFunc.tdesc.vt = md->vtReturn;
8845         pFuncDesc->funcdesc.elemdescFunc.u.paramdesc.wParamFlags = PARAMFLAG_NONE;
8846         pFuncDesc->funcdesc.elemdescFunc.u.paramdesc.pparamdescex = NULL;
8847         pFuncDesc->funcdesc.lprgelemdescParam = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
8848                                                               md->cArgs * sizeof(ELEMDESC));
8849         pFuncDesc->pParamDesc = TLBParDesc_Constructor(md->cArgs);
8850         for(param = 0; param < md->cArgs; param++) {
8851             pFuncDesc->funcdesc.lprgelemdescParam[param].tdesc.vt = md->ppdata[param].vt;
8852             pFuncDesc->pParamDesc[param].Name = TLB_append_str(&pTypeLibImpl->name_list, md->ppdata[param].szName);
8853         }
8854         pFuncDesc->helpcontext = 0;
8855         pFuncDesc->HelpStringContext = 0;
8856         pFuncDesc->HelpString = NULL;
8857         pFuncDesc->Entry = NULL;
8858         list_init(&pFuncDesc->custdata_list);
8859         pTIIface->typeattr.cFuncs++;
8860         ++pFuncDesc;
8861     }
8862 
8863     dump_TypeInfo(pTIIface);
8864 
8865     pTIClass = pTypeLibImpl->typeinfos[1] = ITypeInfoImpl_Constructor();
8866     pTIClass->pTypeLib = pTypeLibImpl;
8867     pTIClass->index = 1;
8868     pTIClass->Name = NULL;
8869     pTIClass->dwHelpContext = -1;
8870     pTIClass->guid = NULL;
8871     pTIClass->typeattr.lcid = lcid;
8872     pTIClass->typeattr.typekind = TKIND_COCLASS;
8873     pTIClass->typeattr.wMajorVerNum = 0;
8874     pTIClass->typeattr.wMinorVerNum = 0;
8875     pTIClass->typeattr.cbAlignment = 2;
8876     pTIClass->typeattr.cbSizeInstance = -1;
8877     pTIClass->typeattr.cbSizeVft = -1;
8878     pTIClass->typeattr.cFuncs = 0;
8879     pTIClass->typeattr.cImplTypes = 1;
8880     pTIClass->typeattr.cVars = 0;
8881     pTIClass->typeattr.wTypeFlags = 0;
8882     pTIClass->hreftype = sizeof(MSFT_TypeInfoBase);
8883 
8884     pTIClass->impltypes = TLBImplType_Alloc(1);
8885 
8886     ref = heap_alloc_zero(sizeof(*ref));
8887     ref->pImpTLInfo = TLB_REF_INTERNAL;
8888     list_add_head(&pTypeLibImpl->ref_list, &ref->entry);
8889 
8890     dump_TypeInfo(pTIClass);
8891 
8892     *pptinfo = (ITypeInfo *)&pTIClass->ITypeInfo2_iface;
8893 
8894     ITypeInfo_AddRef(*pptinfo);
8895     ITypeLib2_Release(&pTypeLibImpl->ITypeLib2_iface);
8896 
8897     return S_OK;
8898 
8899 }
8900 
8901 static HRESULT WINAPI ITypeComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
8902 {
8903     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
8904 
8905     return ITypeInfo2_QueryInterface(&This->ITypeInfo2_iface, riid, ppv);
8906 }
8907 
8908 static ULONG WINAPI ITypeComp_fnAddRef(ITypeComp * iface)
8909 {
8910     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
8911 
8912     return ITypeInfo2_AddRef(&This->ITypeInfo2_iface);
8913 }
8914 
8915 static ULONG WINAPI ITypeComp_fnRelease(ITypeComp * iface)
8916 {
8917     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
8918 
8919     return ITypeInfo2_Release(&This->ITypeInfo2_iface);
8920 }
8921 
8922 static HRESULT WINAPI ITypeComp_fnBind(
8923     ITypeComp * iface,
8924     OLECHAR * szName,
8925     ULONG lHash,
8926     WORD wFlags,
8927     ITypeInfo ** ppTInfo,
8928     DESCKIND * pDescKind,
8929     BINDPTR * pBindPtr)
8930 {
8931     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
8932     const TLBFuncDesc *pFDesc;
8933     const TLBVarDesc *pVDesc;
8934     HRESULT hr = DISP_E_MEMBERNOTFOUND;
8935     UINT fdc;
8936 
8937     TRACE("(%p)->(%s, %x, 0x%x, %p, %p, %p)\n", This, debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
8938 
8939     *pDescKind = DESCKIND_NONE;
8940     pBindPtr->lpfuncdesc = NULL;
8941     *ppTInfo = NULL;
8942 
8943     for(fdc = 0; fdc < This->typeattr.cFuncs; ++fdc){
8944         pFDesc = &This->funcdescs[fdc];
8945         if (!lstrcmpiW(TLB_get_bstr(pFDesc->Name), szName)) {
8946             if (!wFlags || (pFDesc->funcdesc.invkind & wFlags))
8947                 break;
8948             else
8949                 /* name found, but wrong flags */
8950                 hr = TYPE_E_TYPEMISMATCH;
8951         }
8952     }
8953 
8954     if (fdc < This->typeattr.cFuncs)
8955     {
8956         HRESULT hr = TLB_AllocAndInitFuncDesc(
8957             &pFDesc->funcdesc,
8958             &pBindPtr->lpfuncdesc,
8959             This->typeattr.typekind == TKIND_DISPATCH);
8960         if (FAILED(hr))
8961             return hr;
8962         *pDescKind = DESCKIND_FUNCDESC;
8963         *ppTInfo = (ITypeInfo *)&This->ITypeInfo2_iface;
8964         ITypeInfo_AddRef(*ppTInfo);
8965         return S_OK;
8966     } else {
8967         pVDesc = TLB_get_vardesc_by_name(This->vardescs, This->typeattr.cVars, szName);
8968         if(pVDesc){
8969             HRESULT hr = TLB_AllocAndInitVarDesc(&pVDesc->vardesc, &pBindPtr->lpvardesc);
8970             if (FAILED(hr))
8971                 return hr;
8972             *pDescKind = DESCKIND_VARDESC;
8973             *ppTInfo = (ITypeInfo *)&This->ITypeInfo2_iface;
8974             ITypeInfo_AddRef(*ppTInfo);
8975             return S_OK;
8976         }
8977     }
8978 
8979     if (hr == DISP_E_MEMBERNOTFOUND && This->impltypes) {
8980         /* recursive search */
8981         ITypeInfo *pTInfo;
8982         ITypeComp *pTComp;
8983         HRESULT hr;
8984         hr=ITypeInfo2_GetRefTypeInfo(&This->ITypeInfo2_iface, This->impltypes[0].hRef, &pTInfo);
8985         if (SUCCEEDED(hr))
8986         {
8987             hr = ITypeInfo_GetTypeComp(pTInfo,&pTComp);
8988             ITypeInfo_Release(pTInfo);
8989         }
8990         if (SUCCEEDED(hr))
8991         {
8992             hr = ITypeComp_Bind(pTComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
8993             ITypeComp_Release(pTComp);
8994             if (SUCCEEDED(hr) && *pDescKind == DESCKIND_FUNCDESC &&
8995                     This->typeattr.typekind == TKIND_DISPATCH)
8996             {
8997                 FUNCDESC *tmp = pBindPtr->lpfuncdesc;
8998                 hr = TLB_AllocAndInitFuncDesc(tmp, &pBindPtr->lpfuncdesc, TRUE);
8999                 SysFreeString((BSTR)tmp);
9000             }
9001             return hr;
9002         }
9003         WARN("Could not search inherited interface!\n");
9004     }
9005     if (hr == DISP_E_MEMBERNOTFOUND)
9006         hr = S_OK;
9007     TRACE("did not find member with name %s, flags 0x%x\n", debugstr_w(szName), wFlags);
9008     return hr;
9009 }
9010 
9011 static HRESULT WINAPI ITypeComp_fnBindType(
9012     ITypeComp * iface,
9013     OLECHAR * szName,
9014     ULONG lHash,
9015     ITypeInfo ** ppTInfo,
9016     ITypeComp ** ppTComp)
9017 {
9018     TRACE("(%s, %x, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
9019 
9020     /* strange behaviour (does nothing) but like the
9021      * original */
9022 
9023     if (!ppTInfo || !ppTComp)
9024         return E_POINTER;
9025 
9026     *ppTInfo = NULL;
9027     *ppTComp = NULL;
9028 
9029     return S_OK;
9030 }
9031 
9032 static const ITypeCompVtbl tcompvt =
9033 {
9034 
9035     ITypeComp_fnQueryInterface,
9036     ITypeComp_fnAddRef,
9037     ITypeComp_fnRelease,
9038 
9039     ITypeComp_fnBind,
9040     ITypeComp_fnBindType
9041 };
9042 
9043 HRESULT WINAPI CreateTypeLib2(SYSKIND syskind, LPCOLESTR szFile,
9044         ICreateTypeLib2** ppctlib)
9045 {
9046     ITypeLibImpl *This;
9047     HRESULT hres;
9048 
9049     TRACE("(%d,%s,%p)\n", syskind, debugstr_w(szFile), ppctlib);
9050 
9051     if (!szFile) return E_INVALIDARG;
9052 
9053     This = TypeLibImpl_Constructor();
9054     if (!This)
9055         return E_OUTOFMEMORY;
9056 
9057     This->lcid = GetSystemDefaultLCID();
9058     This->syskind = syskind;
9059     This->ptr_size = get_ptr_size(syskind);
9060 
9061     This->path = heap_alloc((lstrlenW(szFile) + 1) * sizeof(WCHAR));
9062     if (!This->path) {
9063         ITypeLib2_Release(&This->ITypeLib2_iface);
9064         return E_OUTOFMEMORY;
9065     }
9066     lstrcpyW(This->path, szFile);
9067 
9068     hres = ITypeLib2_QueryInterface(&This->ITypeLib2_iface, &IID_ICreateTypeLib2, (LPVOID*)ppctlib);
9069     ITypeLib2_Release(&This->ITypeLib2_iface);
9070     return hres;
9071 }
9072 
9073 static HRESULT WINAPI ICreateTypeLib2_fnQueryInterface(ICreateTypeLib2 *iface,
9074         REFIID riid, void **object)
9075 {
9076     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
9077 
9078     return ITypeLib2_QueryInterface(&This->ITypeLib2_iface, riid, object);
9079 }
9080 
9081 static ULONG WINAPI ICreateTypeLib2_fnAddRef(ICreateTypeLib2 *iface)
9082 {
9083     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
9084 
9085     return ITypeLib2_AddRef(&This->ITypeLib2_iface);
9086 }
9087 
9088 static ULONG WINAPI ICreateTypeLib2_fnRelease(ICreateTypeLib2 *iface)
9089 {
9090     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
9091 
9092     return ITypeLib2_Release(&This->ITypeLib2_iface);
9093 }
9094 
9095 static HRESULT WINAPI ICreateTypeLib2_fnCreateTypeInfo(ICreateTypeLib2 *iface,
9096         LPOLESTR name, TYPEKIND kind, ICreateTypeInfo **ctinfo)
9097 {
9098     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
9099     ITypeInfoImpl *info;
9100     HRESULT hres;
9101 
9102     TRACE("%p %s %d %p\n", This, wine_dbgstr_w(name), kind, ctinfo);
9103 
9104     if (!ctinfo || !name)
9105         return E_INVALIDARG;
9106 
9107     info = TLB_get_typeinfo_by_name(This->typeinfos, This->TypeInfoCount, name);
9108     if (info)
9109         return TYPE_E_NAMECONFLICT;
9110 
9111     if (This->typeinfos)
9112         This->typeinfos = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->typeinfos,
9113                 sizeof(ITypeInfoImpl*) * (This->TypeInfoCount + 1));
9114     else
9115         This->typeinfos = heap_alloc_zero(sizeof(ITypeInfoImpl*));
9116 
9117     info = This->typeinfos[This->TypeInfoCount] = ITypeInfoImpl_Constructor();
9118 
9119     info->pTypeLib = This;
9120     info->Name = TLB_append_str(&This->name_list, name);
9121     info->index = This->TypeInfoCount;
9122     info->typeattr.typekind = kind;
9123     info->typeattr.cbAlignment = 4;
9124 
9125     switch (info->typeattr.typekind) {
9126     case TKIND_ENUM:
9127     case TKIND_INTERFACE:
9128     case TKIND_DISPATCH:
9129     case TKIND_COCLASS:
9130         info->typeattr.cbSizeInstance = This->ptr_size;
9131         break;
9132     case TKIND_RECORD:
9133     case TKIND_UNION:
9134         info->typeattr.cbSizeInstance = 0;
9135         break;
9136     case TKIND_MODULE:
9137         info->typeattr.cbSizeInstance = 2;
9138         break;
9139     case TKIND_ALIAS:
9140         info->typeattr.cbSizeInstance = -0x75;
9141         break;
9142     default:
9143         FIXME("unrecognized typekind %d\n", info->typeattr.typekind);
9144         info->typeattr.cbSizeInstance = 0xdeadbeef;
9145         break;
9146     }
9147 
9148     hres = ITypeInfo2_QueryInterface(&info->ITypeInfo2_iface,
9149             &IID_ICreateTypeInfo, (void **)ctinfo);
9150     if (FAILED(hres)) {
9151         ITypeInfo2_Release(&info->ITypeInfo2_iface);
9152         return hres;
9153     }
9154 
9155     info->hreftype = info->index * sizeof(MSFT_TypeInfoBase);
9156 
9157     ++This->TypeInfoCount;
9158 
9159     return S_OK;
9160 }
9161 
9162 static HRESULT WINAPI ICreateTypeLib2_fnSetName(ICreateTypeLib2 *iface,
9163         LPOLESTR name)
9164 {
9165     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
9166 
9167     TRACE("%p %s\n", This, wine_dbgstr_w(name));
9168 
9169     if (!name)
9170         return E_INVALIDARG;
9171 
9172     This->Name = TLB_append_str(&This->name_list, name);
9173 
9174     return S_OK;
9175 }
9176 
9177 static HRESULT WINAPI ICreateTypeLib2_fnSetVersion(ICreateTypeLib2 *iface,
9178         WORD majorVerNum, WORD minorVerNum)
9179 {
9180     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
9181 
9182     TRACE("%p %d %d\n", This, majorVerNum, minorVerNum);
9183 
9184     This->ver_major = majorVerNum;
9185     This->ver_minor = minorVerNum;
9186 
9187     return S_OK;
9188 }
9189 
9190 static HRESULT WINAPI ICreateTypeLib2_fnSetGuid(ICreateTypeLib2 *iface,
9191         REFGUID guid)
9192 {
9193     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
9194 
9195     TRACE("%p %s\n", This, debugstr_guid(guid));
9196 
9197     This->guid = TLB_append_guid(&This->guid_list, guid, -2);
9198 
9199     return S_OK;
9200 }
9201 
9202 static HRESULT WINAPI ICreateTypeLib2_fnSetDocString(ICreateTypeLib2 *iface,
9203         LPOLESTR doc)
9204 {
9205     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
9206 
9207     TRACE("%p %s\n", This, wine_dbgstr_w(doc));
9208 
9209     if (!doc)
9210         return E_INVALIDARG;
9211 
9212     This->DocString = TLB_append_str(&This->string_list, doc);
9213 
9214     return S_OK;
9215 }
9216 
9217 static HRESULT WINAPI ICreateTypeLib2_fnSetHelpFileName(ICreateTypeLib2 *iface,
9218         LPOLESTR helpFileName)
9219 {
9220     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
9221 
9222     TRACE("%p %s\n", This, wine_dbgstr_w(helpFileName));
9223 
9224     if (!helpFileName)
9225         return E_INVALIDARG;
9226 
9227     This->HelpFile = TLB_append_str(&This->string_list, helpFileName);
9228 
9229     return S_OK;
9230 }
9231 
9232 static HRESULT WINAPI ICreateTypeLib2_fnSetHelpContext(ICreateTypeLib2 *iface,
9233         DWORD helpContext)
9234 {
9235     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
9236 
9237     TRACE("%p %d\n", This, helpContext);
9238 
9239     This->dwHelpContext = helpContext;
9240 
9241     return S_OK;
9242 }
9243 
9244 static HRESULT WINAPI ICreateTypeLib2_fnSetLcid(ICreateTypeLib2 *iface,
9245         LCID lcid)
9246 {
9247     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
9248 
9249     TRACE("%p %x\n", This, lcid);
9250 
9251     This->set_lcid = lcid;
9252 
9253     return S_OK;
9254 }
9255 
9256 static HRESULT WINAPI ICreateTypeLib2_fnSetLibFlags(ICreateTypeLib2 *iface,
9257         UINT libFlags)
9258 {
9259     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
9260 
9261     TRACE("%p %x\n", This, libFlags);
9262 
9263     This->libflags = libFlags;
9264 
9265     return S_OK;
9266 }
9267 
9268 typedef struct tagWMSFT_SegContents {
9269     DWORD len;
9270     void *data;
9271 } WMSFT_SegContents;
9272 
9273 typedef struct tagWMSFT_TLBFile {
9274     MSFT_Header header;
9275     WMSFT_SegContents typeinfo_seg;
9276     WMSFT_SegContents impfile_seg;
9277     WMSFT_SegContents impinfo_seg;
9278     WMSFT_SegContents ref_seg;
9279     WMSFT_SegContents guidhash_seg;
9280     WMSFT_SegContents guid_seg;
9281     WMSFT_SegContents namehash_seg;
9282     WMSFT_SegContents name_seg;
9283     WMSFT_SegContents string_seg;
9284     WMSFT_SegContents typdesc_seg;
9285     WMSFT_SegContents arraydesc_seg;
9286     WMSFT_SegContents custdata_seg;
9287     WMSFT_SegContents cdguids_seg;
9288     MSFT_SegDir segdir;
9289     WMSFT_SegContents aux_seg;
9290 } WMSFT_TLBFile;
9291 
9292 static HRESULT WMSFT_compile_strings(ITypeLibImpl *This,
9293         WMSFT_TLBFile *file)
9294 {
9295     TLBString *str;
9296     UINT last_offs;
9297     char *data;
9298 
9299     file->string_seg.len = 0;
9300     LIST_FOR_EACH_ENTRY(str, &This->string_list, TLBString, entry) {
9301         int size;
9302 
9303         size = WideCharToMultiByte(CP_ACP, 0, str->str, lstrlenW(str->str), NULL, 0, NULL, NULL);
9304         if (size == 0)
9305             return E_UNEXPECTED;
9306 
9307         size += sizeof(INT16);
9308         if (size % 4)
9309             size = (size + 4) & ~0x3;
9310         if (size < 8)
9311             size = 8;
9312 
9313         file->string_seg.len += size;
9314 
9315         /* temporarily use str->offset to store the length of the aligned,
9316          * converted string */
9317         str->offset = size;
9318     }
9319 
9320     file->string_seg.data = data = heap_alloc(file->string_seg.len);
9321 
9322     last_offs = 0;
9323     LIST_FOR_EACH_ENTRY(str, &This->string_list, TLBString, entry) {
9324         int size;
9325 
9326         size = WideCharToMultiByte(CP_ACP, 0, str->str, lstrlenW(str->str),
9327                 data + sizeof(INT16), file->string_seg.len - last_offs - sizeof(INT16), NULL, NULL);
9328         if (size == 0) {
9329             heap_free(file->string_seg.data);
9330             return E_UNEXPECTED;
9331         }
9332 
9333         *((INT16*)data) = size;
9334 
9335         memset(data + sizeof(INT16) + size, 0x57, str->offset - size - sizeof(INT16));
9336 
9337         size = str->offset;
9338         data += size;
9339         str->offset = last_offs;
9340         last_offs += size;
9341     }
9342 
9343     return S_OK;
9344 }
9345 
9346 static HRESULT WMSFT_compile_names(ITypeLibImpl *This,
9347         WMSFT_TLBFile *file)
9348 {
9349     TLBString *str;
9350     UINT last_offs;
9351     char *data;
9352     MSFT_NameIntro *last_intro = NULL;
9353 
9354     file->header.nametablecount = 0;
9355     file->header.nametablechars = 0;
9356 
9357     file->name_seg.len = 0;
9358     LIST_FOR_EACH_ENTRY(str, &This->name_list, TLBString, entry) {
9359         int size;
9360 
9361         size = lstrlenW(str->str);
9362         file->header.nametablechars += size;
9363         file->header.nametablecount++;
9364 
9365         size = WideCharToMultiByte(CP_ACP, 0, str->str, size, NULL, 0, NULL, NULL);
9366         if (size == 0)
9367             return E_UNEXPECTED;
9368 
9369         size += sizeof(MSFT_NameIntro);
9370         if (size % 4)
9371             size = (size + 4) & ~0x3;
9372         if (size < 8)
9373             size = 8;
9374 
9375         file->name_seg.len += size;
9376 
9377         /* temporarily use str->offset to store the length of the aligned,
9378          * converted string */
9379         str->offset = size;
9380     }
9381 
9382     /* Allocate bigger buffer so we can temporarily NULL terminate the name */
9383     file->name_seg.data = data = heap_alloc(file->name_seg.len+1);
9384 
9385     last_offs = 0;
9386     LIST_FOR_EACH_ENTRY(str, &This->name_list, TLBString, entry) {
9387         int size, hash;
9388         MSFT_NameIntro *intro = (MSFT_NameIntro*)data;
9389 
9390         size = WideCharToMultiByte(CP_ACP, 0, str->str, lstrlenW(str->str),
9391                 data + sizeof(MSFT_NameIntro),
9392                 file->name_seg.len - last_offs - sizeof(MSFT_NameIntro), NULL, NULL);
9393         if (size == 0) {
9394             heap_free(file->name_seg.data);
9395             return E_UNEXPECTED;
9396         }
9397         data[sizeof(MSFT_NameIntro) + size] = '\0';
9398 
9399         intro->hreftype = -1; /* TODO? */
9400         intro->namelen = size & 0xFF;
9401         /* TODO: namelen & 0xFF00 == ??? maybe HREF type indicator? */
9402         hash = LHashValOfNameSysA(This->syskind, This->lcid, data + sizeof(MSFT_NameIntro));
9403         intro->namelen |= hash << 16;
9404         intro->next_hash = ((DWORD*)file->namehash_seg.data)[hash & 0x7f];
9405         ((DWORD*)file->namehash_seg.data)[hash & 0x7f] = last_offs;
9406 
9407         memset(data + sizeof(MSFT_NameIntro) + size, 0x57,
9408                 str->offset - size - sizeof(MSFT_NameIntro));
9409 
9410         /* update str->offset to actual value to use in other
9411          * compilation functions that require positions within
9412          * the string table */
9413         last_intro = intro;
9414         size = str->offset;
9415         data += size;
9416         str->offset = last_offs;
9417         last_offs += size;
9418     }
9419 
9420     if(last_intro)
9421         last_intro->hreftype = 0; /* last one is 0? */
9422 
9423     return S_OK;
9424 }
9425 
9426 static inline int hash_guid(GUID *guid)
9427 {
9428     int i, hash = 0;
9429 
9430     for (i = 0; i < 8; i ++)
9431         hash ^= ((const short *)guid)[i];
9432 
9433     return hash & 0x1f;
9434 }
9435 
9436 static HRESULT WMSFT_compile_guids(ITypeLibImpl *This, WMSFT_TLBFile *file)
9437 {
9438     TLBGuid *guid;
9439     MSFT_GuidEntry *entry;
9440     DWORD offs;
9441     int hash_key, *guidhashtab;
9442 
9443     file->guid_seg.len = sizeof(MSFT_GuidEntry) * list_count(&This->guid_list);
9444     file->guid_seg.data = heap_alloc(file->guid_seg.len);
9445 
9446     entry = file->guid_seg.data;
9447     offs = 0;
9448     guidhashtab = file->guidhash_seg.data;
9449     LIST_FOR_EACH_ENTRY(guid, &This->guid_list, TLBGuid, entry){
9450         memcpy(&entry->guid, &guid->guid, sizeof(GUID));
9451         entry->hreftype = guid->hreftype;
9452 
9453         hash_key = hash_guid(&guid->guid);
9454         entry->next_hash = guidhashtab[hash_key];
9455         guidhashtab[hash_key] = offs;
9456 
9457         guid->offset = offs;
9458         offs += sizeof(MSFT_GuidEntry);
9459         ++entry;
9460     }
9461 
9462     return S_OK;
9463 }
9464 
9465 static DWORD WMSFT_encode_variant(VARIANT *value, WMSFT_TLBFile *file)
9466 {
9467     VARIANT v = *value;
9468     VARTYPE arg_type = V_VT(value);
9469     int mask = 0;
9470     HRESULT hres;
9471     DWORD ret = file->custdata_seg.len;
9472 
9473     if(arg_type == VT_INT)
9474         arg_type = VT_I4;
9475     if(arg_type == VT_UINT)
9476         arg_type = VT_UI4;
9477 
9478     v = *value;
9479     if(V_VT(value) != arg_type) {
9480         hres = VariantChangeType(&v, value, 0, arg_type);
9481         if(FAILED(hres)){
9482             ERR("VariantChangeType failed: %08x\n", hres);
9483             return -1;
9484         }
9485     }
9486 
9487     /* Check if default value can be stored in-place */
9488     switch(arg_type){
9489     case VT_I4:
9490     case VT_UI4:
9491         mask = 0x3ffffff;
9492         if(V_UI4(&v) > 0x3ffffff)
9493             break;
9494         /* fall through */
9495     case VT_I1:
9496     case VT_UI1:
9497     case VT_BOOL:
9498         if(!mask)
9499             mask = 0xff;
9500         /* fall through */
9501     case VT_I2:
9502     case VT_UI2:
9503         if(!mask)
9504             mask = 0xffff;
9505         return ((0x80 + 0x4 * V_VT(value)) << 24) | (V_UI4(&v) & mask);
9506     }
9507 
9508     /* have to allocate space in custdata_seg */
9509     switch(arg_type) {
9510     case VT_I4:
9511     case VT_R4:
9512     case VT_UI4:
9513     case VT_INT:
9514     case VT_UINT:
9515     case VT_HRESULT:
9516     case VT_PTR: {
9517         /* Construct the data to be allocated */
9518         int *data;
9519 
9520         if(file->custdata_seg.data){
9521             file->custdata_seg.data = heap_realloc(file->custdata_seg.data, file->custdata_seg.len + sizeof(int) * 2);
9522             data = (int *)(((char *)file->custdata_seg.data) + file->custdata_seg.len);
9523             file->custdata_seg.len += sizeof(int) * 2;
9524         }else{
9525             file->custdata_seg.len = sizeof(int) * 2;
9526             data = file->custdata_seg.data = heap_alloc(file->custdata_seg.len);
9527         }
9528 
9529         data[0] = V_VT(value) + (V_UI4(&v) << 16);
9530         data[1] = (V_UI4(&v) >> 16) + 0x57570000;
9531 
9532         /* TODO: Check if the encoded data is already present in custdata_seg */
9533 
9534         return ret;
9535     }
9536 
9537     case VT_BSTR: {
9538         int i, len = (6+SysStringLen(V_BSTR(&v))+3) & ~0x3;
9539         char *data;
9540 
9541         if(file->custdata_seg.data){
9542             file->custdata_seg.data = heap_realloc(file->custdata_seg.data, file->custdata_seg.len + len);
9543             data = ((char *)file->custdata_seg.data) + file->custdata_seg.len;
9544             file->custdata_seg.len += len;
9545         }else{
9546             file->custdata_seg.len = len;
9547             data = file->custdata_seg.data = heap_alloc(file->custdata_seg.len);
9548         }
9549 
9550         *((unsigned short *)data) = V_VT(value);
9551         *((unsigned int *)(data+2)) = SysStringLen(V_BSTR(&v));
9552         for(i=0; i<SysStringLen(V_BSTR(&v)); i++) {
9553             if(V_BSTR(&v)[i] <= 0x7f)
9554                 data[i+6] = V_BSTR(&v)[i];
9555             else
9556                 data[i+6] = '?';
9557         }
9558         WideCharToMultiByte(CP_ACP, 0, V_BSTR(&v), SysStringLen(V_BSTR(&v)), &data[6], len-6, NULL, NULL);
9559         for(i=6+SysStringLen(V_BSTR(&v)); i<len; i++)
9560             data[i] = 0x57;
9561 
9562         /* TODO: Check if the encoded data is already present in custdata_seg */
9563 
9564         return ret;
9565     }
9566     default:
9567         FIXME("Argument type not yet handled\n");
9568         return -1;
9569     }
9570 }
9571 
9572 static DWORD WMSFT_append_typedesc(TYPEDESC *desc, WMSFT_TLBFile *file, DWORD *out_mix, INT16 *out_size);
9573 
9574 static DWORD WMSFT_append_arraydesc(ARRAYDESC *desc, WMSFT_TLBFile *file)
9575 {
9576     DWORD offs = file->arraydesc_seg.len;
9577     DWORD *encoded;
9578     USHORT i;
9579 
9580     /* TODO: we should check for duplicates, but that's harder because each
9581      * chunk is variable length (really we should store TYPEDESC and ARRAYDESC
9582      * at the library-level) */
9583 
9584     file->arraydesc_seg.len += (2 + desc->cDims * 2) * sizeof(DWORD);
9585     if(!file->arraydesc_seg.data)
9586         file->arraydesc_seg.data = heap_alloc(file->arraydesc_seg.len);
9587     else
9588         file->arraydesc_seg.data = heap_realloc(file->arraydesc_seg.data, file->arraydesc_seg.len);
9589     encoded = (DWORD*)((char *)file->arraydesc_seg.data + offs);
9590 
9591     encoded[0] = WMSFT_append_typedesc(&desc->tdescElem, file, NULL, NULL);
9592     encoded[1] = desc->cDims | ((desc->cDims * 2 * sizeof(DWORD)) << 16);
9593     for(i = 0; i < desc->cDims; ++i){
9594         encoded[2 + i * 2] =  desc->rgbounds[i].cElements;
9595         encoded[2 + i * 2 + 1] = desc->rgbounds[i].lLbound;
9596     }
9597 
9598     return offs;
9599 }
9600 
9601 static DWORD WMSFT_append_typedesc(TYPEDESC *desc, WMSFT_TLBFile *file, DWORD *out_mix, INT16 *out_size)
9602 {
9603     DWORD junk;
9604     INT16 junk2;
9605     DWORD offs = 0;
9606     DWORD encoded[2];
9607     VARTYPE vt, subtype;
9608     char *data;
9609 
9610     if(!desc)
9611         return -1;
9612 
9613     if(!out_mix)
9614         out_mix = &junk;
9615     if(!out_size)
9616         out_size = &junk2;
9617 
9618     vt = desc->vt & VT_TYPEMASK;
9619 
9620     if(vt == VT_PTR || vt == VT_SAFEARRAY){
9621         DWORD mix;
9622         encoded[1] = WMSFT_append_typedesc(desc->u.lptdesc, file, &mix, out_size);
9623         encoded[0] = desc->vt | ((mix | VT_BYREF) << 16);
9624         *out_mix = 0x7FFF;
9625         *out_size += 2 * sizeof(DWORD);
9626     }else if(vt == VT_CARRAY){
9627         encoded[0] = desc->vt | (0x7FFE << 16);
9628         encoded[1] = WMSFT_append_arraydesc(desc->u.lpadesc, file);
9629         *out_mix = 0x7FFE;
9630     }else if(vt == VT_USERDEFINED){
9631         encoded[0] = desc->vt | (0x7FFF << 16);
9632         encoded[1] = desc->u.hreftype;
9633         *out_mix = 0x7FFF; /* FIXME: Should get TYPEKIND of the hreftype, e.g. TKIND_ENUM => VT_I4 */
9634     }else{
9635         TRACE("Mixing in-place, VT: 0x%x\n", desc->vt);
9636 
9637         switch(vt){
9638         case VT_INT:
9639             subtype = VT_I4;
9640             break;
9641         case VT_UINT:
9642             subtype = VT_UI4;
9643             break;
9644         case VT_VOID:
9645             subtype = VT_EMPTY;
9646             break;
9647         default:
9648             subtype = vt;
9649             break;
9650         }
9651 
9652         *out_mix = subtype;
9653         return 0x80000000 | (subtype << 16) | desc->vt;
9654     }
9655 
9656     data = file->typdesc_seg.data;
9657     while(offs < file->typdesc_seg.len){
9658         if(!memcmp(&data[offs], encoded, sizeof(encoded)))
9659             return offs;
9660         offs += sizeof(encoded);
9661     }
9662 
9663     file->typdesc_seg.len += sizeof(encoded);
9664     if(!file->typdesc_seg.data)
9665         data = file->typdesc_seg.data = heap_alloc(file->typdesc_seg.len);
9666     else
9667         data = file->typdesc_seg.data = heap_realloc(file->typdesc_seg.data, file->typdesc_seg.len);
9668 
9669     memcpy(&data[offs], encoded, sizeof(encoded));
9670 
9671     return offs;
9672 }
9673 
9674 static DWORD WMSFT_compile_custdata(struct list *custdata_list, WMSFT_TLBFile *file)
9675 {
9676     WMSFT_SegContents *cdguids_seg = &file->cdguids_seg;
9677     DWORD ret = cdguids_seg->len, offs;
9678     MSFT_CDGuid *cdguid;
9679     TLBCustData *cd;
9680 
9681     if(list_empty(custdata_list))
9682         return -1;
9683 
9684     cdguids_seg->len += sizeof(MSFT_CDGuid) * list_count(custdata_list);
9685     if(!cdguids_seg->data){
9686         cdguid = cdguids_seg->data = heap_alloc(cdguids_seg->len);
9687     }else {
9688         cdguids_seg->data = heap_realloc(cdguids_seg->data, cdguids_seg->len);
9689         cdguid = (MSFT_CDGuid*)((char*)cdguids_seg->data + ret);
9690     }
9691 
9692     offs = ret + sizeof(MSFT_CDGuid);
9693     LIST_FOR_EACH_ENTRY(cd, custdata_list, TLBCustData, entry){
9694         cdguid->GuidOffset = cd->guid->offset;
9695         cdguid->DataOffset = WMSFT_encode_variant(&cd->data, file);
9696         cdguid->next = offs;
9697         offs += sizeof(MSFT_CDGuid);
9698         ++cdguid;
9699     }
9700 
9701     --cdguid;
9702     cdguid->next = -1;
9703 
9704     return ret;
9705 }
9706 
9707 static DWORD WMSFT_compile_typeinfo_aux(ITypeInfoImpl *info,
9708         WMSFT_TLBFile *file)
9709 {
9710     WMSFT_SegContents *aux_seg = &file->aux_seg;
9711     DWORD ret = aux_seg->len, i, j, recorded_size = 0, extra_size = 0;
9712     MSFT_VarRecord *varrecord;
9713     MSFT_FuncRecord *funcrecord;
9714     MEMBERID *memid;
9715     DWORD *name, *offsets, offs;
9716 
9717     for(i = 0; i < info->typeattr.cFuncs; ++i){
9718         TLBFuncDesc *desc = &info->funcdescs[i];
9719 
9720         recorded_size += 6 * sizeof(INT); /* mandatory fields */
9721 
9722         /* optional fields */
9723         /* TODO: oArgCustData - FuncSetCustData not impl yet */
9724         if(!list_empty(&desc->custdata_list))
9725             recorded_size += 7 * sizeof(INT);
9726         else if(desc->HelpStringContext != 0)
9727             recorded_size += 6 * sizeof(INT);
9728         /* res9? resA? */
9729         else if(desc->Entry)
9730             recorded_size += 3 * sizeof(INT);
9731         else if(desc->HelpString)
9732             recorded_size += 2 * sizeof(INT);
9733         else if(desc->helpcontext)
9734             recorded_size += sizeof(INT);
9735 
9736         recorded_size += desc->funcdesc.cParams * sizeof(MSFT_ParameterInfo);
9737 
9738         for(j = 0; j < desc->funcdesc.cParams; ++j){
9739             if(desc->funcdesc.lprgelemdescParam[j].u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT){
9740                 recorded_size += desc->funcdesc.cParams * sizeof(INT);
9741                 break;
9742             }
9743         }
9744 
9745         extra_size += 2 * sizeof(INT); /* memberid, name offs */
9746     }
9747 
9748     for(i = 0; i < info->typeattr.cVars; ++i){
9749         TLBVarDesc *desc = &info->vardescs[i];
9750 
9751         recorded_size += 5 * sizeof(INT); /* mandatory fields */
9752 
9753         /* optional fields */
9754         if(desc->HelpStringContext != 0)
9755             recorded_size += 5 * sizeof(INT);
9756         else if(!list_empty(&desc->custdata_list))
9757             recorded_size += 4 * sizeof(INT);
9758         /* res9? */
9759         else if(desc->HelpString)
9760             recorded_size += 2 * sizeof(INT);
9761         else if(desc->HelpContext != 0)
9762             recorded_size += sizeof(INT);
9763 
9764         extra_size += 2 * sizeof(INT); /* memberid, name offs */
9765     }
9766 
9767     if(!recorded_size && !extra_size)
9768         return ret;
9769 
9770     extra_size += sizeof(INT); /* total aux size for this typeinfo */
9771 
9772     aux_seg->len += recorded_size + extra_size;
9773 
9774     aux_seg->len += sizeof(INT) * (info->typeattr.cVars + info->typeattr.cFuncs); /* offsets at the end */
9775 
9776     if(aux_seg->data)
9777         aux_seg->data = heap_realloc(aux_seg->data, aux_seg->len);
9778     else
9779         aux_seg->data = heap_alloc(aux_seg->len);
9780 
9781     *((DWORD*)((char *)aux_seg->data + ret)) = recorded_size;
9782 
9783     offsets = (DWORD*)((char *)aux_seg->data + ret + recorded_size + extra_size);
9784     offs = 0;
9785 
9786     funcrecord = (MSFT_FuncRecord*)(((char *)aux_seg->data) + ret + sizeof(INT));
9787     for(i = 0; i < info->typeattr.cFuncs; ++i){
9788         TLBFuncDesc *desc = &info->funcdescs[i];
9789         DWORD size = 6 * sizeof(INT), paramdefault_size = 0, *paramdefault;
9790 
9791         funcrecord->funcdescsize = sizeof(desc->funcdesc) + desc->funcdesc.cParams * sizeof(ELEMDESC);
9792         funcrecord->DataType = WMSFT_append_typedesc(&desc->funcdesc.elemdescFunc.tdesc, file, NULL, &funcrecord->funcdescsize);
9793         funcrecord->Flags = desc->funcdesc.wFuncFlags;
9794         funcrecord->VtableOffset = desc->funcdesc.oVft;
9795 
9796         /* FKCCIC:
9797          * XXXX XXXX XXXX XXXX  XXXX XXXX XXXX XXXX
9798          *                                      ^^^funckind
9799          *                                 ^^^ ^invkind
9800          *                                ^has_cust_data
9801          *                           ^^^^callconv
9802          *                         ^has_param_defaults
9803          *                        ^oEntry_is_intresource
9804          */
9805         funcrecord->FKCCIC =
9806             desc->funcdesc.funckind |
9807             (desc->funcdesc.invkind << 3) |
9808             (list_empty(&desc->custdata_list) ? 0 : 0x80) |
9809             (desc->funcdesc.callconv << 8);
9810 
9811         if(desc->Entry && desc->Entry != (TLBString*)-1 && IS_INTRESOURCE(desc->Entry))
9812             funcrecord->FKCCIC |= 0x2000;
9813 
9814         for(j = 0; j < desc->funcdesc.cParams; ++j){
9815             if(desc->funcdesc.lprgelemdescParam[j].u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT){
9816                 paramdefault_size = sizeof(INT) * desc->funcdesc.cParams;
9817                 funcrecord->funcdescsize += sizeof(PARAMDESCEX);
9818             }
9819         }
9820         if(paramdefault_size > 0)
9821             funcrecord->FKCCIC |= 0x1000;
9822 
9823         funcrecord->nrargs = desc->funcdesc.cParams;
9824         funcrecord->nroargs = desc->funcdesc.cParamsOpt;
9825 
9826         /* optional fields */
9827         /* res9? resA? */
9828         if(!list_empty(&desc->custdata_list)){
9829             size += 7 * sizeof(INT);
9830             funcrecord->HelpContext = desc->helpcontext;
9831             if(desc->HelpString)
9832                 funcrecord->oHelpString = desc->HelpString->offset;
9833             else
9834                 funcrecord->oHelpString = -1;
9835             if(!desc->Entry)
9836                 funcrecord->oEntry = -1;
9837             else if(IS_INTRESOURCE(desc->Entry))
9838                 funcrecord->oEntry = LOWORD(desc->Entry);
9839             else
9840                 funcrecord->oEntry = desc->Entry->offset;
9841             funcrecord->res9 = -1;
9842             funcrecord->resA = -1;
9843             funcrecord->HelpStringContext = desc->HelpStringContext;
9844             funcrecord->oCustData = WMSFT_compile_custdata(&desc->custdata_list, file);
9845         }else if(desc->HelpStringContext != 0){
9846             size += 6 * sizeof(INT);
9847             funcrecord->HelpContext = desc->helpcontext;
9848             if(desc->HelpString)
9849                 funcrecord->oHelpString = desc->HelpString->offset;
9850             else
9851                 funcrecord->oHelpString = -1;
9852             if(!desc->Entry)
9853                 funcrecord->oEntry = -1;
9854             else if(IS_INTRESOURCE(desc->Entry))
9855                 funcrecord->oEntry = LOWORD(desc->Entry);
9856             else
9857                 funcrecord->oEntry = desc->Entry->offset;
9858             funcrecord->res9 = -1;
9859             funcrecord->resA = -1;
9860             funcrecord->HelpStringContext = desc->HelpStringContext;
9861         }else if(desc->Entry){
9862             size += 3 * sizeof(INT);
9863             funcrecord->HelpContext = desc->helpcontext;
9864             if(desc->HelpString)
9865                 funcrecord->oHelpString = desc->HelpString->offset;
9866             else
9867                 funcrecord->oHelpString = -1;
9868             if(!desc->Entry)
9869                 funcrecord->oEntry = -1;
9870             else if(IS_INTRESOURCE(desc->Entry))
9871                 funcrecord->oEntry = LOWORD(desc->Entry);
9872             else
9873                 funcrecord->oEntry = desc->Entry->offset;
9874         }else if(desc->HelpString){
9875             size += 2 * sizeof(INT);
9876             funcrecord->HelpContext = desc->helpcontext;
9877             funcrecord->oHelpString = desc->HelpString->offset;
9878         }else if(desc->helpcontext){
9879             size += sizeof(INT);
9880             funcrecord->HelpContext = desc->helpcontext;
9881         }
9882 
9883         paramdefault = (DWORD*)((char *)funcrecord + size);
9884         size += paramdefault_size;
9885 
9886         for(j = 0; j < desc->funcdesc.cParams; ++j){
9887             MSFT_ParameterInfo *info = (MSFT_ParameterInfo*)(((char *)funcrecord) + size);
9888 
9889             info->DataType = WMSFT_append_typedesc(&desc->funcdesc.lprgelemdescParam[j].tdesc, file, NULL, &funcrecord->funcdescsize);
9890             if(desc->pParamDesc[j].Name)
9891                 info->oName = desc->pParamDesc[j].Name->offset;
9892             else
9893                 info->oName = -1;
9894             info->Flags = desc->funcdesc.lprgelemdescParam[j].u.paramdesc.wParamFlags;
9895 
9896             if(paramdefault_size){
9897                 if(desc->funcdesc.lprgelemdescParam[j].u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
9898                     *paramdefault = WMSFT_encode_variant(&desc->funcdesc.lprgelemdescParam[j].u.paramdesc.pparamdescex->varDefaultValue, file);
9899                 else if(paramdefault_size)
9900                     *paramdefault = -1;
9901                 ++paramdefault;
9902             }
9903 
9904             size += sizeof(MSFT_ParameterInfo);
9905         }
9906 
9907         funcrecord->Info = size | (i << 16); /* is it just the index? */
9908 
9909         *offsets = offs;
9910         offs += size;
9911         ++offsets;
9912 
9913         funcrecord = (MSFT_FuncRecord*)(((char*)funcrecord) + size);
9914     }
9915 
9916     varrecord = (MSFT_VarRecord*)funcrecord;
9917     for(i = 0; i < info->typeattr.cVars; ++i){
9918         TLBVarDesc *desc = &info->vardescs[i];
9919         DWORD size = 5 * sizeof(INT);
9920 
9921         varrecord->vardescsize = sizeof(desc->vardesc);
9922         varrecord->DataType = WMSFT_append_typedesc(&desc->vardesc.elemdescVar.tdesc, file, NULL, &varrecord->vardescsize);
9923         varrecord->Flags = desc->vardesc.wVarFlags;
9924         varrecord->VarKind = desc->vardesc.varkind;
9925 
9926         if(desc->vardesc.varkind == VAR_CONST){
9927             varrecord->vardescsize += sizeof(VARIANT);
9928             varrecord->OffsValue = WMSFT_encode_variant(desc->vardesc.u.lpvarValue, file);
9929         }else
9930             varrecord->OffsValue = desc->vardesc.u.oInst;
9931 
9932         /* res9? */
9933         if(desc->HelpStringContext != 0){
9934             size += 5 * sizeof(INT);
9935             varrecord->HelpContext = desc->HelpContext;
9936             if(desc->HelpString)
9937                 varrecord->HelpString = desc->HelpString->offset;
9938             else
9939                 varrecord->HelpString = -1;
9940             varrecord->res9 = -1;
9941             varrecord->oCustData = WMSFT_compile_custdata(&desc->custdata_list, file);
9942             varrecord->HelpStringContext = desc->HelpStringContext;
9943         }else if(!list_empty(&desc->custdata_list)){
9944             size += 4 * sizeof(INT);
9945             varrecord->HelpContext = desc->HelpContext;
9946             if(desc->HelpString)
9947                 varrecord->HelpString = desc->HelpString->offset;
9948             else
9949                 varrecord->HelpString = -1;
9950             varrecord->res9 = -1;
9951             varrecord->oCustData = WMSFT_compile_custdata(&desc->custdata_list, file);
9952         }else if(desc->HelpString){
9953             size += 2 * sizeof(INT);
9954             varrecord->HelpContext = desc->HelpContext;
9955             if(desc->HelpString)
9956                 varrecord->HelpString = desc->HelpString->offset;
9957             else
9958                 varrecord->HelpString = -1;
9959         }else if(desc->HelpContext != 0){
9960             size += sizeof(INT);
9961             varrecord->HelpContext = desc->HelpContext;
9962         }
9963 
9964         varrecord->Info = size | (i << 16);
9965 
9966         *offsets = offs;
9967         offs += size;
9968         ++offsets;
9969 
9970         varrecord = (MSFT_VarRecord*)(((char*)varrecord) + size);
9971     }
9972 
9973     memid = (MEMBERID*)varrecord;
9974     for(i = 0; i < info->typeattr.cFuncs; ++i){
9975         TLBFuncDesc *desc = &info->funcdescs[i];
9976         *memid = desc->funcdesc.memid;
9977         ++memid;
9978     }
9979     for(i = 0; i < info->typeattr.cVars; ++i){
9980         TLBVarDesc *desc = &info->vardescs[i];
9981         *memid = desc->vardesc.memid;
9982         ++memid;
9983     }
9984 
9985     name = (UINT*)memid;
9986     for(i = 0; i < info->typeattr.cFuncs; ++i){
9987         TLBFuncDesc *desc = &info->funcdescs[i];
9988         if(desc->Name)
9989             *name = desc->Name->offset;
9990         else
9991             *name = -1;
9992         ++name;
9993     }
9994     for(i = 0; i < info->typeattr.cVars; ++i){
9995         TLBVarDesc *desc = &info->vardescs[i];
9996         if(desc->Name)
9997             *name = desc->Name->offset;
9998         else
9999             *name = -1;
10000         ++name;
10001     }
10002 
10003     return ret;
10004 }
10005 
10006 typedef struct tagWMSFT_RefChunk {
10007     DWORD href;
10008     DWORD res04;
10009     DWORD res08;
10010     DWORD next;
10011 } WMSFT_RefChunk;
10012 
10013 static DWORD WMSFT_compile_typeinfo_ref(ITypeInfoImpl *info, WMSFT_TLBFile *file)
10014 {
10015     DWORD offs = file->ref_seg.len, i;
10016     WMSFT_RefChunk *chunk;
10017 
10018     file->ref_seg.len += info->typeattr.cImplTypes * sizeof(WMSFT_RefChunk);
10019     if(!file->ref_seg.data)
10020         file->ref_seg.data = heap_alloc(file->ref_seg.len);
10021     else
10022         file->ref_seg.data = heap_realloc(file->ref_seg.data, file->ref_seg.len);
10023 
10024     chunk = (WMSFT_RefChunk*)((char*)file->ref_seg.data + offs);
10025 
10026     for(i = 0; i < info->typeattr.cImplTypes; ++i){
10027         chunk->href = info->impltypes[i].hRef;
10028         chunk->res04 = info->impltypes[i].implflags;
10029         chunk->res08 = -1;
10030         if(i < info->typeattr.cImplTypes - 1)
10031             chunk->next = offs + sizeof(WMSFT_RefChunk) * (i + 1);
10032         else
10033             chunk->next = -1;
10034         ++chunk;
10035     }
10036 
10037     return offs;
10038 }
10039 
10040 static DWORD WMSFT_compile_typeinfo(ITypeInfoImpl *info, INT16 index, WMSFT_TLBFile *file, char *data)
10041 {
10042     DWORD size;
10043 
10044     size = sizeof(MSFT_TypeInfoBase);
10045 
10046     if(data){
10047         MSFT_TypeInfoBase *base = (MSFT_TypeInfoBase*)data;
10048         if(info->typeattr.wTypeFlags & TYPEFLAG_FDUAL)
10049             base->typekind = TKIND_DISPATCH;
10050         else
10051             base->typekind = info->typeattr.typekind;
10052         base->typekind |= index << 16; /* TODO: There are some other flags here */
10053         base->typekind |= (info->typeattr.cbAlignment << 11) | (info->typeattr.cbAlignment << 6);
10054         base->memoffset = WMSFT_compile_typeinfo_aux(info, file);
10055         base->res2 = 0;
10056         base->res3 = 0;
10057         base->res4 = 3;
10058         base->res5 = 0;
10059         base->cElement = (info->typeattr.cVars << 16) | info->typeattr.cFuncs;
10060         base->res7 = 0;
10061         base->res8 = 0;
10062         base->res9 = 0;
10063         base->resA = 0;
10064         if(info->guid)
10065             base->posguid = info->guid->offset;
10066         else
10067             base->posguid = -1;
10068         base->flags = info->typeattr.wTypeFlags;
10069         if(info->Name) {
10070             base->NameOffset = info->Name->offset;
10071 
10072             ((unsigned char*)file->name_seg.data)[info->Name->offset+9] = 0x38;
10073             *(HREFTYPE*)((unsigned char*)file->name_seg.data+info->Name->offset) = info->hreftype;
10074         }else {
10075             base->NameOffset = -1;
10076         }
10077         base->version = (info->typeattr.wMinorVerNum << 16) | info->typeattr.wMajorVerNum;
10078         if(info->DocString)
10079             base->docstringoffs = info->DocString->offset;
10080         else
10081             base->docstringoffs = -1;
10082         base->helpstringcontext = info->dwHelpStringContext;
10083         base->helpcontext = info->dwHelpContext;
10084         base->oCustData = WMSFT_compile_custdata(info->pcustdata_list, file);
10085         base->cImplTypes = info->typeattr.cImplTypes;
10086         base->cbSizeVft = info->typeattr.cbSizeVft;
10087         base->size = info->typeattr.cbSizeInstance;
10088         if(info->typeattr.typekind == TKIND_COCLASS){
10089             base->datatype1 = WMSFT_compile_typeinfo_ref(info, file);
10090         }else if(info->typeattr.typekind == TKIND_ALIAS){
10091             base->datatype1 = WMSFT_append_typedesc(info->tdescAlias, file, NULL, NULL);
10092         }else if(info->typeattr.typekind == TKIND_MODULE){
10093             if(info->DllName)
10094                 base->datatype1 = info->DllName->offset;
10095             else
10096                 base->datatype1 = -1;
10097         }else{
10098             if(info->typeattr.cImplTypes > 0)
10099                 base->datatype1 = info->impltypes[0].hRef;
10100             else
10101                 base->datatype1 = -1;
10102         }
10103         base->datatype2 = index; /* FIXME: i think there's more here */
10104         base->res18 = 0;
10105         base->res19 = -1;
10106     }
10107 
10108     return size;
10109 }
10110 
10111 static void WMSFT_compile_typeinfo_seg(ITypeLibImpl *This, WMSFT_TLBFile *file, DWORD *junk)
10112 {
10113     UINT i;
10114 
10115     file->typeinfo_seg.len = 0;
10116     for(i = 0; i < This->TypeInfoCount; ++i){
10117         ITypeInfoImpl *info = This->typeinfos[i];
10118         *junk = file->typeinfo_seg.len;
10119         ++junk;
10120         file->typeinfo_seg.len += WMSFT_compile_typeinfo(info, i, NULL, NULL);
10121     }
10122 
10123     file->typeinfo_seg.data = heap_alloc(file->typeinfo_seg.len);
10124     memset(file->typeinfo_seg.data, 0x96, file->typeinfo_seg.len);
10125 
10126     file->aux_seg.len = 0;
10127     file->aux_seg.data = NULL;
10128 
10129     file->typeinfo_seg.len = 0;
10130     for(i = 0; i < This->TypeInfoCount; ++i){
10131         ITypeInfoImpl *info = This->typeinfos[i];
10132         file->typeinfo_seg.len += WMSFT_compile_typeinfo(info, i, file,
10133                 ((char *)file->typeinfo_seg.data) + file->typeinfo_seg.len);
10134     }
10135 }
10136 
10137 typedef struct tagWMSFT_ImpFile {
10138     INT guid_offs;
10139     LCID lcid;
10140     DWORD version;
10141 } WMSFT_ImpFile;
10142 
10143 static void WMSFT_compile_impfile(ITypeLibImpl *This, WMSFT_TLBFile *file)
10144 {
10145     TLBImpLib *implib;
10146     WMSFT_ImpFile *impfile;
10147     char *data;
10148     DWORD last_offs = 0;
10149 
10150     file->impfile_seg.len = 0;
10151     LIST_FOR_EACH_ENTRY(implib, &This->implib_list, TLBImpLib, entry){
10152         int size = 0;
10153 
10154         if(implib->name){
10155             WCHAR *path = wcsrchr(implib->name, '\\');
10156             if(path)
10157                 ++path;
10158             else
10159                 path = implib->name;
10160             size = WideCharToMultiByte(CP_ACP, 0, path, lstrlenW(path), NULL, 0, NULL, NULL);
10161             if (size == 0)
10162                 ERR("failed to convert wide string: %s\n", debugstr_w(path));
10163         }
10164 
10165         size += sizeof(INT16);
10166         if (size % 4)
10167             size = (size + 4) & ~0x3;
10168         if (size < 8)
10169             size = 8;
10170 
10171         file->impfile_seg.len += sizeof(WMSFT_ImpFile) + size;
10172     }
10173 
10174     data = file->impfile_seg.data = heap_alloc(file->impfile_seg.len);
10175 
10176     LIST_FOR_EACH_ENTRY(implib, &This->implib_list, TLBImpLib, entry){
10177         int strlen = 0, size;
10178 
10179         impfile = (WMSFT_ImpFile*)data;
10180         impfile->guid_offs = implib->guid->offset;
10181         impfile->lcid = implib->lcid;
10182         impfile->version = (implib->wVersionMinor << 16) | implib->wVersionMajor;
10183 
10184         data += sizeof(WMSFT_ImpFile);
10185 
10186         if(implib->name){
10187             WCHAR *path= wcsrchr(implib->name, '\\');
10188             if(path)
10189                 ++path;
10190             else
10191                 path = implib->name;
10192             strlen = WideCharToMultiByte(CP_ACP, 0, path, lstrlenW(path),
10193                     data + sizeof(INT16), file->impfile_seg.len - last_offs - sizeof(INT16), NULL, NULL);
10194             if (strlen == 0)
10195                 ERR("failed to convert wide string: %s\n", debugstr_w(path));
10196         }
10197 
10198         *((INT16*)data) = (strlen << 2) | 1; /* FIXME: is that a flag, or what? */
10199 
10200         size = strlen + sizeof(INT16);
10201         if (size % 4)
10202             size = (size + 4) & ~0x3;
10203         if (size < 8)
10204             size = 8;
10205         memset(data + sizeof(INT16) + strlen, 0x57, size - strlen - sizeof(INT16));
10206 
10207         data += size;
10208         implib->offset = last_offs;
10209         last_offs += size + sizeof(WMSFT_ImpFile);
10210     }
10211 }
10212 
10213 static void WMSFT_compile_impinfo(ITypeLibImpl *This, WMSFT_TLBFile *file)
10214 {
10215     MSFT_ImpInfo *info;
10216     TLBRefType *ref_type;
10217     UINT i = 0;
10218 
10219     WMSFT_compile_impfile(This, file);
10220 
10221     file->impinfo_seg.len = sizeof(MSFT_ImpInfo) * list_count(&This->ref_list);
10222     info = file->impinfo_seg.data = heap_alloc(file->impinfo_seg.len);
10223 
10224     LIST_FOR_EACH_ENTRY(ref_type, &This->ref_list, TLBRefType, entry){
10225         info->flags = i | ((ref_type->tkind & 0xFF) << 24);
10226         if(ref_type->index == TLB_REF_USE_GUID){
10227             info->flags |= MSFT_IMPINFO_OFFSET_IS_GUID;
10228             info->oGuid = ref_type->guid->offset;
10229         }else
10230             info->oGuid = ref_type->index;
10231         info->oImpFile = ref_type->pImpTLInfo->offset;
10232         ++i;
10233         ++info;
10234     }
10235 }
10236 
10237 static void WMSFT_compile_guidhash(ITypeLibImpl *This, WMSFT_TLBFile *file)
10238 {
10239     file->guidhash_seg.len = 0x80;
10240     file->guidhash_seg.data = heap_alloc(file->guidhash_seg.len);
10241     memset(file->guidhash_seg.data, 0xFF, file->guidhash_seg.len);
10242 }
10243 
10244 static void WMSFT_compile_namehash(ITypeLibImpl *This, WMSFT_TLBFile *file)
10245 {
10246     file->namehash_seg.len = 0x200;
10247     file->namehash_seg.data = heap_alloc(file->namehash_seg.len);
10248     memset(file->namehash_seg.data, 0xFF, file->namehash_seg.len);
10249 }
10250 
10251 static void tmp_fill_segdir_seg(MSFT_pSeg *segdir, WMSFT_SegContents *contents, DWORD *running_offset)
10252 {
10253     if(contents && contents->len){
10254         segdir->offset = *running_offset;
10255         segdir->length = contents->len;
10256         *running_offset += segdir->length;
10257     }else{
10258         segdir->offset = -1;
10259         segdir->length = 0;
10260     }
10261 
10262     /* TODO: do these ever change? */
10263     segdir->res08 = -1;
10264     segdir->res0c = 0xf;
10265 }
10266 
10267 static void WMSFT_write_segment(HANDLE outfile, WMSFT_SegContents *segment)
10268 {
10269     DWORD written;
10270     if(segment)
10271         WriteFile(outfile, segment->data, segment->len, &written, NULL);
10272 }
10273 
10274 static HRESULT WMSFT_fixup_typeinfos(ITypeLibImpl *This, WMSFT_TLBFile *file,
10275         DWORD file_len)
10276 {
10277     DWORD i;
10278     MSFT_TypeInfoBase *base = (MSFT_TypeInfoBase *)file->typeinfo_seg.data;
10279 
10280     for(i = 0; i < This->TypeInfoCount; ++i){
10281         base->memoffset += file_len;
10282         ++base;
10283     }
10284 
10285     return S_OK;
10286 }
10287 
10288 static void WMSFT_free_file(WMSFT_TLBFile *file)
10289 {
10290     HeapFree(GetProcessHeap(), 0, file->typeinfo_seg.data);
10291     HeapFree(GetProcessHeap(), 0, file->guidhash_seg.data);
10292     HeapFree(GetProcessHeap(), 0, file->guid_seg.data);
10293     HeapFree(GetProcessHeap(), 0, file->ref_seg.data);
10294     HeapFree(GetProcessHeap(), 0, file->impinfo_seg.data);
10295     HeapFree(GetProcessHeap(), 0, file->impfile_seg.data);
10296     HeapFree(GetProcessHeap(), 0, file->namehash_seg.data);
10297     HeapFree(GetProcessHeap(), 0, file->name_seg.data);
10298     HeapFree(GetProcessHeap(), 0, file->string_seg.data);
10299     HeapFree(GetProcessHeap(), 0, file->typdesc_seg.data);
10300     HeapFree(GetProcessHeap(), 0, file->arraydesc_seg.data);
10301     HeapFree(GetProcessHeap(), 0, file->custdata_seg.data);
10302     HeapFree(GetProcessHeap(), 0, file->cdguids_seg.data);
10303     HeapFree(GetProcessHeap(), 0, file->aux_seg.data);
10304 }
10305 
10306 static HRESULT WINAPI ICreateTypeLib2_fnSaveAllChanges(ICreateTypeLib2 *iface)
10307 {
10308     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
10309     WMSFT_TLBFile file;
10310     DWORD written, junk_size, junk_offs, running_offset;
10311     BOOL br;
10312     HANDLE outfile;
10313     HRESULT hres;
10314     DWORD *junk;
10315     UINT i;
10316 
10317     TRACE("%p\n", This);
10318 
10319     for(i = 0; i < This->TypeInfoCount; ++i)
10320         if(This->typeinfos[i]->needs_layout)
10321             ICreateTypeInfo2_LayOut(&This->typeinfos[i]->ICreateTypeInfo2_iface);
10322 
10323     memset(&file, 0, sizeof(file));
10324 
10325     file.header.magic1 = 0x5446534D;
10326     file.header.magic2 = 0x00010002;
10327     file.header.lcid = This->set_lcid ? This->set_lcid : MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
10328     file.header.lcid2 = This->set_lcid;
10329     file.header.varflags = 0x40 | This->syskind;
10330     if (This->HelpFile)
10331         file.header.varflags |= 0x10;
10332     if (This->HelpStringDll)
10333         file.header.varflags |= HELPDLLFLAG;
10334     file.header.version = (This->ver_minor << 16) | This->ver_major;
10335     file.header.flags = This->libflags;
10336     file.header.helpstringcontext = 0; /* TODO - SetHelpStringContext not implemented yet */
10337     file.header.helpcontext = This->dwHelpContext;
10338     file.header.res44 = 0x20;
10339     file.header.res48 = 0x80;
10340     file.header.dispatchpos = This->dispatch_href;
10341 
10342     WMSFT_compile_namehash(This, &file);
10343     /* do name and string compilation to get offsets for other compilations */
10344     hres = WMSFT_compile_names(This, &file);
10345     if (FAILED(hres)){
10346         WMSFT_free_file(&file);
10347         return hres;
10348     }
10349 
10350     hres = WMSFT_compile_strings(This, &file);
10351     if (FAILED(hres)){
10352         WMSFT_free_file(&file);
10353         return hres;
10354     }
10355 
10356     WMSFT_compile_guidhash(This, &file);
10357     hres = WMSFT_compile_guids(This, &file);
10358     if (FAILED(hres)){
10359         WMSFT_free_file(&file);
10360         return hres;
10361     }
10362 
10363     if(This->HelpFile)
10364         file.header.helpfile = This->HelpFile->offset;
10365     else
10366         file.header.helpfile = -1;
10367 
10368     if(This->DocString)
10369         file.header.helpstring = This->DocString->offset;
10370     else
10371         file.header.helpstring = -1;
10372 
10373     /* do some more segment compilation */
10374     file.header.nimpinfos = list_count(&This->ref_list);
10375     file.header.nrtypeinfos = This->TypeInfoCount;
10376 
10377     if(This->Name)
10378         file.header.NameOffset = This->Name->offset;
10379     else
10380         file.header.NameOffset = -1;
10381 
10382     file.header.CustomDataOffset = WMSFT_compile_custdata(&This->custdata_list, &file);
10383 
10384     if(This->guid)
10385         file.header.posguid = This->guid->offset;
10386     else
10387         file.header.posguid = -1;
10388 
10389     junk_size = file.header.nrtypeinfos * sizeof(DWORD);
10390     if(file.header.varflags & HELPDLLFLAG)
10391         junk_size += sizeof(DWORD);
10392     if(junk_size){
10393         junk = heap_alloc_zero(junk_size);
10394         if(file.header.varflags & HELPDLLFLAG){
10395             *junk = This->HelpStringDll->offset;
10396             junk_offs = 1;
10397         }else
10398             junk_offs = 0;
10399     }else{
10400         junk = NULL;
10401         junk_offs = 0;
10402     }
10403 
10404     WMSFT_compile_typeinfo_seg(This, &file, junk + junk_offs);
10405     WMSFT_compile_impinfo(This, &file);
10406 
10407     running_offset = 0;
10408 
10409     TRACE("header at: 0x%x\n", running_offset);
10410     running_offset += sizeof(file.header);
10411 
10412     TRACE("junk at: 0x%x\n", running_offset);
10413     running_offset += junk_size;
10414 
10415     TRACE("segdir at: 0x%x\n", running_offset);
10416     running_offset += sizeof(file.segdir);
10417 
10418     TRACE("typeinfo at: 0x%x\n", running_offset);
10419     tmp_fill_segdir_seg(&file.segdir.pTypeInfoTab, &file.typeinfo_seg, &running_offset);
10420 
10421     TRACE("guidhashtab at: 0x%x\n", running_offset);
10422     tmp_fill_segdir_seg(&file.segdir.pGuidHashTab, &file.guidhash_seg, &running_offset);
10423 
10424     TRACE("guidtab at: 0x%x\n", running_offset);
10425     tmp_fill_segdir_seg(&file.segdir.pGuidTab, &file.guid_seg, &running_offset);
10426 
10427     TRACE("reftab at: 0x%x\n", running_offset);
10428     tmp_fill_segdir_seg(&file.segdir.pRefTab, &file.ref_seg, &running_offset);
10429 
10430     TRACE("impinfo at: 0x%x\n", running_offset);
10431     tmp_fill_segdir_seg(&file.segdir.pImpInfo, &file.impinfo_seg, &running_offset);
10432 
10433     TRACE("impfiles at: 0x%x\n", running_offset);
10434     tmp_fill_segdir_seg(&file.segdir.pImpFiles, &file.impfile_seg, &running_offset);
10435 
10436     TRACE("namehashtab at: 0x%x\n", running_offset);
10437     tmp_fill_segdir_seg(&file.segdir.pNameHashTab, &file.namehash_seg, &running_offset);
10438 
10439     TRACE("nametab at: 0x%x\n", running_offset);
10440     tmp_fill_segdir_seg(&file.segdir.pNametab, &file.name_seg, &running_offset);
10441 
10442     TRACE("stringtab at: 0x%x\n", running_offset);
10443     tmp_fill_segdir_seg(&file.segdir.pStringtab, &file.string_seg, &running_offset);
10444 
10445     TRACE("typdesc at: 0x%x\n", running_offset);
10446     tmp_fill_segdir_seg(&file.segdir.pTypdescTab, &file.typdesc_seg, &running_offset);
10447 
10448     TRACE("arraydescriptions at: 0x%x\n", running_offset);
10449     tmp_fill_segdir_seg(&file.segdir.pArrayDescriptions, &file.arraydesc_seg, &running_offset);
10450 
10451     TRACE("custdata at: 0x%x\n", running_offset);
10452     tmp_fill_segdir_seg(&file.segdir.pCustData, &file.custdata_seg, &running_offset);
10453 
10454     TRACE("cdguids at: 0x%x\n", running_offset);
10455     tmp_fill_segdir_seg(&file.segdir.pCDGuids, &file.cdguids_seg, &running_offset);
10456 
10457     TRACE("res0e at: 0x%x\n", running_offset);
10458     tmp_fill_segdir_seg(&file.segdir.res0e, NULL, &running_offset);
10459 
10460     TRACE("res0f at: 0x%x\n", running_offset);
10461     tmp_fill_segdir_seg(&file.segdir.res0f, NULL, &running_offset);
10462 
10463     TRACE("aux_seg at: 0x%x\n", running_offset);
10464 
10465     WMSFT_fixup_typeinfos(This, &file, running_offset);
10466 
10467     outfile = CreateFileW(This->path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
10468             FILE_ATTRIBUTE_NORMAL, 0);
10469     if (outfile == INVALID_HANDLE_VALUE){
10470         WMSFT_free_file(&file);
10471         heap_free(junk);
10472         return TYPE_E_IOERROR;
10473     }
10474 
10475     br = WriteFile(outfile, &file.header, sizeof(file.header), &written, NULL);
10476     if (!br) {
10477         WMSFT_free_file(&file);
10478         CloseHandle(outfile);
10479         heap_free(junk);
10480         return TYPE_E_IOERROR;
10481     }
10482 
10483     br = WriteFile(outfile, junk, junk_size, &written, NULL);
10484     heap_free(junk);
10485     if (!br) {
10486         WMSFT_free_file(&file);
10487         CloseHandle(outfile);
10488         return TYPE_E_IOERROR;
10489     }
10490 
10491     br = WriteFile(outfile, &file.segdir, sizeof(file.segdir), &written, NULL);
10492     if (!br) {
10493         WMSFT_free_file(&file);
10494         CloseHandle(outfile);
10495         return TYPE_E_IOERROR;
10496     }
10497 
10498     WMSFT_write_segment(outfile, &file.typeinfo_seg);
10499     WMSFT_write_segment(outfile, &file.guidhash_seg);
10500     WMSFT_write_segment(outfile, &file.guid_seg);
10501     WMSFT_write_segment(outfile, &file.ref_seg);
10502     WMSFT_write_segment(outfile, &file.impinfo_seg);
10503     WMSFT_write_segment(outfile, &file.impfile_seg);
10504     WMSFT_write_segment(outfile, &file.namehash_seg);
10505     WMSFT_write_segment(outfile, &file.name_seg);
10506     WMSFT_write_segment(outfile, &file.string_seg);
10507     WMSFT_write_segment(outfile, &file.typdesc_seg);
10508     WMSFT_write_segment(outfile, &file.arraydesc_seg);
10509     WMSFT_write_segment(outfile, &file.custdata_seg);
10510     WMSFT_write_segment(outfile, &file.cdguids_seg);
10511     WMSFT_write_segment(outfile, &file.aux_seg);
10512 
10513     WMSFT_free_file(&file);
10514 
10515     CloseHandle(outfile);
10516 
10517     return S_OK;
10518 }
10519 
10520 static HRESULT WINAPI ICreateTypeLib2_fnDeleteTypeInfo(ICreateTypeLib2 *iface,
10521         LPOLESTR name)
10522 {
10523     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
10524     FIXME("%p %s - stub\n", This, wine_dbgstr_w(name));
10525     return E_NOTIMPL;
10526 }
10527 
10528 static HRESULT WINAPI ICreateTypeLib2_fnSetCustData(ICreateTypeLib2 *iface,
10529         REFGUID guid, VARIANT *varVal)
10530 {
10531     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
10532     TLBGuid *tlbguid;
10533 
10534     TRACE("%p %s %p\n", This, debugstr_guid(guid), varVal);
10535 
10536     if (!guid || !varVal)
10537         return E_INVALIDARG;
10538 
10539     tlbguid = TLB_append_guid(&This->guid_list, guid, -1);
10540 
10541     return TLB_set_custdata(&This->custdata_list, tlbguid, varVal);
10542 }
10543 
10544 static HRESULT WINAPI ICreateTypeLib2_fnSetHelpStringContext(ICreateTypeLib2 *iface,
10545         ULONG helpStringContext)
10546 {
10547     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
10548     FIXME("%p %u - stub\n", This, helpStringContext);
10549     return E_NOTIMPL;
10550 }
10551 
10552 static HRESULT WINAPI ICreateTypeLib2_fnSetHelpStringDll(ICreateTypeLib2 *iface,
10553         LPOLESTR filename)
10554 {
10555     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
10556     TRACE("%p %s\n", This, wine_dbgstr_w(filename));
10557 
10558     if (!filename)
10559         return E_INVALIDARG;
10560 
10561     This->HelpStringDll = TLB_append_str(&This->string_list, filename);
10562 
10563     return S_OK;
10564 }
10565 
10566 static const ICreateTypeLib2Vtbl CreateTypeLib2Vtbl = {
10567     ICreateTypeLib2_fnQueryInterface,
10568     ICreateTypeLib2_fnAddRef,
10569     ICreateTypeLib2_fnRelease,
10570     ICreateTypeLib2_fnCreateTypeInfo,
10571     ICreateTypeLib2_fnSetName,
10572     ICreateTypeLib2_fnSetVersion,
10573     ICreateTypeLib2_fnSetGuid,
10574     ICreateTypeLib2_fnSetDocString,
10575     ICreateTypeLib2_fnSetHelpFileName,
10576     ICreateTypeLib2_fnSetHelpContext,
10577     ICreateTypeLib2_fnSetLcid,
10578     ICreateTypeLib2_fnSetLibFlags,
10579     ICreateTypeLib2_fnSaveAllChanges,
10580     ICreateTypeLib2_fnDeleteTypeInfo,
10581     ICreateTypeLib2_fnSetCustData,
10582     ICreateTypeLib2_fnSetHelpStringContext,
10583     ICreateTypeLib2_fnSetHelpStringDll
10584 };
10585 
10586 static HRESULT WINAPI ICreateTypeInfo2_fnQueryInterface(ICreateTypeInfo2 *iface,
10587         REFIID riid, void **object)
10588 {
10589     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
10590 
10591     return ITypeInfo2_QueryInterface(&This->ITypeInfo2_iface, riid, object);
10592 }
10593 
10594 static ULONG WINAPI ICreateTypeInfo2_fnAddRef(ICreateTypeInfo2 *iface)
10595 {
10596     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
10597 
10598     return ITypeInfo2_AddRef(&This->ITypeInfo2_iface);
10599 }
10600 
10601 static ULONG WINAPI ICreateTypeInfo2_fnRelease(ICreateTypeInfo2 *iface)
10602 {
10603     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
10604 
10605     return ITypeInfo2_Release(&This->ITypeInfo2_iface);
10606 }
10607 
10608 static HRESULT WINAPI ICreateTypeInfo2_fnSetGuid(ICreateTypeInfo2 *iface,
10609         REFGUID guid)
10610 {
10611     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
10612 
10613     TRACE("%p %s\n", This, debugstr_guid(guid));
10614 
10615     This->guid = TLB_append_guid(&This->pTypeLib->guid_list, guid, This->hreftype);
10616 
10617     return S_OK;
10618 }
10619 
10620 static HRESULT WINAPI ICreateTypeInfo2_fnSetTypeFlags(ICreateTypeInfo2 *iface,
10621         UINT typeFlags)
10622 {
10623     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
10624     WORD old_flags;
10625     HRESULT hres;
10626 
10627     TRACE("%p %x\n", This, typeFlags);
10628 
10629     if (typeFlags & TYPEFLAG_FDUAL) {
10630         static const WCHAR stdole2tlb[] = { 's','t','d','o','l','e','2','.','t','l','b',0 };
10631         ITypeLib *stdole;
10632         ITypeInfo *dispatch;
10633         HREFTYPE hreftype;
10634         HRESULT hres;
10635 
10636         hres = LoadTypeLib(stdole2tlb, &stdole);
10637         if(FAILED(hres))
10638             return hres;
10639 
10640         hres = ITypeLib_GetTypeInfoOfGuid(stdole, &IID_IDispatch, &dispatch);
10641         ITypeLib_Release(stdole);
10642         if(FAILED(hres))
10643             return hres;
10644 
10645         hres = ICreateTypeInfo2_AddRefTypeInfo(iface, dispatch, &hreftype);
10646         ITypeInfo_Release(dispatch);
10647         if(FAILED(hres))
10648             return hres;
10649     }
10650 
10651     old_flags = This->typeattr.wTypeFlags;
10652     This->typeattr.wTypeFlags = typeFlags;
10653 
10654     hres = ICreateTypeInfo2_LayOut(iface);
10655     if (FAILED(hres)) {
10656         This->typeattr.wTypeFlags = old_flags;
10657         return hres;
10658     }
10659 
10660     return S_OK;
10661 }
10662 
10663 static HRESULT WINAPI ICreateTypeInfo2_fnSetDocString(ICreateTypeInfo2 *iface,
10664         LPOLESTR doc)
10665 {
10666     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
10667 
10668     TRACE("%p %s\n", This, wine_dbgstr_w(doc));
10669 
10670     if (!doc)
10671         return E_INVALIDARG;
10672 
10673     This->DocString = TLB_append_str(&This->pTypeLib->string_list, doc);
10674 
10675     return S_OK;
10676 }
10677 
10678 static HRESULT WINAPI ICreateTypeInfo2_fnSetHelpContext(ICreateTypeInfo2 *iface,
10679         DWORD helpContext)
10680 {
10681     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
10682 
10683     TRACE("%p %d\n", This, helpContext);
10684 
10685     This->dwHelpContext = helpContext;
10686 
10687     return S_OK;
10688 }
10689 
10690 static HRESULT WINAPI ICreateTypeInfo2_fnSetVersion(ICreateTypeInfo2 *iface,
10691         WORD majorVerNum, WORD minorVerNum)
10692 {
10693     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
10694 
10695     TRACE("%p %d %d\n", This, majorVerNum, minorVerNum);
10696 
10697     This->typeattr.wMajorVerNum = majorVerNum;
10698     This->typeattr.wMinorVerNum = minorVerNum;
10699 
10700     return S_OK;
10701 }
10702 
10703 static HRESULT WINAPI ICreateTypeInfo2_fnAddRefTypeInfo(ICreateTypeInfo2 *iface,
10704         ITypeInfo *typeInfo, HREFTYPE *refType)
10705 {
10706     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
10707     UINT index;
10708     ITypeLib *container;
10709     TLBRefType *ref_type;
10710     TLBImpLib *implib;
10711     TYPEATTR *typeattr;
10712     TLIBATTR *libattr;
10713     HRESULT hres;
10714 
10715     TRACE("%p %p %p\n", This, typeInfo, refType);
10716 
10717     if (!typeInfo || !refType)
10718         return E_INVALIDARG;
10719 
10720     hres = ITypeInfo_GetContainingTypeLib(typeInfo, &container, &index);
10721     if (FAILED(hres))
10722         return hres;
10723 
10724     if (container == (ITypeLib*)&This->pTypeLib->ITypeLib2_iface) {
10725         ITypeInfoImpl *target = impl_from_ITypeInfo(typeInfo);
10726 
10727         ITypeLib_Release(container);
10728 
10729         *refType = target->hreftype;
10730 
10731         return S_OK;
10732     }
10733 
10734     hres = ITypeLib_GetLibAttr(container, &libattr);
10735     if (FAILED(hres)) {
10736         ITypeLib_Release(container);
10737         return hres;
10738     }
10739 
10740     LIST_FOR_EACH_ENTRY(implib, &This->pTypeLib->implib_list, TLBImpLib, entry){
10741         if(IsEqualGUID(&implib->guid->guid, &libattr->guid) &&
10742                 implib->lcid == libattr->lcid &&
10743                 implib->wVersionMajor == libattr->wMajorVerNum &&
10744                 implib->wVersionMinor == libattr->wMinorVerNum)
10745             break;
10746     }
10747 
10748     if(&implib->entry == &This->pTypeLib->implib_list){
10749         implib = heap_alloc_zero(sizeof(TLBImpLib));
10750 
10751         if((ITypeLib2Vtbl*)container->lpVtbl == &tlbvt){
10752             const ITypeLibImpl *our_container = impl_from_ITypeLib2((ITypeLib2*)container);
10753             implib->name = SysAllocString(our_container->path);
10754         }else{
10755             hres = QueryPathOfRegTypeLib(&libattr->guid, libattr->wMajorVerNum,
10756                     libattr->wMinorVerNum, libattr->lcid, &implib->name);
10757             if(FAILED(hres)){
10758                 implib->name = NULL;
10759                 TRACE("QueryPathOfRegTypeLib failed, no name stored: %08x\n", hres);
10760             }
10761         }
10762 
10763         implib->guid = TLB_append_guid(&This->pTypeLib->guid_list, &libattr->guid, 2);
10764         implib->lcid = libattr->lcid;
10765         implib->wVersionMajor = libattr->wMajorVerNum;
10766         implib->wVersionMinor = libattr->wMinorVerNum;
10767 
10768         list_add_tail(&This->pTypeLib->implib_list, &implib->entry);
10769     }
10770 
10771     ITypeLib_ReleaseTLibAttr(container, libattr);
10772     ITypeLib_Release(container);
10773 
10774     hres = ITypeInfo_GetTypeAttr(typeInfo, &typeattr);
10775     if (FAILED(hres))
10776         return hres;
10777 
10778     index = 0;
10779     LIST_FOR_EACH_ENTRY(ref_type, &This->pTypeLib->ref_list, TLBRefType, entry){
10780         if(ref_type->index == TLB_REF_USE_GUID &&
10781                 IsEqualGUID(&ref_type->guid->guid, &typeattr->guid) &&
10782                 ref_type->tkind == typeattr->typekind)
10783             break;
10784         ++index;
10785     }
10786 
10787     if(&ref_type->entry == &This->pTypeLib->ref_list){
10788         ref_type = heap_alloc_zero(sizeof(TLBRefType));
10789 
10790         ref_type->tkind = typeattr->typekind;
10791         ref_type->pImpTLInfo = implib;
10792         ref_type->reference = index * sizeof(MSFT_ImpInfo);
10793 
10794         ref_type->index = TLB_REF_USE_GUID;
10795 
10796         ref_type->guid = TLB_append_guid(&This->pTypeLib->guid_list, &typeattr->guid, ref_type->reference+1);
10797 
10798         list_add_tail(&This->pTypeLib->ref_list, &ref_type->entry);
10799     }
10800 
10801     ITypeInfo_ReleaseTypeAttr(typeInfo, typeattr);
10802 
10803     *refType = ref_type->reference | 0x1;
10804 
10805     if(IsEqualGUID(&ref_type->guid->guid, &IID_IDispatch))
10806         This->pTypeLib->dispatch_href = *refType;
10807 
10808     return S_OK;
10809 }
10810 
10811 static HRESULT WINAPI ICreateTypeInfo2_fnAddFuncDesc(ICreateTypeInfo2 *iface,
10812         UINT index, FUNCDESC *funcDesc)
10813 {
10814     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
10815     TLBFuncDesc tmp_func_desc, *func_desc;
10816     int buf_size, i;
10817     char *buffer;
10818     HRESULT hres;
10819 
10820     TRACE("%p %u %p\n", This, index, funcDesc);
10821 
10822     if (!funcDesc || funcDesc->oVft & 3)
10823         return E_INVALIDARG;
10824 
10825     switch (This->typeattr.typekind) {
10826     case TKIND_MODULE:
10827         if (funcDesc->funckind != FUNC_STATIC)
10828             return TYPE_E_BADMODULEKIND;
10829         break;
10830     case TKIND_DISPATCH:
10831         if (funcDesc->funckind != FUNC_DISPATCH)
10832             return TYPE_E_BADMODULEKIND;
10833         break;
10834     default:
10835         if (funcDesc->funckind != FUNC_PUREVIRTUAL)
10836             return TYPE_E_BADMODULEKIND;
10837     }
10838 
10839     if (index > This->typeattr.cFuncs)
10840         return TYPE_E_ELEMENTNOTFOUND;
10841 
10842     if (funcDesc->invkind & (INVOKE_PROPERTYPUT | INVOKE_PROPERTYPUTREF) &&
10843             !funcDesc->cParams)
10844         return TYPE_E_INCONSISTENTPROPFUNCS;
10845 
10846 #ifdef _WIN64
10847     if(This->pTypeLib->syskind == SYS_WIN64 &&
10848             funcDesc->oVft % 8 != 0)
10849         return E_INVALIDARG;
10850 #endif
10851 
10852     memset(&tmp_func_desc, 0, sizeof(tmp_func_desc));
10853     TLBFuncDesc_Constructor(&tmp_func_desc);
10854 
10855     tmp_func_desc.funcdesc = *funcDesc;
10856 
10857     if (tmp_func_desc.funcdesc.oVft != 0)
10858         tmp_func_desc.funcdesc.oVft |= 1;
10859 
10860     if (funcDesc->cScodes && funcDesc->lprgscode) {
10861         tmp_func_desc.funcdesc.lprgscode = heap_alloc(sizeof(SCODE) * funcDesc->cScodes);
10862         memcpy(tmp_func_desc.funcdesc.lprgscode, funcDesc->lprgscode, sizeof(SCODE) * funcDesc->cScodes);
10863     } else {
10864         tmp_func_desc.funcdesc.lprgscode = NULL;
10865         tmp_func_desc.funcdesc.cScodes = 0;
10866     }
10867 
10868     buf_size = TLB_SizeElemDesc(&funcDesc->elemdescFunc);
10869     for (i = 0; i < funcDesc->cParams; ++i) {
10870         buf_size += sizeof(ELEMDESC);
10871         buf_size += TLB_SizeElemDesc(funcDesc->lprgelemdescParam + i);
10872     }
10873     tmp_func_desc.funcdesc.lprgelemdescParam = heap_alloc(buf_size);
10874     buffer = (char*)(tmp_func_desc.funcdesc.lprgelemdescParam + funcDesc->cParams);
10875 
10876     hres = TLB_CopyElemDesc(&funcDesc->elemdescFunc, &tmp_func_desc.funcdesc.elemdescFunc, &buffer);
10877     if (FAILED(hres)) {
10878         heap_free(tmp_func_desc.funcdesc.lprgelemdescParam);
10879         heap_free(tmp_func_desc.funcdesc.lprgscode);
10880         return hres;
10881     }
10882 
10883     for (i = 0; i < funcDesc->cParams; ++i) {
10884         hres = TLB_CopyElemDesc(funcDesc->lprgelemdescParam + i,
10885                 tmp_func_desc.funcdesc.lprgelemdescParam + i, &buffer);
10886         if (FAILED(hres)) {
10887             heap_free(tmp_func_desc.funcdesc.lprgelemdescParam);
10888             heap_free(tmp_func_desc.funcdesc.lprgscode);
10889             return hres;
10890         }
10891         if (tmp_func_desc.funcdesc.lprgelemdescParam[i].u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT &&
10892                 tmp_func_desc.funcdesc.lprgelemdescParam[i].tdesc.vt != VT_VARIANT &&
10893                 tmp_func_desc.funcdesc.lprgelemdescParam[i].tdesc.vt != VT_USERDEFINED){
10894             hres = TLB_SanitizeVariant(&tmp_func_desc.funcdesc.lprgelemdescParam[i].u.paramdesc.pparamdescex->varDefaultValue);
10895             if (FAILED(hres)) {
10896                 heap_free(tmp_func_desc.funcdesc.lprgelemdescParam);
10897                 heap_free(tmp_func_desc.funcdesc.lprgscode);
10898                 return hres;
10899             }
10900         }
10901     }
10902 
10903     tmp_func_desc.pParamDesc = TLBParDesc_Constructor(funcDesc->cParams);
10904 
10905     if (This->funcdescs) {
10906         This->funcdescs = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->funcdescs,
10907                 sizeof(TLBFuncDesc) * (This->typeattr.cFuncs + 1));
10908 
10909         if (index < This->typeattr.cFuncs) {
10910             memmove(This->funcdescs + index + 1, This->funcdescs + index,
10911                     (This->typeattr.cFuncs - index) * sizeof(TLBFuncDesc));
10912             func_desc = This->funcdescs + index;
10913         } else
10914             func_desc = This->funcdescs + This->typeattr.cFuncs;
10915 
10916         /* move custdata lists to the new memory location */
10917         for(i = 0; i < This->typeattr.cFuncs + 1; ++i){
10918             if(index != i){
10919                 TLBFuncDesc *fd = &This->funcdescs[i];
10920                 if(fd->custdata_list.prev == fd->custdata_list.next)
10921                     list_init(&fd->custdata_list);
10922                 else{
10923                     fd->custdata_list.prev->next = &fd->custdata_list;
10924                     fd->custdata_list.next->prev = &fd->custdata_list;
10925                 }
10926             }
10927         }
10928     } else
10929         func_desc = This->funcdescs = heap_alloc(sizeof(TLBFuncDesc));
10930 
10931     memcpy(func_desc, &tmp_func_desc, sizeof(tmp_func_desc));
10932     list_init(&func_desc->custdata_list);
10933 
10934     ++This->typeattr.cFuncs;
10935 
10936     This->needs_layout = TRUE;
10937 
10938     return S_OK;
10939 }
10940 
10941 static HRESULT WINAPI ICreateTypeInfo2_fnAddImplType(ICreateTypeInfo2 *iface,
10942         UINT index, HREFTYPE refType)
10943 {
10944     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
10945     TLBImplType *impl_type;
10946     HRESULT hres;
10947 
10948     TRACE("%p %u %d\n", This, index, refType);
10949 
10950     switch(This->typeattr.typekind){
10951         case TKIND_COCLASS: {
10952             if (index == -1) {
10953                 FIXME("Unhandled index: -1\n");
10954                 return E_NOTIMPL;
10955             }
10956 
10957             if(index != This->typeattr.cImplTypes)
10958                 return TYPE_E_ELEMENTNOTFOUND;
10959 
10960             break;
10961         }
10962         case TKIND_INTERFACE:
10963         case TKIND_DISPATCH:
10964             if (index != 0 || This->typeattr.cImplTypes)
10965                 return TYPE_E_ELEMENTNOTFOUND;
10966             break;
10967         default:
10968             FIXME("Unimplemented typekind: %d\n", This->typeattr.typekind);
10969             return E_NOTIMPL;
10970     }
10971 
10972     if (This->impltypes){
10973         UINT i;
10974 
10975         This->impltypes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->impltypes,
10976                 sizeof(TLBImplType) * (This->typeattr.cImplTypes + 1));
10977 
10978         if (index < This->typeattr.cImplTypes) {
10979             memmove(This->impltypes + index + 1, This->impltypes + index,
10980                     (This->typeattr.cImplTypes - index) * sizeof(TLBImplType));
10981             impl_type = This->impltypes + index;
10982         } else
10983             impl_type = This->impltypes + This->typeattr.cImplTypes;
10984 
10985         /* move custdata lists to the new memory location */
10986         for(i = 0; i < This->typeattr.cImplTypes + 1; ++i){
10987             if(index != i){
10988                 TLBImplType *it = &This->impltypes[i];
10989                 if(it->custdata_list.prev == it->custdata_list.next)
10990                     list_init(&it->custdata_list);
10991                 else{
10992                     it->custdata_list.prev->next = &it->custdata_list;
10993                     it->custdata_list.next->prev = &it->custdata_list;
10994                 }
10995             }
10996         }
10997     } else
10998         impl_type = This->impltypes = heap_alloc(sizeof(TLBImplType));
10999 
11000     memset(impl_type, 0, sizeof(TLBImplType));
11001     TLBImplType_Constructor(impl_type);
11002     impl_type->hRef = refType;
11003 
11004     ++This->typeattr.cImplTypes;
11005 
11006     if((refType & (~0x3)) == (This->pTypeLib->dispatch_href & (~0x3)))
11007         This->typeattr.wTypeFlags |= TYPEFLAG_FDISPATCHABLE;
11008 
11009     hres = ICreateTypeInfo2_LayOut(iface);
11010     if (FAILED(hres))
11011         return hres;
11012 
11013     return S_OK;
11014 }
11015 
11016 static HRESULT WINAPI ICreateTypeInfo2_fnSetImplTypeFlags(ICreateTypeInfo2 *iface,
11017         UINT index, INT implTypeFlags)
11018 {
11019     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11020     TLBImplType *impl_type = &This->impltypes[index];
11021 
11022     TRACE("%p %u %x\n", This, index, implTypeFlags);
11023 
11024     if (This->typeattr.typekind != TKIND_COCLASS)
11025         return TYPE_E_BADMODULEKIND;
11026 
11027     if (index >= This->typeattr.cImplTypes)
11028         return TYPE_E_ELEMENTNOTFOUND;
11029 
11030     impl_type->implflags = implTypeFlags;
11031 
11032     return S_OK;
11033 }
11034 
11035 static HRESULT WINAPI ICreateTypeInfo2_fnSetAlignment(ICreateTypeInfo2 *iface,
11036         WORD alignment)
11037 {
11038     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11039 
11040     TRACE("%p %d\n", This, alignment);
11041 
11042     This->typeattr.cbAlignment = alignment;
11043 
11044     return S_OK;
11045 }
11046 
11047 static HRESULT WINAPI ICreateTypeInfo2_fnSetSchema(ICreateTypeInfo2 *iface,
11048         LPOLESTR schema)
11049 {
11050     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11051 
11052     TRACE("%p %s\n", This, wine_dbgstr_w(schema));
11053 
11054     if (!schema)
11055         return E_INVALIDARG;
11056 
11057     This->Schema = TLB_append_str(&This->pTypeLib->string_list, schema);
11058 
11059     This->typeattr.lpstrSchema = This->Schema->str;
11060 
11061     return S_OK;
11062 }
11063 
11064 static HRESULT WINAPI ICreateTypeInfo2_fnAddVarDesc(ICreateTypeInfo2 *iface,
11065         UINT index, VARDESC *varDesc)
11066 {
11067     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11068     TLBVarDesc *var_desc;
11069 
11070     TRACE("%p %u %p\n", This, index, varDesc);
11071 
11072     if (This->vardescs){
11073         UINT i;
11074 
11075         This->vardescs = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->vardescs,
11076                 sizeof(TLBVarDesc) * (This->typeattr.cVars + 1));
11077 
11078         if (index < This->typeattr.cVars) {
11079             memmove(This->vardescs + index + 1, This->vardescs + index,
11080                     (This->typeattr.cVars - index) * sizeof(TLBVarDesc));
11081             var_desc = This->vardescs + index;
11082         } else
11083             var_desc = This->vardescs + This->typeattr.cVars;
11084 
11085         /* move custdata lists to the new memory location */
11086         for(i = 0; i < This->typeattr.cVars + 1; ++i){
11087             if(index != i){
11088                 TLBVarDesc *var = &This->vardescs[i];
11089                 if(var->custdata_list.prev == var->custdata_list.next)
11090                     list_init(&var->custdata_list);
11091                 else{
11092                     var->custdata_list.prev->next = &var->custdata_list;
11093                     var->custdata_list.next->prev = &var->custdata_list;
11094                 }
11095             }
11096         }
11097     } else
11098         var_desc = This->vardescs = heap_alloc_zero(sizeof(TLBVarDesc));
11099 
11100     TLBVarDesc_Constructor(var_desc);
11101     TLB_AllocAndInitVarDesc(varDesc, &var_desc->vardesc_create);
11102     var_desc->vardesc = *var_desc->vardesc_create;
11103 
11104     ++This->typeattr.cVars;
11105 
11106     This->needs_layout = TRUE;
11107 
11108     return S_OK;
11109 }
11110 
11111 static HRESULT WINAPI ICreateTypeInfo2_fnSetFuncAndParamNames(ICreateTypeInfo2 *iface,
11112         UINT index, LPOLESTR *names, UINT numNames)
11113 {
11114     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11115     TLBFuncDesc *func_desc = &This->funcdescs[index];
11116     int i;
11117 
11118     TRACE("%p %u %p %u\n", This, index, names, numNames);
11119 
11120     if (!names)
11121         return E_INVALIDARG;
11122 
11123     if (index >= This->typeattr.cFuncs || numNames == 0)
11124         return TYPE_E_ELEMENTNOTFOUND;
11125 
11126     if (func_desc->funcdesc.invkind & (INVOKE_PROPERTYPUT | INVOKE_PROPERTYPUTREF)){
11127         if(numNames > func_desc->funcdesc.cParams)
11128             return TYPE_E_ELEMENTNOTFOUND;
11129     } else
11130         if(numNames > func_desc->funcdesc.cParams + 1)
11131             return TYPE_E_ELEMENTNOTFOUND;
11132 
11133     for(i = 0; i < This->typeattr.cFuncs; ++i) {
11134         TLBFuncDesc *iter = &This->funcdescs[i];
11135         if (iter->Name && !wcscmp(TLB_get_bstr(iter->Name), *names)) {
11136             if (iter->funcdesc.invkind & (INVOKE_PROPERTYPUT | INVOKE_PROPERTYPUTREF | INVOKE_PROPERTYGET) &&
11137                     func_desc->funcdesc.invkind & (INVOKE_PROPERTYPUT | INVOKE_PROPERTYPUTREF | INVOKE_PROPERTYGET) &&
11138                     func_desc->funcdesc.invkind != iter->funcdesc.invkind)
11139                 continue;
11140             return TYPE_E_AMBIGUOUSNAME;
11141         }
11142     }
11143 
11144     func_desc->Name = TLB_append_str(&This->pTypeLib->name_list, *names);
11145 
11146     for (i = 1; i < numNames; ++i) {
11147         TLBParDesc *par_desc = func_desc->pParamDesc + i - 1;
11148         par_desc->Name = TLB_append_str(&This->pTypeLib->name_list, *(names + i));
11149     }
11150 
11151     return S_OK;
11152 }
11153 
11154 static HRESULT WINAPI ICreateTypeInfo2_fnSetVarName(ICreateTypeInfo2 *iface,
11155         UINT index, LPOLESTR name)
11156 {
11157     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11158 
11159     TRACE("%p %u %s\n", This, index, wine_dbgstr_w(name));
11160 
11161     if(!name)
11162         return E_INVALIDARG;
11163 
11164     if(index >= This->typeattr.cVars)
11165         return TYPE_E_ELEMENTNOTFOUND;
11166 
11167     This->vardescs[index].Name = TLB_append_str(&This->pTypeLib->name_list, name);
11168     return S_OK;
11169 }
11170 
11171 static HRESULT WINAPI ICreateTypeInfo2_fnSetTypeDescAlias(ICreateTypeInfo2 *iface,
11172         TYPEDESC *tdescAlias)
11173 {
11174     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11175     HRESULT hr;
11176 
11177     TRACE("%p %p\n", This, tdescAlias);
11178 
11179     if(!tdescAlias)
11180         return E_INVALIDARG;
11181 
11182     if(This->typeattr.typekind != TKIND_ALIAS)
11183         return TYPE_E_BADMODULEKIND;
11184 
11185     hr = TLB_size_instance(This, This->pTypeLib->syskind, tdescAlias, &This->typeattr.cbSizeInstance, &This->typeattr.cbAlignment);
11186     if(FAILED(hr))
11187         return hr;
11188 
11189     heap_free(This->tdescAlias);
11190     This->tdescAlias = heap_alloc(TLB_SizeTypeDesc(tdescAlias, TRUE));
11191     TLB_CopyTypeDesc(NULL, tdescAlias, This->tdescAlias);
11192 
11193     return S_OK;
11194 }
11195 
11196 static HRESULT WINAPI ICreateTypeInfo2_fnDefineFuncAsDllEntry(ICreateTypeInfo2 *iface,
11197         UINT index, LPOLESTR dllName, LPOLESTR procName)
11198 {
11199     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11200     FIXME("%p %u %s %s - stub\n", This, index, wine_dbgstr_w(dllName), wine_dbgstr_w(procName));
11201     return E_NOTIMPL;
11202 }
11203 
11204 static HRESULT WINAPI ICreateTypeInfo2_fnSetFuncDocString(ICreateTypeInfo2 *iface,
11205         UINT index, LPOLESTR docString)
11206 {
11207     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11208     TLBFuncDesc *func_desc = &This->funcdescs[index];
11209 
11210     TRACE("%p %u %s\n", This, index, wine_dbgstr_w(docString));
11211 
11212     if(!docString)
11213         return E_INVALIDARG;
11214 
11215     if(index >= This->typeattr.cFuncs)
11216         return TYPE_E_ELEMENTNOTFOUND;
11217 
11218     func_desc->HelpString = TLB_append_str(&This->pTypeLib->string_list, docString);
11219 
11220     return S_OK;
11221 }
11222 
11223 static HRESULT WINAPI ICreateTypeInfo2_fnSetVarDocString(ICreateTypeInfo2 *iface,
11224         UINT index, LPOLESTR docString)
11225 {
11226     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11227     TLBVarDesc *var_desc = &This->vardescs[index];
11228 
11229     TRACE("%p %u %s\n", This, index, wine_dbgstr_w(docString));
11230 
11231     if(!docString)
11232         return E_INVALIDARG;
11233 
11234     if(index >= This->typeattr.cVars)
11235         return TYPE_E_ELEMENTNOTFOUND;
11236 
11237     var_desc->HelpString = TLB_append_str(&This->pTypeLib->string_list, docString);
11238 
11239     return S_OK;
11240 }
11241 
11242 static HRESULT WINAPI ICreateTypeInfo2_fnSetFuncHelpContext(ICreateTypeInfo2 *iface,
11243         UINT index, DWORD helpContext)
11244 {
11245     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11246     TLBFuncDesc *func_desc = &This->funcdescs[index];
11247 
11248     TRACE("%p %u %d\n", This, index, helpContext);
11249 
11250     if(index >= This->typeattr.cFuncs)
11251         return TYPE_E_ELEMENTNOTFOUND;
11252 
11253     func_desc->helpcontext = helpContext;
11254 
11255     return S_OK;
11256 }
11257 
11258 static HRESULT WINAPI ICreateTypeInfo2_fnSetVarHelpContext(ICreateTypeInfo2 *iface,
11259         UINT index, DWORD helpContext)
11260 {
11261     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11262     TLBVarDesc *var_desc = &This->vardescs[index];
11263 
11264     TRACE("%p %u %d\n", This, index, helpContext);
11265 
11266     if(index >= This->typeattr.cVars)
11267         return TYPE_E_ELEMENTNOTFOUND;
11268 
11269     var_desc->HelpContext = helpContext;
11270 
11271     return S_OK;
11272 }
11273 
11274 static HRESULT WINAPI ICreateTypeInfo2_fnSetMops(ICreateTypeInfo2 *iface,
11275         UINT index, BSTR bstrMops)
11276 {
11277     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11278     FIXME("%p %u %s - stub\n", This, index, wine_dbgstr_w(bstrMops));
11279     return E_NOTIMPL;
11280 }
11281 
11282 static HRESULT WINAPI ICreateTypeInfo2_fnSetTypeIdldesc(ICreateTypeInfo2 *iface,
11283         IDLDESC *idlDesc)
11284 {
11285     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11286 
11287     TRACE("%p %p\n", This, idlDesc);
11288 
11289     if (!idlDesc)
11290         return E_INVALIDARG;
11291 
11292     This->typeattr.idldescType.dwReserved = idlDesc->dwReserved;
11293     This->typeattr.idldescType.wIDLFlags = idlDesc->wIDLFlags;
11294 
11295     return S_OK;
11296 }
11297 
11298 static HRESULT WINAPI ICreateTypeInfo2_fnLayOut(ICreateTypeInfo2 *iface)
11299 {
11300     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11301     ITypeInfo *tinfo;
11302     TLBFuncDesc *func_desc;
11303     UINT user_vft = 0, i, depth = 0;
11304     HRESULT hres = S_OK;
11305 
11306     TRACE("%p\n", This);
11307 
11308     This->needs_layout = FALSE;
11309 
11310     hres = ICreateTypeInfo2_QueryInterface(iface, &IID_ITypeInfo, (LPVOID*)&tinfo);
11311     if (FAILED(hres))
11312         return hres;
11313 
11314     if (This->typeattr.typekind == TKIND_INTERFACE) {
11315         ITypeInfo *inh;
11316         TYPEATTR *attr;
11317         HREFTYPE inh_href;
11318 
11319         hres = ITypeInfo_GetRefTypeOfImplType(tinfo, 0, &inh_href);
11320 
11321         if (SUCCEEDED(hres)) {
11322             hres = ITypeInfo_GetRefTypeInfo(tinfo, inh_href, &inh);
11323 
11324             if (SUCCEEDED(hres)) {
11325                 hres = ITypeInfo_GetTypeAttr(inh, &attr);
11326                 if (FAILED(hres)) {
11327                     ITypeInfo_Release(inh);
11328                     ITypeInfo_Release(tinfo);
11329                     return hres;
11330                 }
11331                 This->typeattr.cbSizeVft = attr->cbSizeVft;
11332                 ITypeInfo_ReleaseTypeAttr(inh, attr);
11333 
11334                 do{
11335                     ++depth;
11336                     hres = ITypeInfo_GetRefTypeOfImplType(inh, 0, &inh_href);
11337                     if(SUCCEEDED(hres)){
11338                         ITypeInfo *next;
11339                         hres = ITypeInfo_GetRefTypeInfo(inh, inh_href, &next);
11340                         if(SUCCEEDED(hres)){
11341                             ITypeInfo_Release(inh);
11342                             inh = next;
11343                         }
11344                     }
11345                 }while(SUCCEEDED(hres));
11346                 hres = S_OK;
11347 
11348                 ITypeInfo_Release(inh);
11349             } else if (hres == TYPE_E_ELEMENTNOTFOUND) {
11350                 This->typeattr.cbSizeVft = 0;
11351                 hres = S_OK;
11352             } else {
11353                 ITypeInfo_Release(tinfo);
11354                 return hres;
11355             }
11356         } else if (hres == TYPE_E_ELEMENTNOTFOUND) {
11357             This->typeattr.cbSizeVft = 0;
11358             hres = S_OK;
11359         } else {
11360             ITypeInfo_Release(tinfo);
11361             return hres;
11362         }
11363     } else if (This->typeattr.typekind == TKIND_DISPATCH)
11364         This->typeattr.cbSizeVft = 7 * This->pTypeLib->ptr_size;
11365     else
11366         This->typeattr.cbSizeVft = 0;
11367 
11368     func_desc = This->funcdescs;
11369     i = 0;
11370     while (i < This->typeattr.cFuncs) {
11371         if (!(func_desc->funcdesc.oVft & 0x1))
11372             func_desc->funcdesc.oVft = This->typeattr.cbSizeVft;
11373 
11374         if ((func_desc->funcdesc.oVft & 0xFFFC) > user_vft)
11375             user_vft = func_desc->funcdesc.oVft & 0xFFFC;
11376 
11377         This->typeattr.cbSizeVft += This->pTypeLib->ptr_size;
11378 
11379         if (func_desc->funcdesc.memid == MEMBERID_NIL) {
11380             TLBFuncDesc *iter;
11381             UINT j = 0;
11382             BOOL reset = FALSE;
11383 
11384             func_desc->funcdesc.memid = 0x60000000 + (depth << 16) + i;
11385 
11386             iter = This->funcdescs;
11387             while (j < This->typeattr.cFuncs) {
11388                 if (iter != func_desc && iter->funcdesc.memid == func_desc->funcdesc.memid) {
11389                     if (!reset) {
11390                         func_desc->funcdesc.memid = 0x60000000 + (depth << 16) + This->typeattr.cFuncs;
11391                         reset = TRUE;
11392                     } else
11393                         ++func_desc->funcdesc.memid;
11394                     iter = This->funcdescs;
11395                     j = 0;
11396                 } else {
11397                     ++iter;
11398                     ++j;
11399                 }
11400             }
11401         }
11402 
11403         ++func_desc;
11404         ++i;
11405     }
11406 
11407     if (user_vft > This->typeattr.cbSizeVft)
11408         This->typeattr.cbSizeVft = user_vft + This->pTypeLib->ptr_size;
11409 
11410     for(i = 0; i < This->typeattr.cVars; ++i){
11411         TLBVarDesc *var_desc = &This->vardescs[i];
11412         if(var_desc->vardesc.memid == MEMBERID_NIL){
11413             UINT j = 0;
11414             BOOL reset = FALSE;
11415             TLBVarDesc *iter;
11416 
11417             var_desc->vardesc.memid = 0x40000000 + (depth << 16) + i;
11418 
11419             iter = This->vardescs;
11420             while (j < This->typeattr.cVars) {
11421                 if (iter != var_desc && iter->vardesc.memid == var_desc->vardesc.memid) {
11422                     if (!reset) {
11423                         var_desc->vardesc.memid = 0x40000000 + (depth << 16) + This->typeattr.cVars;
11424                         reset = TRUE;
11425                     } else
11426                         ++var_desc->vardesc.memid;
11427                     iter = This->vardescs;
11428                     j = 0;
11429                 } else {
11430                     ++iter;
11431                     ++j;
11432                 }
11433             }
11434         }
11435     }
11436 
11437     ITypeInfo_Release(tinfo);
11438     return hres;
11439 }
11440 
11441 static HRESULT WINAPI ICreateTypeInfo2_fnDeleteFuncDesc(ICreateTypeInfo2 *iface,
11442         UINT index)
11443 {
11444     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11445     FIXME("%p %u - stub\n", This, index);
11446     return E_NOTIMPL;
11447 }
11448 
11449 static HRESULT WINAPI ICreateTypeInfo2_fnDeleteFuncDescByMemId(ICreateTypeInfo2 *iface,
11450         MEMBERID memid, INVOKEKIND invKind)
11451 {
11452     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11453     FIXME("%p %x %d - stub\n", This, memid, invKind);
11454     return E_NOTIMPL;
11455 }
11456 
11457 static HRESULT WINAPI ICreateTypeInfo2_fnDeleteVarDesc(ICreateTypeInfo2 *iface,
11458         UINT index)
11459 {
11460     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11461     FIXME("%p %u - stub\n", This, index);
11462     return E_NOTIMPL;
11463 }
11464 
11465 static HRESULT WINAPI ICreateTypeInfo2_fnDeleteVarDescByMemId(ICreateTypeInfo2 *iface,
11466         MEMBERID memid)
11467 {
11468     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11469     FIXME("%p %x - stub\n", This, memid);
11470     return E_NOTIMPL;
11471 }
11472 
11473 static HRESULT WINAPI ICreateTypeInfo2_fnDeleteImplType(ICreateTypeInfo2 *iface,
11474         UINT index)
11475 {
11476     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11477     FIXME("%p %u - stub\n", This, index);
11478     return E_NOTIMPL;
11479 }
11480 
11481 static HRESULT WINAPI ICreateTypeInfo2_fnSetCustData(ICreateTypeInfo2 *iface,
11482         REFGUID guid, VARIANT *varVal)
11483 {
11484     TLBGuid *tlbguid;
11485 
11486     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11487 
11488     TRACE("%p %s %p\n", This, debugstr_guid(guid), varVal);
11489 
11490     if (!guid || !varVal)
11491         return E_INVALIDARG;
11492 
11493     tlbguid = TLB_append_guid(&This->pTypeLib->guid_list, guid, -1);
11494 
11495     return TLB_set_custdata(This->pcustdata_list, tlbguid, varVal);
11496 }
11497 
11498 static HRESULT WINAPI ICreateTypeInfo2_fnSetFuncCustData(ICreateTypeInfo2 *iface,
11499         UINT index, REFGUID guid, VARIANT *varVal)
11500 {
11501     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11502     FIXME("%p %u %s %p - stub\n", This, index, debugstr_guid(guid), varVal);
11503     return E_NOTIMPL;
11504 }
11505 
11506 static HRESULT WINAPI ICreateTypeInfo2_fnSetParamCustData(ICreateTypeInfo2 *iface,
11507         UINT funcIndex, UINT paramIndex, REFGUID guid, VARIANT *varVal)
11508 {
11509     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11510     FIXME("%p %u %u %s %p - stub\n", This, funcIndex, paramIndex, debugstr_guid(guid), varVal);
11511     return E_NOTIMPL;
11512 }
11513 
11514 static HRESULT WINAPI ICreateTypeInfo2_fnSetVarCustData(ICreateTypeInfo2 *iface,
11515         UINT index, REFGUID guid, VARIANT *varVal)
11516 {
11517     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11518     FIXME("%p %u %s %p - stub\n", This, index, debugstr_guid(guid), varVal);
11519     return E_NOTIMPL;
11520 }
11521 
11522 static HRESULT WINAPI ICreateTypeInfo2_fnSetImplTypeCustData(ICreateTypeInfo2 *iface,
11523         UINT index, REFGUID guid, VARIANT *varVal)
11524 {
11525     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11526     FIXME("%p %u %s %p - stub\n", This, index, debugstr_guid(guid), varVal);
11527     return E_NOTIMPL;
11528 }
11529 
11530 static HRESULT WINAPI ICreateTypeInfo2_fnSetHelpStringContext(ICreateTypeInfo2 *iface,
11531         ULONG helpStringContext)
11532 {
11533     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11534 
11535     TRACE("%p %u\n", This, helpStringContext);
11536 
11537     This->dwHelpStringContext = helpStringContext;
11538 
11539     return S_OK;
11540 }
11541 
11542 static HRESULT WINAPI ICreateTypeInfo2_fnSetFuncHelpStringContext(ICreateTypeInfo2 *iface,
11543         UINT index, ULONG helpStringContext)
11544 {
11545     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11546     FIXME("%p %u %u - stub\n", This, index, helpStringContext);
11547     return E_NOTIMPL;
11548 }
11549 
11550 static HRESULT WINAPI ICreateTypeInfo2_fnSetVarHelpStringContext(ICreateTypeInfo2 *iface,
11551         UINT index, ULONG helpStringContext)
11552 {
11553     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11554     FIXME("%p %u %u - stub\n", This, index, helpStringContext);
11555     return E_NOTIMPL;
11556 }
11557 
11558 static HRESULT WINAPI ICreateTypeInfo2_fnInvalidate(ICreateTypeInfo2 *iface)
11559 {
11560     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11561     FIXME("%p - stub\n", This);
11562     return E_NOTIMPL;
11563 }
11564 
11565 static HRESULT WINAPI ICreateTypeInfo2_fnSetName(ICreateTypeInfo2 *iface,
11566         LPOLESTR name)
11567 {
11568     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11569 
11570     TRACE("%p %s\n", This, wine_dbgstr_w(name));
11571 
11572     if (!name)
11573         return E_INVALIDARG;
11574 
11575     This->Name = TLB_append_str(&This->pTypeLib->name_list, name);
11576 
11577     return S_OK;
11578 }
11579 
11580 static const ICreateTypeInfo2Vtbl CreateTypeInfo2Vtbl = {
11581     ICreateTypeInfo2_fnQueryInterface,
11582     ICreateTypeInfo2_fnAddRef,
11583     ICreateTypeInfo2_fnRelease,
11584     ICreateTypeInfo2_fnSetGuid,
11585     ICreateTypeInfo2_fnSetTypeFlags,
11586     ICreateTypeInfo2_fnSetDocString,
11587     ICreateTypeInfo2_fnSetHelpContext,
11588     ICreateTypeInfo2_fnSetVersion,
11589     ICreateTypeInfo2_fnAddRefTypeInfo,
11590     ICreateTypeInfo2_fnAddFuncDesc,
11591     ICreateTypeInfo2_fnAddImplType,
11592     ICreateTypeInfo2_fnSetImplTypeFlags,
11593     ICreateTypeInfo2_fnSetAlignment,
11594     ICreateTypeInfo2_fnSetSchema,
11595     ICreateTypeInfo2_fnAddVarDesc,
11596     ICreateTypeInfo2_fnSetFuncAndParamNames,
11597     ICreateTypeInfo2_fnSetVarName,
11598     ICreateTypeInfo2_fnSetTypeDescAlias,
11599     ICreateTypeInfo2_fnDefineFuncAsDllEntry,
11600     ICreateTypeInfo2_fnSetFuncDocString,
11601     ICreateTypeInfo2_fnSetVarDocString,
11602     ICreateTypeInfo2_fnSetFuncHelpContext,
11603     ICreateTypeInfo2_fnSetVarHelpContext,
11604     ICreateTypeInfo2_fnSetMops,
11605     ICreateTypeInfo2_fnSetTypeIdldesc,
11606     ICreateTypeInfo2_fnLayOut,
11607     ICreateTypeInfo2_fnDeleteFuncDesc,
11608     ICreateTypeInfo2_fnDeleteFuncDescByMemId,
11609     ICreateTypeInfo2_fnDeleteVarDesc,
11610     ICreateTypeInfo2_fnDeleteVarDescByMemId,
11611     ICreateTypeInfo2_fnDeleteImplType,
11612     ICreateTypeInfo2_fnSetCustData,
11613     ICreateTypeInfo2_fnSetFuncCustData,
11614     ICreateTypeInfo2_fnSetParamCustData,
11615     ICreateTypeInfo2_fnSetVarCustData,
11616     ICreateTypeInfo2_fnSetImplTypeCustData,
11617     ICreateTypeInfo2_fnSetHelpStringContext,
11618     ICreateTypeInfo2_fnSetFuncHelpStringContext,
11619     ICreateTypeInfo2_fnSetVarHelpStringContext,
11620     ICreateTypeInfo2_fnInvalidate,
11621     ICreateTypeInfo2_fnSetName
11622 };
11623 
11624 /******************************************************************************
11625  * ClearCustData (OLEAUT32.171)
11626  *
11627  * Clear a custom data type's data.
11628  *
11629  * PARAMS
11630  *  lpCust [I] The custom data type instance
11631  *
11632  * RETURNS
11633  *  Nothing.
11634  */
11635 void WINAPI ClearCustData(CUSTDATA *lpCust)
11636 {
11637     if (lpCust && lpCust->cCustData)
11638     {
11639         if (lpCust->prgCustData)
11640         {
11641             DWORD i;
11642 
11643             for (i = 0; i < lpCust->cCustData; i++)
11644                 VariantClear(&lpCust->prgCustData[i].varValue);
11645 
11646             CoTaskMemFree(lpCust->prgCustData);
11647             lpCust->prgCustData = NULL;
11648         }
11649         lpCust->cCustData = 0;
11650     }
11651 }
11652