xref: /reactos/dll/win32/oleaut32/typelib.c (revision 3c774903)
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 "config.h"
51 #include "wine/port.h"
52 
53 #include <stdlib.h>
54 #include <string.h>
55 #include <stdarg.h>
56 #include <stdio.h>
57 #include <ctype.h>
58 
59 #define COBJMACROS
60 #define NONAMELESSUNION
61 
62 #include "winerror.h"
63 #include "windef.h"
64 #include "winbase.h"
65 #include "winnls.h"
66 #include "winreg.h"
67 #include "winuser.h"
68 #include "winternl.h"
69 #include "lzexpand.h"
70 
71 #include "wine/unicode.h"
72 #include "objbase.h"
73 #include "typelib.h"
74 #include "wine/debug.h"
75 #include "variant.h"
76 #include "wine/heap.h"
77 #include "wine/list.h"
78 
79 WINE_DEFAULT_DEBUG_CHANNEL(ole);
80 WINE_DECLARE_DEBUG_CHANNEL(typelib);
81 
82 typedef struct
83 {
84     WORD     offset;
85     WORD     length;
86     WORD     flags;
87     WORD     id;
88     WORD     handle;
89     WORD     usage;
90 } NE_NAMEINFO;
91 
92 typedef struct
93 {
94     WORD        type_id;   /* Type identifier */
95     WORD        count;     /* Number of resources of this type */
96     DWORD       resloader; /* SetResourceHandler() */
97     /*
98      * Name info array.
99      */
100 } NE_TYPEINFO;
101 
102 static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt);
103 static HRESULT TLB_AllocAndInitVarDesc(const VARDESC *src, VARDESC **dest_ptr);
104 static void TLB_FreeVarDesc(VARDESC*);
105 
106 /****************************************************************************
107  *              FromLExxx
108  *
109  * Takes p_iVal (which is in little endian) and returns it
110  *   in the host machine's byte order.
111  */
112 #ifdef WORDS_BIGENDIAN
113 static WORD FromLEWord(WORD p_iVal)
114 {
115   return (((p_iVal & 0x00FF) << 8) |
116 	  ((p_iVal & 0xFF00) >> 8));
117 }
118 
119 
120 static DWORD FromLEDWord(DWORD p_iVal)
121 {
122   return (((p_iVal & 0x000000FF) << 24) |
123 	  ((p_iVal & 0x0000FF00) <<  8) |
124 	  ((p_iVal & 0x00FF0000) >>  8) |
125 	  ((p_iVal & 0xFF000000) >> 24));
126 }
127 #else
128 #define FromLEWord(X)  (X)
129 #define FromLEDWord(X) (X)
130 #endif
131 
132 #define DISPATCH_HREF_OFFSET 0x01000000
133 #define DISPATCH_HREF_MASK   0xff000000
134 
135 /****************************************************************************
136  *              FromLExxx
137  *
138  * Fix byte order in any structure if necessary
139  */
140 #ifdef WORDS_BIGENDIAN
141 static void FromLEWords(void *p_Val, int p_iSize)
142 {
143   WORD *Val = p_Val;
144 
145   p_iSize /= sizeof(WORD);
146 
147   while (p_iSize) {
148     *Val = FromLEWord(*Val);
149     Val++;
150     p_iSize--;
151   }
152 }
153 
154 
155 static void FromLEDWords(void *p_Val, int p_iSize)
156 {
157   DWORD *Val = p_Val;
158 
159   p_iSize /= sizeof(DWORD);
160 
161   while (p_iSize) {
162     *Val = FromLEDWord(*Val);
163     Val++;
164     p_iSize--;
165   }
166 }
167 #else
168 #define FromLEWords(X,Y) /*nothing*/
169 #define FromLEDWords(X,Y) /*nothing*/
170 #endif
171 
172 /*
173  * Find a typelib key which matches a requested maj.min version.
174  */
175 static BOOL find_typelib_key( REFGUID guid, WORD *wMaj, WORD *wMin )
176 {
177     static const WCHAR typelibW[] = {'T','y','p','e','l','i','b','\\',0};
178     WCHAR buffer[60];
179     char key_name[16];
180     DWORD len, i;
181     INT best_maj = -1, best_min = -1;
182     HKEY hkey;
183 
184     memcpy( buffer, typelibW, sizeof(typelibW) );
185     StringFromGUID2( guid, buffer + strlenW(buffer), 40 );
186 
187     if (RegOpenKeyExW( HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hkey ) != ERROR_SUCCESS)
188         return FALSE;
189 
190     len = sizeof(key_name);
191     i = 0;
192     while (RegEnumKeyExA(hkey, i++, key_name, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
193     {
194         INT v_maj, v_min;
195 
196         if (sscanf(key_name, "%x.%x", &v_maj, &v_min) == 2)
197         {
198             TRACE("found %s: %x.%x\n", debugstr_w(buffer), v_maj, v_min);
199 
200             if (*wMaj == 0xffff && *wMin == 0xffff)
201             {
202                 if (v_maj > best_maj) best_maj = v_maj;
203                 if (v_min > best_min) best_min = v_min;
204             }
205             else if (*wMaj == v_maj)
206             {
207                 best_maj = v_maj;
208 
209                 if (*wMin == v_min)
210                 {
211                     best_min = v_min;
212                     break; /* exact match */
213                 }
214                 if (*wMin != 0xffff && v_min > best_min) best_min = v_min;
215             }
216         }
217         len = sizeof(key_name);
218     }
219     RegCloseKey( hkey );
220 
221     TRACE("found best_maj %d, best_min %d\n", best_maj, best_min);
222 
223     if (*wMaj == 0xffff && *wMin == 0xffff)
224     {
225         if (best_maj >= 0 && best_min >= 0)
226         {
227             *wMaj = best_maj;
228             *wMin = best_min;
229             return TRUE;
230         }
231     }
232 
233     if (*wMaj == best_maj && best_min >= 0)
234     {
235         *wMin = best_min;
236         return TRUE;
237     }
238     return FALSE;
239 }
240 
241 /* get the path of a typelib key, in the form "Typelib\\<guid>\\<maj>.<min>" */
242 /* buffer must be at least 60 characters long */
243 static WCHAR *get_typelib_key( REFGUID guid, WORD wMaj, WORD wMin, WCHAR *buffer )
244 {
245     static const WCHAR TypelibW[] = {'T','y','p','e','l','i','b','\\',0};
246     static const WCHAR VersionFormatW[] = {'\\','%','x','.','%','x',0};
247 
248     memcpy( buffer, TypelibW, sizeof(TypelibW) );
249     StringFromGUID2( guid, buffer + strlenW(buffer), 40 );
250     sprintfW( buffer + strlenW(buffer), VersionFormatW, wMaj, wMin );
251     return buffer;
252 }
253 
254 /* get the path of an interface key, in the form "Interface\\<guid>" */
255 /* buffer must be at least 50 characters long */
256 static WCHAR *get_interface_key( REFGUID guid, WCHAR *buffer )
257 {
258     static const WCHAR InterfaceW[] = {'I','n','t','e','r','f','a','c','e','\\',0};
259 
260     memcpy( buffer, InterfaceW, sizeof(InterfaceW) );
261     StringFromGUID2( guid, buffer + strlenW(buffer), 40 );
262     return buffer;
263 }
264 
265 /* get the lcid subkey for a typelib, in the form "<lcid>\\<syskind>" */
266 /* buffer must be at least 16 characters long */
267 static WCHAR *get_lcid_subkey( LCID lcid, SYSKIND syskind, WCHAR *buffer )
268 {
269     static const WCHAR LcidFormatW[] = {'%','l','x','\\',0};
270     static const WCHAR win16W[] = {'w','i','n','1','6',0};
271     static const WCHAR win32W[] = {'w','i','n','3','2',0};
272     static const WCHAR win64W[] = {'w','i','n','6','4',0};
273 
274     sprintfW( buffer, LcidFormatW, lcid );
275     switch(syskind)
276     {
277     case SYS_WIN16: strcatW( buffer, win16W ); break;
278     case SYS_WIN32: strcatW( buffer, win32W ); break;
279     case SYS_WIN64: strcatW( buffer, win64W ); break;
280     default:
281         TRACE("Typelib is for unsupported syskind %i\n", syskind);
282         return NULL;
283     }
284     return buffer;
285 }
286 
287 static HRESULT TLB_ReadTypeLib(LPCWSTR pszFileName, LPWSTR pszPath, UINT cchPath, ITypeLib2 **ppTypeLib);
288 
289 struct tlibredirect_data
290 {
291     ULONG  size;
292     DWORD  res;
293     ULONG  name_len;
294     ULONG  name_offset;
295     LANGID langid;
296     WORD   flags;
297     ULONG  help_len;
298     ULONG  help_offset;
299     WORD   major_version;
300     WORD   minor_version;
301 };
302 
303 /* Get the path to a registered type library. Helper for QueryPathOfRegTypeLib. */
304 static HRESULT query_typelib_path( REFGUID guid, WORD wMaj, WORD wMin,
305                                    SYSKIND syskind, LCID lcid, BSTR *path, BOOL redir )
306 {
307     HRESULT hr = TYPE_E_LIBNOTREGISTERED;
308     LCID myLCID = lcid;
309     HKEY hkey;
310     WCHAR buffer[60];
311     WCHAR Path[MAX_PATH];
312     LONG res;
313 
314     TRACE_(typelib)("(%s, %x.%x, 0x%x, %p)\n", debugstr_guid(guid), wMaj, wMin, lcid, path);
315 
316     if (redir)
317     {
318         ACTCTX_SECTION_KEYED_DATA data;
319 
320         data.cbSize = sizeof(data);
321         if (FindActCtxSectionGuid( 0, NULL, ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION, guid, &data ))
322         {
323             struct tlibredirect_data *tlib = (struct tlibredirect_data*)data.lpData;
324             WCHAR *nameW;
325             DWORD len;
326 
327             if ((wMaj != 0xffff || wMin != 0xffff) && (tlib->major_version != wMaj || tlib->minor_version < wMin))
328                 return TYPE_E_LIBNOTREGISTERED;
329 
330             nameW = (WCHAR*)((BYTE*)data.lpSectionBase + tlib->name_offset);
331             len = SearchPathW( NULL, nameW, NULL, sizeof(Path)/sizeof(WCHAR), Path, NULL );
332             if (!len) return TYPE_E_LIBNOTREGISTERED;
333 
334             TRACE_(typelib)("got path from context %s\n", debugstr_w(Path));
335             *path = SysAllocString( Path );
336             return S_OK;
337         }
338     }
339 
340     if (!find_typelib_key( guid, &wMaj, &wMin )) return TYPE_E_LIBNOTREGISTERED;
341     get_typelib_key( guid, wMaj, wMin, buffer );
342 
343     res = RegOpenKeyExW( HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hkey );
344     if (res == ERROR_FILE_NOT_FOUND)
345     {
346         TRACE_(typelib)("%s not found\n", debugstr_w(buffer));
347         return TYPE_E_LIBNOTREGISTERED;
348     }
349     else if (res != ERROR_SUCCESS)
350     {
351         TRACE_(typelib)("failed to open %s for read access\n", debugstr_w(buffer));
352         return TYPE_E_REGISTRYACCESS;
353     }
354 
355     while (hr != S_OK)
356     {
357         LONG dwPathLen = sizeof(Path);
358 
359         get_lcid_subkey( myLCID, syskind, buffer );
360 
361         if (RegQueryValueW(hkey, buffer, Path, &dwPathLen))
362         {
363             if (!lcid)
364                 break;
365             else if (myLCID == lcid)
366             {
367                 /* try with sub-langid */
368                 myLCID = SUBLANGID(lcid);
369             }
370             else if ((myLCID == SUBLANGID(lcid)) && myLCID)
371             {
372                 /* try with system langid */
373                 myLCID = 0;
374             }
375             else
376             {
377                 break;
378             }
379         }
380         else
381         {
382             *path = SysAllocString( Path );
383             hr = S_OK;
384         }
385     }
386     RegCloseKey( hkey );
387     TRACE_(typelib)("-- 0x%08x\n", hr);
388     return hr;
389 }
390 
391 /****************************************************************************
392  *		QueryPathOfRegTypeLib	[OLEAUT32.164]
393  *
394  * Gets the path to a registered type library.
395  *
396  * PARAMS
397  *  guid [I] referenced guid
398  *  wMaj [I] major version
399  *  wMin [I] minor version
400  *  lcid [I] locale id
401  *  path [O] path of typelib
402  *
403  * RETURNS
404  *  Success: S_OK.
405  *  Failure: If the type library is not registered then TYPE_E_LIBNOTREGISTERED
406  *  or TYPE_E_REGISTRYACCESS if the type library registration key couldn't be
407  *  opened.
408  */
409 HRESULT WINAPI QueryPathOfRegTypeLib( REFGUID guid, WORD wMaj, WORD wMin, LCID lcid, LPBSTR path )
410 {
411     BOOL redir = TRUE;
412 #ifdef _WIN64
413     HRESULT hres = query_typelib_path( guid, wMaj, wMin, SYS_WIN64, lcid, path, TRUE );
414     if(SUCCEEDED(hres))
415         return hres;
416     redir = FALSE;
417 #endif
418     return query_typelib_path( guid, wMaj, wMin, SYS_WIN32, lcid, path, redir );
419 }
420 
421 /******************************************************************************
422  * CreateTypeLib [OLEAUT32.160]  creates a typelib
423  *
424  * RETURNS
425  *    Success: S_OK
426  *    Failure: Status
427  */
428 HRESULT WINAPI CreateTypeLib(SYSKIND syskind, LPCOLESTR file, ICreateTypeLib **ctlib)
429 {
430     ICreateTypeLib2 *typelib2;
431     HRESULT hres;
432 
433     FIXME("(%d, %s, %p): forwarding to CreateTypeLib2\n", syskind, debugstr_w(file), ctlib);
434 
435     hres = CreateTypeLib2(syskind, file, &typelib2);
436     if(SUCCEEDED(hres))
437     {
438         hres = ICreateTypeLib2_QueryInterface(typelib2, &IID_ICreateTypeLib, (void **)&ctlib);
439         ICreateTypeLib2_Release(typelib2);
440     }
441 
442     return hres;
443 }
444 
445 /******************************************************************************
446  *		LoadTypeLib	[OLEAUT32.161]
447  *
448  * Loads a type library
449  *
450  * PARAMS
451  *  szFile [I] Name of file to load from.
452  *  pptLib [O] Pointer that receives ITypeLib object on success.
453  *
454  * RETURNS
455  *    Success: S_OK
456  *    Failure: Status
457  *
458  * SEE
459  *  LoadTypeLibEx, LoadRegTypeLib, CreateTypeLib.
460  */
461 HRESULT WINAPI LoadTypeLib(const OLECHAR *szFile, ITypeLib * *pptLib)
462 {
463     TRACE("(%s,%p)\n",debugstr_w(szFile), pptLib);
464     return LoadTypeLibEx(szFile, REGKIND_DEFAULT, pptLib);
465 }
466 
467 /******************************************************************************
468  *		LoadTypeLibEx	[OLEAUT32.183]
469  *
470  * Loads and optionally registers a type library
471  *
472  * RETURNS
473  *    Success: S_OK
474  *    Failure: Status
475  */
476 HRESULT WINAPI LoadTypeLibEx(
477     LPCOLESTR szFile,  /* [in] Name of file to load from */
478     REGKIND  regkind,  /* [in] Specify kind of registration */
479     ITypeLib **pptLib) /* [out] Pointer to pointer to loaded type library */
480 {
481     WCHAR szPath[MAX_PATH+1];
482     HRESULT res;
483 
484     TRACE("(%s,%d,%p)\n",debugstr_w(szFile), regkind, pptLib);
485 
486     if (!szFile || !pptLib)
487         return E_INVALIDARG;
488 
489     *pptLib = NULL;
490 
491     res = TLB_ReadTypeLib(szFile, szPath, MAX_PATH + 1, (ITypeLib2**)pptLib);
492 
493     if (SUCCEEDED(res))
494         switch(regkind)
495         {
496             case REGKIND_DEFAULT:
497                 /* don't register typelibs supplied with full path. Experimentation confirms the following */
498                 if (((szFile[0] == '\\') && (szFile[1] == '\\')) ||
499                     (szFile[0] && (szFile[1] == ':'))) break;
500                 /* else fall-through */
501 
502             case REGKIND_REGISTER:
503                 if (FAILED(res = RegisterTypeLib(*pptLib, szPath, NULL)))
504                 {
505                     ITypeLib_Release(*pptLib);
506                     *pptLib = 0;
507                 }
508                 break;
509             case REGKIND_NONE:
510                 break;
511         }
512 
513     TRACE(" returns %08x\n",res);
514     return res;
515 }
516 
517 /******************************************************************************
518  *		LoadRegTypeLib	[OLEAUT32.162]
519  *
520  * Loads a registered type library.
521  *
522  * PARAMS
523  *  rguid     [I] GUID of the registered type library.
524  *  wVerMajor [I] major version.
525  *  wVerMinor [I] minor version.
526  *  lcid      [I] locale ID.
527  *  ppTLib    [O] pointer that receives an ITypeLib object on success.
528  *
529  * RETURNS
530  *  Success: S_OK.
531  *  Failure: Any HRESULT code returned from QueryPathOfRegTypeLib or
532  *  LoadTypeLib.
533  */
534 HRESULT WINAPI LoadRegTypeLib(
535 	REFGUID rguid,
536 	WORD wVerMajor,
537 	WORD wVerMinor,
538 	LCID lcid,
539 	ITypeLib **ppTLib)
540 {
541     BSTR bstr=NULL;
542     HRESULT res;
543 
544     *ppTLib = NULL;
545 
546     res = QueryPathOfRegTypeLib( rguid, wVerMajor, wVerMinor, lcid, &bstr);
547 
548     if(SUCCEEDED(res))
549     {
550         res= LoadTypeLib(bstr, ppTLib);
551         SysFreeString(bstr);
552 
553         if ((wVerMajor!=0xffff || wVerMinor!=0xffff) && *ppTLib)
554         {
555             TLIBATTR *attr;
556 
557             res = ITypeLib_GetLibAttr(*ppTLib, &attr);
558             if (res == S_OK)
559             {
560                 BOOL mismatch = attr->wMajorVerNum != wVerMajor || attr->wMinorVerNum < wVerMinor;
561                 ITypeLib_ReleaseTLibAttr(*ppTLib, attr);
562 
563                 if (mismatch)
564                 {
565                     ITypeLib_Release(*ppTLib);
566                     *ppTLib = NULL;
567                     res = TYPE_E_LIBNOTREGISTERED;
568                 }
569             }
570         }
571     }
572 
573     TRACE("(IID: %s) load %s (%p)\n",debugstr_guid(rguid), SUCCEEDED(res)? "SUCCESS":"FAILED", *ppTLib);
574 
575     return res;
576 }
577 
578 
579 /* some string constants shared between RegisterTypeLib and UnRegisterTypeLib */
580 static const WCHAR TypeLibW[] = {'T','y','p','e','L','i','b',0};
581 static const WCHAR FLAGSW[] = {'F','L','A','G','S',0};
582 static const WCHAR HELPDIRW[] = {'H','E','L','P','D','I','R',0};
583 static const WCHAR ProxyStubClsidW[] = {'P','r','o','x','y','S','t','u','b','C','l','s','i','d',0};
584 static const WCHAR ProxyStubClsid32W[] = {'P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
585 
586 static void TLB_register_interface(TLIBATTR *libattr, LPOLESTR name, TYPEATTR *tattr, DWORD flag)
587 {
588     WCHAR keyName[60];
589     HKEY key, subKey;
590 
591     static const WCHAR PSOA[] = {'{','0','0','0','2','0','4','2','4','-',
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         if (name)
600             RegSetValueExW(key, NULL, 0, REG_SZ,
601                            (BYTE *)name, (strlenW(name)+1) * sizeof(OLECHAR));
602 
603         if (RegCreateKeyExW(key, ProxyStubClsidW, 0, NULL, 0,
604             KEY_WRITE | flag, NULL, &subKey, NULL) == ERROR_SUCCESS) {
605             RegSetValueExW(subKey, NULL, 0, REG_SZ,
606                            (const BYTE *)PSOA, sizeof PSOA);
607             RegCloseKey(subKey);
608         }
609 
610         if (RegCreateKeyExW(key, ProxyStubClsid32W, 0, NULL, 0,
611             KEY_WRITE | flag, NULL, &subKey, NULL) == ERROR_SUCCESS) {
612             RegSetValueExW(subKey, NULL, 0, REG_SZ,
613                            (const BYTE *)PSOA, sizeof PSOA);
614             RegCloseKey(subKey);
615         }
616 
617         if (RegCreateKeyExW(key, TypeLibW, 0, NULL, 0,
618             KEY_WRITE | flag, NULL, &subKey, NULL) == ERROR_SUCCESS)
619         {
620             WCHAR buffer[40];
621             static const WCHAR fmtver[] = {'%','x','.','%','x',0 };
622             static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
623 
624             StringFromGUID2(&libattr->guid, buffer, 40);
625             RegSetValueExW(subKey, NULL, 0, REG_SZ,
626                            (BYTE *)buffer, (strlenW(buffer)+1) * sizeof(WCHAR));
627             sprintfW(buffer, fmtver, libattr->wMajorVerNum, libattr->wMinorVerNum);
628             RegSetValueExW(subKey, VersionW, 0, REG_SZ,
629                            (BYTE*)buffer, (strlenW(buffer)+1) * sizeof(WCHAR));
630             RegCloseKey(subKey);
631         }
632 
633         RegCloseKey(key);
634     }
635 }
636 
637 /******************************************************************************
638  *		RegisterTypeLib	[OLEAUT32.163]
639  * Adds information about a type library to the System Registry
640  * NOTES
641  *    Docs: ITypeLib FAR * ptlib
642  *    Docs: OLECHAR FAR* szFullPath
643  *    Docs: OLECHAR FAR* szHelpDir
644  *
645  * RETURNS
646  *    Success: S_OK
647  *    Failure: Status
648  */
649 HRESULT WINAPI RegisterTypeLib(
650      ITypeLib * ptlib,     /* [in] Pointer to the library*/
651      OLECHAR * szFullPath, /* [in] full Path of the library*/
652      OLECHAR * szHelpDir)  /* [in] dir to the helpfile for the library,
653 							 may be NULL*/
654 {
655     HRESULT res;
656     TLIBATTR *attr;
657     WCHAR keyName[60];
658     WCHAR tmp[16];
659     HKEY key, subKey;
660     UINT types, tidx;
661     TYPEKIND kind;
662     DWORD disposition;
663 
664     if (ptlib == NULL || szFullPath == NULL)
665         return E_INVALIDARG;
666 
667     if (FAILED(ITypeLib_GetLibAttr(ptlib, &attr)))
668         return E_FAIL;
669 
670 #ifndef _WIN64
671     if (attr->syskind == SYS_WIN64) return TYPE_E_BADMODULEKIND;
672 #endif
673 
674     get_typelib_key( &attr->guid, attr->wMajorVerNum, attr->wMinorVerNum, keyName );
675 
676     res = S_OK;
677     if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0,
678         KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS)
679     {
680         LPOLESTR doc;
681 
682         /* Set the human-readable name of the typelib */
683         if (FAILED(ITypeLib_GetDocumentation(ptlib, -1, NULL, &doc, NULL, NULL)))
684             res = E_FAIL;
685         else if (doc)
686         {
687             if (RegSetValueExW(key, NULL, 0, REG_SZ,
688                 (BYTE *)doc, (lstrlenW(doc)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS)
689                 res = E_FAIL;
690 
691             SysFreeString(doc);
692         }
693 
694         /* Make up the name of the typelib path subkey */
695         if (!get_lcid_subkey( attr->lcid, attr->syskind, tmp )) res = E_FAIL;
696 
697         /* Create the typelib path subkey */
698         if (res == S_OK && RegCreateKeyExW(key, tmp, 0, NULL, 0,
699             KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
700         {
701             if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
702                 (BYTE *)szFullPath, (lstrlenW(szFullPath)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS)
703                 res = E_FAIL;
704 
705             RegCloseKey(subKey);
706         }
707         else
708             res = E_FAIL;
709 
710         /* Create the flags subkey */
711         if (res == S_OK && RegCreateKeyExW(key, FLAGSW, 0, NULL, 0,
712             KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
713         {
714             /* FIXME: is %u correct? */
715             static const WCHAR formatW[] = {'%','u',0};
716             WCHAR buf[20];
717             sprintfW(buf, formatW, attr->wLibFlags);
718             if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
719                                (BYTE *)buf, (strlenW(buf) + 1)*sizeof(WCHAR) ) != ERROR_SUCCESS)
720                 res = E_FAIL;
721 
722             RegCloseKey(subKey);
723         }
724         else
725             res = E_FAIL;
726 
727         /* create the helpdir subkey */
728         if (res == S_OK && RegCreateKeyExW(key, HELPDIRW, 0, NULL, 0,
729             KEY_WRITE, NULL, &subKey, &disposition) == ERROR_SUCCESS)
730         {
731             BOOL freeHelpDir = FALSE;
732             OLECHAR* pIndexStr;
733 
734             /* if we created a new key, and helpDir was null, set the helpdir
735                to the directory which contains the typelib. However,
736                if we just opened an existing key, we leave the helpdir alone */
737             if ((disposition == REG_CREATED_NEW_KEY) && (szHelpDir == NULL)) {
738                 szHelpDir = SysAllocString(szFullPath);
739                 pIndexStr = strrchrW(szHelpDir, '\\');
740                 if (pIndexStr) {
741                     *pIndexStr = 0;
742                 }
743                 freeHelpDir = TRUE;
744             }
745 
746             /* if we have an szHelpDir, set it! */
747             if (szHelpDir != NULL) {
748                 if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
749                     (BYTE *)szHelpDir, (lstrlenW(szHelpDir)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS) {
750                     res = E_FAIL;
751                 }
752             }
753 
754             /* tidy up */
755             if (freeHelpDir) SysFreeString(szHelpDir);
756             RegCloseKey(subKey);
757 
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     *strrchrW( 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 = sizeof(subKeyName)/sizeof(WCHAR);
983     deleteOtherStuff = TRUE;
984     i = 0;
985     while(RegEnumKeyExW(key, i++, subKeyName, &tmpLength, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
986         tmpLength = sizeof(subKeyName)/sizeof(WCHAR);
987 
988         /* if its not FLAGS or HELPDIR, then we must keep the rest of the key */
989         if (!strcmpW(subKeyName, FLAGSW)) continue;
990         if (!strcmpW(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         *strrchrW( 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 (strcmpW(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; /* FIXME: this is only the non inherited part */
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) && !strncasecmp( (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) && !strncasecmp( (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 = strrchrW(pszFileName, '\\');
3300     if(index_str && *++index_str != '\0')
3301     {
3302         LPWSTR end_ptr;
3303         LONG idx = strtolW(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(strchrW(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, (strlenW(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 (!strcmpiW(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((strlenW(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]) strcatW(buf, spaceW);
3768         MultiByteToWideChar(CP_ACP, 0, p, -1, buf + strlenW(buf), buf_size - strlenW(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 && !strcmpW(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 += (strlenW(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 = strlenW(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 __ASM_GLOBAL_FUNC( call_method,
6409                    "pushl %ebp\n\t"
6410                    __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
6411                    __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
6412                    "movl %esp,%ebp\n\t"
6413                    __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
6414                    "pushl %esi\n\t"
6415                   __ASM_CFI(".cfi_rel_offset %esi,-4\n\t")
6416                    "pushl %edi\n\t"
6417                   __ASM_CFI(".cfi_rel_offset %edi,-8\n\t")
6418                    "movl 12(%ebp),%edx\n\t"
6419                    "movl %esp,%edi\n\t"
6420                    "shll $2,%edx\n\t"
6421                    "jz 1f\n\t"
6422                    "subl %edx,%edi\n\t"
6423                    "andl $~15,%edi\n\t"
6424                    "movl %edi,%esp\n\t"
6425                    "movl 12(%ebp),%ecx\n\t"
6426                    "movl 16(%ebp),%esi\n\t"
6427                    "cld\n\t"
6428                    "rep; movsl\n"
6429                    "1:\tcall *8(%ebp)\n\t"
6430                    "subl %esp,%edi\n\t"
6431                    "movl 20(%ebp),%ecx\n\t"
6432                    "movl %edi,(%ecx)\n\t"
6433                    "leal -8(%ebp),%esp\n\t"
6434                    "popl %edi\n\t"
6435                    __ASM_CFI(".cfi_same_value %edi\n\t")
6436                    "popl %esi\n\t"
6437                    __ASM_CFI(".cfi_same_value %esi\n\t")
6438                    "popl %ebp\n\t"
6439                    __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
6440                    __ASM_CFI(".cfi_same_value %ebp\n\t")
6441                    "ret" )
6442 
6443 /* same function but returning floating point */
6444 static double (* const call_double_method)(void*,int,const DWORD*,int*) = (void *)call_method;
6445 
6446 /* ITypeInfo::Invoke
6447  *
6448  * Invokes a method, or accesses a property of an object, that implements the
6449  * interface described by the type description.
6450  */
6451 DWORD _invoke(FARPROC func, CALLCONV callconv, int nrargs, DWORD_PTR *args)
6452 {
6453     DWORD res;
6454     int stack_offset;
6455 
6456     if (TRACE_ON(ole)) {
6457 	int i;
6458 	TRACE("Calling %p(",func);
6459 	for (i=0;i<min(nrargs,30);i++) TRACE("%08lx,",args[i]);
6460 	if (nrargs > 30) TRACE("...");
6461 	TRACE(")\n");
6462     }
6463 
6464     switch (callconv) {
6465     case CC_STDCALL:
6466     case CC_CDECL:
6467         res = call_method(func, nrargs, (DWORD *)args, &stack_offset);
6468 	break;
6469     default:
6470 	FIXME("unsupported calling convention %d\n",callconv);
6471 	res = -1;
6472 	break;
6473     }
6474     TRACE("returns %08x\n",res);
6475     return res;
6476 }
6477 
6478 #elif defined(__x86_64__)
6479 
6480 extern DWORD_PTR CDECL call_method( void *func, int nb_args, const DWORD_PTR *args );
6481 __ASM_GLOBAL_FUNC( call_method,
6482                    "pushq %rbp\n\t"
6483                    __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t")
6484                    __ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
6485                    "movq %rsp,%rbp\n\t"
6486                    __ASM_CFI(".cfi_def_cfa_register %rbp\n\t")
6487                    "pushq %rsi\n\t"
6488                    __ASM_CFI(".cfi_rel_offset %rsi,-8\n\t")
6489                    "pushq %rdi\n\t"
6490                    __ASM_CFI(".cfi_rel_offset %rdi,-16\n\t")
6491                    "movq %rcx,%rax\n\t"
6492                    "movq $4,%rcx\n\t"
6493                    "cmp %rcx,%rdx\n\t"
6494                    "cmovgq %rdx,%rcx\n\t"
6495                    "leaq 0(,%rcx,8),%rdx\n\t"
6496                    "subq %rdx,%rsp\n\t"
6497                    "andq $~15,%rsp\n\t"
6498                    "movq %rsp,%rdi\n\t"
6499                    "movq %r8,%rsi\n\t"
6500                    "rep; movsq\n\t"
6501                    "movq 0(%rsp),%rcx\n\t"
6502                    "movq 8(%rsp),%rdx\n\t"
6503                    "movq 16(%rsp),%r8\n\t"
6504                    "movq 24(%rsp),%r9\n\t"
6505                    "movq 0(%rsp),%xmm0\n\t"
6506                    "movq 8(%rsp),%xmm1\n\t"
6507                    "movq 16(%rsp),%xmm2\n\t"
6508                    "movq 24(%rsp),%xmm3\n\t"
6509                    "callq *%rax\n\t"
6510                    "leaq -16(%rbp),%rsp\n\t"
6511                    "popq %rdi\n\t"
6512                    __ASM_CFI(".cfi_same_value %rdi\n\t")
6513                    "popq %rsi\n\t"
6514                    __ASM_CFI(".cfi_same_value %rsi\n\t")
6515                    __ASM_CFI(".cfi_def_cfa_register %rsp\n\t")
6516                    "popq %rbp\n\t"
6517                    __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t")
6518                    __ASM_CFI(".cfi_same_value %rbp\n\t")
6519                    "ret")
6520 
6521 /* same function but returning floating point */
6522 static double (CDECL * const call_double_method)(void*,int,const DWORD_PTR*) = (void *)call_method;
6523 
6524 DWORD _invoke(FARPROC func, CALLCONV callconv, int nrargs, DWORD_PTR *args)
6525 {
6526     DWORD res;
6527 
6528     if (TRACE_ON(ole))
6529     {
6530         int i;
6531         TRACE("Calling %p(", func);
6532         for (i=0; i<min(nrargs, 30); i++) TRACE("%016lx,", args[i]);
6533         if (nrargs > 30) TRACE("...");
6534         TRACE(")\n");
6535     }
6536 
6537     switch (callconv) {
6538     case CC_STDCALL:
6539     case CC_CDECL:
6540         res = call_method(func, nrargs, args);
6541         break;
6542     default:
6543         FIXME("unsupported calling convention %d\n", callconv);
6544         res = -1;
6545         break;
6546     }
6547 
6548     TRACE("returns %08x\n", res);
6549     return res;
6550 }
6551 
6552 #elif defined(__arm__)
6553 
6554 extern LONGLONG CDECL call_method( void *func, int nb_stk_args, const DWORD *stk_args, const DWORD *reg_args );
6555 __ASM_GLOBAL_FUNC( call_method,
6556                     /* r0 = *func
6557                      * r1 = nb_stk_args
6558                      * r2 = *stk_args (pointer to 'nb_stk_args' DWORD values to push on stack)
6559                      * 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)
6560                      */
6561 
6562                     "push {fp, lr}\n\t"             /* Save frame pointer and return address (stack still aligned to 8 bytes) */
6563                     "mov fp, sp\n\t"                /* Save stack pointer as our frame for cleaning the stack on return */
6564 
6565                     "lsls r1, r1, #2\n\t"           /* r1 = nb_stk_args * sizeof(DWORD) */
6566                     "beq 1f\n\t"                    /* Skip allocation if no stack args */
6567                     "add r2, r2, r1\n"              /* Calculate ending address of incoming stack data */
6568                     "2:\tldr ip, [r2, #-4]!\n\t"    /* Get next value */
6569                     "str ip, [sp, #-4]!\n\t"        /* Push it on the stack */
6570                     "subs r1, r1, #4\n\t"           /* Decrement count */
6571                     "bgt 2b\n\t"                    /* Loop till done */
6572 
6573                     "1:\n\t"
6574 #ifndef __SOFTFP__
6575                     "vldm r3!, {s0-s15}\n\t"        /* Load the s0-s15/d0-d7 arguments */
6576 #endif
6577                     "mov ip, r0\n\t"                /* Save the function call address to ip before we nuke r0 with arguments to pass */
6578                     "ldm r3, {r0-r3}\n\t"           /* Load the r0-r3 arguments */
6579 
6580                     "blx ip\n\t"                    /* Call the target function */
6581 
6582                     "mov sp, fp\n\t"                /* Clean the stack using fp */
6583                     "pop {fp, pc}\n\t"              /* Restore fp and return */
6584                 )
6585 
6586 /* same function but returning single/double floating point */
6587 static float (CDECL * const call_float_method)(void *, int, const DWORD *, const DWORD *) = (void *)call_method;
6588 static double (CDECL * const call_double_method)(void *, int, const DWORD *, const DWORD *) = (void *)call_method;
6589 
6590 #endif  /* __x86_64__ */
6591 
6592 static HRESULT userdefined_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
6593 {
6594     HRESULT hr = S_OK;
6595     ITypeInfo *tinfo2 = NULL;
6596     TYPEATTR *tattr = NULL;
6597 
6598     hr = ITypeInfo_GetRefTypeInfo(tinfo, tdesc->u.hreftype, &tinfo2);
6599     if (hr)
6600     {
6601         ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED, "
6602             "hr = 0x%08x\n",
6603               tdesc->u.hreftype, hr);
6604         return hr;
6605     }
6606     hr = ITypeInfo_GetTypeAttr(tinfo2, &tattr);
6607     if (hr)
6608     {
6609         ERR("ITypeInfo_GetTypeAttr failed, hr = 0x%08x\n", hr);
6610         ITypeInfo_Release(tinfo2);
6611         return hr;
6612     }
6613 
6614     switch (tattr->typekind)
6615     {
6616     case TKIND_ENUM:
6617         *vt |= VT_I4;
6618         break;
6619 
6620     case TKIND_ALIAS:
6621         hr = typedescvt_to_variantvt(tinfo2, &tattr->tdescAlias, vt);
6622         break;
6623 
6624     case TKIND_INTERFACE:
6625         if (tattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE)
6626            *vt |= VT_DISPATCH;
6627         else
6628            *vt |= VT_UNKNOWN;
6629         break;
6630 
6631     case TKIND_DISPATCH:
6632         *vt |= VT_DISPATCH;
6633         break;
6634 
6635     case TKIND_COCLASS:
6636         *vt |= VT_DISPATCH;
6637         break;
6638 
6639     case TKIND_RECORD:
6640         FIXME("TKIND_RECORD unhandled.\n");
6641         hr = E_NOTIMPL;
6642         break;
6643 
6644     case TKIND_UNION:
6645         FIXME("TKIND_UNION unhandled.\n");
6646         hr = E_NOTIMPL;
6647         break;
6648 
6649     default:
6650         FIXME("TKIND %d unhandled.\n",tattr->typekind);
6651         hr = E_NOTIMPL;
6652         break;
6653     }
6654     ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
6655     ITypeInfo_Release(tinfo2);
6656     return hr;
6657 }
6658 
6659 static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
6660 {
6661     HRESULT hr = S_OK;
6662 
6663     /* enforce only one level of pointer indirection */
6664     if (!(*vt & VT_BYREF) && !(*vt & VT_ARRAY) && (tdesc->vt == VT_PTR))
6665     {
6666         tdesc = tdesc->u.lptdesc;
6667 
6668         /* munch VT_PTR -> VT_USERDEFINED(interface) into VT_UNKNOWN or
6669          * VT_DISPATCH and VT_PTR -> VT_PTR -> VT_USERDEFINED(interface) into
6670          * VT_BYREF|VT_DISPATCH or VT_BYREF|VT_UNKNOWN */
6671         if ((tdesc->vt == VT_USERDEFINED) ||
6672             ((tdesc->vt == VT_PTR) && (tdesc->u.lptdesc->vt == VT_USERDEFINED)))
6673         {
6674             VARTYPE vt_userdefined = 0;
6675             const TYPEDESC *tdesc_userdefined = tdesc;
6676             if (tdesc->vt == VT_PTR)
6677             {
6678                 vt_userdefined = VT_BYREF;
6679                 tdesc_userdefined = tdesc->u.lptdesc;
6680             }
6681             hr = userdefined_to_variantvt(tinfo, tdesc_userdefined, &vt_userdefined);
6682             if ((hr == S_OK) &&
6683                 (((vt_userdefined & VT_TYPEMASK) == VT_UNKNOWN) ||
6684                  ((vt_userdefined & VT_TYPEMASK) == VT_DISPATCH)))
6685             {
6686                 *vt |= vt_userdefined;
6687                 return S_OK;
6688             }
6689         }
6690         *vt = VT_BYREF;
6691     }
6692 
6693     switch (tdesc->vt)
6694     {
6695     case VT_HRESULT:
6696         *vt |= VT_ERROR;
6697         break;
6698     case VT_USERDEFINED:
6699         hr = userdefined_to_variantvt(tinfo, tdesc, vt);
6700         break;
6701     case VT_VOID:
6702     case VT_CARRAY:
6703     case VT_PTR:
6704     case VT_LPSTR:
6705     case VT_LPWSTR:
6706         ERR("cannot convert type %d into variant VT\n", tdesc->vt);
6707         hr = DISP_E_BADVARTYPE;
6708         break;
6709     case VT_SAFEARRAY:
6710         *vt |= VT_ARRAY;
6711         hr = typedescvt_to_variantvt(tinfo, tdesc->u.lptdesc, vt);
6712         break;
6713     case VT_INT:
6714         *vt |= VT_I4;
6715         break;
6716     case VT_UINT:
6717         *vt |= VT_UI4;
6718         break;
6719     default:
6720         *vt |= tdesc->vt;
6721         break;
6722     }
6723     return hr;
6724 }
6725 
6726 static HRESULT get_iface_guid(ITypeInfo *tinfo, HREFTYPE href, GUID *guid)
6727 {
6728     ITypeInfo *tinfo2;
6729     TYPEATTR *tattr;
6730     HRESULT hres;
6731 
6732     hres = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2);
6733     if(FAILED(hres))
6734         return hres;
6735 
6736     hres = ITypeInfo_GetTypeAttr(tinfo2, &tattr);
6737     if(FAILED(hres)) {
6738         ITypeInfo_Release(tinfo2);
6739         return hres;
6740     }
6741 
6742     switch(tattr->typekind) {
6743     case TKIND_ALIAS:
6744         hres = get_iface_guid(tinfo2, tattr->tdescAlias.u.hreftype, guid);
6745         break;
6746 
6747     case TKIND_INTERFACE:
6748     case TKIND_DISPATCH:
6749         *guid = tattr->guid;
6750         break;
6751 
6752     case TKIND_COCLASS: {
6753         unsigned int i;
6754         int type_flags;
6755 
6756         for(i = 0; i < tattr->cImplTypes; i++)
6757             if(SUCCEEDED(ITypeInfo_GetImplTypeFlags(tinfo2, i, &type_flags)) &&
6758                type_flags == (IMPLTYPEFLAG_FSOURCE|IMPLTYPEFLAG_FDEFAULT)) break;
6759 
6760         if(i < tattr->cImplTypes) {
6761             hres = ITypeInfo_GetRefTypeOfImplType(tinfo2, i, &href);
6762             if(SUCCEEDED(hres)) hres = get_iface_guid(tinfo2, href, guid);
6763         } else hres = E_UNEXPECTED;
6764         break;
6765     }
6766 
6767     default:
6768         ERR("Unexpected typekind %d\n", tattr->typekind);
6769         hres = E_UNEXPECTED;
6770     }
6771 
6772     ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
6773     ITypeInfo_Release(tinfo2);
6774     return hres;
6775 }
6776 
6777 /***********************************************************************
6778  *		DispCallFunc (OLEAUT32.@)
6779  *
6780  * Invokes a function of the specified calling convention, passing the
6781  * specified arguments and returns the result.
6782  *
6783  * PARAMS
6784  *  pvInstance  [I] Optional pointer to the instance whose function to invoke.
6785  *  oVft        [I] The offset in the vtable. See notes.
6786  *  cc          [I] Calling convention of the function to call.
6787  *  vtReturn    [I] The return type of the function.
6788  *  cActuals    [I] Number of parameters.
6789  *  prgvt       [I] The types of the parameters to pass. This is used for sizing only.
6790  *  prgpvarg    [I] The arguments to pass.
6791  *  pvargResult [O] The return value of the function. Can be NULL.
6792  *
6793  * RETURNS
6794  *  Success: S_OK.
6795  *  Failure: HRESULT code.
6796  *
6797  * NOTES
6798  *  The HRESULT return value of this function is not affected by the return
6799  *  value of the user supplied function, which is returned in pvargResult.
6800  *
6801  *  If pvInstance is NULL then a non-object function is to be called and oVft
6802  *  is the address of the function to call.
6803  *
6804  * The cc parameter can be one of the following values:
6805  *|CC_FASTCALL
6806  *|CC_CDECL
6807  *|CC_PASCAL
6808  *|CC_STDCALL
6809  *|CC_FPFASTCALL
6810  *|CC_SYSCALL
6811  *|CC_MPWCDECL
6812  *|CC_MPWPASCAL
6813  *
6814  */
6815 HRESULT WINAPI
6816 DispCallFunc(
6817     void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals,
6818     VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult)
6819 {
6820 #ifdef __i386__
6821     int argspos, stack_offset;
6822     void *func;
6823     UINT i;
6824     DWORD *args;
6825 
6826     TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
6827         pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
6828         pvargResult, V_VT(pvargResult));
6829 
6830     if (cc != CC_STDCALL && cc != CC_CDECL)
6831     {
6832         FIXME("unsupported calling convention %d\n",cc);
6833         return E_INVALIDARG;
6834     }
6835 
6836     /* maximum size for an argument is sizeof(VARIANT) */
6837     args = heap_alloc(sizeof(VARIANT) * cActuals + sizeof(DWORD) * 2 );
6838 
6839     /* start at 1 in case we need to pass a pointer to the return value as arg 0 */
6840     argspos = 1;
6841     if (pvInstance)
6842     {
6843         const FARPROC *vtable = *(FARPROC **)pvInstance;
6844         func = vtable[oVft/sizeof(void *)];
6845         args[argspos++] = (DWORD)pvInstance; /* the This pointer is always the first parameter */
6846     }
6847     else func = (void *)oVft;
6848 
6849     for (i = 0; i < cActuals; i++)
6850     {
6851         VARIANT *arg = prgpvarg[i];
6852 
6853         switch (prgvt[i])
6854         {
6855         case VT_EMPTY:
6856             break;
6857         case VT_I8:
6858         case VT_UI8:
6859         case VT_R8:
6860         case VT_DATE:
6861         case VT_CY:
6862             memcpy( &args[argspos], &V_I8(arg), sizeof(V_I8(arg)) );
6863             argspos += sizeof(V_I8(arg)) / sizeof(DWORD);
6864             break;
6865         case VT_DECIMAL:
6866         case VT_VARIANT:
6867             memcpy( &args[argspos], arg, sizeof(*arg) );
6868             argspos += sizeof(*arg) / sizeof(DWORD);
6869             break;
6870         case VT_BOOL:  /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
6871             args[argspos++] = V_BOOL(arg);
6872             break;
6873         default:
6874             args[argspos++] = V_UI4(arg);
6875             break;
6876         }
6877         TRACE("arg %u: type %s %s\n", i, debugstr_vt(prgvt[i]), debugstr_variant(arg));
6878     }
6879 
6880     switch (vtReturn)
6881     {
6882     case VT_EMPTY:
6883         call_method( func, argspos - 1, args + 1, &stack_offset );
6884         break;
6885     case VT_R4:
6886         V_R4(pvargResult) = call_double_method( func, argspos - 1, args + 1, &stack_offset );
6887         break;
6888     case VT_R8:
6889     case VT_DATE:
6890         V_R8(pvargResult) = call_double_method( func, argspos - 1, args + 1, &stack_offset );
6891         break;
6892     case VT_DECIMAL:
6893     case VT_VARIANT:
6894         if (pvInstance)
6895         {
6896             args[0] = (DWORD)pvInstance;  /* arg 0 is a pointer to the instance */
6897             args[1] = (DWORD)pvargResult; /* arg 1 is a pointer to the result */
6898             call_method( func, argspos, args, &stack_offset );
6899         }
6900         else
6901         {
6902             args[0] = (DWORD)pvargResult;  /* arg 0 is a pointer to the result */
6903             call_method( func, argspos, args, &stack_offset );
6904         }
6905         break;
6906     case VT_I8:
6907     case VT_UI8:
6908     case VT_CY:
6909         V_UI8(pvargResult) = call_method( func, argspos - 1, args + 1, &stack_offset );
6910         break;
6911     case VT_HRESULT:
6912         WARN("invalid return type %u\n", vtReturn);
6913         heap_free( args );
6914         return E_INVALIDARG;
6915     default:
6916         V_UI4(pvargResult) = call_method( func, argspos - 1, args + 1, &stack_offset );
6917         break;
6918     }
6919     heap_free( args );
6920     if (stack_offset && cc == CC_STDCALL)
6921     {
6922         WARN( "stack pointer off by %d\n", stack_offset );
6923         return DISP_E_BADCALLEE;
6924     }
6925     if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
6926     TRACE("retval: %s\n", debugstr_variant(pvargResult));
6927     return S_OK;
6928 
6929 #elif defined(__x86_64__)
6930     int argspos;
6931     UINT i;
6932     DWORD_PTR *args;
6933     void *func;
6934 
6935     TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
6936           pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
6937           pvargResult, V_VT(pvargResult));
6938 
6939     if (cc != CC_STDCALL && cc != CC_CDECL)
6940     {
6941 	FIXME("unsupported calling convention %d\n",cc);
6942         return E_INVALIDARG;
6943     }
6944 
6945     /* maximum size for an argument is sizeof(DWORD_PTR) */
6946     args = heap_alloc( sizeof(DWORD_PTR) * (cActuals + 2) );
6947 
6948     /* start at 1 in case we need to pass a pointer to the return value as arg 0 */
6949     argspos = 1;
6950     if (pvInstance)
6951     {
6952         const FARPROC *vtable = *(FARPROC **)pvInstance;
6953         func = vtable[oVft/sizeof(void *)];
6954         args[argspos++] = (DWORD_PTR)pvInstance; /* the This pointer is always the first parameter */
6955     }
6956     else func = (void *)oVft;
6957 
6958     for (i = 0; i < cActuals; i++)
6959     {
6960         VARIANT *arg = prgpvarg[i];
6961 
6962         switch (prgvt[i])
6963         {
6964         case VT_DECIMAL:
6965         case VT_VARIANT:
6966             args[argspos++] = (ULONG_PTR)arg;
6967             break;
6968         case VT_BOOL:  /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
6969             args[argspos++] = V_BOOL(arg);
6970             break;
6971         default:
6972             args[argspos++] = V_UI8(arg);
6973             break;
6974         }
6975         TRACE("arg %u: type %s %s\n", i, debugstr_vt(prgvt[i]), debugstr_variant(arg));
6976     }
6977 
6978     switch (vtReturn)
6979     {
6980     case VT_R4:
6981         V_R4(pvargResult) = call_double_method( func, argspos - 1, args + 1 );
6982         break;
6983     case VT_R8:
6984     case VT_DATE:
6985         V_R8(pvargResult) = call_double_method( func, argspos - 1, args + 1 );
6986         break;
6987     case VT_DECIMAL:
6988     case VT_VARIANT:
6989         if (pvInstance)
6990         {
6991             args[0] = (DWORD_PTR)pvInstance;  /* arg 0 is a pointer to the instance */
6992             args[1] = (DWORD_PTR)pvargResult; /* arg 1 is a pointer to the result */
6993             call_method( func, argspos, args );
6994         }
6995         else
6996         {
6997             args[0] = (DWORD_PTR)pvargResult;  /* arg 0 is a pointer to the result */
6998             call_method( func, argspos, args );
6999         }
7000         break;
7001     case VT_HRESULT:
7002         WARN("invalid return type %u\n", vtReturn);
7003         heap_free( args );
7004         return E_INVALIDARG;
7005     default:
7006         V_UI8(pvargResult) = call_method( func, argspos - 1, args + 1 );
7007         break;
7008     }
7009     heap_free( args );
7010     if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
7011     TRACE("retval: %s\n", debugstr_variant(pvargResult));
7012     return S_OK;
7013 
7014 #elif defined(__arm__)
7015     int argspos;
7016     void *func;
7017     UINT i;
7018     DWORD *args;
7019     struct {
7020 #ifndef __SOFTFP__
7021         union {
7022             float s[16];
7023             double d[8];
7024         } sd;
7025 #endif
7026         DWORD r[4];
7027     } regs;
7028     int rcount;     /* 32-bit register index count */
7029 #ifndef __SOFTFP__
7030     int scount = 0; /* single-precision float register index count */
7031     int dcount = 0; /* double-precision float register index count */
7032 #endif
7033 
7034     TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
7035         pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg, pvargResult, V_VT(pvargResult));
7036 
7037     if (cc != CC_STDCALL && cc != CC_CDECL)
7038     {
7039         FIXME("unsupported calling convention %d\n",cc);
7040         return E_INVALIDARG;
7041     }
7042 
7043     argspos = 0;
7044     rcount = 0;
7045 
7046     /* Determine if we need to pass a pointer for the return value as arg 0.  If so, do that */
7047     /*  first as it will need to be in the 'r' registers:                                    */
7048     switch (vtReturn)
7049     {
7050     case VT_DECIMAL:
7051     case VT_VARIANT:
7052         regs.r[rcount++] = (DWORD)pvargResult;  /* arg 0 is a pointer to the result */
7053         break;
7054     case VT_HRESULT:
7055         WARN("invalid return type %u\n", vtReturn);
7056         return E_INVALIDARG;
7057     default:                    /* And all others are in 'r', 's', or 'd' registers or have no return value */
7058         break;
7059     }
7060 
7061     if (pvInstance)
7062     {
7063         const FARPROC *vtable = *(FARPROC **)pvInstance;
7064         func = vtable[oVft/sizeof(void *)];
7065         regs.r[rcount++] = (DWORD)pvInstance; /* the This pointer is always the first parameter */
7066     }
7067     else func = (void *)oVft;
7068 
7069     /* maximum size for an argument is sizeof(VARIANT).  Also allow for return pointer and stack alignment. */
7070     args = heap_alloc( sizeof(VARIANT) * cActuals + sizeof(DWORD) * 4 );
7071 
7072     for (i = 0; i < cActuals; i++)
7073     {
7074         VARIANT *arg = prgpvarg[i];
7075         DWORD *pdwarg = (DWORD *)(arg);     /* a reinterpret_cast of the variant, used for copying structures when they are split between registers and stack */
7076         int ntemp;              /* Used for counting words split between registers and stack */
7077 
7078         switch (prgvt[i])
7079         {
7080         case VT_EMPTY:
7081             break;
7082         case VT_R8:             /* these must be 8-byte aligned, and put in 'd' regs or stack, as they are double-floats */
7083         case VT_DATE:
7084 #ifndef __SOFTFP__
7085             dcount = max( (scount + 1) / 2, dcount );
7086             if (dcount < 8)
7087             {
7088                 regs.sd.d[dcount++] = V_R8(arg);
7089             }
7090             else
7091             {
7092                 argspos += (argspos % 2);   /* align argspos to 8-bytes */
7093                 memcpy( &args[argspos], &V_R8(arg), sizeof(V_R8(arg)) );
7094                 argspos += sizeof(V_R8(arg)) / sizeof(DWORD);
7095             }
7096             break;
7097 #endif
7098         case VT_I8:             /* these must be 8-byte aligned, and put in 'r' regs or stack, as they are long-longs */
7099         case VT_UI8:
7100         case VT_CY:
7101             if (rcount < 3)
7102             {
7103                 rcount += (rcount % 2);     /* align rcount to 8-byte register pair */
7104                 memcpy( &regs.r[rcount], &V_UI8(arg), sizeof(V_UI8(arg)) );
7105                 rcount += sizeof(V_UI8(arg)) / sizeof(DWORD);
7106             }
7107             else
7108             {
7109                 rcount = 4;                 /* Make sure we flag that all 'r' regs are full */
7110                 argspos += (argspos % 2);   /* align argspos to 8-bytes */
7111                 memcpy( &args[argspos], &V_UI8(arg), sizeof(V_UI8(arg)) );
7112                 argspos += sizeof(V_UI8(arg)) / sizeof(DWORD);
7113             }
7114             break;
7115         case VT_DECIMAL:        /* these structures are 8-byte aligned, and put in 'r' regs or stack, can be split between the two */
7116         case VT_VARIANT:
7117             /* 8-byte align 'r' and/or stack: */
7118             if (rcount < 3)
7119                 rcount += (rcount % 2);
7120             else
7121             {
7122                 rcount = 4;
7123                 argspos += (argspos % 2);
7124             }
7125             ntemp = sizeof(*arg) / sizeof(DWORD);
7126             while (ntemp > 0)
7127             {
7128                 if (rcount < 4)
7129                     regs.r[rcount++] = *pdwarg++;
7130                 else
7131                     args[argspos++] = *pdwarg++;
7132                 --ntemp;
7133             }
7134             break;
7135         case VT_BOOL:  /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
7136             if (rcount < 4)
7137                 regs.r[rcount++] = V_BOOL(arg);
7138             else
7139                 args[argspos++] = V_BOOL(arg);
7140             break;
7141         case VT_R4:             /* these must be 4-byte aligned, and put in 's' regs or stack, as they are single-floats */
7142 #ifndef __SOFTFP__
7143             if (!(scount % 2)) scount = max( scount, dcount * 2 );
7144             if (scount < 16)
7145                 regs.sd.s[scount++] = V_R4(arg);
7146             else
7147                 args[argspos++] = V_UI4(arg);
7148             break;
7149 #endif
7150         default:
7151             if (rcount < 4)
7152                 regs.r[rcount++] = V_UI4(arg);
7153             else
7154                 args[argspos++] = V_UI4(arg);
7155             break;
7156         }
7157         TRACE("arg %u: type %s %s\n", i, debugstr_vt(prgvt[i]), debugstr_variant(arg));
7158     }
7159 
7160     argspos += (argspos % 2);   /* Make sure stack function alignment is 8-byte */
7161 
7162     switch (vtReturn)
7163     {
7164     case VT_EMPTY:      /* EMPTY = no return value */
7165     case VT_DECIMAL:    /* DECIMAL and VARIANT already have a pointer argument passed (see above) */
7166     case VT_VARIANT:
7167         call_method( func, argspos, args, (DWORD*)&regs );
7168         break;
7169     case VT_R4:
7170         V_R4(pvargResult) = call_float_method( func, argspos, args, (DWORD*)&regs );
7171         break;
7172     case VT_R8:
7173     case VT_DATE:
7174         V_R8(pvargResult) = call_double_method( func, argspos, args, (DWORD*)&regs );
7175         break;
7176     case VT_I8:
7177     case VT_UI8:
7178     case VT_CY:
7179         V_UI8(pvargResult) = call_method( func, argspos, args, (DWORD*)&regs );
7180         break;
7181     default:
7182         V_UI4(pvargResult) = call_method( func, argspos, args, (DWORD*)&regs );
7183         break;
7184     }
7185     heap_free( args );
7186     if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
7187     TRACE("retval: %s\n", debugstr_variant(pvargResult));
7188     return S_OK;
7189 
7190 #else
7191     FIXME( "(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d)): not implemented for this CPU\n",
7192            pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg, pvargResult, V_VT(pvargResult));
7193     return E_NOTIMPL;
7194 #endif
7195 }
7196 
7197 static inline BOOL func_restricted( const FUNCDESC *desc )
7198 {
7199     return (desc->wFuncFlags & FUNCFLAG_FRESTRICTED) && (desc->memid >= 0);
7200 }
7201 
7202 #define INVBUF_ELEMENT_SIZE \
7203     (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *) + sizeof(VARTYPE))
7204 #define INVBUF_GET_ARG_ARRAY(buffer, params) (buffer)
7205 #define INVBUF_GET_MISSING_ARG_ARRAY(buffer, params) \
7206     ((VARIANTARG *)((char *)(buffer) + sizeof(VARIANTARG) * (params)))
7207 #define INVBUF_GET_ARG_PTR_ARRAY(buffer, params) \
7208     ((VARIANTARG **)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG)) * (params)))
7209 #define INVBUF_GET_ARG_TYPE_ARRAY(buffer, params) \
7210     ((VARTYPE *)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *)) * (params)))
7211 
7212 static HRESULT WINAPI ITypeInfo_fnInvoke(
7213     ITypeInfo2 *iface,
7214     VOID  *pIUnk,
7215     MEMBERID memid,
7216     UINT16 wFlags,
7217     DISPPARAMS  *pDispParams,
7218     VARIANT  *pVarResult,
7219     EXCEPINFO  *pExcepInfo,
7220     UINT  *pArgErr)
7221 {
7222     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
7223     int i;
7224     unsigned int var_index;
7225     TYPEKIND type_kind;
7226     HRESULT hres;
7227     const TLBFuncDesc *pFuncInfo;
7228     UINT fdc;
7229 
7230     TRACE("(%p)(%p,id=%d,flags=0x%08x,%p,%p,%p,%p)\n",
7231       This,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr
7232     );
7233 
7234     if( This->typeattr.wTypeFlags & TYPEFLAG_FRESTRICTED )
7235         return DISP_E_MEMBERNOTFOUND;
7236 
7237     if (!pDispParams)
7238     {
7239         ERR("NULL pDispParams not allowed\n");
7240         return E_INVALIDARG;
7241     }
7242 
7243     dump_DispParms(pDispParams);
7244 
7245     if (pDispParams->cNamedArgs > pDispParams->cArgs)
7246     {
7247         ERR("named argument array cannot be bigger than argument array (%d/%d)\n",
7248             pDispParams->cNamedArgs, pDispParams->cArgs);
7249         return E_INVALIDARG;
7250     }
7251 
7252     /* we do this instead of using GetFuncDesc since it will return a fake
7253      * FUNCDESC for dispinterfaces and we want the real function description */
7254     for (fdc = 0; fdc < This->typeattr.cFuncs; ++fdc){
7255         pFuncInfo = &This->funcdescs[fdc];
7256         if ((memid == pFuncInfo->funcdesc.memid) &&
7257             (wFlags & pFuncInfo->funcdesc.invkind) &&
7258             !func_restricted( &pFuncInfo->funcdesc ))
7259             break;
7260     }
7261 
7262     if (fdc < This->typeattr.cFuncs) {
7263         const FUNCDESC *func_desc = &pFuncInfo->funcdesc;
7264 
7265         if (TRACE_ON(ole))
7266         {
7267             TRACE("invoking:\n");
7268             dump_TLBFuncDescOne(pFuncInfo);
7269         }
7270 
7271 	switch (func_desc->funckind) {
7272 	case FUNC_PUREVIRTUAL:
7273 	case FUNC_VIRTUAL: {
7274             void *buffer = heap_alloc_zero(INVBUF_ELEMENT_SIZE * func_desc->cParams);
7275             VARIANT varresult;
7276             VARIANT retval; /* pointer for storing byref retvals in */
7277             VARIANTARG **prgpvarg = INVBUF_GET_ARG_PTR_ARRAY(buffer, func_desc->cParams);
7278             VARIANTARG *rgvarg = INVBUF_GET_ARG_ARRAY(buffer, func_desc->cParams);
7279             VARTYPE *rgvt = INVBUF_GET_ARG_TYPE_ARRAY(buffer, func_desc->cParams);
7280             UINT cNamedArgs = pDispParams->cNamedArgs;
7281             DISPID *rgdispidNamedArgs = pDispParams->rgdispidNamedArgs;
7282             UINT vargs_converted=0;
7283 
7284             hres = S_OK;
7285 
7286             if (func_desc->invkind & (INVOKE_PROPERTYPUT|INVOKE_PROPERTYPUTREF))
7287             {
7288                 if (!cNamedArgs || (rgdispidNamedArgs[0] != DISPID_PROPERTYPUT))
7289                 {
7290                     ERR("first named arg for property put invocation must be DISPID_PROPERTYPUT\n");
7291                     hres = DISP_E_PARAMNOTFOUND;
7292                     goto func_fail;
7293                 }
7294             }
7295 
7296             if (func_desc->cParamsOpt < 0 && cNamedArgs)
7297             {
7298                 ERR("functions with the vararg attribute do not support named arguments\n");
7299                 hres = DISP_E_NONAMEDARGS;
7300                 goto func_fail;
7301             }
7302 
7303             for (i = 0; i < func_desc->cParams; i++)
7304             {
7305                 TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc;
7306                 hres = typedescvt_to_variantvt((ITypeInfo *)iface, tdesc, &rgvt[i]);
7307                 if (FAILED(hres))
7308                     goto func_fail;
7309             }
7310 
7311             TRACE("changing args\n");
7312             for (i = 0; i < func_desc->cParams; i++)
7313             {
7314                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
7315                 TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc;
7316                 VARIANTARG *src_arg;
7317 
7318                 if (wParamFlags & PARAMFLAG_FLCID)
7319                 {
7320                     VARIANTARG *arg;
7321                     arg = prgpvarg[i] = &rgvarg[i];
7322                     V_VT(arg) = VT_I4;
7323                     V_I4(arg) = This->pTypeLib->lcid;
7324                     continue;
7325                 }
7326 
7327                 src_arg = NULL;
7328 
7329                 if (cNamedArgs)
7330                 {
7331                     USHORT j;
7332                     for (j = 0; j < cNamedArgs; j++)
7333                         if (rgdispidNamedArgs[j] == i || (i == func_desc->cParams-1 && rgdispidNamedArgs[j] == DISPID_PROPERTYPUT))
7334                         {
7335                             src_arg = &pDispParams->rgvarg[j];
7336                             break;
7337                         }
7338                 }
7339 
7340                 if (!src_arg && vargs_converted + cNamedArgs < pDispParams->cArgs)
7341                 {
7342                     src_arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted];
7343                     vargs_converted++;
7344                 }
7345 
7346                 if (wParamFlags & PARAMFLAG_FRETVAL)
7347                 {
7348                     /* under most conditions the caller is not allowed to
7349                      * pass in a dispparam arg in the index of what would be
7350                      * the retval parameter. however, there is an exception
7351                      * where the extra parameter is used in an extra
7352                      * IDispatch::Invoke below */
7353                     if ((i < pDispParams->cArgs) &&
7354                         ((func_desc->cParams != 1) || !pVarResult ||
7355                          !(func_desc->invkind & INVOKE_PROPERTYGET)))
7356                     {
7357                         hres = DISP_E_BADPARAMCOUNT;
7358                         break;
7359                     }
7360 
7361                     /* note: this check is placed so that if the caller passes
7362                      * in a VARIANTARG for the retval we just ignore it, like
7363                      * native does */
7364                     if (i == func_desc->cParams - 1)
7365                     {
7366                         VARIANTARG *arg;
7367                         arg = prgpvarg[i] = &rgvarg[i];
7368                         memset(arg, 0, sizeof(*arg));
7369                         V_VT(arg) = rgvt[i];
7370                         memset(&retval, 0, sizeof(retval));
7371                         V_BYREF(arg) = &retval;
7372                     }
7373                     else
7374                     {
7375                         ERR("[retval] parameter must be the last parameter of the method (%d/%d)\n", i, func_desc->cParams);
7376                         hres = E_UNEXPECTED;
7377                         break;
7378                     }
7379                 }
7380                 else if (src_arg && !((wParamFlags & PARAMFLAG_FOPT) &&
7381                          V_VT(src_arg) == VT_ERROR && V_ERROR(src_arg) == DISP_E_PARAMNOTFOUND))
7382                 {
7383                     TRACE("%s\n", debugstr_variant(src_arg));
7384 
7385                     if(rgvt[i]!=V_VT(src_arg))
7386                     {
7387                         if (rgvt[i] == VT_VARIANT)
7388                             hres = VariantCopy(&rgvarg[i], src_arg);
7389                         else if (rgvt[i] == (VT_VARIANT | VT_BYREF))
7390                         {
7391                             if (rgvt[i] == V_VT(src_arg))
7392                                 V_VARIANTREF(&rgvarg[i]) = V_VARIANTREF(src_arg);
7393                             else
7394                             {
7395                                 VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
7396                                 if (wParamFlags & PARAMFLAG_FIN)
7397                                     hres = VariantCopy(&missing_arg[i], src_arg);
7398                                 V_VARIANTREF(&rgvarg[i]) = &missing_arg[i];
7399                             }
7400                             V_VT(&rgvarg[i]) = rgvt[i];
7401                         }
7402                         else if ((rgvt[i] == (VT_VARIANT | VT_ARRAY) || rgvt[i] == (VT_VARIANT | VT_ARRAY | VT_BYREF)) && func_desc->cParamsOpt < 0)
7403                         {
7404                             SAFEARRAY *a;
7405                             SAFEARRAYBOUND bound;
7406                             VARIANT *v;
7407                             LONG j;
7408                             bound.lLbound = 0;
7409                             bound.cElements = pDispParams->cArgs-i;
7410                             if (!(a = SafeArrayCreate(VT_VARIANT, 1, &bound)))
7411                             {
7412                                 ERR("SafeArrayCreate failed\n");
7413                                 break;
7414                             }
7415                             hres = SafeArrayAccessData(a, (LPVOID)&v);
7416                             if (hres != S_OK)
7417                             {
7418                                 ERR("SafeArrayAccessData failed with %x\n", hres);
7419                                 SafeArrayDestroy(a);
7420                                 break;
7421                             }
7422                             for (j = 0; j < bound.cElements; j++)
7423                                 VariantCopy(&v[j], &pDispParams->rgvarg[pDispParams->cArgs - 1 - i - j]);
7424                             hres = SafeArrayUnaccessData(a);
7425                             if (hres != S_OK)
7426                             {
7427                                 ERR("SafeArrayUnaccessData failed with %x\n", hres);
7428                                 SafeArrayDestroy(a);
7429                                 break;
7430                             }
7431                             if (rgvt[i] & VT_BYREF)
7432                                 V_BYREF(&rgvarg[i]) = &a;
7433                             else
7434                                 V_ARRAY(&rgvarg[i]) = a;
7435                             V_VT(&rgvarg[i]) = rgvt[i];
7436                         }
7437                         else if ((rgvt[i] & VT_BYREF) && !V_ISBYREF(src_arg))
7438                         {
7439                             VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
7440                             if (wParamFlags & PARAMFLAG_FIN)
7441                                 hres = VariantChangeType(&missing_arg[i], src_arg, 0, rgvt[i] & ~VT_BYREF);
7442                             else
7443                                 V_VT(&missing_arg[i]) = rgvt[i] & ~VT_BYREF;
7444                             V_BYREF(&rgvarg[i]) = &V_NONE(&missing_arg[i]);
7445                             V_VT(&rgvarg[i]) = rgvt[i];
7446                         }
7447                         else if ((rgvt[i] & VT_BYREF) && (rgvt[i] == V_VT(src_arg)))
7448                         {
7449                             V_BYREF(&rgvarg[i]) = V_BYREF(src_arg);
7450                             V_VT(&rgvarg[i]) = rgvt[i];
7451                         }
7452                         else
7453                         {
7454                             /* FIXME: this doesn't work for VT_BYREF arguments if
7455                              * they are not the same type as in the paramdesc */
7456                             V_VT(&rgvarg[i]) = V_VT(src_arg);
7457                             hres = VariantChangeType(&rgvarg[i], src_arg, 0, rgvt[i]);
7458                             V_VT(&rgvarg[i]) = rgvt[i];
7459                         }
7460 
7461                         if (FAILED(hres))
7462                         {
7463                             ERR("failed to convert param %d to %s from %s\n", i,
7464                                 debugstr_vt(rgvt[i]), debugstr_variant(src_arg));
7465                             break;
7466                         }
7467                         prgpvarg[i] = &rgvarg[i];
7468                     }
7469                     else
7470                     {
7471                         prgpvarg[i] = src_arg;
7472                     }
7473 
7474                     if((tdesc->vt == VT_USERDEFINED || (tdesc->vt == VT_PTR && tdesc->u.lptdesc->vt == VT_USERDEFINED))
7475                        && (V_VT(prgpvarg[i]) == VT_DISPATCH || V_VT(prgpvarg[i]) == VT_UNKNOWN)
7476                        && V_UNKNOWN(prgpvarg[i])) {
7477                         IUnknown *userdefined_iface;
7478                         GUID guid;
7479 
7480                         if (tdesc->vt == VT_PTR)
7481                             tdesc = tdesc->u.lptdesc;
7482 
7483                         hres = get_iface_guid((ITypeInfo*)iface, tdesc->u.hreftype, &guid);
7484                         if(FAILED(hres))
7485                             break;
7486 
7487                         hres = IUnknown_QueryInterface(V_UNKNOWN(prgpvarg[i]), &guid, (void**)&userdefined_iface);
7488                         if(FAILED(hres)) {
7489                             ERR("argument does not support %s interface\n", debugstr_guid(&guid));
7490                             break;
7491                         }
7492 
7493                         IUnknown_Release(V_UNKNOWN(prgpvarg[i]));
7494                         V_UNKNOWN(prgpvarg[i]) = userdefined_iface;
7495                     }
7496                 }
7497                 else if (wParamFlags & PARAMFLAG_FOPT)
7498                 {
7499                     VARIANTARG *arg;
7500                     arg = prgpvarg[i] = &rgvarg[i];
7501                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
7502                     {
7503                         hres = VariantCopy(arg, &func_desc->lprgelemdescParam[i].u.paramdesc.pparamdescex->varDefaultValue);
7504                         if (FAILED(hres))
7505                             break;
7506                     }
7507                     else
7508                     {
7509                         VARIANTARG *missing_arg;
7510                         /* if the function wants a pointer to a variant then
7511                          * set that up, otherwise just pass the VT_ERROR in
7512                          * the argument by value */
7513                         if (rgvt[i] & VT_BYREF)
7514                         {
7515                             missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams) + i;
7516                             V_VT(arg) = VT_VARIANT | VT_BYREF;
7517                             V_VARIANTREF(arg) = missing_arg;
7518                         }
7519                         else
7520                             missing_arg = arg;
7521                         V_VT(missing_arg) = VT_ERROR;
7522                         V_ERROR(missing_arg) = DISP_E_PARAMNOTFOUND;
7523                     }
7524                 }
7525                 else
7526                 {
7527                     hres = DISP_E_BADPARAMCOUNT;
7528                     break;
7529                 }
7530             }
7531             if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
7532 
7533             /* VT_VOID is a special case for return types, so it is not
7534              * handled in the general function */
7535             if (func_desc->elemdescFunc.tdesc.vt == VT_VOID)
7536                 V_VT(&varresult) = VT_EMPTY;
7537             else
7538             {
7539                 V_VT(&varresult) = 0;
7540                 hres = typedescvt_to_variantvt((ITypeInfo *)iface, &func_desc->elemdescFunc.tdesc, &V_VT(&varresult));
7541                 if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
7542             }
7543 
7544             hres = DispCallFunc(pIUnk, func_desc->oVft & 0xFFFC, func_desc->callconv,
7545                                 V_VT(&varresult), func_desc->cParams, rgvt,
7546                                 prgpvarg, &varresult);
7547 
7548             vargs_converted = 0;
7549 
7550             for (i = 0; i < func_desc->cParams; i++)
7551             {
7552                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
7553                 VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
7554 
7555                 if (wParamFlags & PARAMFLAG_FLCID)
7556                     continue;
7557                 else if (wParamFlags & PARAMFLAG_FRETVAL)
7558                 {
7559                     TRACE("[retval] value: %s\n", debugstr_variant(prgpvarg[i]));
7560 
7561                     if (pVarResult)
7562                     {
7563                         VariantInit(pVarResult);
7564                         /* deref return value */
7565                         hres = VariantCopyInd(pVarResult, prgpvarg[i]);
7566                     }
7567 
7568                     VARIANT_ClearInd(prgpvarg[i]);
7569                 }
7570                 else if (vargs_converted < pDispParams->cArgs)
7571                 {
7572                     VARIANTARG *arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted];
7573                     if (wParamFlags & PARAMFLAG_FOUT)
7574                     {
7575                         if ((rgvt[i] & VT_BYREF) && !(V_VT(arg) & VT_BYREF))
7576                         {
7577                             hres = VariantChangeType(arg, &rgvarg[i], 0, V_VT(arg));
7578 
7579                             if (FAILED(hres))
7580                             {
7581                                 ERR("failed to convert param %d to vt %d\n", i,
7582                                     V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted]));
7583                                 break;
7584                             }
7585                         }
7586                     }
7587                     else if (V_VT(prgpvarg[i]) == (VT_VARIANT | VT_ARRAY) &&
7588                              func_desc->cParamsOpt < 0 &&
7589                              i == func_desc->cParams-1)
7590                     {
7591                         SAFEARRAY *a = V_ARRAY(prgpvarg[i]);
7592                         LONG j, ubound;
7593                         VARIANT *v;
7594                         hres = SafeArrayGetUBound(a, 1, &ubound);
7595                         if (hres != S_OK)
7596                         {
7597                             ERR("SafeArrayGetUBound failed with %x\n", hres);
7598                             break;
7599                         }
7600                         hres = SafeArrayAccessData(a, (LPVOID)&v);
7601                         if (hres != S_OK)
7602                         {
7603                             ERR("SafeArrayAccessData failed with %x\n", hres);
7604                             break;
7605                         }
7606                         for (j = 0; j <= ubound; j++)
7607                             VariantClear(&v[j]);
7608                         hres = SafeArrayUnaccessData(a);
7609                         if (hres != S_OK)
7610                         {
7611                             ERR("SafeArrayUnaccessData failed with %x\n", hres);
7612                             break;
7613                         }
7614                     }
7615                     VariantClear(&rgvarg[i]);
7616                     vargs_converted++;
7617                 }
7618                 else if (wParamFlags & PARAMFLAG_FOPT)
7619                 {
7620                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
7621                         VariantClear(&rgvarg[i]);
7622                 }
7623 
7624                 VariantClear(&missing_arg[i]);
7625             }
7626 
7627             if ((V_VT(&varresult) == VT_ERROR) && FAILED(V_ERROR(&varresult)))
7628             {
7629                 WARN("invoked function failed with error 0x%08x\n", V_ERROR(&varresult));
7630                 hres = DISP_E_EXCEPTION;
7631                 if (pExcepInfo)
7632                 {
7633                     IErrorInfo *pErrorInfo;
7634                     pExcepInfo->scode = V_ERROR(&varresult);
7635                     if (GetErrorInfo(0, &pErrorInfo) == S_OK)
7636                     {
7637                         IErrorInfo_GetDescription(pErrorInfo, &pExcepInfo->bstrDescription);
7638                         IErrorInfo_GetHelpFile(pErrorInfo, &pExcepInfo->bstrHelpFile);
7639                         IErrorInfo_GetSource(pErrorInfo, &pExcepInfo->bstrSource);
7640                         IErrorInfo_GetHelpContext(pErrorInfo, &pExcepInfo->dwHelpContext);
7641 
7642                         IErrorInfo_Release(pErrorInfo);
7643                     }
7644                 }
7645             }
7646             if (V_VT(&varresult) != VT_ERROR)
7647             {
7648                 TRACE("varresult value: %s\n", debugstr_variant(&varresult));
7649 
7650                 if (pVarResult)
7651                 {
7652                     VariantClear(pVarResult);
7653                     *pVarResult = varresult;
7654                 }
7655                 else
7656                     VariantClear(&varresult);
7657             }
7658 
7659             if (SUCCEEDED(hres) && pVarResult && (func_desc->cParams == 1) &&
7660                 (func_desc->invkind & INVOKE_PROPERTYGET) &&
7661                 (func_desc->lprgelemdescParam[0].u.paramdesc.wParamFlags & PARAMFLAG_FRETVAL) &&
7662                 (pDispParams->cArgs != 0))
7663             {
7664                 if (V_VT(pVarResult) == VT_DISPATCH)
7665                 {
7666                     IDispatch *pDispatch = V_DISPATCH(pVarResult);
7667                     /* Note: not VariantClear; we still need the dispatch
7668                      * pointer to be valid */
7669                     VariantInit(pVarResult);
7670                     hres = IDispatch_Invoke(pDispatch, DISPID_VALUE, &IID_NULL,
7671                         GetSystemDefaultLCID(), wFlags,
7672                         pDispParams, pVarResult, pExcepInfo, pArgErr);
7673                     IDispatch_Release(pDispatch);
7674                 }
7675                 else
7676                 {
7677                     VariantClear(pVarResult);
7678                     hres = DISP_E_NOTACOLLECTION;
7679                 }
7680             }
7681 
7682 func_fail:
7683             heap_free(buffer);
7684             break;
7685         }
7686 	case FUNC_DISPATCH:  {
7687 	   IDispatch *disp;
7688 
7689 	   hres = IUnknown_QueryInterface((LPUNKNOWN)pIUnk,&IID_IDispatch,(LPVOID*)&disp);
7690 	   if (SUCCEEDED(hres)) {
7691                FIXME("Calling Invoke in IDispatch iface. untested!\n");
7692                hres = IDispatch_Invoke(
7693                                      disp,memid,&IID_NULL,LOCALE_USER_DEFAULT,wFlags,pDispParams,
7694                                      pVarResult,pExcepInfo,pArgErr
7695                                      );
7696                if (FAILED(hres))
7697                    FIXME("IDispatch::Invoke failed with %08x. (Could be not a real error?)\n", hres);
7698                IDispatch_Release(disp);
7699            } else
7700 	       FIXME("FUNC_DISPATCH used on object without IDispatch iface?\n");
7701            break;
7702 	}
7703 	default:
7704             FIXME("Unknown function invocation type %d\n", func_desc->funckind);
7705             hres = E_FAIL;
7706             break;
7707         }
7708 
7709         TRACE("-- 0x%08x\n", hres);
7710         return hres;
7711 
7712     } else if(SUCCEEDED(hres = ITypeInfo2_GetVarIndexOfMemId(iface, memid, &var_index))) {
7713         VARDESC *var_desc;
7714 
7715         hres = ITypeInfo2_GetVarDesc(iface, var_index, &var_desc);
7716         if(FAILED(hres)) return hres;
7717 
7718         FIXME("varseek: Found memid, but variable-based invoking not supported\n");
7719         dump_VARDESC(var_desc);
7720         ITypeInfo2_ReleaseVarDesc(iface, var_desc);
7721         return E_NOTIMPL;
7722     }
7723 
7724     /* not found, look for it in inherited interfaces */
7725     ITypeInfo2_GetTypeKind(iface, &type_kind);
7726     if(type_kind == TKIND_INTERFACE || type_kind == TKIND_DISPATCH) {
7727         if(This->impltypes) {
7728             /* recursive search */
7729             ITypeInfo *pTInfo;
7730             hres = ITypeInfo2_GetRefTypeInfo(iface, This->impltypes[0].hRef, &pTInfo);
7731             if(SUCCEEDED(hres)){
7732                 hres = ITypeInfo_Invoke(pTInfo,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr);
7733                 ITypeInfo_Release(pTInfo);
7734                 return hres;
7735             }
7736             WARN("Could not search inherited interface!\n");
7737         }
7738     }
7739     WARN("did not find member id %d, flags 0x%x!\n", memid, wFlags);
7740     return DISP_E_MEMBERNOTFOUND;
7741 }
7742 
7743 /* ITypeInfo::GetDocumentation
7744  *
7745  * Retrieves the documentation string, the complete Help file name and path,
7746  * and the context ID for the Help topic for a specified type description.
7747  *
7748  * (Can be tested by the Visual Basic Editor in Word for instance.)
7749  */
7750 static HRESULT WINAPI ITypeInfo_fnGetDocumentation( ITypeInfo2 *iface,
7751         MEMBERID memid, BSTR  *pBstrName, BSTR  *pBstrDocString,
7752         DWORD  *pdwHelpContext, BSTR  *pBstrHelpFile)
7753 {
7754     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
7755     const TLBFuncDesc *pFDesc;
7756     const TLBVarDesc *pVDesc;
7757     TRACE("(%p) memid %d Name(%p) DocString(%p)"
7758           " HelpContext(%p) HelpFile(%p)\n",
7759         This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
7760     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
7761         if(pBstrName)
7762             *pBstrName=SysAllocString(TLB_get_bstr(This->Name));
7763         if(pBstrDocString)
7764             *pBstrDocString=SysAllocString(TLB_get_bstr(This->DocString));
7765         if(pdwHelpContext)
7766             *pdwHelpContext=This->dwHelpContext;
7767         if(pBstrHelpFile)
7768             *pBstrHelpFile=SysAllocString(TLB_get_bstr(This->pTypeLib->HelpFile));
7769         return S_OK;
7770     }else {/* for a member */
7771         pFDesc = TLB_get_funcdesc_by_memberid(This->funcdescs, This->typeattr.cFuncs, memid);
7772         if(pFDesc){
7773             if(pBstrName)
7774               *pBstrName = SysAllocString(TLB_get_bstr(pFDesc->Name));
7775             if(pBstrDocString)
7776               *pBstrDocString=SysAllocString(TLB_get_bstr(pFDesc->HelpString));
7777             if(pdwHelpContext)
7778               *pdwHelpContext=pFDesc->helpcontext;
7779             if(pBstrHelpFile)
7780               *pBstrHelpFile = SysAllocString(TLB_get_bstr(This->pTypeLib->HelpFile));
7781             return S_OK;
7782         }
7783         pVDesc = TLB_get_vardesc_by_memberid(This->vardescs, This->typeattr.cVars, memid);
7784         if(pVDesc){
7785             if(pBstrName)
7786               *pBstrName = SysAllocString(TLB_get_bstr(pVDesc->Name));
7787             if(pBstrDocString)
7788               *pBstrDocString=SysAllocString(TLB_get_bstr(pVDesc->HelpString));
7789             if(pdwHelpContext)
7790               *pdwHelpContext=pVDesc->HelpContext;
7791             if(pBstrHelpFile)
7792               *pBstrHelpFile = SysAllocString(TLB_get_bstr(This->pTypeLib->HelpFile));
7793             return S_OK;
7794         }
7795     }
7796 
7797     if(This->impltypes &&
7798        (This->typeattr.typekind == TKIND_INTERFACE || This->typeattr.typekind == TKIND_DISPATCH)) {
7799         /* recursive search */
7800         ITypeInfo *pTInfo;
7801         HRESULT result;
7802         result = ITypeInfo2_GetRefTypeInfo(iface, This->impltypes[0].hRef, &pTInfo);
7803         if(SUCCEEDED(result)) {
7804             result = ITypeInfo_GetDocumentation(pTInfo, memid, pBstrName,
7805                 pBstrDocString, pdwHelpContext, pBstrHelpFile);
7806             ITypeInfo_Release(pTInfo);
7807             return result;
7808         }
7809         WARN("Could not search inherited interface!\n");
7810     }
7811 
7812     WARN("member %d not found\n", memid);
7813     return TYPE_E_ELEMENTNOTFOUND;
7814 }
7815 
7816 /*  ITypeInfo::GetDllEntry
7817  *
7818  * Retrieves a description or specification of an entry point for a function
7819  * in a DLL.
7820  */
7821 static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid,
7822         INVOKEKIND invKind, BSTR  *pBstrDllName, BSTR  *pBstrName,
7823         WORD  *pwOrdinal)
7824 {
7825     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
7826     const TLBFuncDesc *pFDesc;
7827 
7828     TRACE("(%p)->(memid %x, %d, %p, %p, %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
7829 
7830     if (pBstrDllName) *pBstrDllName = NULL;
7831     if (pBstrName) *pBstrName = NULL;
7832     if (pwOrdinal) *pwOrdinal = 0;
7833 
7834     if (This->typeattr.typekind != TKIND_MODULE)
7835         return TYPE_E_BADMODULEKIND;
7836 
7837     pFDesc = TLB_get_funcdesc_by_memberid(This->funcdescs, This->typeattr.cFuncs, memid);
7838     if(pFDesc){
7839 	    dump_TypeInfo(This);
7840 	    if (TRACE_ON(ole))
7841 		dump_TLBFuncDescOne(pFDesc);
7842 
7843 	    if (pBstrDllName)
7844 		*pBstrDllName = SysAllocString(TLB_get_bstr(This->DllName));
7845 
7846             if (!IS_INTRESOURCE(pFDesc->Entry) && (pFDesc->Entry != (void*)-1)) {
7847 		if (pBstrName)
7848 		    *pBstrName = SysAllocString(TLB_get_bstr(pFDesc->Entry));
7849 		if (pwOrdinal)
7850 		    *pwOrdinal = -1;
7851 		return S_OK;
7852 	    }
7853 	    if (pBstrName)
7854 		*pBstrName = NULL;
7855 	    if (pwOrdinal)
7856 		*pwOrdinal = LOWORD(pFDesc->Entry);
7857 	    return S_OK;
7858         }
7859     return TYPE_E_ELEMENTNOTFOUND;
7860 }
7861 
7862 /* internal function to make the inherited interfaces' methods appear
7863  * part of the interface */
7864 static HRESULT ITypeInfoImpl_GetDispatchRefTypeInfo( ITypeInfo *iface,
7865     HREFTYPE *hRefType, ITypeInfo  **ppTInfo)
7866 {
7867     ITypeInfoImpl *This = impl_from_ITypeInfo(iface);
7868     HRESULT hr;
7869 
7870     TRACE("%p, 0x%x\n", iface, *hRefType);
7871 
7872     if (This->impltypes && (*hRefType & DISPATCH_HREF_MASK))
7873     {
7874         ITypeInfo *pSubTypeInfo;
7875 
7876         hr = ITypeInfo_GetRefTypeInfo(iface, This->impltypes[0].hRef, &pSubTypeInfo);
7877         if (FAILED(hr))
7878             return hr;
7879 
7880         hr = ITypeInfoImpl_GetDispatchRefTypeInfo(pSubTypeInfo,
7881                                                   hRefType, ppTInfo);
7882         ITypeInfo_Release(pSubTypeInfo);
7883         if (SUCCEEDED(hr))
7884             return hr;
7885     }
7886     *hRefType -= DISPATCH_HREF_OFFSET;
7887 
7888     if (!(*hRefType & DISPATCH_HREF_MASK))
7889         return ITypeInfo_GetRefTypeInfo(iface, *hRefType, ppTInfo);
7890     else
7891         return E_FAIL;
7892 }
7893 
7894 struct search_res_tlb_params
7895 {
7896     const GUID *guid;
7897     ITypeLib *pTLib;
7898 };
7899 
7900 static BOOL CALLBACK search_res_tlb(HMODULE hModule, LPCWSTR lpszType, LPWSTR lpszName, LONG_PTR lParam)
7901 {
7902     struct search_res_tlb_params *params = (LPVOID)lParam;
7903     static const WCHAR formatW[] = {'\\','%','d',0};
7904     WCHAR szPath[MAX_PATH+1];
7905     ITypeLib *pTLib = NULL;
7906     HRESULT ret;
7907     DWORD len;
7908 
7909     if (IS_INTRESOURCE(lpszName) == FALSE)
7910         return TRUE;
7911 
7912     if (!(len = GetModuleFileNameW(hModule, szPath, MAX_PATH)))
7913         return TRUE;
7914 
7915     if (snprintfW(szPath + len, sizeof(szPath)/sizeof(WCHAR) - len, formatW, LOWORD(lpszName)) < 0)
7916         return TRUE;
7917 
7918     ret = LoadTypeLibEx(szPath, REGKIND_NONE, &pTLib);
7919     if (SUCCEEDED(ret))
7920     {
7921         ITypeLibImpl *impl = impl_from_ITypeLib(pTLib);
7922         if (IsEqualGUID(params->guid, impl->guid))
7923         {
7924             params->pTLib = pTLib;
7925             return FALSE; /* stop enumeration */
7926         }
7927         ITypeLib_Release(pTLib);
7928     }
7929 
7930     return TRUE;
7931 }
7932 
7933 /* ITypeInfo::GetRefTypeInfo
7934  *
7935  * If a type description references other type descriptions, it retrieves
7936  * the referenced type descriptions.
7937  */
7938 static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo(
7939 	ITypeInfo2 *iface,
7940         HREFTYPE hRefType,
7941 	ITypeInfo  **ppTInfo)
7942 {
7943     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
7944     HRESULT result = E_FAIL;
7945 
7946     if(!ppTInfo)
7947         return E_INVALIDARG;
7948 
7949     if ((INT)hRefType < 0) {
7950         ITypeInfoImpl *pTypeInfoImpl;
7951 
7952         if (!(This->typeattr.wTypeFlags & TYPEFLAG_FDUAL) ||
7953                 !(This->typeattr.typekind == TKIND_INTERFACE ||
7954                     This->typeattr.typekind == TKIND_DISPATCH))
7955             return TYPE_E_ELEMENTNOTFOUND;
7956 
7957         /* when we meet a DUAL typeinfo, we must create the alternate
7958         * version of it.
7959         */
7960         pTypeInfoImpl = ITypeInfoImpl_Constructor();
7961 
7962         *pTypeInfoImpl = *This;
7963         pTypeInfoImpl->ref = 0;
7964         list_init(&pTypeInfoImpl->custdata_list);
7965 
7966         if (This->typeattr.typekind == TKIND_INTERFACE)
7967             pTypeInfoImpl->typeattr.typekind = TKIND_DISPATCH;
7968         else
7969             pTypeInfoImpl->typeattr.typekind = TKIND_INTERFACE;
7970 
7971         *ppTInfo = (ITypeInfo *)&pTypeInfoImpl->ITypeInfo2_iface;
7972         /* the AddRef implicitly adds a reference to the parent typelib, which
7973          * stops the copied data from being destroyed until the new typeinfo's
7974          * refcount goes to zero, but we need to signal to the new instance to
7975          * not free its data structures when it is destroyed */
7976         pTypeInfoImpl->not_attached_to_typelib = TRUE;
7977 
7978         ITypeInfo_AddRef(*ppTInfo);
7979 
7980         result = S_OK;
7981     } else if ((hRefType & DISPATCH_HREF_MASK) &&
7982         (This->typeattr.typekind == TKIND_DISPATCH))
7983     {
7984         HREFTYPE href_dispatch = hRefType;
7985         result = ITypeInfoImpl_GetDispatchRefTypeInfo((ITypeInfo *)iface, &href_dispatch, ppTInfo);
7986     } else {
7987         TLBRefType *ref_type;
7988         ITypeLib *pTLib = NULL;
7989         UINT i;
7990 
7991         if(!(hRefType & 0x1)){
7992             for(i = 0; i < This->pTypeLib->TypeInfoCount; ++i)
7993             {
7994                 if (This->pTypeLib->typeinfos[i]->hreftype == (hRefType&(~0x3)))
7995                 {
7996                     result = S_OK;
7997                     *ppTInfo = (ITypeInfo*)&This->pTypeLib->typeinfos[i]->ITypeInfo2_iface;
7998                     ITypeInfo_AddRef(*ppTInfo);
7999                     goto end;
8000                 }
8001             }
8002         }
8003 
8004         LIST_FOR_EACH_ENTRY(ref_type, &This->pTypeLib->ref_list, TLBRefType, entry)
8005         {
8006             if(ref_type->reference == (hRefType & (~0x3)))
8007                 break;
8008         }
8009         if(&ref_type->entry == &This->pTypeLib->ref_list)
8010         {
8011             FIXME("Can't find pRefType for ref %x\n", hRefType);
8012             goto end;
8013         }
8014 
8015         if(ref_type->pImpTLInfo == TLB_REF_INTERNAL) {
8016             UINT Index;
8017             TRACE("internal reference\n");
8018             result = ITypeInfo2_GetContainingTypeLib(iface, &pTLib, &Index);
8019         } else {
8020             if(ref_type->pImpTLInfo->pImpTypeLib) {
8021                 TRACE("typeinfo in imported typelib that is already loaded\n");
8022                 pTLib = (ITypeLib*)&ref_type->pImpTLInfo->pImpTypeLib->ITypeLib2_iface;
8023                 ITypeLib_AddRef(pTLib);
8024                 result = S_OK;
8025             } else {
8026                 static const WCHAR TYPELIBW[] = {'T','Y','P','E','L','I','B',0};
8027                 struct search_res_tlb_params params;
8028                 BSTR libnam;
8029 
8030                 TRACE("typeinfo in imported typelib that isn't already loaded\n");
8031 
8032                 /* Search in resource table */
8033                 params.guid  = TLB_get_guid_null(ref_type->pImpTLInfo->guid);
8034                 params.pTLib = NULL;
8035                 EnumResourceNamesW(NULL, TYPELIBW, search_res_tlb, (LONG_PTR)&params);
8036                 pTLib  = params.pTLib;
8037                 result = S_OK;
8038 
8039                 if (!pTLib)
8040                 {
8041                     /* Search on disk */
8042                     result = query_typelib_path(TLB_get_guid_null(ref_type->pImpTLInfo->guid),
8043                             ref_type->pImpTLInfo->wVersionMajor,
8044                             ref_type->pImpTLInfo->wVersionMinor,
8045                             This->pTypeLib->syskind,
8046                             ref_type->pImpTLInfo->lcid, &libnam, TRUE);
8047                     if (FAILED(result))
8048                         libnam = SysAllocString(ref_type->pImpTLInfo->name);
8049 
8050                     result = LoadTypeLib(libnam, &pTLib);
8051                     SysFreeString(libnam);
8052                 }
8053 
8054                 if(SUCCEEDED(result)) {
8055                     ref_type->pImpTLInfo->pImpTypeLib = impl_from_ITypeLib(pTLib);
8056                     ITypeLib_AddRef(pTLib);
8057                 }
8058             }
8059         }
8060         if(SUCCEEDED(result)) {
8061             if(ref_type->index == TLB_REF_USE_GUID)
8062                 result = ITypeLib_GetTypeInfoOfGuid(pTLib, TLB_get_guid_null(ref_type->guid), ppTInfo);
8063             else
8064                 result = ITypeLib_GetTypeInfo(pTLib, ref_type->index, ppTInfo);
8065         }
8066         if (pTLib != NULL)
8067             ITypeLib_Release(pTLib);
8068     }
8069 
8070 end:
8071     TRACE("(%p) hreftype 0x%04x loaded %s (%p)\n", This, hRefType,
8072           SUCCEEDED(result)? "SUCCESS":"FAILURE", *ppTInfo);
8073     return result;
8074 }
8075 
8076 /* ITypeInfo::AddressOfMember
8077  *
8078  * Retrieves the addresses of static functions or variables, such as those
8079  * defined in a DLL.
8080  */
8081 static HRESULT WINAPI ITypeInfo_fnAddressOfMember( ITypeInfo2 *iface,
8082         MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
8083 {
8084     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8085     HRESULT hr;
8086     BSTR dll, entry;
8087     WORD ordinal;
8088     HMODULE module;
8089 
8090     TRACE("(%p)->(0x%x, 0x%x, %p)\n", This, memid, invKind, ppv);
8091 
8092     hr = ITypeInfo2_GetDllEntry(iface, memid, invKind, &dll, &entry, &ordinal);
8093     if (FAILED(hr))
8094         return hr;
8095 
8096     module = LoadLibraryW(dll);
8097     if (!module)
8098     {
8099         ERR("couldn't load %s\n", debugstr_w(dll));
8100         SysFreeString(dll);
8101         SysFreeString(entry);
8102         return STG_E_FILENOTFOUND;
8103     }
8104     /* FIXME: store library somewhere where we can free it */
8105 
8106     if (entry)
8107     {
8108         LPSTR entryA;
8109         INT len = WideCharToMultiByte(CP_ACP, 0, entry, -1, NULL, 0, NULL, NULL);
8110         entryA = heap_alloc(len);
8111         WideCharToMultiByte(CP_ACP, 0, entry, -1, entryA, len, NULL, NULL);
8112 
8113         *ppv = GetProcAddress(module, entryA);
8114         if (!*ppv)
8115             ERR("function not found %s\n", debugstr_a(entryA));
8116 
8117         heap_free(entryA);
8118     }
8119     else
8120     {
8121         *ppv = GetProcAddress(module, MAKEINTRESOURCEA(ordinal));
8122         if (!*ppv)
8123             ERR("function not found %d\n", ordinal);
8124     }
8125 
8126     SysFreeString(dll);
8127     SysFreeString(entry);
8128 
8129     if (!*ppv)
8130         return TYPE_E_DLLFUNCTIONNOTFOUND;
8131 
8132     return S_OK;
8133 }
8134 
8135 /* ITypeInfo::CreateInstance
8136  *
8137  * Creates a new instance of a type that describes a component object class
8138  * (coclass).
8139  */
8140 static HRESULT WINAPI ITypeInfo_fnCreateInstance( ITypeInfo2 *iface,
8141         IUnknown *pOuterUnk, REFIID riid, VOID  **ppvObj)
8142 {
8143     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8144     HRESULT hr;
8145     TYPEATTR *pTA;
8146 
8147     TRACE("(%p)->(%p, %s, %p)\n", This, pOuterUnk, debugstr_guid(riid), ppvObj);
8148 
8149     *ppvObj = NULL;
8150 
8151     if(pOuterUnk)
8152     {
8153         WARN("Not able to aggregate\n");
8154         return CLASS_E_NOAGGREGATION;
8155     }
8156 
8157     hr = ITypeInfo2_GetTypeAttr(iface, &pTA);
8158     if(FAILED(hr)) return hr;
8159 
8160     if(pTA->typekind != TKIND_COCLASS)
8161     {
8162         WARN("CreateInstance on typeinfo of type %x\n", pTA->typekind);
8163         hr = E_INVALIDARG;
8164         goto end;
8165     }
8166 
8167     hr = S_FALSE;
8168     if(pTA->wTypeFlags & TYPEFLAG_FAPPOBJECT)
8169     {
8170         IUnknown *pUnk;
8171         hr = GetActiveObject(&pTA->guid, NULL, &pUnk);
8172         TRACE("GetActiveObject rets %08x\n", hr);
8173         if(hr == S_OK)
8174         {
8175             hr = IUnknown_QueryInterface(pUnk, riid, ppvObj);
8176             IUnknown_Release(pUnk);
8177         }
8178     }
8179 
8180     if(hr != S_OK)
8181         hr = CoCreateInstance(&pTA->guid, NULL,
8182                               CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
8183                               riid, ppvObj);
8184 
8185 end:
8186     ITypeInfo2_ReleaseTypeAttr(iface, pTA);
8187     return hr;
8188 }
8189 
8190 /* ITypeInfo::GetMops
8191  *
8192  * Retrieves marshalling information.
8193  */
8194 static HRESULT WINAPI ITypeInfo_fnGetMops( ITypeInfo2 *iface, MEMBERID memid,
8195 				BSTR  *pBstrMops)
8196 {
8197     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8198     FIXME("(%p %d) stub!\n", This, memid);
8199     *pBstrMops = NULL;
8200     return S_OK;
8201 }
8202 
8203 /* ITypeInfo::GetContainingTypeLib
8204  *
8205  * Retrieves the containing type library and the index of the type description
8206  * within that type library.
8207  */
8208 static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( ITypeInfo2 *iface,
8209         ITypeLib  * *ppTLib, UINT  *pIndex)
8210 {
8211     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8212 
8213     /* If a pointer is null, we simply ignore it, the ATL in particular passes pIndex as 0 */
8214     if (pIndex) {
8215       *pIndex=This->index;
8216       TRACE("returning pIndex=%d\n", *pIndex);
8217     }
8218 
8219     if (ppTLib) {
8220       *ppTLib = (ITypeLib *)&This->pTypeLib->ITypeLib2_iface;
8221       ITypeLib_AddRef(*ppTLib);
8222       TRACE("returning ppTLib=%p\n", *ppTLib);
8223     }
8224 
8225     return S_OK;
8226 }
8227 
8228 /* ITypeInfo::ReleaseTypeAttr
8229  *
8230  * Releases a TYPEATTR previously returned by Get
8231  *
8232  */
8233 static void WINAPI ITypeInfo_fnReleaseTypeAttr( ITypeInfo2 *iface,
8234         TYPEATTR* pTypeAttr)
8235 {
8236     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8237     TRACE("(%p)->(%p)\n", This, pTypeAttr);
8238     heap_free(pTypeAttr);
8239 }
8240 
8241 /* ITypeInfo::ReleaseFuncDesc
8242  *
8243  * Releases a FUNCDESC previously returned by GetFuncDesc. *
8244  */
8245 static void WINAPI ITypeInfo_fnReleaseFuncDesc(
8246 	ITypeInfo2 *iface,
8247         FUNCDESC *pFuncDesc)
8248 {
8249     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8250     SHORT i;
8251 
8252     TRACE("(%p)->(%p)\n", This, pFuncDesc);
8253 
8254     for (i = 0; i < pFuncDesc->cParams; i++)
8255         TLB_FreeElemDesc(&pFuncDesc->lprgelemdescParam[i]);
8256     TLB_FreeElemDesc(&pFuncDesc->elemdescFunc);
8257 
8258     SysFreeString((BSTR)pFuncDesc);
8259 }
8260 
8261 /* ITypeInfo::ReleaseVarDesc
8262  *
8263  * Releases a VARDESC previously returned by GetVarDesc.
8264  */
8265 static void WINAPI ITypeInfo_fnReleaseVarDesc( ITypeInfo2 *iface,
8266         VARDESC *pVarDesc)
8267 {
8268     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8269     TRACE("(%p)->(%p)\n", This, pVarDesc);
8270 
8271     TLB_FreeVarDesc(pVarDesc);
8272 }
8273 
8274 /* ITypeInfo2::GetTypeKind
8275  *
8276  * Returns the TYPEKIND enumeration quickly, without doing any allocations.
8277  *
8278  */
8279 static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo2 * iface,
8280     TYPEKIND *pTypeKind)
8281 {
8282     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8283     *pTypeKind = This->typeattr.typekind;
8284     TRACE("(%p) type 0x%0x\n", This,*pTypeKind);
8285     return S_OK;
8286 }
8287 
8288 /* ITypeInfo2::GetTypeFlags
8289  *
8290  * Returns the type flags without any allocations. This returns a DWORD type
8291  * flag, which expands the type flags without growing the TYPEATTR (type
8292  * attribute).
8293  *
8294  */
8295 static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo2 *iface, ULONG *pTypeFlags)
8296 {
8297     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8298     *pTypeFlags=This->typeattr.wTypeFlags;
8299     TRACE("(%p) flags 0x%x\n", This,*pTypeFlags);
8300     return S_OK;
8301 }
8302 
8303 /* ITypeInfo2::GetFuncIndexOfMemId
8304  * Binds to a specific member based on a known DISPID, where the member name
8305  * is not known (for example, when binding to a default member).
8306  *
8307  */
8308 static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo2 * iface,
8309     MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex)
8310 {
8311     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8312     UINT fdc;
8313     HRESULT result;
8314 
8315     for (fdc = 0; fdc < This->typeattr.cFuncs; ++fdc){
8316         const TLBFuncDesc *pFuncInfo = &This->funcdescs[fdc];
8317         if(memid == pFuncInfo->funcdesc.memid && (invKind & pFuncInfo->funcdesc.invkind))
8318             break;
8319     }
8320     if(fdc < This->typeattr.cFuncs) {
8321         *pFuncIndex = fdc;
8322         result = S_OK;
8323     } else
8324         result = TYPE_E_ELEMENTNOTFOUND;
8325 
8326     TRACE("(%p) memid 0x%08x invKind 0x%04x -> %s\n", This,
8327           memid, invKind, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
8328     return result;
8329 }
8330 
8331 /* TypeInfo2::GetVarIndexOfMemId
8332  *
8333  * Binds to a specific member based on a known DISPID, where the member name
8334  * is not known (for example, when binding to a default member).
8335  *
8336  */
8337 static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( ITypeInfo2 * iface,
8338     MEMBERID memid, UINT *pVarIndex)
8339 {
8340     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8341     TLBVarDesc *pVarInfo;
8342 
8343     TRACE("%p %d %p\n", iface, memid, pVarIndex);
8344 
8345     pVarInfo = TLB_get_vardesc_by_memberid(This->vardescs, This->typeattr.cVars, memid);
8346     if(!pVarInfo)
8347         return TYPE_E_ELEMENTNOTFOUND;
8348 
8349     *pVarIndex = (pVarInfo - This->vardescs);
8350 
8351     return S_OK;
8352 }
8353 
8354 /* ITypeInfo2::GetCustData
8355  *
8356  * Gets the custom data
8357  */
8358 static HRESULT WINAPI ITypeInfo2_fnGetCustData(
8359 	ITypeInfo2 * iface,
8360 	REFGUID guid,
8361 	VARIANT *pVarVal)
8362 {
8363     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8364     TLBCustData *pCData;
8365 
8366     TRACE("%p %s %p\n", This, debugstr_guid(guid), pVarVal);
8367 
8368     if(!guid || !pVarVal)
8369         return E_INVALIDARG;
8370 
8371     pCData = TLB_get_custdata_by_guid(This->pcustdata_list, guid);
8372 
8373     VariantInit( pVarVal);
8374     if (pCData)
8375         VariantCopy( pVarVal, &pCData->data);
8376     else
8377         VariantClear( pVarVal );
8378     return S_OK;
8379 }
8380 
8381 /* ITypeInfo2::GetFuncCustData
8382  *
8383  * Gets the custom data
8384  */
8385 static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData(
8386 	ITypeInfo2 * iface,
8387 	UINT index,
8388 	REFGUID guid,
8389 	VARIANT *pVarVal)
8390 {
8391     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8392     TLBCustData *pCData;
8393     TLBFuncDesc *pFDesc = &This->funcdescs[index];
8394 
8395     TRACE("%p %u %s %p\n", This, index, debugstr_guid(guid), pVarVal);
8396 
8397     if(index >= This->typeattr.cFuncs)
8398         return TYPE_E_ELEMENTNOTFOUND;
8399 
8400     pCData = TLB_get_custdata_by_guid(&pFDesc->custdata_list, guid);
8401     if(!pCData)
8402         return TYPE_E_ELEMENTNOTFOUND;
8403 
8404     VariantInit(pVarVal);
8405     VariantCopy(pVarVal, &pCData->data);
8406 
8407     return S_OK;
8408 }
8409 
8410 /* ITypeInfo2::GetParamCustData
8411  *
8412  * Gets the custom data
8413  */
8414 static HRESULT WINAPI ITypeInfo2_fnGetParamCustData(
8415 	ITypeInfo2 * iface,
8416 	UINT indexFunc,
8417 	UINT indexParam,
8418 	REFGUID guid,
8419 	VARIANT *pVarVal)
8420 {
8421     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8422     TLBCustData *pCData;
8423     TLBFuncDesc *pFDesc = &This->funcdescs[indexFunc];
8424 
8425     TRACE("%p %u %u %s %p\n", This, indexFunc, indexParam,
8426             debugstr_guid(guid), pVarVal);
8427 
8428     if(indexFunc >= This->typeattr.cFuncs)
8429         return TYPE_E_ELEMENTNOTFOUND;
8430 
8431     if(indexParam >= pFDesc->funcdesc.cParams)
8432         return TYPE_E_ELEMENTNOTFOUND;
8433 
8434     pCData = TLB_get_custdata_by_guid(&pFDesc->pParamDesc[indexParam].custdata_list, guid);
8435     if(!pCData)
8436         return TYPE_E_ELEMENTNOTFOUND;
8437 
8438     VariantInit(pVarVal);
8439     VariantCopy(pVarVal, &pCData->data);
8440 
8441     return S_OK;
8442 }
8443 
8444 /* ITypeInfo2::GetVarCustData
8445  *
8446  * Gets the custom data
8447  */
8448 static HRESULT WINAPI ITypeInfo2_fnGetVarCustData(
8449 	ITypeInfo2 * iface,
8450 	UINT index,
8451 	REFGUID guid,
8452 	VARIANT *pVarVal)
8453 {
8454     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8455     TLBCustData *pCData;
8456     TLBVarDesc *pVDesc = &This->vardescs[index];
8457 
8458     TRACE("%p %s %p\n", This, debugstr_guid(guid), pVarVal);
8459 
8460     if(index >= This->typeattr.cVars)
8461         return TYPE_E_ELEMENTNOTFOUND;
8462 
8463     pCData = TLB_get_custdata_by_guid(&pVDesc->custdata_list, guid);
8464     if(!pCData)
8465         return TYPE_E_ELEMENTNOTFOUND;
8466 
8467     VariantInit(pVarVal);
8468     VariantCopy(pVarVal, &pCData->data);
8469 
8470     return S_OK;
8471 }
8472 
8473 /* ITypeInfo2::GetImplCustData
8474  *
8475  * Gets the custom data
8476  */
8477 static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData(
8478 	ITypeInfo2 * iface,
8479 	UINT index,
8480 	REFGUID guid,
8481 	VARIANT *pVarVal)
8482 {
8483     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8484     TLBCustData *pCData;
8485     TLBImplType *pRDesc = &This->impltypes[index];
8486 
8487     TRACE("%p %u %s %p\n", This, index, debugstr_guid(guid), pVarVal);
8488 
8489     if(index >= This->typeattr.cImplTypes)
8490         return TYPE_E_ELEMENTNOTFOUND;
8491 
8492     pCData = TLB_get_custdata_by_guid(&pRDesc->custdata_list, guid);
8493     if(!pCData)
8494         return TYPE_E_ELEMENTNOTFOUND;
8495 
8496     VariantInit(pVarVal);
8497     VariantCopy(pVarVal, &pCData->data);
8498 
8499     return S_OK;
8500 }
8501 
8502 /* ITypeInfo2::GetDocumentation2
8503  *
8504  * Retrieves the documentation string, the complete Help file name and path,
8505  * the localization context to use, and the context ID for the library Help
8506  * topic in the Help file.
8507  *
8508  */
8509 static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2(
8510 	ITypeInfo2 * iface,
8511 	MEMBERID memid,
8512 	LCID lcid,
8513 	BSTR *pbstrHelpString,
8514 	DWORD *pdwHelpStringContext,
8515 	BSTR *pbstrHelpStringDll)
8516 {
8517     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8518     const TLBFuncDesc *pFDesc;
8519     const TLBVarDesc *pVDesc;
8520     TRACE("(%p) memid %d lcid(0x%x)  HelpString(%p) "
8521           "HelpStringContext(%p) HelpStringDll(%p)\n",
8522           This, memid, lcid, pbstrHelpString, pdwHelpStringContext,
8523           pbstrHelpStringDll );
8524     /* the help string should be obtained from the helpstringdll,
8525      * using the _DLLGetDocumentation function, based on the supplied
8526      * lcid. Nice to do sometime...
8527      */
8528     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
8529         if(pbstrHelpString)
8530             *pbstrHelpString=SysAllocString(TLB_get_bstr(This->Name));
8531         if(pdwHelpStringContext)
8532             *pdwHelpStringContext=This->dwHelpStringContext;
8533         if(pbstrHelpStringDll)
8534             *pbstrHelpStringDll=
8535                 SysAllocString(TLB_get_bstr(This->pTypeLib->HelpStringDll));/* FIXME */
8536         return S_OK;
8537     }else {/* for a member */
8538         pFDesc = TLB_get_funcdesc_by_memberid(This->funcdescs, This->typeattr.cFuncs, memid);
8539         if(pFDesc){
8540             if(pbstrHelpString)
8541                 *pbstrHelpString=SysAllocString(TLB_get_bstr(pFDesc->HelpString));
8542             if(pdwHelpStringContext)
8543                 *pdwHelpStringContext=pFDesc->HelpStringContext;
8544             if(pbstrHelpStringDll)
8545                 *pbstrHelpStringDll=
8546                     SysAllocString(TLB_get_bstr(This->pTypeLib->HelpStringDll));/* FIXME */
8547             return S_OK;
8548         }
8549         pVDesc = TLB_get_vardesc_by_memberid(This->vardescs, This->typeattr.cVars, memid);
8550         if(pVDesc){
8551             if(pbstrHelpString)
8552                 *pbstrHelpString=SysAllocString(TLB_get_bstr(pVDesc->HelpString));
8553             if(pdwHelpStringContext)
8554                 *pdwHelpStringContext=pVDesc->HelpStringContext;
8555             if(pbstrHelpStringDll)
8556                 *pbstrHelpStringDll=
8557                     SysAllocString(TLB_get_bstr(This->pTypeLib->HelpStringDll));/* FIXME */
8558             return S_OK;
8559         }
8560     }
8561     return TYPE_E_ELEMENTNOTFOUND;
8562 }
8563 
8564 /* ITypeInfo2::GetAllCustData
8565  *
8566  * Gets all custom data items for the Type info.
8567  *
8568  */
8569 static HRESULT WINAPI ITypeInfo2_fnGetAllCustData(
8570 	ITypeInfo2 * iface,
8571 	CUSTDATA *pCustData)
8572 {
8573     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8574 
8575     TRACE("%p %p\n", This, pCustData);
8576 
8577     return TLB_copy_all_custdata(This->pcustdata_list, pCustData);
8578 }
8579 
8580 /* ITypeInfo2::GetAllFuncCustData
8581  *
8582  * Gets all custom data items for the specified Function
8583  *
8584  */
8585 static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData(
8586 	ITypeInfo2 * iface,
8587 	UINT index,
8588 	CUSTDATA *pCustData)
8589 {
8590     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8591     TLBFuncDesc *pFDesc = &This->funcdescs[index];
8592 
8593     TRACE("%p %u %p\n", This, index, pCustData);
8594 
8595     if(index >= This->typeattr.cFuncs)
8596         return TYPE_E_ELEMENTNOTFOUND;
8597 
8598     return TLB_copy_all_custdata(&pFDesc->custdata_list, pCustData);
8599 }
8600 
8601 /* ITypeInfo2::GetAllParamCustData
8602  *
8603  * Gets all custom data items for the Functions
8604  *
8605  */
8606 static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo2 * iface,
8607     UINT indexFunc, UINT indexParam, CUSTDATA *pCustData)
8608 {
8609     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8610     TLBFuncDesc *pFDesc = &This->funcdescs[indexFunc];
8611 
8612     TRACE("%p %u %u %p\n", This, indexFunc, indexParam, pCustData);
8613 
8614     if(indexFunc >= This->typeattr.cFuncs)
8615         return TYPE_E_ELEMENTNOTFOUND;
8616 
8617     if(indexParam >= pFDesc->funcdesc.cParams)
8618         return TYPE_E_ELEMENTNOTFOUND;
8619 
8620     return TLB_copy_all_custdata(&pFDesc->pParamDesc[indexParam].custdata_list, pCustData);
8621 }
8622 
8623 /* ITypeInfo2::GetAllVarCustData
8624  *
8625  * Gets all custom data items for the specified Variable
8626  *
8627  */
8628 static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo2 * iface,
8629     UINT index, CUSTDATA *pCustData)
8630 {
8631     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8632     TLBVarDesc * pVDesc = &This->vardescs[index];
8633 
8634     TRACE("%p %u %p\n", This, index, pCustData);
8635 
8636     if(index >= This->typeattr.cVars)
8637         return TYPE_E_ELEMENTNOTFOUND;
8638 
8639     return TLB_copy_all_custdata(&pVDesc->custdata_list, pCustData);
8640 }
8641 
8642 /* ITypeInfo2::GetAllImplCustData
8643  *
8644  * Gets all custom data items for the specified implementation type
8645  *
8646  */
8647 static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData(
8648 	ITypeInfo2 * iface,
8649 	UINT index,
8650 	CUSTDATA *pCustData)
8651 {
8652     ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
8653     TLBImplType *pRDesc = &This->impltypes[index];
8654 
8655     TRACE("%p %u %p\n", This, index, pCustData);
8656 
8657     if(index >= This->typeattr.cImplTypes)
8658         return TYPE_E_ELEMENTNOTFOUND;
8659 
8660     return TLB_copy_all_custdata(&pRDesc->custdata_list, pCustData);
8661 }
8662 
8663 static const ITypeInfo2Vtbl tinfvt =
8664 {
8665 
8666     ITypeInfo_fnQueryInterface,
8667     ITypeInfo_fnAddRef,
8668     ITypeInfo_fnRelease,
8669 
8670     ITypeInfo_fnGetTypeAttr,
8671     ITypeInfo_fnGetTypeComp,
8672     ITypeInfo_fnGetFuncDesc,
8673     ITypeInfo_fnGetVarDesc,
8674     ITypeInfo_fnGetNames,
8675     ITypeInfo_fnGetRefTypeOfImplType,
8676     ITypeInfo_fnGetImplTypeFlags,
8677     ITypeInfo_fnGetIDsOfNames,
8678     ITypeInfo_fnInvoke,
8679     ITypeInfo_fnGetDocumentation,
8680     ITypeInfo_fnGetDllEntry,
8681     ITypeInfo_fnGetRefTypeInfo,
8682     ITypeInfo_fnAddressOfMember,
8683     ITypeInfo_fnCreateInstance,
8684     ITypeInfo_fnGetMops,
8685     ITypeInfo_fnGetContainingTypeLib,
8686     ITypeInfo_fnReleaseTypeAttr,
8687     ITypeInfo_fnReleaseFuncDesc,
8688     ITypeInfo_fnReleaseVarDesc,
8689 
8690     ITypeInfo2_fnGetTypeKind,
8691     ITypeInfo2_fnGetTypeFlags,
8692     ITypeInfo2_fnGetFuncIndexOfMemId,
8693     ITypeInfo2_fnGetVarIndexOfMemId,
8694     ITypeInfo2_fnGetCustData,
8695     ITypeInfo2_fnGetFuncCustData,
8696     ITypeInfo2_fnGetParamCustData,
8697     ITypeInfo2_fnGetVarCustData,
8698     ITypeInfo2_fnGetImplTypeCustData,
8699     ITypeInfo2_fnGetDocumentation2,
8700     ITypeInfo2_fnGetAllCustData,
8701     ITypeInfo2_fnGetAllFuncCustData,
8702     ITypeInfo2_fnGetAllParamCustData,
8703     ITypeInfo2_fnGetAllVarCustData,
8704     ITypeInfo2_fnGetAllImplTypeCustData,
8705 };
8706 
8707 /******************************************************************************
8708  * CreateDispTypeInfo [OLEAUT32.31]
8709  *
8710  * Build type information for an object so it can be called through an
8711  * IDispatch interface.
8712  *
8713  * RETURNS
8714  *  Success: S_OK. pptinfo contains the created ITypeInfo object.
8715  *  Failure: E_INVALIDARG, if one or more arguments is invalid.
8716  *
8717  * NOTES
8718  *  This call allows an objects methods to be accessed through IDispatch, by
8719  *  building an ITypeInfo object that IDispatch can use to call through.
8720  */
8721 HRESULT WINAPI CreateDispTypeInfo(
8722 	INTERFACEDATA *pidata, /* [I] Description of the interface to build type info for */
8723 	LCID lcid, /* [I] Locale Id */
8724 	ITypeInfo **pptinfo) /* [O] Destination for created ITypeInfo object */
8725 {
8726     ITypeInfoImpl *pTIClass, *pTIIface;
8727     ITypeLibImpl *pTypeLibImpl;
8728     unsigned int param, func;
8729     TLBFuncDesc *pFuncDesc;
8730     TLBRefType *ref;
8731 
8732     TRACE("\n");
8733     pTypeLibImpl = TypeLibImpl_Constructor();
8734     if (!pTypeLibImpl) return E_FAIL;
8735 
8736     pTypeLibImpl->TypeInfoCount = 2;
8737     pTypeLibImpl->typeinfos = heap_alloc_zero(pTypeLibImpl->TypeInfoCount * sizeof(ITypeInfoImpl*));
8738 
8739     pTIIface = pTypeLibImpl->typeinfos[0] = ITypeInfoImpl_Constructor();
8740     pTIIface->pTypeLib = pTypeLibImpl;
8741     pTIIface->index = 0;
8742     pTIIface->Name = NULL;
8743     pTIIface->dwHelpContext = -1;
8744     pTIIface->guid = NULL;
8745     pTIIface->typeattr.lcid = lcid;
8746     pTIIface->typeattr.typekind = TKIND_INTERFACE;
8747     pTIIface->typeattr.wMajorVerNum = 0;
8748     pTIIface->typeattr.wMinorVerNum = 0;
8749     pTIIface->typeattr.cbAlignment = 2;
8750     pTIIface->typeattr.cbSizeInstance = -1;
8751     pTIIface->typeattr.cbSizeVft = -1;
8752     pTIIface->typeattr.cFuncs = 0;
8753     pTIIface->typeattr.cImplTypes = 0;
8754     pTIIface->typeattr.cVars = 0;
8755     pTIIface->typeattr.wTypeFlags = 0;
8756     pTIIface->hreftype = 0;
8757 
8758     pTIIface->funcdescs = TLBFuncDesc_Alloc(pidata->cMembers);
8759     pFuncDesc = pTIIface->funcdescs;
8760     for(func = 0; func < pidata->cMembers; func++) {
8761         METHODDATA *md = pidata->pmethdata + func;
8762         pFuncDesc->Name = TLB_append_str(&pTypeLibImpl->name_list, md->szName);
8763         pFuncDesc->funcdesc.memid = md->dispid;
8764         pFuncDesc->funcdesc.lprgscode = NULL;
8765         pFuncDesc->funcdesc.funckind = FUNC_VIRTUAL;
8766         pFuncDesc->funcdesc.invkind = md->wFlags;
8767         pFuncDesc->funcdesc.callconv = md->cc;
8768         pFuncDesc->funcdesc.cParams = md->cArgs;
8769         pFuncDesc->funcdesc.cParamsOpt = 0;
8770         pFuncDesc->funcdesc.oVft = md->iMeth * sizeof(void *);
8771         pFuncDesc->funcdesc.cScodes = 0;
8772         pFuncDesc->funcdesc.wFuncFlags = 0;
8773         pFuncDesc->funcdesc.elemdescFunc.tdesc.vt = md->vtReturn;
8774         pFuncDesc->funcdesc.elemdescFunc.u.paramdesc.wParamFlags = PARAMFLAG_NONE;
8775         pFuncDesc->funcdesc.elemdescFunc.u.paramdesc.pparamdescex = NULL;
8776         pFuncDesc->funcdesc.lprgelemdescParam = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
8777                                                               md->cArgs * sizeof(ELEMDESC));
8778         pFuncDesc->pParamDesc = TLBParDesc_Constructor(md->cArgs);
8779         for(param = 0; param < md->cArgs; param++) {
8780             pFuncDesc->funcdesc.lprgelemdescParam[param].tdesc.vt = md->ppdata[param].vt;
8781             pFuncDesc->pParamDesc[param].Name = TLB_append_str(&pTypeLibImpl->name_list, md->ppdata[param].szName);
8782         }
8783         pFuncDesc->helpcontext = 0;
8784         pFuncDesc->HelpStringContext = 0;
8785         pFuncDesc->HelpString = NULL;
8786         pFuncDesc->Entry = NULL;
8787         list_init(&pFuncDesc->custdata_list);
8788         pTIIface->typeattr.cFuncs++;
8789         ++pFuncDesc;
8790     }
8791 
8792     dump_TypeInfo(pTIIface);
8793 
8794     pTIClass = pTypeLibImpl->typeinfos[1] = ITypeInfoImpl_Constructor();
8795     pTIClass->pTypeLib = pTypeLibImpl;
8796     pTIClass->index = 1;
8797     pTIClass->Name = NULL;
8798     pTIClass->dwHelpContext = -1;
8799     pTIClass->guid = NULL;
8800     pTIClass->typeattr.lcid = lcid;
8801     pTIClass->typeattr.typekind = TKIND_COCLASS;
8802     pTIClass->typeattr.wMajorVerNum = 0;
8803     pTIClass->typeattr.wMinorVerNum = 0;
8804     pTIClass->typeattr.cbAlignment = 2;
8805     pTIClass->typeattr.cbSizeInstance = -1;
8806     pTIClass->typeattr.cbSizeVft = -1;
8807     pTIClass->typeattr.cFuncs = 0;
8808     pTIClass->typeattr.cImplTypes = 1;
8809     pTIClass->typeattr.cVars = 0;
8810     pTIClass->typeattr.wTypeFlags = 0;
8811     pTIClass->hreftype = sizeof(MSFT_TypeInfoBase);
8812 
8813     pTIClass->impltypes = TLBImplType_Alloc(1);
8814 
8815     ref = heap_alloc_zero(sizeof(*ref));
8816     ref->pImpTLInfo = TLB_REF_INTERNAL;
8817     list_add_head(&pTypeLibImpl->ref_list, &ref->entry);
8818 
8819     dump_TypeInfo(pTIClass);
8820 
8821     *pptinfo = (ITypeInfo *)&pTIClass->ITypeInfo2_iface;
8822 
8823     ITypeInfo_AddRef(*pptinfo);
8824     ITypeLib2_Release(&pTypeLibImpl->ITypeLib2_iface);
8825 
8826     return S_OK;
8827 
8828 }
8829 
8830 static HRESULT WINAPI ITypeComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
8831 {
8832     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
8833 
8834     return ITypeInfo2_QueryInterface(&This->ITypeInfo2_iface, riid, ppv);
8835 }
8836 
8837 static ULONG WINAPI ITypeComp_fnAddRef(ITypeComp * iface)
8838 {
8839     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
8840 
8841     return ITypeInfo2_AddRef(&This->ITypeInfo2_iface);
8842 }
8843 
8844 static ULONG WINAPI ITypeComp_fnRelease(ITypeComp * iface)
8845 {
8846     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
8847 
8848     return ITypeInfo2_Release(&This->ITypeInfo2_iface);
8849 }
8850 
8851 static HRESULT WINAPI ITypeComp_fnBind(
8852     ITypeComp * iface,
8853     OLECHAR * szName,
8854     ULONG lHash,
8855     WORD wFlags,
8856     ITypeInfo ** ppTInfo,
8857     DESCKIND * pDescKind,
8858     BINDPTR * pBindPtr)
8859 {
8860     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
8861     const TLBFuncDesc *pFDesc;
8862     const TLBVarDesc *pVDesc;
8863     HRESULT hr = DISP_E_MEMBERNOTFOUND;
8864     UINT fdc;
8865 
8866     TRACE("(%p)->(%s, %x, 0x%x, %p, %p, %p)\n", This, debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
8867 
8868     *pDescKind = DESCKIND_NONE;
8869     pBindPtr->lpfuncdesc = NULL;
8870     *ppTInfo = NULL;
8871 
8872     for(fdc = 0; fdc < This->typeattr.cFuncs; ++fdc){
8873         pFDesc = &This->funcdescs[fdc];
8874         if (!lstrcmpiW(TLB_get_bstr(pFDesc->Name), szName)) {
8875             if (!wFlags || (pFDesc->funcdesc.invkind & wFlags))
8876                 break;
8877             else
8878                 /* name found, but wrong flags */
8879                 hr = TYPE_E_TYPEMISMATCH;
8880         }
8881     }
8882 
8883     if (fdc < This->typeattr.cFuncs)
8884     {
8885         HRESULT hr = TLB_AllocAndInitFuncDesc(
8886             &pFDesc->funcdesc,
8887             &pBindPtr->lpfuncdesc,
8888             This->typeattr.typekind == TKIND_DISPATCH);
8889         if (FAILED(hr))
8890             return hr;
8891         *pDescKind = DESCKIND_FUNCDESC;
8892         *ppTInfo = (ITypeInfo *)&This->ITypeInfo2_iface;
8893         ITypeInfo_AddRef(*ppTInfo);
8894         return S_OK;
8895     } else {
8896         pVDesc = TLB_get_vardesc_by_name(This->vardescs, This->typeattr.cVars, szName);
8897         if(pVDesc){
8898             HRESULT hr = TLB_AllocAndInitVarDesc(&pVDesc->vardesc, &pBindPtr->lpvardesc);
8899             if (FAILED(hr))
8900                 return hr;
8901             *pDescKind = DESCKIND_VARDESC;
8902             *ppTInfo = (ITypeInfo *)&This->ITypeInfo2_iface;
8903             ITypeInfo_AddRef(*ppTInfo);
8904             return S_OK;
8905         }
8906     }
8907 
8908     if (hr == DISP_E_MEMBERNOTFOUND && This->impltypes) {
8909         /* recursive search */
8910         ITypeInfo *pTInfo;
8911         ITypeComp *pTComp;
8912         HRESULT hr;
8913         hr=ITypeInfo2_GetRefTypeInfo(&This->ITypeInfo2_iface, This->impltypes[0].hRef, &pTInfo);
8914         if (SUCCEEDED(hr))
8915         {
8916             hr = ITypeInfo_GetTypeComp(pTInfo,&pTComp);
8917             ITypeInfo_Release(pTInfo);
8918         }
8919         if (SUCCEEDED(hr))
8920         {
8921             hr = ITypeComp_Bind(pTComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
8922             ITypeComp_Release(pTComp);
8923             if (SUCCEEDED(hr) && *pDescKind == DESCKIND_FUNCDESC &&
8924                     This->typeattr.typekind == TKIND_DISPATCH)
8925             {
8926                 FUNCDESC *tmp = pBindPtr->lpfuncdesc;
8927                 hr = TLB_AllocAndInitFuncDesc(tmp, &pBindPtr->lpfuncdesc, TRUE);
8928                 SysFreeString((BSTR)tmp);
8929             }
8930             return hr;
8931         }
8932         WARN("Could not search inherited interface!\n");
8933     }
8934     if (hr == DISP_E_MEMBERNOTFOUND)
8935         hr = S_OK;
8936     TRACE("did not find member with name %s, flags 0x%x\n", debugstr_w(szName), wFlags);
8937     return hr;
8938 }
8939 
8940 static HRESULT WINAPI ITypeComp_fnBindType(
8941     ITypeComp * iface,
8942     OLECHAR * szName,
8943     ULONG lHash,
8944     ITypeInfo ** ppTInfo,
8945     ITypeComp ** ppTComp)
8946 {
8947     TRACE("(%s, %x, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
8948 
8949     /* strange behaviour (does nothing) but like the
8950      * original */
8951 
8952     if (!ppTInfo || !ppTComp)
8953         return E_POINTER;
8954 
8955     *ppTInfo = NULL;
8956     *ppTComp = NULL;
8957 
8958     return S_OK;
8959 }
8960 
8961 static const ITypeCompVtbl tcompvt =
8962 {
8963 
8964     ITypeComp_fnQueryInterface,
8965     ITypeComp_fnAddRef,
8966     ITypeComp_fnRelease,
8967 
8968     ITypeComp_fnBind,
8969     ITypeComp_fnBindType
8970 };
8971 
8972 HRESULT WINAPI CreateTypeLib2(SYSKIND syskind, LPCOLESTR szFile,
8973         ICreateTypeLib2** ppctlib)
8974 {
8975     ITypeLibImpl *This;
8976     HRESULT hres;
8977 
8978     TRACE("(%d,%s,%p)\n", syskind, debugstr_w(szFile), ppctlib);
8979 
8980     if (!szFile) return E_INVALIDARG;
8981 
8982     This = TypeLibImpl_Constructor();
8983     if (!This)
8984         return E_OUTOFMEMORY;
8985 
8986     This->lcid = GetSystemDefaultLCID();
8987     This->syskind = syskind;
8988     This->ptr_size = get_ptr_size(syskind);
8989 
8990     This->path = heap_alloc((lstrlenW(szFile) + 1) * sizeof(WCHAR));
8991     if (!This->path) {
8992         ITypeLib2_Release(&This->ITypeLib2_iface);
8993         return E_OUTOFMEMORY;
8994     }
8995     lstrcpyW(This->path, szFile);
8996 
8997     hres = ITypeLib2_QueryInterface(&This->ITypeLib2_iface, &IID_ICreateTypeLib2, (LPVOID*)ppctlib);
8998     ITypeLib2_Release(&This->ITypeLib2_iface);
8999     return hres;
9000 }
9001 
9002 static HRESULT WINAPI ICreateTypeLib2_fnQueryInterface(ICreateTypeLib2 *iface,
9003         REFIID riid, void **object)
9004 {
9005     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
9006 
9007     return ITypeLib2_QueryInterface(&This->ITypeLib2_iface, riid, object);
9008 }
9009 
9010 static ULONG WINAPI ICreateTypeLib2_fnAddRef(ICreateTypeLib2 *iface)
9011 {
9012     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
9013 
9014     return ITypeLib2_AddRef(&This->ITypeLib2_iface);
9015 }
9016 
9017 static ULONG WINAPI ICreateTypeLib2_fnRelease(ICreateTypeLib2 *iface)
9018 {
9019     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
9020 
9021     return ITypeLib2_Release(&This->ITypeLib2_iface);
9022 }
9023 
9024 static HRESULT WINAPI ICreateTypeLib2_fnCreateTypeInfo(ICreateTypeLib2 *iface,
9025         LPOLESTR name, TYPEKIND kind, ICreateTypeInfo **ctinfo)
9026 {
9027     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
9028     ITypeInfoImpl *info;
9029     HRESULT hres;
9030 
9031     TRACE("%p %s %d %p\n", This, wine_dbgstr_w(name), kind, ctinfo);
9032 
9033     if (!ctinfo || !name)
9034         return E_INVALIDARG;
9035 
9036     info = TLB_get_typeinfo_by_name(This->typeinfos, This->TypeInfoCount, name);
9037     if (info)
9038         return TYPE_E_NAMECONFLICT;
9039 
9040     if (This->typeinfos)
9041         This->typeinfos = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->typeinfos,
9042                 sizeof(ITypeInfoImpl*) * (This->TypeInfoCount + 1));
9043     else
9044         This->typeinfos = heap_alloc_zero(sizeof(ITypeInfoImpl*));
9045 
9046     info = This->typeinfos[This->TypeInfoCount] = ITypeInfoImpl_Constructor();
9047 
9048     info->pTypeLib = This;
9049     info->Name = TLB_append_str(&This->name_list, name);
9050     info->index = This->TypeInfoCount;
9051     info->typeattr.typekind = kind;
9052     info->typeattr.cbAlignment = 4;
9053 
9054     switch (info->typeattr.typekind) {
9055     case TKIND_ENUM:
9056     case TKIND_INTERFACE:
9057     case TKIND_DISPATCH:
9058     case TKIND_COCLASS:
9059         info->typeattr.cbSizeInstance = This->ptr_size;
9060         break;
9061     case TKIND_RECORD:
9062     case TKIND_UNION:
9063         info->typeattr.cbSizeInstance = 0;
9064         break;
9065     case TKIND_MODULE:
9066         info->typeattr.cbSizeInstance = 2;
9067         break;
9068     case TKIND_ALIAS:
9069         info->typeattr.cbSizeInstance = -0x75;
9070         break;
9071     default:
9072         FIXME("unrecognized typekind %d\n", info->typeattr.typekind);
9073         info->typeattr.cbSizeInstance = 0xdeadbeef;
9074         break;
9075     }
9076 
9077     hres = ITypeInfo2_QueryInterface(&info->ITypeInfo2_iface,
9078             &IID_ICreateTypeInfo, (void **)ctinfo);
9079     if (FAILED(hres)) {
9080         ITypeInfo2_Release(&info->ITypeInfo2_iface);
9081         return hres;
9082     }
9083 
9084     info->hreftype = info->index * sizeof(MSFT_TypeInfoBase);
9085 
9086     ++This->TypeInfoCount;
9087 
9088     return S_OK;
9089 }
9090 
9091 static HRESULT WINAPI ICreateTypeLib2_fnSetName(ICreateTypeLib2 *iface,
9092         LPOLESTR name)
9093 {
9094     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
9095 
9096     TRACE("%p %s\n", This, wine_dbgstr_w(name));
9097 
9098     if (!name)
9099         return E_INVALIDARG;
9100 
9101     This->Name = TLB_append_str(&This->name_list, name);
9102 
9103     return S_OK;
9104 }
9105 
9106 static HRESULT WINAPI ICreateTypeLib2_fnSetVersion(ICreateTypeLib2 *iface,
9107         WORD majorVerNum, WORD minorVerNum)
9108 {
9109     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
9110 
9111     TRACE("%p %d %d\n", This, majorVerNum, minorVerNum);
9112 
9113     This->ver_major = majorVerNum;
9114     This->ver_minor = minorVerNum;
9115 
9116     return S_OK;
9117 }
9118 
9119 static HRESULT WINAPI ICreateTypeLib2_fnSetGuid(ICreateTypeLib2 *iface,
9120         REFGUID guid)
9121 {
9122     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
9123 
9124     TRACE("%p %s\n", This, debugstr_guid(guid));
9125 
9126     This->guid = TLB_append_guid(&This->guid_list, guid, -2);
9127 
9128     return S_OK;
9129 }
9130 
9131 static HRESULT WINAPI ICreateTypeLib2_fnSetDocString(ICreateTypeLib2 *iface,
9132         LPOLESTR doc)
9133 {
9134     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
9135 
9136     TRACE("%p %s\n", This, wine_dbgstr_w(doc));
9137 
9138     if (!doc)
9139         return E_INVALIDARG;
9140 
9141     This->DocString = TLB_append_str(&This->string_list, doc);
9142 
9143     return S_OK;
9144 }
9145 
9146 static HRESULT WINAPI ICreateTypeLib2_fnSetHelpFileName(ICreateTypeLib2 *iface,
9147         LPOLESTR helpFileName)
9148 {
9149     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
9150 
9151     TRACE("%p %s\n", This, wine_dbgstr_w(helpFileName));
9152 
9153     if (!helpFileName)
9154         return E_INVALIDARG;
9155 
9156     This->HelpFile = TLB_append_str(&This->string_list, helpFileName);
9157 
9158     return S_OK;
9159 }
9160 
9161 static HRESULT WINAPI ICreateTypeLib2_fnSetHelpContext(ICreateTypeLib2 *iface,
9162         DWORD helpContext)
9163 {
9164     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
9165 
9166     TRACE("%p %d\n", This, helpContext);
9167 
9168     This->dwHelpContext = helpContext;
9169 
9170     return S_OK;
9171 }
9172 
9173 static HRESULT WINAPI ICreateTypeLib2_fnSetLcid(ICreateTypeLib2 *iface,
9174         LCID lcid)
9175 {
9176     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
9177 
9178     TRACE("%p %x\n", This, lcid);
9179 
9180     This->set_lcid = lcid;
9181 
9182     return S_OK;
9183 }
9184 
9185 static HRESULT WINAPI ICreateTypeLib2_fnSetLibFlags(ICreateTypeLib2 *iface,
9186         UINT libFlags)
9187 {
9188     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
9189 
9190     TRACE("%p %x\n", This, libFlags);
9191 
9192     This->libflags = libFlags;
9193 
9194     return S_OK;
9195 }
9196 
9197 typedef struct tagWMSFT_SegContents {
9198     DWORD len;
9199     void *data;
9200 } WMSFT_SegContents;
9201 
9202 typedef struct tagWMSFT_TLBFile {
9203     MSFT_Header header;
9204     WMSFT_SegContents typeinfo_seg;
9205     WMSFT_SegContents impfile_seg;
9206     WMSFT_SegContents impinfo_seg;
9207     WMSFT_SegContents ref_seg;
9208     WMSFT_SegContents guidhash_seg;
9209     WMSFT_SegContents guid_seg;
9210     WMSFT_SegContents namehash_seg;
9211     WMSFT_SegContents name_seg;
9212     WMSFT_SegContents string_seg;
9213     WMSFT_SegContents typdesc_seg;
9214     WMSFT_SegContents arraydesc_seg;
9215     WMSFT_SegContents custdata_seg;
9216     WMSFT_SegContents cdguids_seg;
9217     MSFT_SegDir segdir;
9218     WMSFT_SegContents aux_seg;
9219 } WMSFT_TLBFile;
9220 
9221 static HRESULT WMSFT_compile_strings(ITypeLibImpl *This,
9222         WMSFT_TLBFile *file)
9223 {
9224     TLBString *str;
9225     UINT last_offs;
9226     char *data;
9227 
9228     file->string_seg.len = 0;
9229     LIST_FOR_EACH_ENTRY(str, &This->string_list, TLBString, entry) {
9230         int size;
9231 
9232         size = WideCharToMultiByte(CP_ACP, 0, str->str, strlenW(str->str), NULL, 0, NULL, NULL);
9233         if (size == 0)
9234             return E_UNEXPECTED;
9235 
9236         size += sizeof(INT16);
9237         if (size % 4)
9238             size = (size + 4) & ~0x3;
9239         if (size < 8)
9240             size = 8;
9241 
9242         file->string_seg.len += size;
9243 
9244         /* temporarily use str->offset to store the length of the aligned,
9245          * converted string */
9246         str->offset = size;
9247     }
9248 
9249     file->string_seg.data = data = heap_alloc(file->string_seg.len);
9250 
9251     last_offs = 0;
9252     LIST_FOR_EACH_ENTRY(str, &This->string_list, TLBString, entry) {
9253         int size;
9254 
9255         size = WideCharToMultiByte(CP_ACP, 0, str->str, strlenW(str->str),
9256                 data + sizeof(INT16), file->string_seg.len - last_offs - sizeof(INT16), NULL, NULL);
9257         if (size == 0) {
9258             heap_free(file->string_seg.data);
9259             return E_UNEXPECTED;
9260         }
9261 
9262         *((INT16*)data) = size;
9263 
9264         memset(data + sizeof(INT16) + size, 0x57, str->offset - size - sizeof(INT16));
9265 
9266         size = str->offset;
9267         data += size;
9268         str->offset = last_offs;
9269         last_offs += size;
9270     }
9271 
9272     return S_OK;
9273 }
9274 
9275 static HRESULT WMSFT_compile_names(ITypeLibImpl *This,
9276         WMSFT_TLBFile *file)
9277 {
9278     TLBString *str;
9279     UINT last_offs;
9280     char *data;
9281     MSFT_NameIntro *last_intro = NULL;
9282 
9283     file->header.nametablecount = 0;
9284     file->header.nametablechars = 0;
9285 
9286     file->name_seg.len = 0;
9287     LIST_FOR_EACH_ENTRY(str, &This->name_list, TLBString, entry) {
9288         int size;
9289 
9290         size = strlenW(str->str);
9291         file->header.nametablechars += size;
9292         file->header.nametablecount++;
9293 
9294         size = WideCharToMultiByte(CP_ACP, 0, str->str, size, NULL, 0, NULL, NULL);
9295         if (size == 0)
9296             return E_UNEXPECTED;
9297 
9298         size += sizeof(MSFT_NameIntro);
9299         if (size % 4)
9300             size = (size + 4) & ~0x3;
9301         if (size < 8)
9302             size = 8;
9303 
9304         file->name_seg.len += size;
9305 
9306         /* temporarily use str->offset to store the length of the aligned,
9307          * converted string */
9308         str->offset = size;
9309     }
9310 
9311     /* Allocate bigger buffer so we can temporarily NULL terminate the name */
9312     file->name_seg.data = data = heap_alloc(file->name_seg.len+1);
9313 
9314     last_offs = 0;
9315     LIST_FOR_EACH_ENTRY(str, &This->name_list, TLBString, entry) {
9316         int size, hash;
9317         MSFT_NameIntro *intro = (MSFT_NameIntro*)data;
9318 
9319         size = WideCharToMultiByte(CP_ACP, 0, str->str, strlenW(str->str),
9320                 data + sizeof(MSFT_NameIntro),
9321                 file->name_seg.len - last_offs - sizeof(MSFT_NameIntro), NULL, NULL);
9322         if (size == 0) {
9323             heap_free(file->name_seg.data);
9324             return E_UNEXPECTED;
9325         }
9326         data[sizeof(MSFT_NameIntro) + size] = '\0';
9327 
9328         intro->hreftype = -1; /* TODO? */
9329         intro->namelen = size & 0xFF;
9330         /* TODO: namelen & 0xFF00 == ??? maybe HREF type indicator? */
9331         hash = LHashValOfNameSysA(This->syskind, This->lcid, data + sizeof(MSFT_NameIntro));
9332         intro->namelen |= hash << 16;
9333         intro->next_hash = ((DWORD*)file->namehash_seg.data)[hash & 0x7f];
9334         ((DWORD*)file->namehash_seg.data)[hash & 0x7f] = last_offs;
9335 
9336         memset(data + sizeof(MSFT_NameIntro) + size, 0x57,
9337                 str->offset - size - sizeof(MSFT_NameIntro));
9338 
9339         /* update str->offset to actual value to use in other
9340          * compilation functions that require positions within
9341          * the string table */
9342         last_intro = intro;
9343         size = str->offset;
9344         data += size;
9345         str->offset = last_offs;
9346         last_offs += size;
9347     }
9348 
9349     if(last_intro)
9350         last_intro->hreftype = 0; /* last one is 0? */
9351 
9352     return S_OK;
9353 }
9354 
9355 static inline int hash_guid(GUID *guid)
9356 {
9357     int i, hash = 0;
9358 
9359     for (i = 0; i < 8; i ++)
9360         hash ^= ((const short *)guid)[i];
9361 
9362     return hash & 0x1f;
9363 }
9364 
9365 static HRESULT WMSFT_compile_guids(ITypeLibImpl *This, WMSFT_TLBFile *file)
9366 {
9367     TLBGuid *guid;
9368     MSFT_GuidEntry *entry;
9369     DWORD offs;
9370     int hash_key, *guidhashtab;
9371 
9372     file->guid_seg.len = sizeof(MSFT_GuidEntry) * list_count(&This->guid_list);
9373     file->guid_seg.data = heap_alloc(file->guid_seg.len);
9374 
9375     entry = file->guid_seg.data;
9376     offs = 0;
9377     guidhashtab = file->guidhash_seg.data;
9378     LIST_FOR_EACH_ENTRY(guid, &This->guid_list, TLBGuid, entry){
9379         memcpy(&entry->guid, &guid->guid, sizeof(GUID));
9380         entry->hreftype = guid->hreftype;
9381 
9382         hash_key = hash_guid(&guid->guid);
9383         entry->next_hash = guidhashtab[hash_key];
9384         guidhashtab[hash_key] = offs;
9385 
9386         guid->offset = offs;
9387         offs += sizeof(MSFT_GuidEntry);
9388         ++entry;
9389     }
9390 
9391     return S_OK;
9392 }
9393 
9394 static DWORD WMSFT_encode_variant(VARIANT *value, WMSFT_TLBFile *file)
9395 {
9396     VARIANT v = *value;
9397     VARTYPE arg_type = V_VT(value);
9398     int mask = 0;
9399     HRESULT hres;
9400     DWORD ret = file->custdata_seg.len;
9401 
9402     if(arg_type == VT_INT)
9403         arg_type = VT_I4;
9404     if(arg_type == VT_UINT)
9405         arg_type = VT_UI4;
9406 
9407     v = *value;
9408     if(V_VT(value) != arg_type) {
9409         hres = VariantChangeType(&v, value, 0, arg_type);
9410         if(FAILED(hres)){
9411             ERR("VariantChangeType failed: %08x\n", hres);
9412             return -1;
9413         }
9414     }
9415 
9416     /* Check if default value can be stored in-place */
9417     switch(arg_type){
9418     case VT_I4:
9419     case VT_UI4:
9420         mask = 0x3ffffff;
9421         if(V_UI4(&v) > 0x3ffffff)
9422             break;
9423         /* fall through */
9424     case VT_I1:
9425     case VT_UI1:
9426     case VT_BOOL:
9427         if(!mask)
9428             mask = 0xff;
9429         /* fall through */
9430     case VT_I2:
9431     case VT_UI2:
9432         if(!mask)
9433             mask = 0xffff;
9434         return ((0x80 + 0x4 * V_VT(value)) << 24) | (V_UI4(&v) & mask);
9435     }
9436 
9437     /* have to allocate space in custdata_seg */
9438     switch(arg_type) {
9439     case VT_I4:
9440     case VT_R4:
9441     case VT_UI4:
9442     case VT_INT:
9443     case VT_UINT:
9444     case VT_HRESULT:
9445     case VT_PTR: {
9446         /* Construct the data to be allocated */
9447         int *data;
9448 
9449         if(file->custdata_seg.data){
9450             file->custdata_seg.data = heap_realloc(file->custdata_seg.data, file->custdata_seg.len + sizeof(int) * 2);
9451             data = (int *)(((char *)file->custdata_seg.data) + file->custdata_seg.len);
9452             file->custdata_seg.len += sizeof(int) * 2;
9453         }else{
9454             file->custdata_seg.len = sizeof(int) * 2;
9455             data = file->custdata_seg.data = heap_alloc(file->custdata_seg.len);
9456         }
9457 
9458         data[0] = V_VT(value) + (V_UI4(&v) << 16);
9459         data[1] = (V_UI4(&v) >> 16) + 0x57570000;
9460 
9461         /* TODO: Check if the encoded data is already present in custdata_seg */
9462 
9463         return ret;
9464     }
9465 
9466     case VT_BSTR: {
9467         int i, len = (6+SysStringLen(V_BSTR(&v))+3) & ~0x3;
9468         char *data;
9469 
9470         if(file->custdata_seg.data){
9471             file->custdata_seg.data = heap_realloc(file->custdata_seg.data, file->custdata_seg.len + len);
9472             data = ((char *)file->custdata_seg.data) + file->custdata_seg.len;
9473             file->custdata_seg.len += len;
9474         }else{
9475             file->custdata_seg.len = len;
9476             data = file->custdata_seg.data = heap_alloc(file->custdata_seg.len);
9477         }
9478 
9479         *((unsigned short *)data) = V_VT(value);
9480         *((unsigned int *)(data+2)) = SysStringLen(V_BSTR(&v));
9481         for(i=0; i<SysStringLen(V_BSTR(&v)); i++) {
9482             if(V_BSTR(&v)[i] <= 0x7f)
9483                 data[i+6] = V_BSTR(&v)[i];
9484             else
9485                 data[i+6] = '?';
9486         }
9487         WideCharToMultiByte(CP_ACP, 0, V_BSTR(&v), SysStringLen(V_BSTR(&v)), &data[6], len-6, NULL, NULL);
9488         for(i=6+SysStringLen(V_BSTR(&v)); i<len; i++)
9489             data[i] = 0x57;
9490 
9491         /* TODO: Check if the encoded data is already present in custdata_seg */
9492 
9493         return ret;
9494     }
9495     default:
9496         FIXME("Argument type not yet handled\n");
9497         return -1;
9498     }
9499 }
9500 
9501 static DWORD WMSFT_append_typedesc(TYPEDESC *desc, WMSFT_TLBFile *file, DWORD *out_mix, INT16 *out_size);
9502 
9503 static DWORD WMSFT_append_arraydesc(ARRAYDESC *desc, WMSFT_TLBFile *file)
9504 {
9505     DWORD offs = file->arraydesc_seg.len;
9506     DWORD *encoded;
9507     USHORT i;
9508 
9509     /* TODO: we should check for duplicates, but that's harder because each
9510      * chunk is variable length (really we should store TYPEDESC and ARRAYDESC
9511      * at the library-level) */
9512 
9513     file->arraydesc_seg.len += (2 + desc->cDims * 2) * sizeof(DWORD);
9514     if(!file->arraydesc_seg.data)
9515         file->arraydesc_seg.data = heap_alloc(file->arraydesc_seg.len);
9516     else
9517         file->arraydesc_seg.data = heap_realloc(file->arraydesc_seg.data, file->arraydesc_seg.len);
9518     encoded = (DWORD*)((char *)file->arraydesc_seg.data + offs);
9519 
9520     encoded[0] = WMSFT_append_typedesc(&desc->tdescElem, file, NULL, NULL);
9521     encoded[1] = desc->cDims | ((desc->cDims * 2 * sizeof(DWORD)) << 16);
9522     for(i = 0; i < desc->cDims; ++i){
9523         encoded[2 + i * 2] =  desc->rgbounds[i].cElements;
9524         encoded[2 + i * 2 + 1] = desc->rgbounds[i].lLbound;
9525     }
9526 
9527     return offs;
9528 }
9529 
9530 static DWORD WMSFT_append_typedesc(TYPEDESC *desc, WMSFT_TLBFile *file, DWORD *out_mix, INT16 *out_size)
9531 {
9532     DWORD junk;
9533     INT16 junk2;
9534     DWORD offs = 0;
9535     DWORD encoded[2];
9536     VARTYPE vt, subtype;
9537     char *data;
9538 
9539     if(!desc)
9540         return -1;
9541 
9542     if(!out_mix)
9543         out_mix = &junk;
9544     if(!out_size)
9545         out_size = &junk2;
9546 
9547     vt = desc->vt & VT_TYPEMASK;
9548 
9549     if(vt == VT_PTR || vt == VT_SAFEARRAY){
9550         DWORD mix;
9551         encoded[1] = WMSFT_append_typedesc(desc->u.lptdesc, file, &mix, out_size);
9552         encoded[0] = desc->vt | ((mix | VT_BYREF) << 16);
9553         *out_mix = 0x7FFF;
9554         *out_size += 2 * sizeof(DWORD);
9555     }else if(vt == VT_CARRAY){
9556         encoded[0] = desc->vt | (0x7FFE << 16);
9557         encoded[1] = WMSFT_append_arraydesc(desc->u.lpadesc, file);
9558         *out_mix = 0x7FFE;
9559     }else if(vt == VT_USERDEFINED){
9560         encoded[0] = desc->vt | (0x7FFF << 16);
9561         encoded[1] = desc->u.hreftype;
9562         *out_mix = 0x7FFF; /* FIXME: Should get TYPEKIND of the hreftype, e.g. TKIND_ENUM => VT_I4 */
9563     }else{
9564         TRACE("Mixing in-place, VT: 0x%x\n", desc->vt);
9565 
9566         switch(vt){
9567         case VT_INT:
9568             subtype = VT_I4;
9569             break;
9570         case VT_UINT:
9571             subtype = VT_UI4;
9572             break;
9573         case VT_VOID:
9574             subtype = VT_EMPTY;
9575             break;
9576         default:
9577             subtype = vt;
9578             break;
9579         }
9580 
9581         *out_mix = subtype;
9582         return 0x80000000 | (subtype << 16) | desc->vt;
9583     }
9584 
9585     data = file->typdesc_seg.data;
9586     while(offs < file->typdesc_seg.len){
9587         if(!memcmp(&data[offs], encoded, sizeof(encoded)))
9588             return offs;
9589         offs += sizeof(encoded);
9590     }
9591 
9592     file->typdesc_seg.len += sizeof(encoded);
9593     if(!file->typdesc_seg.data)
9594         data = file->typdesc_seg.data = heap_alloc(file->typdesc_seg.len);
9595     else
9596         data = file->typdesc_seg.data = heap_realloc(file->typdesc_seg.data, file->typdesc_seg.len);
9597 
9598     memcpy(&data[offs], encoded, sizeof(encoded));
9599 
9600     return offs;
9601 }
9602 
9603 static DWORD WMSFT_compile_custdata(struct list *custdata_list, WMSFT_TLBFile *file)
9604 {
9605     WMSFT_SegContents *cdguids_seg = &file->cdguids_seg;
9606     DWORD ret = cdguids_seg->len, offs;
9607     MSFT_CDGuid *cdguid;
9608     TLBCustData *cd;
9609 
9610     if(list_empty(custdata_list))
9611         return -1;
9612 
9613     cdguids_seg->len += sizeof(MSFT_CDGuid) * list_count(custdata_list);
9614     if(!cdguids_seg->data){
9615         cdguid = cdguids_seg->data = heap_alloc(cdguids_seg->len);
9616     }else {
9617         cdguids_seg->data = heap_realloc(cdguids_seg->data, cdguids_seg->len);
9618         cdguid = (MSFT_CDGuid*)((char*)cdguids_seg->data + ret);
9619     }
9620 
9621     offs = ret + sizeof(MSFT_CDGuid);
9622     LIST_FOR_EACH_ENTRY(cd, custdata_list, TLBCustData, entry){
9623         cdguid->GuidOffset = cd->guid->offset;
9624         cdguid->DataOffset = WMSFT_encode_variant(&cd->data, file);
9625         cdguid->next = offs;
9626         offs += sizeof(MSFT_CDGuid);
9627         ++cdguid;
9628     }
9629 
9630     --cdguid;
9631     cdguid->next = -1;
9632 
9633     return ret;
9634 }
9635 
9636 static DWORD WMSFT_compile_typeinfo_aux(ITypeInfoImpl *info,
9637         WMSFT_TLBFile *file)
9638 {
9639     WMSFT_SegContents *aux_seg = &file->aux_seg;
9640     DWORD ret = aux_seg->len, i, j, recorded_size = 0, extra_size = 0;
9641     MSFT_VarRecord *varrecord;
9642     MSFT_FuncRecord *funcrecord;
9643     MEMBERID *memid;
9644     DWORD *name, *offsets, offs;
9645 
9646     for(i = 0; i < info->typeattr.cFuncs; ++i){
9647         TLBFuncDesc *desc = &info->funcdescs[i];
9648 
9649         recorded_size += 6 * sizeof(INT); /* mandatory fields */
9650 
9651         /* optional fields */
9652         /* TODO: oArgCustData - FuncSetCustData not impl yet */
9653         if(!list_empty(&desc->custdata_list))
9654             recorded_size += 7 * sizeof(INT);
9655         else if(desc->HelpStringContext != 0)
9656             recorded_size += 6 * sizeof(INT);
9657         /* res9? resA? */
9658         else if(desc->Entry)
9659             recorded_size += 3 * sizeof(INT);
9660         else if(desc->HelpString)
9661             recorded_size += 2 * sizeof(INT);
9662         else if(desc->helpcontext)
9663             recorded_size += sizeof(INT);
9664 
9665         recorded_size += desc->funcdesc.cParams * sizeof(MSFT_ParameterInfo);
9666 
9667         for(j = 0; j < desc->funcdesc.cParams; ++j){
9668             if(desc->funcdesc.lprgelemdescParam[j].u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT){
9669                 recorded_size += desc->funcdesc.cParams * sizeof(INT);
9670                 break;
9671             }
9672         }
9673 
9674         extra_size += 2 * sizeof(INT); /* memberid, name offs */
9675     }
9676 
9677     for(i = 0; i < info->typeattr.cVars; ++i){
9678         TLBVarDesc *desc = &info->vardescs[i];
9679 
9680         recorded_size += 5 * sizeof(INT); /* mandatory fields */
9681 
9682         /* optional fields */
9683         if(desc->HelpStringContext != 0)
9684             recorded_size += 5 * sizeof(INT);
9685         else if(!list_empty(&desc->custdata_list))
9686             recorded_size += 4 * sizeof(INT);
9687         /* res9? */
9688         else if(desc->HelpString)
9689             recorded_size += 2 * sizeof(INT);
9690         else if(desc->HelpContext != 0)
9691             recorded_size += sizeof(INT);
9692 
9693         extra_size += 2 * sizeof(INT); /* memberid, name offs */
9694     }
9695 
9696     if(!recorded_size && !extra_size)
9697         return ret;
9698 
9699     extra_size += sizeof(INT); /* total aux size for this typeinfo */
9700 
9701     aux_seg->len += recorded_size + extra_size;
9702 
9703     aux_seg->len += sizeof(INT) * (info->typeattr.cVars + info->typeattr.cFuncs); /* offsets at the end */
9704 
9705     if(aux_seg->data)
9706         aux_seg->data = heap_realloc(aux_seg->data, aux_seg->len);
9707     else
9708         aux_seg->data = heap_alloc(aux_seg->len);
9709 
9710     *((DWORD*)((char *)aux_seg->data + ret)) = recorded_size;
9711 
9712     offsets = (DWORD*)((char *)aux_seg->data + ret + recorded_size + extra_size);
9713     offs = 0;
9714 
9715     funcrecord = (MSFT_FuncRecord*)(((char *)aux_seg->data) + ret + sizeof(INT));
9716     for(i = 0; i < info->typeattr.cFuncs; ++i){
9717         TLBFuncDesc *desc = &info->funcdescs[i];
9718         DWORD size = 6 * sizeof(INT), paramdefault_size = 0, *paramdefault;
9719 
9720         funcrecord->funcdescsize = sizeof(desc->funcdesc) + desc->funcdesc.cParams * sizeof(ELEMDESC);
9721         funcrecord->DataType = WMSFT_append_typedesc(&desc->funcdesc.elemdescFunc.tdesc, file, NULL, &funcrecord->funcdescsize);
9722         funcrecord->Flags = desc->funcdesc.wFuncFlags;
9723         funcrecord->VtableOffset = desc->funcdesc.oVft;
9724 
9725         /* FKCCIC:
9726          * XXXX XXXX XXXX XXXX  XXXX XXXX XXXX XXXX
9727          *                                      ^^^funckind
9728          *                                 ^^^ ^invkind
9729          *                                ^has_cust_data
9730          *                           ^^^^callconv
9731          *                         ^has_param_defaults
9732          *                        ^oEntry_is_intresource
9733          */
9734         funcrecord->FKCCIC =
9735             desc->funcdesc.funckind |
9736             (desc->funcdesc.invkind << 3) |
9737             (list_empty(&desc->custdata_list) ? 0 : 0x80) |
9738             (desc->funcdesc.callconv << 8);
9739 
9740         if(desc->Entry && desc->Entry != (TLBString*)-1 && IS_INTRESOURCE(desc->Entry))
9741             funcrecord->FKCCIC |= 0x2000;
9742 
9743         for(j = 0; j < desc->funcdesc.cParams; ++j){
9744             if(desc->funcdesc.lprgelemdescParam[j].u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT){
9745                 paramdefault_size = sizeof(INT) * desc->funcdesc.cParams;
9746                 funcrecord->funcdescsize += sizeof(PARAMDESCEX);
9747             }
9748         }
9749         if(paramdefault_size > 0)
9750             funcrecord->FKCCIC |= 0x1000;
9751 
9752         funcrecord->nrargs = desc->funcdesc.cParams;
9753         funcrecord->nroargs = desc->funcdesc.cParamsOpt;
9754 
9755         /* optional fields */
9756         /* res9? resA? */
9757         if(!list_empty(&desc->custdata_list)){
9758             size += 7 * sizeof(INT);
9759             funcrecord->HelpContext = desc->helpcontext;
9760             if(desc->HelpString)
9761                 funcrecord->oHelpString = desc->HelpString->offset;
9762             else
9763                 funcrecord->oHelpString = -1;
9764             if(!desc->Entry)
9765                 funcrecord->oEntry = -1;
9766             else if(IS_INTRESOURCE(desc->Entry))
9767                 funcrecord->oEntry = LOWORD(desc->Entry);
9768             else
9769                 funcrecord->oEntry = desc->Entry->offset;
9770             funcrecord->res9 = -1;
9771             funcrecord->resA = -1;
9772             funcrecord->HelpStringContext = desc->HelpStringContext;
9773             funcrecord->oCustData = WMSFT_compile_custdata(&desc->custdata_list, file);
9774         }else if(desc->HelpStringContext != 0){
9775             size += 6 * sizeof(INT);
9776             funcrecord->HelpContext = desc->helpcontext;
9777             if(desc->HelpString)
9778                 funcrecord->oHelpString = desc->HelpString->offset;
9779             else
9780                 funcrecord->oHelpString = -1;
9781             if(!desc->Entry)
9782                 funcrecord->oEntry = -1;
9783             else if(IS_INTRESOURCE(desc->Entry))
9784                 funcrecord->oEntry = LOWORD(desc->Entry);
9785             else
9786                 funcrecord->oEntry = desc->Entry->offset;
9787             funcrecord->res9 = -1;
9788             funcrecord->resA = -1;
9789             funcrecord->HelpStringContext = desc->HelpStringContext;
9790         }else if(desc->Entry){
9791             size += 3 * sizeof(INT);
9792             funcrecord->HelpContext = desc->helpcontext;
9793             if(desc->HelpString)
9794                 funcrecord->oHelpString = desc->HelpString->offset;
9795             else
9796                 funcrecord->oHelpString = -1;
9797             if(!desc->Entry)
9798                 funcrecord->oEntry = -1;
9799             else if(IS_INTRESOURCE(desc->Entry))
9800                 funcrecord->oEntry = LOWORD(desc->Entry);
9801             else
9802                 funcrecord->oEntry = desc->Entry->offset;
9803         }else if(desc->HelpString){
9804             size += 2 * sizeof(INT);
9805             funcrecord->HelpContext = desc->helpcontext;
9806             funcrecord->oHelpString = desc->HelpString->offset;
9807         }else if(desc->helpcontext){
9808             size += sizeof(INT);
9809             funcrecord->HelpContext = desc->helpcontext;
9810         }
9811 
9812         paramdefault = (DWORD*)((char *)funcrecord + size);
9813         size += paramdefault_size;
9814 
9815         for(j = 0; j < desc->funcdesc.cParams; ++j){
9816             MSFT_ParameterInfo *info = (MSFT_ParameterInfo*)(((char *)funcrecord) + size);
9817 
9818             info->DataType = WMSFT_append_typedesc(&desc->funcdesc.lprgelemdescParam[j].tdesc, file, NULL, &funcrecord->funcdescsize);
9819             if(desc->pParamDesc[j].Name)
9820                 info->oName = desc->pParamDesc[j].Name->offset;
9821             else
9822                 info->oName = -1;
9823             info->Flags = desc->funcdesc.lprgelemdescParam[j].u.paramdesc.wParamFlags;
9824 
9825             if(paramdefault_size){
9826                 if(desc->funcdesc.lprgelemdescParam[j].u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
9827                     *paramdefault = WMSFT_encode_variant(&desc->funcdesc.lprgelemdescParam[j].u.paramdesc.pparamdescex->varDefaultValue, file);
9828                 else if(paramdefault_size)
9829                     *paramdefault = -1;
9830                 ++paramdefault;
9831             }
9832 
9833             size += sizeof(MSFT_ParameterInfo);
9834         }
9835 
9836         funcrecord->Info = size | (i << 16); /* is it just the index? */
9837 
9838         *offsets = offs;
9839         offs += size;
9840         ++offsets;
9841 
9842         funcrecord = (MSFT_FuncRecord*)(((char*)funcrecord) + size);
9843     }
9844 
9845     varrecord = (MSFT_VarRecord*)funcrecord;
9846     for(i = 0; i < info->typeattr.cVars; ++i){
9847         TLBVarDesc *desc = &info->vardescs[i];
9848         DWORD size = 5 * sizeof(INT);
9849 
9850         varrecord->vardescsize = sizeof(desc->vardesc);
9851         varrecord->DataType = WMSFT_append_typedesc(&desc->vardesc.elemdescVar.tdesc, file, NULL, &varrecord->vardescsize);
9852         varrecord->Flags = desc->vardesc.wVarFlags;
9853         varrecord->VarKind = desc->vardesc.varkind;
9854 
9855         if(desc->vardesc.varkind == VAR_CONST){
9856             varrecord->vardescsize += sizeof(VARIANT);
9857             varrecord->OffsValue = WMSFT_encode_variant(desc->vardesc.u.lpvarValue, file);
9858         }else
9859             varrecord->OffsValue = desc->vardesc.u.oInst;
9860 
9861         /* res9? */
9862         if(desc->HelpStringContext != 0){
9863             size += 5 * sizeof(INT);
9864             varrecord->HelpContext = desc->HelpContext;
9865             if(desc->HelpString)
9866                 varrecord->HelpString = desc->HelpString->offset;
9867             else
9868                 varrecord->HelpString = -1;
9869             varrecord->res9 = -1;
9870             varrecord->oCustData = WMSFT_compile_custdata(&desc->custdata_list, file);
9871             varrecord->HelpStringContext = desc->HelpStringContext;
9872         }else if(!list_empty(&desc->custdata_list)){
9873             size += 4 * sizeof(INT);
9874             varrecord->HelpContext = desc->HelpContext;
9875             if(desc->HelpString)
9876                 varrecord->HelpString = desc->HelpString->offset;
9877             else
9878                 varrecord->HelpString = -1;
9879             varrecord->res9 = -1;
9880             varrecord->oCustData = WMSFT_compile_custdata(&desc->custdata_list, file);
9881         }else if(desc->HelpString){
9882             size += 2 * sizeof(INT);
9883             varrecord->HelpContext = desc->HelpContext;
9884             if(desc->HelpString)
9885                 varrecord->HelpString = desc->HelpString->offset;
9886             else
9887                 varrecord->HelpString = -1;
9888         }else if(desc->HelpContext != 0){
9889             size += sizeof(INT);
9890             varrecord->HelpContext = desc->HelpContext;
9891         }
9892 
9893         varrecord->Info = size | (i << 16);
9894 
9895         *offsets = offs;
9896         offs += size;
9897         ++offsets;
9898 
9899         varrecord = (MSFT_VarRecord*)(((char*)varrecord) + size);
9900     }
9901 
9902     memid = (MEMBERID*)varrecord;
9903     for(i = 0; i < info->typeattr.cFuncs; ++i){
9904         TLBFuncDesc *desc = &info->funcdescs[i];
9905         *memid = desc->funcdesc.memid;
9906         ++memid;
9907     }
9908     for(i = 0; i < info->typeattr.cVars; ++i){
9909         TLBVarDesc *desc = &info->vardescs[i];
9910         *memid = desc->vardesc.memid;
9911         ++memid;
9912     }
9913 
9914     name = (UINT*)memid;
9915     for(i = 0; i < info->typeattr.cFuncs; ++i){
9916         TLBFuncDesc *desc = &info->funcdescs[i];
9917         if(desc->Name)
9918             *name = desc->Name->offset;
9919         else
9920             *name = -1;
9921         ++name;
9922     }
9923     for(i = 0; i < info->typeattr.cVars; ++i){
9924         TLBVarDesc *desc = &info->vardescs[i];
9925         if(desc->Name)
9926             *name = desc->Name->offset;
9927         else
9928             *name = -1;
9929         ++name;
9930     }
9931 
9932     return ret;
9933 }
9934 
9935 typedef struct tagWMSFT_RefChunk {
9936     DWORD href;
9937     DWORD res04;
9938     DWORD res08;
9939     DWORD next;
9940 } WMSFT_RefChunk;
9941 
9942 static DWORD WMSFT_compile_typeinfo_ref(ITypeInfoImpl *info, WMSFT_TLBFile *file)
9943 {
9944     DWORD offs = file->ref_seg.len, i;
9945     WMSFT_RefChunk *chunk;
9946 
9947     file->ref_seg.len += info->typeattr.cImplTypes * sizeof(WMSFT_RefChunk);
9948     if(!file->ref_seg.data)
9949         file->ref_seg.data = heap_alloc(file->ref_seg.len);
9950     else
9951         file->ref_seg.data = heap_realloc(file->ref_seg.data, file->ref_seg.len);
9952 
9953     chunk = (WMSFT_RefChunk*)((char*)file->ref_seg.data + offs);
9954 
9955     for(i = 0; i < info->typeattr.cImplTypes; ++i){
9956         chunk->href = info->impltypes[i].hRef;
9957         chunk->res04 = info->impltypes[i].implflags;
9958         chunk->res08 = -1;
9959         if(i < info->typeattr.cImplTypes - 1)
9960             chunk->next = offs + sizeof(WMSFT_RefChunk) * (i + 1);
9961         else
9962             chunk->next = -1;
9963         ++chunk;
9964     }
9965 
9966     return offs;
9967 }
9968 
9969 static DWORD WMSFT_compile_typeinfo(ITypeInfoImpl *info, INT16 index, WMSFT_TLBFile *file, char *data)
9970 {
9971     DWORD size;
9972 
9973     size = sizeof(MSFT_TypeInfoBase);
9974 
9975     if(data){
9976         MSFT_TypeInfoBase *base = (MSFT_TypeInfoBase*)data;
9977         if(info->typeattr.wTypeFlags & TYPEFLAG_FDUAL)
9978             base->typekind = TKIND_DISPATCH;
9979         else
9980             base->typekind = info->typeattr.typekind;
9981         base->typekind |= index << 16; /* TODO: There are some other flags here */
9982         base->typekind |= (info->typeattr.cbAlignment << 11) | (info->typeattr.cbAlignment << 6);
9983         base->memoffset = WMSFT_compile_typeinfo_aux(info, file);
9984         base->res2 = 0;
9985         base->res3 = 0;
9986         base->res4 = 3;
9987         base->res5 = 0;
9988         base->cElement = (info->typeattr.cVars << 16) | info->typeattr.cFuncs;
9989         base->res7 = 0;
9990         base->res8 = 0;
9991         base->res9 = 0;
9992         base->resA = 0;
9993         if(info->guid)
9994             base->posguid = info->guid->offset;
9995         else
9996             base->posguid = -1;
9997         base->flags = info->typeattr.wTypeFlags;
9998         if(info->Name) {
9999             base->NameOffset = info->Name->offset;
10000 
10001             ((unsigned char*)file->name_seg.data)[info->Name->offset+9] = 0x38;
10002             *(HREFTYPE*)((unsigned char*)file->name_seg.data+info->Name->offset) = info->hreftype;
10003         }else {
10004             base->NameOffset = -1;
10005         }
10006         base->version = (info->typeattr.wMinorVerNum << 16) | info->typeattr.wMajorVerNum;
10007         if(info->DocString)
10008             base->docstringoffs = info->DocString->offset;
10009         else
10010             base->docstringoffs = -1;
10011         base->helpstringcontext = info->dwHelpStringContext;
10012         base->helpcontext = info->dwHelpContext;
10013         base->oCustData = WMSFT_compile_custdata(info->pcustdata_list, file);
10014         base->cImplTypes = info->typeattr.cImplTypes;
10015         base->cbSizeVft = info->typeattr.cbSizeVft;
10016         base->size = info->typeattr.cbSizeInstance;
10017         if(info->typeattr.typekind == TKIND_COCLASS){
10018             base->datatype1 = WMSFT_compile_typeinfo_ref(info, file);
10019         }else if(info->typeattr.typekind == TKIND_ALIAS){
10020             base->datatype1 = WMSFT_append_typedesc(info->tdescAlias, file, NULL, NULL);
10021         }else if(info->typeattr.typekind == TKIND_MODULE){
10022             if(info->DllName)
10023                 base->datatype1 = info->DllName->offset;
10024             else
10025                 base->datatype1 = -1;
10026         }else{
10027             if(info->typeattr.cImplTypes > 0)
10028                 base->datatype1 = info->impltypes[0].hRef;
10029             else
10030                 base->datatype1 = -1;
10031         }
10032         base->datatype2 = index; /* FIXME: i think there's more here */
10033         base->res18 = 0;
10034         base->res19 = -1;
10035     }
10036 
10037     return size;
10038 }
10039 
10040 static void WMSFT_compile_typeinfo_seg(ITypeLibImpl *This, WMSFT_TLBFile *file, DWORD *junk)
10041 {
10042     UINT i;
10043 
10044     file->typeinfo_seg.len = 0;
10045     for(i = 0; i < This->TypeInfoCount; ++i){
10046         ITypeInfoImpl *info = This->typeinfos[i];
10047         *junk = file->typeinfo_seg.len;
10048         ++junk;
10049         file->typeinfo_seg.len += WMSFT_compile_typeinfo(info, i, NULL, NULL);
10050     }
10051 
10052     file->typeinfo_seg.data = heap_alloc(file->typeinfo_seg.len);
10053     memset(file->typeinfo_seg.data, 0x96, file->typeinfo_seg.len);
10054 
10055     file->aux_seg.len = 0;
10056     file->aux_seg.data = NULL;
10057 
10058     file->typeinfo_seg.len = 0;
10059     for(i = 0; i < This->TypeInfoCount; ++i){
10060         ITypeInfoImpl *info = This->typeinfos[i];
10061         file->typeinfo_seg.len += WMSFT_compile_typeinfo(info, i, file,
10062                 ((char *)file->typeinfo_seg.data) + file->typeinfo_seg.len);
10063     }
10064 }
10065 
10066 typedef struct tagWMSFT_ImpFile {
10067     INT guid_offs;
10068     LCID lcid;
10069     DWORD version;
10070 } WMSFT_ImpFile;
10071 
10072 static void WMSFT_compile_impfile(ITypeLibImpl *This, WMSFT_TLBFile *file)
10073 {
10074     TLBImpLib *implib;
10075     WMSFT_ImpFile *impfile;
10076     char *data;
10077     DWORD last_offs = 0;
10078 
10079     file->impfile_seg.len = 0;
10080     LIST_FOR_EACH_ENTRY(implib, &This->implib_list, TLBImpLib, entry){
10081         int size = 0;
10082 
10083         if(implib->name){
10084             WCHAR *path = strrchrW(implib->name, '\\');
10085             if(path)
10086                 ++path;
10087             else
10088                 path = implib->name;
10089             size = WideCharToMultiByte(CP_ACP, 0, path, strlenW(path), NULL, 0, NULL, NULL);
10090             if (size == 0)
10091                 ERR("failed to convert wide string: %s\n", debugstr_w(path));
10092         }
10093 
10094         size += sizeof(INT16);
10095         if (size % 4)
10096             size = (size + 4) & ~0x3;
10097         if (size < 8)
10098             size = 8;
10099 
10100         file->impfile_seg.len += sizeof(WMSFT_ImpFile) + size;
10101     }
10102 
10103     data = file->impfile_seg.data = heap_alloc(file->impfile_seg.len);
10104 
10105     LIST_FOR_EACH_ENTRY(implib, &This->implib_list, TLBImpLib, entry){
10106         int strlen = 0, size;
10107 
10108         impfile = (WMSFT_ImpFile*)data;
10109         impfile->guid_offs = implib->guid->offset;
10110         impfile->lcid = implib->lcid;
10111         impfile->version = (implib->wVersionMinor << 16) | implib->wVersionMajor;
10112 
10113         data += sizeof(WMSFT_ImpFile);
10114 
10115         if(implib->name){
10116             WCHAR *path= strrchrW(implib->name, '\\');
10117             if(path)
10118                 ++path;
10119             else
10120                 path = implib->name;
10121             strlen = WideCharToMultiByte(CP_ACP, 0, path, strlenW(path),
10122                     data + sizeof(INT16), file->impfile_seg.len - last_offs - sizeof(INT16), NULL, NULL);
10123             if (strlen == 0)
10124                 ERR("failed to convert wide string: %s\n", debugstr_w(path));
10125         }
10126 
10127         *((INT16*)data) = (strlen << 2) | 1; /* FIXME: is that a flag, or what? */
10128 
10129         size = strlen + sizeof(INT16);
10130         if (size % 4)
10131             size = (size + 4) & ~0x3;
10132         if (size < 8)
10133             size = 8;
10134         memset(data + sizeof(INT16) + strlen, 0x57, size - strlen - sizeof(INT16));
10135 
10136         data += size;
10137         implib->offset = last_offs;
10138         last_offs += size + sizeof(WMSFT_ImpFile);
10139     }
10140 }
10141 
10142 static void WMSFT_compile_impinfo(ITypeLibImpl *This, WMSFT_TLBFile *file)
10143 {
10144     MSFT_ImpInfo *info;
10145     TLBRefType *ref_type;
10146     UINT i = 0;
10147 
10148     WMSFT_compile_impfile(This, file);
10149 
10150     file->impinfo_seg.len = sizeof(MSFT_ImpInfo) * list_count(&This->ref_list);
10151     info = file->impinfo_seg.data = heap_alloc(file->impinfo_seg.len);
10152 
10153     LIST_FOR_EACH_ENTRY(ref_type, &This->ref_list, TLBRefType, entry){
10154         info->flags = i | ((ref_type->tkind & 0xFF) << 24);
10155         if(ref_type->index == TLB_REF_USE_GUID){
10156             info->flags |= MSFT_IMPINFO_OFFSET_IS_GUID;
10157             info->oGuid = ref_type->guid->offset;
10158         }else
10159             info->oGuid = ref_type->index;
10160         info->oImpFile = ref_type->pImpTLInfo->offset;
10161         ++i;
10162         ++info;
10163     }
10164 }
10165 
10166 static void WMSFT_compile_guidhash(ITypeLibImpl *This, WMSFT_TLBFile *file)
10167 {
10168     file->guidhash_seg.len = 0x80;
10169     file->guidhash_seg.data = heap_alloc(file->guidhash_seg.len);
10170     memset(file->guidhash_seg.data, 0xFF, file->guidhash_seg.len);
10171 }
10172 
10173 static void WMSFT_compile_namehash(ITypeLibImpl *This, WMSFT_TLBFile *file)
10174 {
10175     file->namehash_seg.len = 0x200;
10176     file->namehash_seg.data = heap_alloc(file->namehash_seg.len);
10177     memset(file->namehash_seg.data, 0xFF, file->namehash_seg.len);
10178 }
10179 
10180 static void tmp_fill_segdir_seg(MSFT_pSeg *segdir, WMSFT_SegContents *contents, DWORD *running_offset)
10181 {
10182     if(contents && contents->len){
10183         segdir->offset = *running_offset;
10184         segdir->length = contents->len;
10185         *running_offset += segdir->length;
10186     }else{
10187         segdir->offset = -1;
10188         segdir->length = 0;
10189     }
10190 
10191     /* TODO: do these ever change? */
10192     segdir->res08 = -1;
10193     segdir->res0c = 0xf;
10194 }
10195 
10196 static void WMSFT_write_segment(HANDLE outfile, WMSFT_SegContents *segment)
10197 {
10198     DWORD written;
10199     if(segment)
10200         WriteFile(outfile, segment->data, segment->len, &written, NULL);
10201 }
10202 
10203 static HRESULT WMSFT_fixup_typeinfos(ITypeLibImpl *This, WMSFT_TLBFile *file,
10204         DWORD file_len)
10205 {
10206     DWORD i;
10207     MSFT_TypeInfoBase *base = (MSFT_TypeInfoBase *)file->typeinfo_seg.data;
10208 
10209     for(i = 0; i < This->TypeInfoCount; ++i){
10210         base->memoffset += file_len;
10211         ++base;
10212     }
10213 
10214     return S_OK;
10215 }
10216 
10217 static void WMSFT_free_file(WMSFT_TLBFile *file)
10218 {
10219     HeapFree(GetProcessHeap(), 0, file->typeinfo_seg.data);
10220     HeapFree(GetProcessHeap(), 0, file->guidhash_seg.data);
10221     HeapFree(GetProcessHeap(), 0, file->guid_seg.data);
10222     HeapFree(GetProcessHeap(), 0, file->ref_seg.data);
10223     HeapFree(GetProcessHeap(), 0, file->impinfo_seg.data);
10224     HeapFree(GetProcessHeap(), 0, file->impfile_seg.data);
10225     HeapFree(GetProcessHeap(), 0, file->namehash_seg.data);
10226     HeapFree(GetProcessHeap(), 0, file->name_seg.data);
10227     HeapFree(GetProcessHeap(), 0, file->string_seg.data);
10228     HeapFree(GetProcessHeap(), 0, file->typdesc_seg.data);
10229     HeapFree(GetProcessHeap(), 0, file->arraydesc_seg.data);
10230     HeapFree(GetProcessHeap(), 0, file->custdata_seg.data);
10231     HeapFree(GetProcessHeap(), 0, file->cdguids_seg.data);
10232     HeapFree(GetProcessHeap(), 0, file->aux_seg.data);
10233 }
10234 
10235 static HRESULT WINAPI ICreateTypeLib2_fnSaveAllChanges(ICreateTypeLib2 *iface)
10236 {
10237     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
10238     WMSFT_TLBFile file;
10239     DWORD written, junk_size, junk_offs, running_offset;
10240     BOOL br;
10241     HANDLE outfile;
10242     HRESULT hres;
10243     DWORD *junk;
10244     UINT i;
10245 
10246     TRACE("%p\n", This);
10247 
10248     for(i = 0; i < This->TypeInfoCount; ++i)
10249         if(This->typeinfos[i]->needs_layout)
10250             ICreateTypeInfo2_LayOut(&This->typeinfos[i]->ICreateTypeInfo2_iface);
10251 
10252     memset(&file, 0, sizeof(file));
10253 
10254     file.header.magic1 = 0x5446534D;
10255     file.header.magic2 = 0x00010002;
10256     file.header.lcid = This->set_lcid ? This->set_lcid : MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
10257     file.header.lcid2 = This->set_lcid;
10258     file.header.varflags = 0x40 | This->syskind;
10259     if (This->HelpFile)
10260         file.header.varflags |= 0x10;
10261     if (This->HelpStringDll)
10262         file.header.varflags |= HELPDLLFLAG;
10263     file.header.version = (This->ver_minor << 16) | This->ver_major;
10264     file.header.flags = This->libflags;
10265     file.header.helpstringcontext = 0; /* TODO - SetHelpStringContext not implemented yet */
10266     file.header.helpcontext = This->dwHelpContext;
10267     file.header.res44 = 0x20;
10268     file.header.res48 = 0x80;
10269     file.header.dispatchpos = This->dispatch_href;
10270 
10271     WMSFT_compile_namehash(This, &file);
10272     /* do name and string compilation to get offsets for other compilations */
10273     hres = WMSFT_compile_names(This, &file);
10274     if (FAILED(hres)){
10275         WMSFT_free_file(&file);
10276         return hres;
10277     }
10278 
10279     hres = WMSFT_compile_strings(This, &file);
10280     if (FAILED(hres)){
10281         WMSFT_free_file(&file);
10282         return hres;
10283     }
10284 
10285     WMSFT_compile_guidhash(This, &file);
10286     hres = WMSFT_compile_guids(This, &file);
10287     if (FAILED(hres)){
10288         WMSFT_free_file(&file);
10289         return hres;
10290     }
10291 
10292     if(This->HelpFile)
10293         file.header.helpfile = This->HelpFile->offset;
10294     else
10295         file.header.helpfile = -1;
10296 
10297     if(This->DocString)
10298         file.header.helpstring = This->DocString->offset;
10299     else
10300         file.header.helpstring = -1;
10301 
10302     /* do some more segment compilation */
10303     file.header.nimpinfos = list_count(&This->ref_list);
10304     file.header.nrtypeinfos = This->TypeInfoCount;
10305 
10306     if(This->Name)
10307         file.header.NameOffset = This->Name->offset;
10308     else
10309         file.header.NameOffset = -1;
10310 
10311     file.header.CustomDataOffset = WMSFT_compile_custdata(&This->custdata_list, &file);
10312 
10313     if(This->guid)
10314         file.header.posguid = This->guid->offset;
10315     else
10316         file.header.posguid = -1;
10317 
10318     junk_size = file.header.nrtypeinfos * sizeof(DWORD);
10319     if(file.header.varflags & HELPDLLFLAG)
10320         junk_size += sizeof(DWORD);
10321     if(junk_size){
10322         junk = heap_alloc_zero(junk_size);
10323         if(file.header.varflags & HELPDLLFLAG){
10324             *junk = This->HelpStringDll->offset;
10325             junk_offs = 1;
10326         }else
10327             junk_offs = 0;
10328     }else{
10329         junk = NULL;
10330         junk_offs = 0;
10331     }
10332 
10333     WMSFT_compile_typeinfo_seg(This, &file, junk + junk_offs);
10334     WMSFT_compile_impinfo(This, &file);
10335 
10336     running_offset = 0;
10337 
10338     TRACE("header at: 0x%x\n", running_offset);
10339     running_offset += sizeof(file.header);
10340 
10341     TRACE("junk at: 0x%x\n", running_offset);
10342     running_offset += junk_size;
10343 
10344     TRACE("segdir at: 0x%x\n", running_offset);
10345     running_offset += sizeof(file.segdir);
10346 
10347     TRACE("typeinfo at: 0x%x\n", running_offset);
10348     tmp_fill_segdir_seg(&file.segdir.pTypeInfoTab, &file.typeinfo_seg, &running_offset);
10349 
10350     TRACE("guidhashtab at: 0x%x\n", running_offset);
10351     tmp_fill_segdir_seg(&file.segdir.pGuidHashTab, &file.guidhash_seg, &running_offset);
10352 
10353     TRACE("guidtab at: 0x%x\n", running_offset);
10354     tmp_fill_segdir_seg(&file.segdir.pGuidTab, &file.guid_seg, &running_offset);
10355 
10356     TRACE("reftab at: 0x%x\n", running_offset);
10357     tmp_fill_segdir_seg(&file.segdir.pRefTab, &file.ref_seg, &running_offset);
10358 
10359     TRACE("impinfo at: 0x%x\n", running_offset);
10360     tmp_fill_segdir_seg(&file.segdir.pImpInfo, &file.impinfo_seg, &running_offset);
10361 
10362     TRACE("impfiles at: 0x%x\n", running_offset);
10363     tmp_fill_segdir_seg(&file.segdir.pImpFiles, &file.impfile_seg, &running_offset);
10364 
10365     TRACE("namehashtab at: 0x%x\n", running_offset);
10366     tmp_fill_segdir_seg(&file.segdir.pNameHashTab, &file.namehash_seg, &running_offset);
10367 
10368     TRACE("nametab at: 0x%x\n", running_offset);
10369     tmp_fill_segdir_seg(&file.segdir.pNametab, &file.name_seg, &running_offset);
10370 
10371     TRACE("stringtab at: 0x%x\n", running_offset);
10372     tmp_fill_segdir_seg(&file.segdir.pStringtab, &file.string_seg, &running_offset);
10373 
10374     TRACE("typdesc at: 0x%x\n", running_offset);
10375     tmp_fill_segdir_seg(&file.segdir.pTypdescTab, &file.typdesc_seg, &running_offset);
10376 
10377     TRACE("arraydescriptions at: 0x%x\n", running_offset);
10378     tmp_fill_segdir_seg(&file.segdir.pArrayDescriptions, &file.arraydesc_seg, &running_offset);
10379 
10380     TRACE("custdata at: 0x%x\n", running_offset);
10381     tmp_fill_segdir_seg(&file.segdir.pCustData, &file.custdata_seg, &running_offset);
10382 
10383     TRACE("cdguids at: 0x%x\n", running_offset);
10384     tmp_fill_segdir_seg(&file.segdir.pCDGuids, &file.cdguids_seg, &running_offset);
10385 
10386     TRACE("res0e at: 0x%x\n", running_offset);
10387     tmp_fill_segdir_seg(&file.segdir.res0e, NULL, &running_offset);
10388 
10389     TRACE("res0f at: 0x%x\n", running_offset);
10390     tmp_fill_segdir_seg(&file.segdir.res0f, NULL, &running_offset);
10391 
10392     TRACE("aux_seg at: 0x%x\n", running_offset);
10393 
10394     WMSFT_fixup_typeinfos(This, &file, running_offset);
10395 
10396     outfile = CreateFileW(This->path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
10397             FILE_ATTRIBUTE_NORMAL, 0);
10398     if (outfile == INVALID_HANDLE_VALUE){
10399         WMSFT_free_file(&file);
10400         heap_free(junk);
10401         return TYPE_E_IOERROR;
10402     }
10403 
10404     br = WriteFile(outfile, &file.header, sizeof(file.header), &written, NULL);
10405     if (!br) {
10406         WMSFT_free_file(&file);
10407         CloseHandle(outfile);
10408         heap_free(junk);
10409         return TYPE_E_IOERROR;
10410     }
10411 
10412     br = WriteFile(outfile, junk, junk_size, &written, NULL);
10413     heap_free(junk);
10414     if (!br) {
10415         WMSFT_free_file(&file);
10416         CloseHandle(outfile);
10417         return TYPE_E_IOERROR;
10418     }
10419 
10420     br = WriteFile(outfile, &file.segdir, sizeof(file.segdir), &written, NULL);
10421     if (!br) {
10422         WMSFT_free_file(&file);
10423         CloseHandle(outfile);
10424         return TYPE_E_IOERROR;
10425     }
10426 
10427     WMSFT_write_segment(outfile, &file.typeinfo_seg);
10428     WMSFT_write_segment(outfile, &file.guidhash_seg);
10429     WMSFT_write_segment(outfile, &file.guid_seg);
10430     WMSFT_write_segment(outfile, &file.ref_seg);
10431     WMSFT_write_segment(outfile, &file.impinfo_seg);
10432     WMSFT_write_segment(outfile, &file.impfile_seg);
10433     WMSFT_write_segment(outfile, &file.namehash_seg);
10434     WMSFT_write_segment(outfile, &file.name_seg);
10435     WMSFT_write_segment(outfile, &file.string_seg);
10436     WMSFT_write_segment(outfile, &file.typdesc_seg);
10437     WMSFT_write_segment(outfile, &file.arraydesc_seg);
10438     WMSFT_write_segment(outfile, &file.custdata_seg);
10439     WMSFT_write_segment(outfile, &file.cdguids_seg);
10440     WMSFT_write_segment(outfile, &file.aux_seg);
10441 
10442     WMSFT_free_file(&file);
10443 
10444     CloseHandle(outfile);
10445 
10446     return S_OK;
10447 }
10448 
10449 static HRESULT WINAPI ICreateTypeLib2_fnDeleteTypeInfo(ICreateTypeLib2 *iface,
10450         LPOLESTR name)
10451 {
10452     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
10453     FIXME("%p %s - stub\n", This, wine_dbgstr_w(name));
10454     return E_NOTIMPL;
10455 }
10456 
10457 static HRESULT WINAPI ICreateTypeLib2_fnSetCustData(ICreateTypeLib2 *iface,
10458         REFGUID guid, VARIANT *varVal)
10459 {
10460     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
10461     TLBGuid *tlbguid;
10462 
10463     TRACE("%p %s %p\n", This, debugstr_guid(guid), varVal);
10464 
10465     if (!guid || !varVal)
10466         return E_INVALIDARG;
10467 
10468     tlbguid = TLB_append_guid(&This->guid_list, guid, -1);
10469 
10470     return TLB_set_custdata(&This->custdata_list, tlbguid, varVal);
10471 }
10472 
10473 static HRESULT WINAPI ICreateTypeLib2_fnSetHelpStringContext(ICreateTypeLib2 *iface,
10474         ULONG helpStringContext)
10475 {
10476     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
10477     FIXME("%p %u - stub\n", This, helpStringContext);
10478     return E_NOTIMPL;
10479 }
10480 
10481 static HRESULT WINAPI ICreateTypeLib2_fnSetHelpStringDll(ICreateTypeLib2 *iface,
10482         LPOLESTR filename)
10483 {
10484     ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
10485     TRACE("%p %s\n", This, wine_dbgstr_w(filename));
10486 
10487     if (!filename)
10488         return E_INVALIDARG;
10489 
10490     This->HelpStringDll = TLB_append_str(&This->string_list, filename);
10491 
10492     return S_OK;
10493 }
10494 
10495 static const ICreateTypeLib2Vtbl CreateTypeLib2Vtbl = {
10496     ICreateTypeLib2_fnQueryInterface,
10497     ICreateTypeLib2_fnAddRef,
10498     ICreateTypeLib2_fnRelease,
10499     ICreateTypeLib2_fnCreateTypeInfo,
10500     ICreateTypeLib2_fnSetName,
10501     ICreateTypeLib2_fnSetVersion,
10502     ICreateTypeLib2_fnSetGuid,
10503     ICreateTypeLib2_fnSetDocString,
10504     ICreateTypeLib2_fnSetHelpFileName,
10505     ICreateTypeLib2_fnSetHelpContext,
10506     ICreateTypeLib2_fnSetLcid,
10507     ICreateTypeLib2_fnSetLibFlags,
10508     ICreateTypeLib2_fnSaveAllChanges,
10509     ICreateTypeLib2_fnDeleteTypeInfo,
10510     ICreateTypeLib2_fnSetCustData,
10511     ICreateTypeLib2_fnSetHelpStringContext,
10512     ICreateTypeLib2_fnSetHelpStringDll
10513 };
10514 
10515 static HRESULT WINAPI ICreateTypeInfo2_fnQueryInterface(ICreateTypeInfo2 *iface,
10516         REFIID riid, void **object)
10517 {
10518     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
10519 
10520     return ITypeInfo2_QueryInterface(&This->ITypeInfo2_iface, riid, object);
10521 }
10522 
10523 static ULONG WINAPI ICreateTypeInfo2_fnAddRef(ICreateTypeInfo2 *iface)
10524 {
10525     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
10526 
10527     return ITypeInfo2_AddRef(&This->ITypeInfo2_iface);
10528 }
10529 
10530 static ULONG WINAPI ICreateTypeInfo2_fnRelease(ICreateTypeInfo2 *iface)
10531 {
10532     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
10533 
10534     return ITypeInfo2_Release(&This->ITypeInfo2_iface);
10535 }
10536 
10537 static HRESULT WINAPI ICreateTypeInfo2_fnSetGuid(ICreateTypeInfo2 *iface,
10538         REFGUID guid)
10539 {
10540     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
10541 
10542     TRACE("%p %s\n", This, debugstr_guid(guid));
10543 
10544     This->guid = TLB_append_guid(&This->pTypeLib->guid_list, guid, This->hreftype);
10545 
10546     return S_OK;
10547 }
10548 
10549 static HRESULT WINAPI ICreateTypeInfo2_fnSetTypeFlags(ICreateTypeInfo2 *iface,
10550         UINT typeFlags)
10551 {
10552     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
10553     WORD old_flags;
10554     HRESULT hres;
10555 
10556     TRACE("%p %x\n", This, typeFlags);
10557 
10558     if (typeFlags & TYPEFLAG_FDUAL) {
10559         static const WCHAR stdole2tlb[] = { 's','t','d','o','l','e','2','.','t','l','b',0 };
10560         ITypeLib *stdole;
10561         ITypeInfo *dispatch;
10562         HREFTYPE hreftype;
10563         HRESULT hres;
10564 
10565         hres = LoadTypeLib(stdole2tlb, &stdole);
10566         if(FAILED(hres))
10567             return hres;
10568 
10569         hres = ITypeLib_GetTypeInfoOfGuid(stdole, &IID_IDispatch, &dispatch);
10570         ITypeLib_Release(stdole);
10571         if(FAILED(hres))
10572             return hres;
10573 
10574         hres = ICreateTypeInfo2_AddRefTypeInfo(iface, dispatch, &hreftype);
10575         ITypeInfo_Release(dispatch);
10576         if(FAILED(hres))
10577             return hres;
10578     }
10579 
10580     old_flags = This->typeattr.wTypeFlags;
10581     This->typeattr.wTypeFlags = typeFlags;
10582 
10583     hres = ICreateTypeInfo2_LayOut(iface);
10584     if (FAILED(hres)) {
10585         This->typeattr.wTypeFlags = old_flags;
10586         return hres;
10587     }
10588 
10589     return S_OK;
10590 }
10591 
10592 static HRESULT WINAPI ICreateTypeInfo2_fnSetDocString(ICreateTypeInfo2 *iface,
10593         LPOLESTR doc)
10594 {
10595     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
10596 
10597     TRACE("%p %s\n", This, wine_dbgstr_w(doc));
10598 
10599     if (!doc)
10600         return E_INVALIDARG;
10601 
10602     This->DocString = TLB_append_str(&This->pTypeLib->string_list, doc);
10603 
10604     return S_OK;
10605 }
10606 
10607 static HRESULT WINAPI ICreateTypeInfo2_fnSetHelpContext(ICreateTypeInfo2 *iface,
10608         DWORD helpContext)
10609 {
10610     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
10611 
10612     TRACE("%p %d\n", This, helpContext);
10613 
10614     This->dwHelpContext = helpContext;
10615 
10616     return S_OK;
10617 }
10618 
10619 static HRESULT WINAPI ICreateTypeInfo2_fnSetVersion(ICreateTypeInfo2 *iface,
10620         WORD majorVerNum, WORD minorVerNum)
10621 {
10622     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
10623 
10624     TRACE("%p %d %d\n", This, majorVerNum, minorVerNum);
10625 
10626     This->typeattr.wMajorVerNum = majorVerNum;
10627     This->typeattr.wMinorVerNum = minorVerNum;
10628 
10629     return S_OK;
10630 }
10631 
10632 static HRESULT WINAPI ICreateTypeInfo2_fnAddRefTypeInfo(ICreateTypeInfo2 *iface,
10633         ITypeInfo *typeInfo, HREFTYPE *refType)
10634 {
10635     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
10636     UINT index;
10637     ITypeLib *container;
10638     TLBRefType *ref_type;
10639     TLBImpLib *implib;
10640     TYPEATTR *typeattr;
10641     TLIBATTR *libattr;
10642     HRESULT hres;
10643 
10644     TRACE("%p %p %p\n", This, typeInfo, refType);
10645 
10646     if (!typeInfo || !refType)
10647         return E_INVALIDARG;
10648 
10649     hres = ITypeInfo_GetContainingTypeLib(typeInfo, &container, &index);
10650     if (FAILED(hres))
10651         return hres;
10652 
10653     if (container == (ITypeLib*)&This->pTypeLib->ITypeLib2_iface) {
10654         ITypeInfoImpl *target = impl_from_ITypeInfo(typeInfo);
10655 
10656         ITypeLib_Release(container);
10657 
10658         *refType = target->hreftype;
10659 
10660         return S_OK;
10661     }
10662 
10663     hres = ITypeLib_GetLibAttr(container, &libattr);
10664     if (FAILED(hres)) {
10665         ITypeLib_Release(container);
10666         return hres;
10667     }
10668 
10669     LIST_FOR_EACH_ENTRY(implib, &This->pTypeLib->implib_list, TLBImpLib, entry){
10670         if(IsEqualGUID(&implib->guid->guid, &libattr->guid) &&
10671                 implib->lcid == libattr->lcid &&
10672                 implib->wVersionMajor == libattr->wMajorVerNum &&
10673                 implib->wVersionMinor == libattr->wMinorVerNum)
10674             break;
10675     }
10676 
10677     if(&implib->entry == &This->pTypeLib->implib_list){
10678         implib = heap_alloc_zero(sizeof(TLBImpLib));
10679 
10680         if((ITypeLib2Vtbl*)container->lpVtbl == &tlbvt){
10681             const ITypeLibImpl *our_container = impl_from_ITypeLib2((ITypeLib2*)container);
10682             implib->name = SysAllocString(our_container->path);
10683         }else{
10684             hres = QueryPathOfRegTypeLib(&libattr->guid, libattr->wMajorVerNum,
10685                     libattr->wMinorVerNum, libattr->lcid, &implib->name);
10686             if(FAILED(hres)){
10687                 implib->name = NULL;
10688                 TRACE("QueryPathOfRegTypeLib failed, no name stored: %08x\n", hres);
10689             }
10690         }
10691 
10692         implib->guid = TLB_append_guid(&This->pTypeLib->guid_list, &libattr->guid, 2);
10693         implib->lcid = libattr->lcid;
10694         implib->wVersionMajor = libattr->wMajorVerNum;
10695         implib->wVersionMinor = libattr->wMinorVerNum;
10696 
10697         list_add_tail(&This->pTypeLib->implib_list, &implib->entry);
10698     }
10699 
10700     ITypeLib_ReleaseTLibAttr(container, libattr);
10701     ITypeLib_Release(container);
10702 
10703     hres = ITypeInfo_GetTypeAttr(typeInfo, &typeattr);
10704     if (FAILED(hres))
10705         return hres;
10706 
10707     index = 0;
10708     LIST_FOR_EACH_ENTRY(ref_type, &This->pTypeLib->ref_list, TLBRefType, entry){
10709         if(ref_type->index == TLB_REF_USE_GUID &&
10710                 IsEqualGUID(&ref_type->guid->guid, &typeattr->guid) &&
10711                 ref_type->tkind == typeattr->typekind)
10712             break;
10713         ++index;
10714     }
10715 
10716     if(&ref_type->entry == &This->pTypeLib->ref_list){
10717         ref_type = heap_alloc_zero(sizeof(TLBRefType));
10718 
10719         ref_type->tkind = typeattr->typekind;
10720         ref_type->pImpTLInfo = implib;
10721         ref_type->reference = index * sizeof(MSFT_ImpInfo);
10722 
10723         ref_type->index = TLB_REF_USE_GUID;
10724 
10725         ref_type->guid = TLB_append_guid(&This->pTypeLib->guid_list, &typeattr->guid, ref_type->reference+1);
10726 
10727         list_add_tail(&This->pTypeLib->ref_list, &ref_type->entry);
10728     }
10729 
10730     ITypeInfo_ReleaseTypeAttr(typeInfo, typeattr);
10731 
10732     *refType = ref_type->reference | 0x1;
10733 
10734     if(IsEqualGUID(&ref_type->guid->guid, &IID_IDispatch))
10735         This->pTypeLib->dispatch_href = *refType;
10736 
10737     return S_OK;
10738 }
10739 
10740 static HRESULT WINAPI ICreateTypeInfo2_fnAddFuncDesc(ICreateTypeInfo2 *iface,
10741         UINT index, FUNCDESC *funcDesc)
10742 {
10743     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
10744     TLBFuncDesc tmp_func_desc, *func_desc;
10745     int buf_size, i;
10746     char *buffer;
10747     HRESULT hres;
10748 
10749     TRACE("%p %u %p\n", This, index, funcDesc);
10750 
10751     if (!funcDesc || funcDesc->oVft & 3)
10752         return E_INVALIDARG;
10753 
10754     switch (This->typeattr.typekind) {
10755     case TKIND_MODULE:
10756         if (funcDesc->funckind != FUNC_STATIC)
10757             return TYPE_E_BADMODULEKIND;
10758         break;
10759     case TKIND_DISPATCH:
10760         if (funcDesc->funckind != FUNC_DISPATCH)
10761             return TYPE_E_BADMODULEKIND;
10762         break;
10763     default:
10764         if (funcDesc->funckind != FUNC_PUREVIRTUAL)
10765             return TYPE_E_BADMODULEKIND;
10766     }
10767 
10768     if (index > This->typeattr.cFuncs)
10769         return TYPE_E_ELEMENTNOTFOUND;
10770 
10771     if (funcDesc->invkind & (INVOKE_PROPERTYPUT | INVOKE_PROPERTYPUTREF) &&
10772             !funcDesc->cParams)
10773         return TYPE_E_INCONSISTENTPROPFUNCS;
10774 
10775 #ifdef _WIN64
10776     if(This->pTypeLib->syskind == SYS_WIN64 &&
10777             funcDesc->oVft % 8 != 0)
10778         return E_INVALIDARG;
10779 #endif
10780 
10781     memset(&tmp_func_desc, 0, sizeof(tmp_func_desc));
10782     TLBFuncDesc_Constructor(&tmp_func_desc);
10783 
10784     tmp_func_desc.funcdesc = *funcDesc;
10785 
10786     if (tmp_func_desc.funcdesc.oVft != 0)
10787         tmp_func_desc.funcdesc.oVft |= 1;
10788 
10789     if (funcDesc->cScodes && funcDesc->lprgscode) {
10790         tmp_func_desc.funcdesc.lprgscode = heap_alloc(sizeof(SCODE) * funcDesc->cScodes);
10791         memcpy(tmp_func_desc.funcdesc.lprgscode, funcDesc->lprgscode, sizeof(SCODE) * funcDesc->cScodes);
10792     } else {
10793         tmp_func_desc.funcdesc.lprgscode = NULL;
10794         tmp_func_desc.funcdesc.cScodes = 0;
10795     }
10796 
10797     buf_size = TLB_SizeElemDesc(&funcDesc->elemdescFunc);
10798     for (i = 0; i < funcDesc->cParams; ++i) {
10799         buf_size += sizeof(ELEMDESC);
10800         buf_size += TLB_SizeElemDesc(funcDesc->lprgelemdescParam + i);
10801     }
10802     tmp_func_desc.funcdesc.lprgelemdescParam = heap_alloc(buf_size);
10803     buffer = (char*)(tmp_func_desc.funcdesc.lprgelemdescParam + funcDesc->cParams);
10804 
10805     hres = TLB_CopyElemDesc(&funcDesc->elemdescFunc, &tmp_func_desc.funcdesc.elemdescFunc, &buffer);
10806     if (FAILED(hres)) {
10807         heap_free(tmp_func_desc.funcdesc.lprgelemdescParam);
10808         heap_free(tmp_func_desc.funcdesc.lprgscode);
10809         return hres;
10810     }
10811 
10812     for (i = 0; i < funcDesc->cParams; ++i) {
10813         hres = TLB_CopyElemDesc(funcDesc->lprgelemdescParam + i,
10814                 tmp_func_desc.funcdesc.lprgelemdescParam + i, &buffer);
10815         if (FAILED(hres)) {
10816             heap_free(tmp_func_desc.funcdesc.lprgelemdescParam);
10817             heap_free(tmp_func_desc.funcdesc.lprgscode);
10818             return hres;
10819         }
10820         if (tmp_func_desc.funcdesc.lprgelemdescParam[i].u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT &&
10821                 tmp_func_desc.funcdesc.lprgelemdescParam[i].tdesc.vt != VT_VARIANT &&
10822                 tmp_func_desc.funcdesc.lprgelemdescParam[i].tdesc.vt != VT_USERDEFINED){
10823             hres = TLB_SanitizeVariant(&tmp_func_desc.funcdesc.lprgelemdescParam[i].u.paramdesc.pparamdescex->varDefaultValue);
10824             if (FAILED(hres)) {
10825                 heap_free(tmp_func_desc.funcdesc.lprgelemdescParam);
10826                 heap_free(tmp_func_desc.funcdesc.lprgscode);
10827                 return hres;
10828             }
10829         }
10830     }
10831 
10832     tmp_func_desc.pParamDesc = TLBParDesc_Constructor(funcDesc->cParams);
10833 
10834     if (This->funcdescs) {
10835         This->funcdescs = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->funcdescs,
10836                 sizeof(TLBFuncDesc) * (This->typeattr.cFuncs + 1));
10837 
10838         if (index < This->typeattr.cFuncs) {
10839             memmove(This->funcdescs + index + 1, This->funcdescs + index,
10840                     (This->typeattr.cFuncs - index) * sizeof(TLBFuncDesc));
10841             func_desc = This->funcdescs + index;
10842         } else
10843             func_desc = This->funcdescs + This->typeattr.cFuncs;
10844 
10845         /* move custdata lists to the new memory location */
10846         for(i = 0; i < This->typeattr.cFuncs + 1; ++i){
10847             if(index != i){
10848                 TLBFuncDesc *fd = &This->funcdescs[i];
10849                 if(fd->custdata_list.prev == fd->custdata_list.next)
10850                     list_init(&fd->custdata_list);
10851                 else{
10852                     fd->custdata_list.prev->next = &fd->custdata_list;
10853                     fd->custdata_list.next->prev = &fd->custdata_list;
10854                 }
10855             }
10856         }
10857     } else
10858         func_desc = This->funcdescs = heap_alloc(sizeof(TLBFuncDesc));
10859 
10860     memcpy(func_desc, &tmp_func_desc, sizeof(tmp_func_desc));
10861     list_init(&func_desc->custdata_list);
10862 
10863     ++This->typeattr.cFuncs;
10864 
10865     This->needs_layout = TRUE;
10866 
10867     return S_OK;
10868 }
10869 
10870 static HRESULT WINAPI ICreateTypeInfo2_fnAddImplType(ICreateTypeInfo2 *iface,
10871         UINT index, HREFTYPE refType)
10872 {
10873     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
10874     TLBImplType *impl_type;
10875     HRESULT hres;
10876 
10877     TRACE("%p %u %d\n", This, index, refType);
10878 
10879     switch(This->typeattr.typekind){
10880         case TKIND_COCLASS: {
10881             if (index == -1) {
10882                 FIXME("Unhandled index: -1\n");
10883                 return E_NOTIMPL;
10884             }
10885 
10886             if(index != This->typeattr.cImplTypes)
10887                 return TYPE_E_ELEMENTNOTFOUND;
10888 
10889             break;
10890         }
10891         case TKIND_INTERFACE:
10892         case TKIND_DISPATCH:
10893             if (index != 0 || This->typeattr.cImplTypes)
10894                 return TYPE_E_ELEMENTNOTFOUND;
10895             break;
10896         default:
10897             FIXME("Unimplemented typekind: %d\n", This->typeattr.typekind);
10898             return E_NOTIMPL;
10899     }
10900 
10901     if (This->impltypes){
10902         UINT i;
10903 
10904         This->impltypes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->impltypes,
10905                 sizeof(TLBImplType) * (This->typeattr.cImplTypes + 1));
10906 
10907         if (index < This->typeattr.cImplTypes) {
10908             memmove(This->impltypes + index + 1, This->impltypes + index,
10909                     (This->typeattr.cImplTypes - index) * sizeof(TLBImplType));
10910             impl_type = This->impltypes + index;
10911         } else
10912             impl_type = This->impltypes + This->typeattr.cImplTypes;
10913 
10914         /* move custdata lists to the new memory location */
10915         for(i = 0; i < This->typeattr.cImplTypes + 1; ++i){
10916             if(index != i){
10917                 TLBImplType *it = &This->impltypes[i];
10918                 if(it->custdata_list.prev == it->custdata_list.next)
10919                     list_init(&it->custdata_list);
10920                 else{
10921                     it->custdata_list.prev->next = &it->custdata_list;
10922                     it->custdata_list.next->prev = &it->custdata_list;
10923                 }
10924             }
10925         }
10926     } else
10927         impl_type = This->impltypes = heap_alloc(sizeof(TLBImplType));
10928 
10929     memset(impl_type, 0, sizeof(TLBImplType));
10930     TLBImplType_Constructor(impl_type);
10931     impl_type->hRef = refType;
10932 
10933     ++This->typeattr.cImplTypes;
10934 
10935     if((refType & (~0x3)) == (This->pTypeLib->dispatch_href & (~0x3)))
10936         This->typeattr.wTypeFlags |= TYPEFLAG_FDISPATCHABLE;
10937 
10938     hres = ICreateTypeInfo2_LayOut(iface);
10939     if (FAILED(hres))
10940         return hres;
10941 
10942     return S_OK;
10943 }
10944 
10945 static HRESULT WINAPI ICreateTypeInfo2_fnSetImplTypeFlags(ICreateTypeInfo2 *iface,
10946         UINT index, INT implTypeFlags)
10947 {
10948     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
10949     TLBImplType *impl_type = &This->impltypes[index];
10950 
10951     TRACE("%p %u %x\n", This, index, implTypeFlags);
10952 
10953     if (This->typeattr.typekind != TKIND_COCLASS)
10954         return TYPE_E_BADMODULEKIND;
10955 
10956     if (index >= This->typeattr.cImplTypes)
10957         return TYPE_E_ELEMENTNOTFOUND;
10958 
10959     impl_type->implflags = implTypeFlags;
10960 
10961     return S_OK;
10962 }
10963 
10964 static HRESULT WINAPI ICreateTypeInfo2_fnSetAlignment(ICreateTypeInfo2 *iface,
10965         WORD alignment)
10966 {
10967     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
10968 
10969     TRACE("%p %d\n", This, alignment);
10970 
10971     This->typeattr.cbAlignment = alignment;
10972 
10973     return S_OK;
10974 }
10975 
10976 static HRESULT WINAPI ICreateTypeInfo2_fnSetSchema(ICreateTypeInfo2 *iface,
10977         LPOLESTR schema)
10978 {
10979     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
10980 
10981     TRACE("%p %s\n", This, wine_dbgstr_w(schema));
10982 
10983     if (!schema)
10984         return E_INVALIDARG;
10985 
10986     This->Schema = TLB_append_str(&This->pTypeLib->string_list, schema);
10987 
10988     This->typeattr.lpstrSchema = This->Schema->str;
10989 
10990     return S_OK;
10991 }
10992 
10993 static HRESULT WINAPI ICreateTypeInfo2_fnAddVarDesc(ICreateTypeInfo2 *iface,
10994         UINT index, VARDESC *varDesc)
10995 {
10996     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
10997     TLBVarDesc *var_desc;
10998 
10999     TRACE("%p %u %p\n", This, index, varDesc);
11000 
11001     if (This->vardescs){
11002         UINT i;
11003 
11004         This->vardescs = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->vardescs,
11005                 sizeof(TLBVarDesc) * (This->typeattr.cVars + 1));
11006 
11007         if (index < This->typeattr.cVars) {
11008             memmove(This->vardescs + index + 1, This->vardescs + index,
11009                     (This->typeattr.cVars - index) * sizeof(TLBVarDesc));
11010             var_desc = This->vardescs + index;
11011         } else
11012             var_desc = This->vardescs + This->typeattr.cVars;
11013 
11014         /* move custdata lists to the new memory location */
11015         for(i = 0; i < This->typeattr.cVars + 1; ++i){
11016             if(index != i){
11017                 TLBVarDesc *var = &This->vardescs[i];
11018                 if(var->custdata_list.prev == var->custdata_list.next)
11019                     list_init(&var->custdata_list);
11020                 else{
11021                     var->custdata_list.prev->next = &var->custdata_list;
11022                     var->custdata_list.next->prev = &var->custdata_list;
11023                 }
11024             }
11025         }
11026     } else
11027         var_desc = This->vardescs = heap_alloc_zero(sizeof(TLBVarDesc));
11028 
11029     TLBVarDesc_Constructor(var_desc);
11030     TLB_AllocAndInitVarDesc(varDesc, &var_desc->vardesc_create);
11031     var_desc->vardesc = *var_desc->vardesc_create;
11032 
11033     ++This->typeattr.cVars;
11034 
11035     This->needs_layout = TRUE;
11036 
11037     return S_OK;
11038 }
11039 
11040 static HRESULT WINAPI ICreateTypeInfo2_fnSetFuncAndParamNames(ICreateTypeInfo2 *iface,
11041         UINT index, LPOLESTR *names, UINT numNames)
11042 {
11043     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11044     TLBFuncDesc *func_desc = &This->funcdescs[index];
11045     int i;
11046 
11047     TRACE("%p %u %p %u\n", This, index, names, numNames);
11048 
11049     if (!names)
11050         return E_INVALIDARG;
11051 
11052     if (index >= This->typeattr.cFuncs || numNames == 0)
11053         return TYPE_E_ELEMENTNOTFOUND;
11054 
11055     if (func_desc->funcdesc.invkind & (INVOKE_PROPERTYPUT | INVOKE_PROPERTYPUTREF)){
11056         if(numNames > func_desc->funcdesc.cParams)
11057             return TYPE_E_ELEMENTNOTFOUND;
11058     } else
11059         if(numNames > func_desc->funcdesc.cParams + 1)
11060             return TYPE_E_ELEMENTNOTFOUND;
11061 
11062     for(i = 0; i < This->typeattr.cFuncs; ++i) {
11063         TLBFuncDesc *iter = &This->funcdescs[i];
11064         if (iter->Name && !strcmpW(TLB_get_bstr(iter->Name), *names)) {
11065             if (iter->funcdesc.invkind & (INVOKE_PROPERTYPUT | INVOKE_PROPERTYPUTREF | INVOKE_PROPERTYGET) &&
11066                     func_desc->funcdesc.invkind & (INVOKE_PROPERTYPUT | INVOKE_PROPERTYPUTREF | INVOKE_PROPERTYGET) &&
11067                     func_desc->funcdesc.invkind != iter->funcdesc.invkind)
11068                 continue;
11069             return TYPE_E_AMBIGUOUSNAME;
11070         }
11071     }
11072 
11073     func_desc->Name = TLB_append_str(&This->pTypeLib->name_list, *names);
11074 
11075     for (i = 1; i < numNames; ++i) {
11076         TLBParDesc *par_desc = func_desc->pParamDesc + i - 1;
11077         par_desc->Name = TLB_append_str(&This->pTypeLib->name_list, *(names + i));
11078     }
11079 
11080     return S_OK;
11081 }
11082 
11083 static HRESULT WINAPI ICreateTypeInfo2_fnSetVarName(ICreateTypeInfo2 *iface,
11084         UINT index, LPOLESTR name)
11085 {
11086     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11087 
11088     TRACE("%p %u %s\n", This, index, wine_dbgstr_w(name));
11089 
11090     if(!name)
11091         return E_INVALIDARG;
11092 
11093     if(index >= This->typeattr.cVars)
11094         return TYPE_E_ELEMENTNOTFOUND;
11095 
11096     This->vardescs[index].Name = TLB_append_str(&This->pTypeLib->name_list, name);
11097     return S_OK;
11098 }
11099 
11100 static HRESULT WINAPI ICreateTypeInfo2_fnSetTypeDescAlias(ICreateTypeInfo2 *iface,
11101         TYPEDESC *tdescAlias)
11102 {
11103     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11104     HRESULT hr;
11105 
11106     TRACE("%p %p\n", This, tdescAlias);
11107 
11108     if(!tdescAlias)
11109         return E_INVALIDARG;
11110 
11111     if(This->typeattr.typekind != TKIND_ALIAS)
11112         return TYPE_E_BADMODULEKIND;
11113 
11114     hr = TLB_size_instance(This, This->pTypeLib->syskind, tdescAlias, &This->typeattr.cbSizeInstance, &This->typeattr.cbAlignment);
11115     if(FAILED(hr))
11116         return hr;
11117 
11118     heap_free(This->tdescAlias);
11119     This->tdescAlias = heap_alloc(TLB_SizeTypeDesc(tdescAlias, TRUE));
11120     TLB_CopyTypeDesc(NULL, tdescAlias, This->tdescAlias);
11121 
11122     return S_OK;
11123 }
11124 
11125 static HRESULT WINAPI ICreateTypeInfo2_fnDefineFuncAsDllEntry(ICreateTypeInfo2 *iface,
11126         UINT index, LPOLESTR dllName, LPOLESTR procName)
11127 {
11128     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11129     FIXME("%p %u %s %s - stub\n", This, index, wine_dbgstr_w(dllName), wine_dbgstr_w(procName));
11130     return E_NOTIMPL;
11131 }
11132 
11133 static HRESULT WINAPI ICreateTypeInfo2_fnSetFuncDocString(ICreateTypeInfo2 *iface,
11134         UINT index, LPOLESTR docString)
11135 {
11136     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11137     TLBFuncDesc *func_desc = &This->funcdescs[index];
11138 
11139     TRACE("%p %u %s\n", This, index, wine_dbgstr_w(docString));
11140 
11141     if(!docString)
11142         return E_INVALIDARG;
11143 
11144     if(index >= This->typeattr.cFuncs)
11145         return TYPE_E_ELEMENTNOTFOUND;
11146 
11147     func_desc->HelpString = TLB_append_str(&This->pTypeLib->string_list, docString);
11148 
11149     return S_OK;
11150 }
11151 
11152 static HRESULT WINAPI ICreateTypeInfo2_fnSetVarDocString(ICreateTypeInfo2 *iface,
11153         UINT index, LPOLESTR docString)
11154 {
11155     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11156     TLBVarDesc *var_desc = &This->vardescs[index];
11157 
11158     TRACE("%p %u %s\n", This, index, wine_dbgstr_w(docString));
11159 
11160     if(!docString)
11161         return E_INVALIDARG;
11162 
11163     if(index >= This->typeattr.cVars)
11164         return TYPE_E_ELEMENTNOTFOUND;
11165 
11166     var_desc->HelpString = TLB_append_str(&This->pTypeLib->string_list, docString);
11167 
11168     return S_OK;
11169 }
11170 
11171 static HRESULT WINAPI ICreateTypeInfo2_fnSetFuncHelpContext(ICreateTypeInfo2 *iface,
11172         UINT index, DWORD helpContext)
11173 {
11174     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11175     TLBFuncDesc *func_desc = &This->funcdescs[index];
11176 
11177     TRACE("%p %u %d\n", This, index, helpContext);
11178 
11179     if(index >= This->typeattr.cFuncs)
11180         return TYPE_E_ELEMENTNOTFOUND;
11181 
11182     func_desc->helpcontext = helpContext;
11183 
11184     return S_OK;
11185 }
11186 
11187 static HRESULT WINAPI ICreateTypeInfo2_fnSetVarHelpContext(ICreateTypeInfo2 *iface,
11188         UINT index, DWORD helpContext)
11189 {
11190     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11191     TLBVarDesc *var_desc = &This->vardescs[index];
11192 
11193     TRACE("%p %u %d\n", This, index, helpContext);
11194 
11195     if(index >= This->typeattr.cVars)
11196         return TYPE_E_ELEMENTNOTFOUND;
11197 
11198     var_desc->HelpContext = helpContext;
11199 
11200     return S_OK;
11201 }
11202 
11203 static HRESULT WINAPI ICreateTypeInfo2_fnSetMops(ICreateTypeInfo2 *iface,
11204         UINT index, BSTR bstrMops)
11205 {
11206     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11207     FIXME("%p %u %s - stub\n", This, index, wine_dbgstr_w(bstrMops));
11208     return E_NOTIMPL;
11209 }
11210 
11211 static HRESULT WINAPI ICreateTypeInfo2_fnSetTypeIdldesc(ICreateTypeInfo2 *iface,
11212         IDLDESC *idlDesc)
11213 {
11214     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11215 
11216     TRACE("%p %p\n", This, idlDesc);
11217 
11218     if (!idlDesc)
11219         return E_INVALIDARG;
11220 
11221     This->typeattr.idldescType.dwReserved = idlDesc->dwReserved;
11222     This->typeattr.idldescType.wIDLFlags = idlDesc->wIDLFlags;
11223 
11224     return S_OK;
11225 }
11226 
11227 static HRESULT WINAPI ICreateTypeInfo2_fnLayOut(ICreateTypeInfo2 *iface)
11228 {
11229     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11230     ITypeInfo *tinfo;
11231     TLBFuncDesc *func_desc;
11232     UINT user_vft = 0, i, depth = 0;
11233     HRESULT hres = S_OK;
11234 
11235     TRACE("%p\n", This);
11236 
11237     This->needs_layout = FALSE;
11238 
11239     hres = ICreateTypeInfo2_QueryInterface(iface, &IID_ITypeInfo, (LPVOID*)&tinfo);
11240     if (FAILED(hres))
11241         return hres;
11242 
11243     if (This->typeattr.typekind == TKIND_INTERFACE) {
11244         ITypeInfo *inh;
11245         TYPEATTR *attr;
11246         HREFTYPE inh_href;
11247 
11248         hres = ITypeInfo_GetRefTypeOfImplType(tinfo, 0, &inh_href);
11249 
11250         if (SUCCEEDED(hres)) {
11251             hres = ITypeInfo_GetRefTypeInfo(tinfo, inh_href, &inh);
11252 
11253             if (SUCCEEDED(hres)) {
11254                 hres = ITypeInfo_GetTypeAttr(inh, &attr);
11255                 if (FAILED(hres)) {
11256                     ITypeInfo_Release(inh);
11257                     ITypeInfo_Release(tinfo);
11258                     return hres;
11259                 }
11260                 This->typeattr.cbSizeVft = attr->cbSizeVft;
11261                 ITypeInfo_ReleaseTypeAttr(inh, attr);
11262 
11263                 do{
11264                     ++depth;
11265                     hres = ITypeInfo_GetRefTypeOfImplType(inh, 0, &inh_href);
11266                     if(SUCCEEDED(hres)){
11267                         ITypeInfo *next;
11268                         hres = ITypeInfo_GetRefTypeInfo(inh, inh_href, &next);
11269                         if(SUCCEEDED(hres)){
11270                             ITypeInfo_Release(inh);
11271                             inh = next;
11272                         }
11273                     }
11274                 }while(SUCCEEDED(hres));
11275                 hres = S_OK;
11276 
11277                 ITypeInfo_Release(inh);
11278             } else if (hres == TYPE_E_ELEMENTNOTFOUND) {
11279                 This->typeattr.cbSizeVft = 0;
11280                 hres = S_OK;
11281             } else {
11282                 ITypeInfo_Release(tinfo);
11283                 return hres;
11284             }
11285         } else if (hres == TYPE_E_ELEMENTNOTFOUND) {
11286             This->typeattr.cbSizeVft = 0;
11287             hres = S_OK;
11288         } else {
11289             ITypeInfo_Release(tinfo);
11290             return hres;
11291         }
11292     } else if (This->typeattr.typekind == TKIND_DISPATCH)
11293         This->typeattr.cbSizeVft = 7 * This->pTypeLib->ptr_size;
11294     else
11295         This->typeattr.cbSizeVft = 0;
11296 
11297     func_desc = This->funcdescs;
11298     i = 0;
11299     while (i < This->typeattr.cFuncs) {
11300         if (!(func_desc->funcdesc.oVft & 0x1))
11301             func_desc->funcdesc.oVft = This->typeattr.cbSizeVft;
11302 
11303         if ((func_desc->funcdesc.oVft & 0xFFFC) > user_vft)
11304             user_vft = func_desc->funcdesc.oVft & 0xFFFC;
11305 
11306         This->typeattr.cbSizeVft += This->pTypeLib->ptr_size;
11307 
11308         if (func_desc->funcdesc.memid == MEMBERID_NIL) {
11309             TLBFuncDesc *iter;
11310             UINT j = 0;
11311             BOOL reset = FALSE;
11312 
11313             func_desc->funcdesc.memid = 0x60000000 + (depth << 16) + i;
11314 
11315             iter = This->funcdescs;
11316             while (j < This->typeattr.cFuncs) {
11317                 if (iter != func_desc && iter->funcdesc.memid == func_desc->funcdesc.memid) {
11318                     if (!reset) {
11319                         func_desc->funcdesc.memid = 0x60000000 + (depth << 16) + This->typeattr.cFuncs;
11320                         reset = TRUE;
11321                     } else
11322                         ++func_desc->funcdesc.memid;
11323                     iter = This->funcdescs;
11324                     j = 0;
11325                 } else {
11326                     ++iter;
11327                     ++j;
11328                 }
11329             }
11330         }
11331 
11332         ++func_desc;
11333         ++i;
11334     }
11335 
11336     if (user_vft > This->typeattr.cbSizeVft)
11337         This->typeattr.cbSizeVft = user_vft + This->pTypeLib->ptr_size;
11338 
11339     for(i = 0; i < This->typeattr.cVars; ++i){
11340         TLBVarDesc *var_desc = &This->vardescs[i];
11341         if(var_desc->vardesc.memid == MEMBERID_NIL){
11342             UINT j = 0;
11343             BOOL reset = FALSE;
11344             TLBVarDesc *iter;
11345 
11346             var_desc->vardesc.memid = 0x40000000 + (depth << 16) + i;
11347 
11348             iter = This->vardescs;
11349             while (j < This->typeattr.cVars) {
11350                 if (iter != var_desc && iter->vardesc.memid == var_desc->vardesc.memid) {
11351                     if (!reset) {
11352                         var_desc->vardesc.memid = 0x40000000 + (depth << 16) + This->typeattr.cVars;
11353                         reset = TRUE;
11354                     } else
11355                         ++var_desc->vardesc.memid;
11356                     iter = This->vardescs;
11357                     j = 0;
11358                 } else {
11359                     ++iter;
11360                     ++j;
11361                 }
11362             }
11363         }
11364     }
11365 
11366     ITypeInfo_Release(tinfo);
11367     return hres;
11368 }
11369 
11370 static HRESULT WINAPI ICreateTypeInfo2_fnDeleteFuncDesc(ICreateTypeInfo2 *iface,
11371         UINT index)
11372 {
11373     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11374     FIXME("%p %u - stub\n", This, index);
11375     return E_NOTIMPL;
11376 }
11377 
11378 static HRESULT WINAPI ICreateTypeInfo2_fnDeleteFuncDescByMemId(ICreateTypeInfo2 *iface,
11379         MEMBERID memid, INVOKEKIND invKind)
11380 {
11381     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11382     FIXME("%p %x %d - stub\n", This, memid, invKind);
11383     return E_NOTIMPL;
11384 }
11385 
11386 static HRESULT WINAPI ICreateTypeInfo2_fnDeleteVarDesc(ICreateTypeInfo2 *iface,
11387         UINT index)
11388 {
11389     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11390     FIXME("%p %u - stub\n", This, index);
11391     return E_NOTIMPL;
11392 }
11393 
11394 static HRESULT WINAPI ICreateTypeInfo2_fnDeleteVarDescByMemId(ICreateTypeInfo2 *iface,
11395         MEMBERID memid)
11396 {
11397     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11398     FIXME("%p %x - stub\n", This, memid);
11399     return E_NOTIMPL;
11400 }
11401 
11402 static HRESULT WINAPI ICreateTypeInfo2_fnDeleteImplType(ICreateTypeInfo2 *iface,
11403         UINT index)
11404 {
11405     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11406     FIXME("%p %u - stub\n", This, index);
11407     return E_NOTIMPL;
11408 }
11409 
11410 static HRESULT WINAPI ICreateTypeInfo2_fnSetCustData(ICreateTypeInfo2 *iface,
11411         REFGUID guid, VARIANT *varVal)
11412 {
11413     TLBGuid *tlbguid;
11414 
11415     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11416 
11417     TRACE("%p %s %p\n", This, debugstr_guid(guid), varVal);
11418 
11419     if (!guid || !varVal)
11420         return E_INVALIDARG;
11421 
11422     tlbguid = TLB_append_guid(&This->pTypeLib->guid_list, guid, -1);
11423 
11424     return TLB_set_custdata(This->pcustdata_list, tlbguid, varVal);
11425 }
11426 
11427 static HRESULT WINAPI ICreateTypeInfo2_fnSetFuncCustData(ICreateTypeInfo2 *iface,
11428         UINT index, REFGUID guid, VARIANT *varVal)
11429 {
11430     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11431     FIXME("%p %u %s %p - stub\n", This, index, debugstr_guid(guid), varVal);
11432     return E_NOTIMPL;
11433 }
11434 
11435 static HRESULT WINAPI ICreateTypeInfo2_fnSetParamCustData(ICreateTypeInfo2 *iface,
11436         UINT funcIndex, UINT paramIndex, REFGUID guid, VARIANT *varVal)
11437 {
11438     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11439     FIXME("%p %u %u %s %p - stub\n", This, funcIndex, paramIndex, debugstr_guid(guid), varVal);
11440     return E_NOTIMPL;
11441 }
11442 
11443 static HRESULT WINAPI ICreateTypeInfo2_fnSetVarCustData(ICreateTypeInfo2 *iface,
11444         UINT index, REFGUID guid, VARIANT *varVal)
11445 {
11446     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11447     FIXME("%p %u %s %p - stub\n", This, index, debugstr_guid(guid), varVal);
11448     return E_NOTIMPL;
11449 }
11450 
11451 static HRESULT WINAPI ICreateTypeInfo2_fnSetImplTypeCustData(ICreateTypeInfo2 *iface,
11452         UINT index, REFGUID guid, VARIANT *varVal)
11453 {
11454     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11455     FIXME("%p %u %s %p - stub\n", This, index, debugstr_guid(guid), varVal);
11456     return E_NOTIMPL;
11457 }
11458 
11459 static HRESULT WINAPI ICreateTypeInfo2_fnSetHelpStringContext(ICreateTypeInfo2 *iface,
11460         ULONG helpStringContext)
11461 {
11462     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11463 
11464     TRACE("%p %u\n", This, helpStringContext);
11465 
11466     This->dwHelpStringContext = helpStringContext;
11467 
11468     return S_OK;
11469 }
11470 
11471 static HRESULT WINAPI ICreateTypeInfo2_fnSetFuncHelpStringContext(ICreateTypeInfo2 *iface,
11472         UINT index, ULONG helpStringContext)
11473 {
11474     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11475     FIXME("%p %u %u - stub\n", This, index, helpStringContext);
11476     return E_NOTIMPL;
11477 }
11478 
11479 static HRESULT WINAPI ICreateTypeInfo2_fnSetVarHelpStringContext(ICreateTypeInfo2 *iface,
11480         UINT index, ULONG helpStringContext)
11481 {
11482     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11483     FIXME("%p %u %u - stub\n", This, index, helpStringContext);
11484     return E_NOTIMPL;
11485 }
11486 
11487 static HRESULT WINAPI ICreateTypeInfo2_fnInvalidate(ICreateTypeInfo2 *iface)
11488 {
11489     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11490     FIXME("%p - stub\n", This);
11491     return E_NOTIMPL;
11492 }
11493 
11494 static HRESULT WINAPI ICreateTypeInfo2_fnSetName(ICreateTypeInfo2 *iface,
11495         LPOLESTR name)
11496 {
11497     ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
11498 
11499     TRACE("%p %s\n", This, wine_dbgstr_w(name));
11500 
11501     if (!name)
11502         return E_INVALIDARG;
11503 
11504     This->Name = TLB_append_str(&This->pTypeLib->name_list, name);
11505 
11506     return S_OK;
11507 }
11508 
11509 static const ICreateTypeInfo2Vtbl CreateTypeInfo2Vtbl = {
11510     ICreateTypeInfo2_fnQueryInterface,
11511     ICreateTypeInfo2_fnAddRef,
11512     ICreateTypeInfo2_fnRelease,
11513     ICreateTypeInfo2_fnSetGuid,
11514     ICreateTypeInfo2_fnSetTypeFlags,
11515     ICreateTypeInfo2_fnSetDocString,
11516     ICreateTypeInfo2_fnSetHelpContext,
11517     ICreateTypeInfo2_fnSetVersion,
11518     ICreateTypeInfo2_fnAddRefTypeInfo,
11519     ICreateTypeInfo2_fnAddFuncDesc,
11520     ICreateTypeInfo2_fnAddImplType,
11521     ICreateTypeInfo2_fnSetImplTypeFlags,
11522     ICreateTypeInfo2_fnSetAlignment,
11523     ICreateTypeInfo2_fnSetSchema,
11524     ICreateTypeInfo2_fnAddVarDesc,
11525     ICreateTypeInfo2_fnSetFuncAndParamNames,
11526     ICreateTypeInfo2_fnSetVarName,
11527     ICreateTypeInfo2_fnSetTypeDescAlias,
11528     ICreateTypeInfo2_fnDefineFuncAsDllEntry,
11529     ICreateTypeInfo2_fnSetFuncDocString,
11530     ICreateTypeInfo2_fnSetVarDocString,
11531     ICreateTypeInfo2_fnSetFuncHelpContext,
11532     ICreateTypeInfo2_fnSetVarHelpContext,
11533     ICreateTypeInfo2_fnSetMops,
11534     ICreateTypeInfo2_fnSetTypeIdldesc,
11535     ICreateTypeInfo2_fnLayOut,
11536     ICreateTypeInfo2_fnDeleteFuncDesc,
11537     ICreateTypeInfo2_fnDeleteFuncDescByMemId,
11538     ICreateTypeInfo2_fnDeleteVarDesc,
11539     ICreateTypeInfo2_fnDeleteVarDescByMemId,
11540     ICreateTypeInfo2_fnDeleteImplType,
11541     ICreateTypeInfo2_fnSetCustData,
11542     ICreateTypeInfo2_fnSetFuncCustData,
11543     ICreateTypeInfo2_fnSetParamCustData,
11544     ICreateTypeInfo2_fnSetVarCustData,
11545     ICreateTypeInfo2_fnSetImplTypeCustData,
11546     ICreateTypeInfo2_fnSetHelpStringContext,
11547     ICreateTypeInfo2_fnSetFuncHelpStringContext,
11548     ICreateTypeInfo2_fnSetVarHelpStringContext,
11549     ICreateTypeInfo2_fnInvalidate,
11550     ICreateTypeInfo2_fnSetName
11551 };
11552 
11553 /******************************************************************************
11554  * ClearCustData (OLEAUT32.171)
11555  *
11556  * Clear a custom data type's data.
11557  *
11558  * PARAMS
11559  *  lpCust [I] The custom data type instance
11560  *
11561  * RETURNS
11562  *  Nothing.
11563  */
11564 void WINAPI ClearCustData(CUSTDATA *lpCust)
11565 {
11566     if (lpCust && lpCust->cCustData)
11567     {
11568         if (lpCust->prgCustData)
11569         {
11570             DWORD i;
11571 
11572             for (i = 0; i < lpCust->cCustData; i++)
11573                 VariantClear(&lpCust->prgCustData[i].varValue);
11574 
11575             CoTaskMemFree(lpCust->prgCustData);
11576             lpCust->prgCustData = NULL;
11577         }
11578         lpCust->cCustData = 0;
11579     }
11580 }
11581