6ed9ce9eb73d1668090c0c45b42dad4c95e44b8f
[reactos.git] / dll / win32 / oleaut32 / typelib.c
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, ARRAY_SIZE( Path ), 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 = ARRAY_SIZE(subKeyName);
983 deleteOtherStuff = TRUE;
984 i = 0;
985 while(RegEnumKeyExW(key, i++, subKeyName, &tmpLength, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
986 tmpLength = ARRAY_SIZE(subKeyName);
987
988 /* if its not FLAGS or HELPDIR, then we must keep the rest of the key */
989 if (!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;
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)pTypeLibIm