[OLEAUT32] Sync with Wine Staging 4.18. CORE-16441
[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 <stdlib.h>
51 #include <string.h>
52 #include <stdarg.h>
53 #include <stdio.h>
54 #include <ctype.h>
55
56 #define COBJMACROS
57 #define NONAMELESSUNION
58
59 #include "winerror.h"
60 #include "windef.h"
61 #include "winbase.h"
62 #include "winnls.h"
63 #include "winreg.h"
64 #include "winuser.h"
65 #include "winternl.h"
66 #include "lzexpand.h"
67
68 #include "objbase.h"
69 #include "typelib.h"
70 #include "wine/debug.h"
71 #include "variant.h"
72 #include "wine/asm.h"
73 #include "wine/heap.h"
74 #include "wine/list.h"
75
76 WINE_DEFAULT_DEBUG_CHANNEL(ole);
77 WINE_DECLARE_DEBUG_CHANNEL(typelib);
78
79 typedef struct
80 {
81 WORD offset;
82 WORD length;
83 WORD flags;
84 WORD id;
85 WORD handle;
86 WORD usage;
87 } NE_NAMEINFO;
88
89 typedef struct
90 {
91 WORD type_id; /* Type identifier */
92 WORD count; /* Number of resources of this type */
93 DWORD resloader; /* SetResourceHandler() */
94 /*
95 * Name info array.
96 */
97 } NE_TYPEINFO;
98
99 static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt);
100 static HRESULT TLB_AllocAndInitVarDesc(const VARDESC *src, VARDESC **dest_ptr);
101 static void TLB_FreeVarDesc(VARDESC*);
102
103 /****************************************************************************
104 * FromLExxx
105 *
106 * Takes p_iVal (which is in little endian) and returns it
107 * in the host machine's byte order.
108 */
109 #ifdef WORDS_BIGENDIAN
110 static WORD FromLEWord(WORD p_iVal)
111 {
112 return (((p_iVal & 0x00FF) << 8) |
113 ((p_iVal & 0xFF00) >> 8));
114 }
115
116
117 static DWORD FromLEDWord(DWORD p_iVal)
118 {
119 return (((p_iVal & 0x000000FF) << 24) |
120 ((p_iVal & 0x0000FF00) << 8) |
121 ((p_iVal & 0x00FF0000) >> 8) |
122 ((p_iVal & 0xFF000000) >> 24));
123 }
124 #else
125 #define FromLEWord(X) (X)
126 #define FromLEDWord(X) (X)
127 #endif
128
129 #define DISPATCH_HREF_OFFSET 0x01000000
130 #define DISPATCH_HREF_MASK 0xff000000
131
132 /****************************************************************************
133 * FromLExxx
134 *
135 * Fix byte order in any structure if necessary
136 */
137 #ifdef WORDS_BIGENDIAN
138 static void FromLEWords(void *p_Val, int p_iSize)
139 {
140 WORD *Val = p_Val;
141
142 p_iSize /= sizeof(WORD);
143
144 while (p_iSize) {
145 *Val = FromLEWord(*Val);
146 Val++;
147 p_iSize--;
148 }
149 }
150
151
152 static void FromLEDWords(void *p_Val, int p_iSize)
153 {
154 DWORD *Val = p_Val;
155
156 p_iSize /= sizeof(DWORD);
157
158 while (p_iSize) {
159 *Val = FromLEDWord(*Val);
160 Val++;
161 p_iSize--;
162 }
163 }
164 #else
165 #define FromLEWords(X,Y) /*nothing*/
166 #define FromLEDWords(X,Y) /*nothing*/
167 #endif
168
169 /*
170 * Find a typelib key which matches a requested maj.min version.
171 */
172 static BOOL find_typelib_key( REFGUID guid, WORD *wMaj, WORD *wMin )
173 {
174 static const WCHAR typelibW[] = {'T','y','p','e','l','i','b','\\',0};
175 WCHAR buffer[60];
176 char key_name[16];
177 DWORD len, i;
178 INT best_maj = -1, best_min = -1;
179 HKEY hkey;
180
181 memcpy( buffer, typelibW, sizeof(typelibW) );
182 StringFromGUID2( guid, buffer + lstrlenW(buffer), 40 );
183
184 if (RegOpenKeyExW( HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hkey ) != ERROR_SUCCESS)
185 return FALSE;
186
187 len = sizeof(key_name);
188 i = 0;
189 while (RegEnumKeyExA(hkey, i++, key_name, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
190 {
191 INT v_maj, v_min;
192
193 if (sscanf(key_name, "%x.%x", &v_maj, &v_min) == 2)
194 {
195 TRACE("found %s: %x.%x\n", debugstr_w(buffer), v_maj, v_min);
196
197 if (*wMaj == 0xffff && *wMin == 0xffff)
198 {
199 if (v_maj > best_maj) best_maj = v_maj;
200 if (v_min > best_min) best_min = v_min;
201 }
202 else if (*wMaj == v_maj)
203 {
204 best_maj = v_maj;
205
206 if (*wMin == v_min)
207 {
208 best_min = v_min;
209 break; /* exact match */
210 }
211 if (*wMin != 0xffff && v_min > best_min) best_min = v_min;
212 }
213 }
214 len = sizeof(key_name);
215 }
216 RegCloseKey( hkey );
217
218 TRACE("found best_maj %d, best_min %d\n", best_maj, best_min);
219
220 if (*wMaj == 0xffff && *wMin == 0xffff)
221 {
222 if (best_maj >= 0 && best_min >= 0)
223 {
224 *wMaj = best_maj;
225 *wMin = best_min;
226 return TRUE;
227 }
228 }
229
230 if (*wMaj == best_maj && best_min >= 0)
231 {
232 *wMin = best_min;
233 return TRUE;
234 }
235 return FALSE;
236 }
237
238 /* get the path of a typelib key, in the form "Typelib\\<guid>\\<maj>.<min>" */
239 /* buffer must be at least 60 characters long */
240 static WCHAR *get_typelib_key( REFGUID guid, WORD wMaj, WORD wMin, WCHAR *buffer )
241 {
242 static const WCHAR TypelibW[] = {'T','y','p','e','l','i','b','\\',0};
243 static const WCHAR VersionFormatW[] = {'\\','%','x','.','%','x',0};
244
245 memcpy( buffer, TypelibW, sizeof(TypelibW) );
246 StringFromGUID2( guid, buffer + lstrlenW(buffer), 40 );
247 swprintf( buffer + lstrlenW(buffer), VersionFormatW, wMaj, wMin );
248 return buffer;
249 }
250
251 /* get the path of an interface key, in the form "Interface\\<guid>" */
252 /* buffer must be at least 50 characters long */
253 static WCHAR *get_interface_key( REFGUID guid, WCHAR *buffer )
254 {
255 static const WCHAR InterfaceW[] = {'I','n','t','e','r','f','a','c','e','\\',0};
256
257 memcpy( buffer, InterfaceW, sizeof(InterfaceW) );
258 StringFromGUID2( guid, buffer + lstrlenW(buffer), 40 );
259 return buffer;
260 }
261
262 /* get the lcid subkey for a typelib, in the form "<lcid>\\<syskind>" */
263 /* buffer must be at least 16 characters long */
264 static WCHAR *get_lcid_subkey( LCID lcid, SYSKIND syskind, WCHAR *buffer )
265 {
266 static const WCHAR LcidFormatW[] = {'%','l','x','\\',0};
267 static const WCHAR win16W[] = {'w','i','n','1','6',0};
268 static const WCHAR win32W[] = {'w','i','n','3','2',0};
269 static const WCHAR win64W[] = {'w','i','n','6','4',0};
270
271 swprintf( buffer, LcidFormatW, lcid );
272 switch(syskind)
273 {
274 case SYS_WIN16: lstrcatW( buffer, win16W ); break;
275 case SYS_WIN32: lstrcatW( buffer, win32W ); break;
276 case SYS_WIN64: lstrcatW( buffer, win64W ); break;
277 default:
278 TRACE("Typelib is for unsupported syskind %i\n", syskind);
279 return NULL;
280 }
281 return buffer;
282 }
283
284 static HRESULT TLB_ReadTypeLib(LPCWSTR pszFileName, LPWSTR pszPath, UINT cchPath, ITypeLib2 **ppTypeLib);
285
286 struct tlibredirect_data
287 {
288 ULONG size;
289 DWORD res;
290 ULONG name_len;
291 ULONG name_offset;
292 LANGID langid;
293 WORD flags;
294 ULONG help_len;
295 ULONG help_offset;
296 WORD major_version;
297 WORD minor_version;
298 };
299
300 /* Get the path to a registered type library. Helper for QueryPathOfRegTypeLib. */
301 static HRESULT query_typelib_path( REFGUID guid, WORD wMaj, WORD wMin,
302 SYSKIND syskind, LCID lcid, BSTR *path, BOOL redir )
303 {
304 HRESULT hr = TYPE_E_LIBNOTREGISTERED;
305 LCID myLCID = lcid;
306 HKEY hkey;
307 WCHAR buffer[60];
308 WCHAR Path[MAX_PATH];
309 LONG res;
310
311 TRACE_(typelib)("(%s, %x.%x, 0x%x, %p)\n", debugstr_guid(guid), wMaj, wMin, lcid, path);
312
313 if (redir)
314 {
315 ACTCTX_SECTION_KEYED_DATA data;
316
317 data.cbSize = sizeof(data);
318 if (FindActCtxSectionGuid( 0, NULL, ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION, guid, &data ))
319 {
320 struct tlibredirect_data *tlib = (struct tlibredirect_data*)data.lpData;
321 WCHAR *nameW;
322 DWORD len;
323
324 if ((wMaj != 0xffff || wMin != 0xffff) && (tlib->major_version != wMaj || tlib->minor_version < wMin))
325 return TYPE_E_LIBNOTREGISTERED;
326
327 nameW = (WCHAR*)((BYTE*)data.lpSectionBase + tlib->name_offset);
328 len = SearchPathW( NULL, nameW, NULL, ARRAY_SIZE( Path ), Path, NULL );
329 if (!len) return TYPE_E_LIBNOTREGISTERED;
330
331 TRACE_(typelib)("got path from context %s\n", debugstr_w(Path));
332 *path = SysAllocString( Path );
333 return S_OK;
334 }
335 }
336
337 if (!find_typelib_key( guid, &wMaj, &wMin )) return TYPE_E_LIBNOTREGISTERED;
338 get_typelib_key( guid, wMaj, wMin, buffer );
339
340 res = RegOpenKeyExW( HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hkey );
341 if (res == ERROR_FILE_NOT_FOUND)
342 {
343 TRACE_(typelib)("%s not found\n", debugstr_w(buffer));
344 return TYPE_E_LIBNOTREGISTERED;
345 }
346 else if (res != ERROR_SUCCESS)
347 {
348 TRACE_(typelib)("failed to open %s for read access\n", debugstr_w(buffer));
349 return TYPE_E_REGISTRYACCESS;
350 }
351
352 while (hr != S_OK)
353 {
354 LONG dwPathLen = sizeof(Path);
355
356 get_lcid_subkey( myLCID, syskind, buffer );
357
358 if (RegQueryValueW(hkey, buffer, Path, &dwPathLen))
359 {
360 if (!lcid)
361 break;
362 else if (myLCID == lcid)
363 {
364 /* try with sub-langid */
365 myLCID = SUBLANGID(lcid);
366 }
367 else if ((myLCID == SUBLANGID(lcid)) && myLCID)
368 {
369 /* try with system langid */
370 myLCID = 0;
371 }
372 else
373 {
374 break;
375 }
376 }
377 else
378 {
379 *path = SysAllocString( Path );
380 hr = S_OK;
381 }
382 }
383 RegCloseKey( hkey );
384 TRACE_(typelib)("-- 0x%08x\n", hr);
385 return hr;
386 }
387
388 /****************************************************************************
389 * QueryPathOfRegTypeLib [OLEAUT32.164]
390 *
391 * Gets the path to a registered type library.
392 *
393 * PARAMS
394 * guid [I] referenced guid
395 * wMaj [I] major version
396 * wMin [I] minor version
397 * lcid [I] locale id
398 * path [O] path of typelib
399 *
400 * RETURNS
401 * Success: S_OK.
402 * Failure: If the type library is not registered then TYPE_E_LIBNOTREGISTERED
403 * or TYPE_E_REGISTRYACCESS if the type library registration key couldn't be
404 * opened.
405 */
406 HRESULT WINAPI QueryPathOfRegTypeLib( REFGUID guid, WORD wMaj, WORD wMin, LCID lcid, LPBSTR path )
407 {
408 BOOL redir = TRUE;
409 #ifdef _WIN64
410 HRESULT hres = query_typelib_path( guid, wMaj, wMin, SYS_WIN64, lcid, path, TRUE );
411 if(SUCCEEDED(hres))
412 return hres;
413 redir = FALSE;
414 #endif
415 return query_typelib_path( guid, wMaj, wMin, SYS_WIN32, lcid, path, redir );
416 }
417
418 /******************************************************************************
419 * CreateTypeLib [OLEAUT32.160] creates a typelib
420 *
421 * RETURNS
422 * Success: S_OK
423 * Failure: Status
424 */
425 HRESULT WINAPI CreateTypeLib(SYSKIND syskind, LPCOLESTR file, ICreateTypeLib **ctlib)
426 {
427 ICreateTypeLib2 *typelib2;
428 HRESULT hres;
429
430 FIXME("(%d, %s, %p): forwarding to CreateTypeLib2\n", syskind, debugstr_w(file), ctlib);
431
432 hres = CreateTypeLib2(syskind, file, &typelib2);
433 if(SUCCEEDED(hres))
434 {
435 hres = ICreateTypeLib2_QueryInterface(typelib2, &IID_ICreateTypeLib, (void **)&ctlib);
436 ICreateTypeLib2_Release(typelib2);
437 }
438
439 return hres;
440 }
441
442 /******************************************************************************
443 * LoadTypeLib [OLEAUT32.161]
444 *
445 * Loads a type library
446 *
447 * PARAMS
448 * szFile [I] Name of file to load from.
449 * pptLib [O] Pointer that receives ITypeLib object on success.
450 *
451 * RETURNS
452 * Success: S_OK
453 * Failure: Status
454 *
455 * SEE
456 * LoadTypeLibEx, LoadRegTypeLib, CreateTypeLib.
457 */
458 HRESULT WINAPI LoadTypeLib(const OLECHAR *szFile, ITypeLib * *pptLib)
459 {
460 TRACE("(%s,%p)\n",debugstr_w(szFile), pptLib);
461 return LoadTypeLibEx(szFile, REGKIND_DEFAULT, pptLib);
462 }
463
464 /******************************************************************************
465 * LoadTypeLibEx [OLEAUT32.183]
466 *
467 * Loads and optionally registers a type library
468 *
469 * RETURNS
470 * Success: S_OK
471 * Failure: Status
472 */
473 HRESULT WINAPI LoadTypeLibEx(
474 LPCOLESTR szFile, /* [in] Name of file to load from */
475 REGKIND regkind, /* [in] Specify kind of registration */
476 ITypeLib **pptLib) /* [out] Pointer to pointer to loaded type library */
477 {
478 WCHAR szPath[MAX_PATH+1];
479 HRESULT res;
480
481 TRACE("(%s,%d,%p)\n",debugstr_w(szFile), regkind, pptLib);
482
483 if (!szFile || !pptLib)
484 return E_INVALIDARG;
485
486 *pptLib = NULL;
487
488 res = TLB_ReadTypeLib(szFile, szPath, MAX_PATH + 1, (ITypeLib2**)pptLib);
489
490 if (SUCCEEDED(res))
491 switch(regkind)
492 {
493 case REGKIND_DEFAULT:
494 /* don't register typelibs supplied with full path. Experimentation confirms the following */
495 if (((szFile[0] == '\\') && (szFile[1] == '\\')) ||
496 (szFile[0] && (szFile[1] == ':'))) break;
497 /* else fall-through */
498
499 case REGKIND_REGISTER:
500 if (FAILED(res = RegisterTypeLib(*pptLib, szPath, NULL)))
501 {
502 ITypeLib_Release(*pptLib);
503 *pptLib = 0;
504 }
505 break;
506 case REGKIND_NONE:
507 break;
508 }
509
510 TRACE(" returns %08x\n",res);
511 return res;
512 }
513
514 /******************************************************************************
515 * LoadRegTypeLib [OLEAUT32.162]
516 *
517 * Loads a registered type library.
518 *
519 * PARAMS
520 * rguid [I] GUID of the registered type library.
521 * wVerMajor [I] major version.
522 * wVerMinor [I] minor version.
523 * lcid [I] locale ID.
524 * ppTLib [O] pointer that receives an ITypeLib object on success.
525 *
526 * RETURNS
527 * Success: S_OK.
528 * Failure: Any HRESULT code returned from QueryPathOfRegTypeLib or
529 * LoadTypeLib.
530 */
531 HRESULT WINAPI LoadRegTypeLib(
532 REFGUID rguid,
533 WORD wVerMajor,
534 WORD wVerMinor,
535 LCID lcid,
536 ITypeLib **ppTLib)
537 {
538 BSTR bstr=NULL;
539 HRESULT res;
540
541 *ppTLib = NULL;
542
543 res = QueryPathOfRegTypeLib( rguid, wVerMajor, wVerMinor, lcid, &bstr);
544
545 if(SUCCEEDED(res))
546 {
547 res= LoadTypeLib(bstr, ppTLib);
548 SysFreeString(bstr);
549
550 if ((wVerMajor!=0xffff || wVerMinor!=0xffff) && *ppTLib)
551 {
552 TLIBATTR *attr;
553
554 res = ITypeLib_GetLibAttr(*ppTLib, &attr);
555 if (res == S_OK)
556 {
557 BOOL mismatch = attr->wMajorVerNum != wVerMajor || attr->wMinorVerNum < wVerMinor;
558 ITypeLib_ReleaseTLibAttr(*ppTLib, attr);
559
560 if (mismatch)
561 {
562 ITypeLib_Release(*ppTLib);
563 *ppTLib = NULL;
564 res = TYPE_E_LIBNOTREGISTERED;
565 }
566 }
567 }
568 }
569
570 TRACE("(IID: %s) load %s (%p)\n",debugstr_guid(rguid), SUCCEEDED(res)? "SUCCESS":"FAILED", *ppTLib);
571
572 return res;
573 }
574
575
576 /* some string constants shared between RegisterTypeLib and UnRegisterTypeLib */
577 static const WCHAR TypeLibW[] = {'T','y','p','e','L','i','b',0};
578 static const WCHAR FLAGSW[] = {'F','L','A','G','S',0};
579 static const WCHAR HELPDIRW[] = {'H','E','L','P','D','I','R',0};
580 static const WCHAR ProxyStubClsidW[] = {'P','r','o','x','y','S','t','u','b','C','l','s','i','d',0};
581 static const WCHAR ProxyStubClsid32W[] = {'P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
582
583 static void TLB_register_interface(TLIBATTR *libattr, LPOLESTR name, TYPEATTR *tattr, DWORD flag)
584 {
585 WCHAR keyName[60];
586 HKEY key, subKey;
587
588 static const WCHAR typelib_proxy_clsid[] = {'{','0','0','0','2','0','4','2','4','-',
589 '0','0','0','0','-','0','0','0','0','-','C','0','0','0','-',
590 '0','0','0','0','0','0','0','0','0','0','4','6','}',0};
591 static const WCHAR dispatch_proxy_clsid[] = {'{','0','0','0','2','0','4','2','0','-',
592 '0','0','0','0','-','0','0','0','0','-','C','0','0','0','-',
593 '0','0','0','0','0','0','0','0','0','0','4','6','}',0};
594
595 get_interface_key( &tattr->guid, keyName );
596 if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0,
597 KEY_WRITE | flag, NULL, &key, NULL) == ERROR_SUCCESS)
598 {
599 const WCHAR *proxy_clsid;
600
601 if (tattr->typekind == TKIND_INTERFACE || (tattr->wTypeFlags & TYPEFLAG_FDUAL))
602 proxy_clsid = typelib_proxy_clsid;
603 else
604 proxy_clsid = dispatch_proxy_clsid;
605
606 if (name)
607 RegSetValueExW(key, NULL, 0, REG_SZ,
608 (BYTE *)name, (lstrlenW(name)+1) * sizeof(OLECHAR));
609
610 if (RegCreateKeyExW(key, ProxyStubClsidW, 0, NULL, 0,
611 KEY_WRITE | flag, NULL, &subKey, NULL) == ERROR_SUCCESS) {
612 RegSetValueExW(subKey, NULL, 0, REG_SZ,
613 (const BYTE *)proxy_clsid, sizeof(typelib_proxy_clsid));
614 RegCloseKey(subKey);
615 }
616
617 if (RegCreateKeyExW(key, ProxyStubClsid32W, 0, NULL, 0,
618 KEY_WRITE | flag, NULL, &subKey, NULL) == ERROR_SUCCESS) {
619 RegSetValueExW(subKey, NULL, 0, REG_SZ,
620 (const BYTE *)proxy_clsid, sizeof(typelib_proxy_clsid));
621 RegCloseKey(subKey);
622 }
623
624 if (RegCreateKeyExW(key, TypeLibW, 0, NULL, 0,
625 KEY_WRITE | flag, NULL, &subKey, NULL) == ERROR_SUCCESS)
626 {
627 WCHAR buffer[40];
628 static const WCHAR fmtver[] = {'%','x','.','%','x',0 };
629 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
630
631 StringFromGUID2(&libattr->guid, buffer, 40);
632 RegSetValueExW(subKey, NULL, 0, REG_SZ,
633 (BYTE *)buffer, (lstrlenW(buffer)+1) * sizeof(WCHAR));
634 swprintf(buffer, fmtver, libattr->wMajorVerNum, libattr->wMinorVerNum);
635 RegSetValueExW(subKey, VersionW, 0, REG_SZ,
636 (BYTE*)buffer, (lstrlenW(buffer)+1) * sizeof(WCHAR));
637 RegCloseKey(subKey);
638 }
639
640 RegCloseKey(key);
641 }
642 }
643
644 /******************************************************************************
645 * RegisterTypeLib [OLEAUT32.163]
646 * Adds information about a type library to the System Registry
647 * NOTES
648 * Docs: ITypeLib FAR * ptlib
649 * Docs: OLECHAR FAR* szFullPath
650 * Docs: OLECHAR FAR* szHelpDir
651 *
652 * RETURNS
653 * Success: S_OK
654 * Failure: Status
655 */
656 HRESULT WINAPI RegisterTypeLib(ITypeLib *ptlib, const WCHAR *szFullPath, const WCHAR *szHelpDir)
657 {
658 HRESULT res;
659 TLIBATTR *attr;
660 WCHAR keyName[60];
661 WCHAR tmp[16];
662 HKEY key, subKey;
663 UINT types, tidx;
664 TYPEKIND kind;
665 DWORD disposition;
666
667 if (ptlib == NULL || szFullPath == NULL)
668 return E_INVALIDARG;
669
670 if (FAILED(ITypeLib_GetLibAttr(ptlib, &attr)))
671 return E_FAIL;
672
673 #ifndef _WIN64
674 if (attr->syskind == SYS_WIN64) return TYPE_E_BADMODULEKIND;
675 #endif
676
677 get_typelib_key( &attr->guid, attr->wMajorVerNum, attr->wMinorVerNum, keyName );
678
679 res = S_OK;
680 if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0,
681 KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS)
682 {
683 LPOLESTR doc;
684
685 /* Set the human-readable name of the typelib */
686 if (FAILED(ITypeLib_GetDocumentation(ptlib, -1, NULL, &doc, NULL, NULL)))
687 res = E_FAIL;
688 else if (doc)
689 {
690 if (RegSetValueExW(key, NULL, 0, REG_SZ,
691 (BYTE *)doc, (lstrlenW(doc)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS)
692 res = E_FAIL;
693
694 SysFreeString(doc);
695 }
696
697 /* Make up the name of the typelib path subkey */
698 if (!get_lcid_subkey( attr->lcid, attr->syskind, tmp )) res = E_FAIL;
699
700 /* Create the typelib path subkey */
701 if (res == S_OK && RegCreateKeyExW(key, tmp, 0, NULL, 0,
702 KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
703 {
704 if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
705 (BYTE *)szFullPath, (lstrlenW(szFullPath)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS)
706 res = E_FAIL;
707
708 RegCloseKey(subKey);
709 }
710 else
711 res = E_FAIL;
712
713 /* Create the flags subkey */
714 if (res == S_OK && RegCreateKeyExW(key, FLAGSW, 0, NULL, 0,
715 KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
716 {
717 /* FIXME: is %u correct? */
718 static const WCHAR formatW[] = {'%','u',0};
719 WCHAR buf[20];
720 swprintf(buf, formatW, attr->wLibFlags);
721 if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
722 (BYTE *)buf, (lstrlenW(buf) + 1)*sizeof(WCHAR) ) != ERROR_SUCCESS)
723 res = E_FAIL;
724
725 RegCloseKey(subKey);
726 }
727 else
728 res = E_FAIL;
729
730 /* create the helpdir subkey */
731 if (res == S_OK && RegCreateKeyExW(key, HELPDIRW, 0, NULL, 0,
732 KEY_WRITE, NULL, &subKey, &disposition) == ERROR_SUCCESS)
733 {
734 BSTR freeHelpDir = NULL;
735 OLECHAR* pIndexStr;
736
737 /* if we created a new key, and helpDir was null, set the helpdir
738 to the directory which contains the typelib. However,
739 if we just opened an existing key, we leave the helpdir alone */
740 if ((disposition == REG_CREATED_NEW_KEY) && (szHelpDir == NULL)) {
741 szHelpDir = freeHelpDir = SysAllocString(szFullPath);
742 pIndexStr = wcsrchr(szHelpDir, '\\');
743 if (pIndexStr) {
744 *pIndexStr = 0;
745 }
746 }
747
748 /* if we have an szHelpDir, set it! */
749 if (szHelpDir != NULL) {
750 if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
751 (BYTE *)szHelpDir, (lstrlenW(szHelpDir)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS) {
752 res = E_FAIL;
753 }
754 }
755
756 SysFreeString(freeHelpDir);
757 RegCloseKey(subKey);
758 } else {
759 res = E_FAIL;
760 }
761
762 RegCloseKey(key);
763 }
764 else
765 res = E_FAIL;
766
767 /* register OLE Automation-compatible interfaces for this typelib */
768 types = ITypeLib_GetTypeInfoCount(ptlib);
769 for (tidx=0; tidx<types; tidx++) {
770 if (SUCCEEDED(ITypeLib_GetTypeInfoType(ptlib, tidx, &kind))) {
771 LPOLESTR name = NULL;
772 ITypeInfo *tinfo = NULL;
773
774 ITypeLib_GetDocumentation(ptlib, tidx, &name, NULL, NULL, NULL);
775
776 switch (kind) {
777 case TKIND_INTERFACE:
778 TRACE_(typelib)("%d: interface %s\n", tidx, debugstr_w(name));
779 ITypeLib_GetTypeInfo(ptlib, tidx, &tinfo);
780 break;
781
782 case TKIND_DISPATCH:
783 TRACE_(typelib)("%d: dispinterface %s\n", tidx, debugstr_w(name));
784 ITypeLib_GetTypeInfo(ptlib, tidx, &tinfo);
785 break;
786
787 default:
788 TRACE_(typelib)("%d: %s\n", tidx, debugstr_w(name));
789 break;
790 }
791
792 if (tinfo) {
793 TYPEATTR *tattr = NULL;
794 ITypeInfo_GetTypeAttr(tinfo, &tattr);
795
796 if (tattr) {
797 TRACE_(typelib)("guid=%s, flags=%04x (",
798 debugstr_guid(&tattr->guid),
799 tattr->wTypeFlags);
800
801 if (TRACE_ON(typelib)) {
802 #define XX(x) if (TYPEFLAG_##x & tattr->wTypeFlags) MESSAGE(#x"|");
803 XX(FAPPOBJECT);
804 XX(FCANCREATE);
805 XX(FLICENSED);
806 XX(FPREDECLID);
807 XX(FHIDDEN);
808 XX(FCONTROL);
809 XX(FDUAL);
810 XX(FNONEXTENSIBLE);
811 XX(FOLEAUTOMATION);
812 XX(FRESTRICTED);
813 XX(FAGGREGATABLE);
814 XX(FREPLACEABLE);
815 XX(FDISPATCHABLE);
816 XX(FREVERSEBIND);
817 XX(FPROXY);
818 #undef XX
819 MESSAGE("\n");
820 }
821
822 /* Register all dispinterfaces (which includes dual interfaces) and
823 oleautomation interfaces */
824 if ((kind == TKIND_INTERFACE && (tattr->wTypeFlags & TYPEFLAG_FOLEAUTOMATION)) ||
825 kind == TKIND_DISPATCH)
826 {
827 BOOL is_wow64;
828 DWORD opposite = (sizeof(void*) == 8 ? KEY_WOW64_32KEY : KEY_WOW64_64KEY);
829
830 /* register interface<->typelib coupling */
831 TLB_register_interface(attr, name, tattr, 0);
832
833 /* register TLBs into the opposite registry view, too */
834 if(opposite == KEY_WOW64_32KEY ||
835 (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64))
836 TLB_register_interface(attr, name, tattr, opposite);
837 }
838
839 ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
840 }
841
842 ITypeInfo_Release(tinfo);
843 }
844
845 SysFreeString(name);
846 }
847 }
848
849 ITypeLib_ReleaseTLibAttr(ptlib, attr);
850
851 return res;
852 }
853
854 static void TLB_unregister_interface(GUID *guid, REGSAM flag)
855 {
856 WCHAR subKeyName[50];
857 HKEY subKey;
858
859 /* the path to the type */
860 get_interface_key( guid, subKeyName );
861
862 /* Delete its bits */
863 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, subKeyName, 0, KEY_WRITE | flag, &subKey) != ERROR_SUCCESS)
864 return;
865
866 RegDeleteKeyW(subKey, ProxyStubClsidW);
867 RegDeleteKeyW(subKey, ProxyStubClsid32W);
868 RegDeleteKeyW(subKey, TypeLibW);
869 RegCloseKey(subKey);
870 RegDeleteKeyExW(HKEY_CLASSES_ROOT, subKeyName, flag, 0);
871 }
872
873 /******************************************************************************
874 * UnRegisterTypeLib [OLEAUT32.186]
875 * Removes information about a type library from the System Registry
876 * NOTES
877 *
878 * RETURNS
879 * Success: S_OK
880 * Failure: Status
881 */
882 HRESULT WINAPI UnRegisterTypeLib(
883 REFGUID libid, /* [in] Guid of the library */
884 WORD wVerMajor, /* [in] major version */
885 WORD wVerMinor, /* [in] minor version */
886 LCID lcid, /* [in] locale id */
887 SYSKIND syskind)
888 {
889 BSTR tlibPath = NULL;
890 DWORD tmpLength;
891 WCHAR keyName[60];
892 WCHAR subKeyName[50];
893 int result = S_OK;
894 DWORD i = 0;
895 BOOL deleteOtherStuff;
896 HKEY key = NULL;
897 TYPEATTR* typeAttr = NULL;
898 TYPEKIND kind;
899 ITypeInfo* typeInfo = NULL;
900 ITypeLib* typeLib = NULL;
901 int numTypes;
902
903 TRACE("(IID: %s)\n",debugstr_guid(libid));
904
905 /* Create the path to the key */
906 get_typelib_key( libid, wVerMajor, wVerMinor, keyName );
907
908 if (syskind != SYS_WIN16 && syskind != SYS_WIN32 && syskind != SYS_WIN64)
909 {
910 TRACE("Unsupported syskind %i\n", syskind);
911 result = E_INVALIDARG;
912 goto end;
913 }
914
915 /* get the path to the typelib on disk */
916 if (query_typelib_path(libid, wVerMajor, wVerMinor, syskind, lcid, &tlibPath, FALSE) != S_OK) {
917 result = E_INVALIDARG;
918 goto end;
919 }
920
921 /* Try and open the key to the type library. */
922 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, keyName, 0, KEY_READ | KEY_WRITE, &key) != ERROR_SUCCESS) {
923 result = E_INVALIDARG;
924 goto end;
925 }
926
927 /* Try and load the type library */
928 if (LoadTypeLibEx(tlibPath, REGKIND_NONE, &typeLib) != S_OK) {
929 result = TYPE_E_INVALIDSTATE;
930 goto end;
931 }
932
933 /* remove any types registered with this typelib */
934 numTypes = ITypeLib_GetTypeInfoCount(typeLib);
935 for (i=0; i<numTypes; i++) {
936 /* get the kind of type */
937 if (ITypeLib_GetTypeInfoType(typeLib, i, &kind) != S_OK) {
938 goto enddeleteloop;
939 }
940
941 /* skip non-interfaces, and get type info for the type */
942 if ((kind != TKIND_INTERFACE) && (kind != TKIND_DISPATCH)) {
943 goto enddeleteloop;
944 }
945 if (ITypeLib_GetTypeInfo(typeLib, i, &typeInfo) != S_OK) {
946 goto enddeleteloop;
947 }
948 if (ITypeInfo_GetTypeAttr(typeInfo, &typeAttr) != S_OK) {
949 goto enddeleteloop;
950 }
951
952 if ((kind == TKIND_INTERFACE && (typeAttr->wTypeFlags & TYPEFLAG_FOLEAUTOMATION)) ||
953 kind == TKIND_DISPATCH)
954 {
955 BOOL is_wow64;
956 REGSAM opposite = (sizeof(void*) == 8 ? KEY_WOW64_32KEY : KEY_WOW64_64KEY);
957
958 TLB_unregister_interface(&typeAttr->guid, 0);
959
960 /* unregister TLBs into the opposite registry view, too */
961 if(opposite == KEY_WOW64_32KEY ||
962 (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)) {
963 TLB_unregister_interface(&typeAttr->guid, opposite);
964 }
965 }
966
967 enddeleteloop:
968 if (typeAttr) ITypeInfo_ReleaseTypeAttr(typeInfo, typeAttr);
969 typeAttr = NULL;
970 if (typeInfo) ITypeInfo_Release(typeInfo);
971 typeInfo = NULL;
972 }
973
974 /* Now, delete the type library path subkey */
975 get_lcid_subkey( lcid, syskind, subKeyName );
976 RegDeleteKeyW(key, subKeyName);
977 *wcsrchr( subKeyName, '\\' ) = 0; /* remove last path component */
978 RegDeleteKeyW(key, subKeyName);
979
980 /* check if there is anything besides the FLAGS/HELPDIR keys.
981 If there is, we don't delete them */
982 tmpLength = ARRAY_SIZE(subKeyName);
983 deleteOtherStuff = TRUE;
984 i = 0;
985 while(RegEnumKeyExW(key, i++, subKeyName, &tmpLength, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
986 tmpLength = ARRAY_SIZE(subKeyName);
987
988 /* if its not FLAGS or HELPDIR, then we must keep the rest of the key */
989 if (!wcscmp(subKeyName, FLAGSW)) continue;
990 if (!wcscmp(subKeyName, HELPDIRW)) continue;
991 deleteOtherStuff = FALSE;
992 break;
993 }
994
995 /* only delete the other parts of the key if we're absolutely sure */
996 if (deleteOtherStuff) {
997 RegDeleteKeyW(key, FLAGSW);
998 RegDeleteKeyW(key, HELPDIRW);
999 RegCloseKey(key);
1000 key = NULL;
1001
1002 RegDeleteKeyW(HKEY_CLASSES_ROOT, keyName);
1003 *wcsrchr( keyName, '\\' ) = 0; /* remove last path component */
1004 RegDeleteKeyW(HKEY_CLASSES_ROOT, keyName);
1005 }
1006
1007 end:
1008 SysFreeString(tlibPath);
1009 if (typeLib) ITypeLib_Release(typeLib);
1010 if (key) RegCloseKey(key);
1011 return result;
1012 }
1013
1014 /******************************************************************************
1015 * RegisterTypeLibForUser [OLEAUT32.442]
1016 * Adds information about a type library to the user registry
1017 * NOTES
1018 * Docs: ITypeLib FAR * ptlib
1019 * Docs: OLECHAR FAR* szFullPath
1020 * Docs: OLECHAR FAR* szHelpDir
1021 *
1022 * RETURNS
1023 * Success: S_OK
1024 * Failure: Status
1025 */
1026 HRESULT WINAPI RegisterTypeLibForUser(
1027 ITypeLib * ptlib, /* [in] Pointer to the library*/
1028 OLECHAR * szFullPath, /* [in] full Path of the library*/
1029 OLECHAR * szHelpDir) /* [in] dir to the helpfile for the library,
1030 may be NULL*/
1031 {
1032 FIXME("(%p, %s, %s) registering the typelib system-wide\n", ptlib,
1033 debugstr_w(szFullPath), debugstr_w(szHelpDir));
1034 return RegisterTypeLib(ptlib, szFullPath, szHelpDir);
1035 }
1036
1037 /******************************************************************************
1038 * UnRegisterTypeLibForUser [OLEAUT32.443]
1039 * Removes information about a type library from the user registry
1040 *
1041 * RETURNS
1042 * Success: S_OK
1043 * Failure: Status
1044 */
1045 HRESULT WINAPI UnRegisterTypeLibForUser(
1046 REFGUID libid, /* [in] GUID of the library */
1047 WORD wVerMajor, /* [in] major version */
1048 WORD wVerMinor, /* [in] minor version */
1049 LCID lcid, /* [in] locale id */
1050 SYSKIND syskind)
1051 {
1052 FIXME("(%s, %u, %u, %u, %u) unregistering the typelib system-wide\n",
1053 debugstr_guid(libid), wVerMajor, wVerMinor, lcid, syskind);
1054 return UnRegisterTypeLib(libid, wVerMajor, wVerMinor, lcid, syskind);
1055 }
1056
1057 /*======================= ITypeLib implementation =======================*/
1058
1059 typedef struct tagTLBGuid {
1060 GUID guid;
1061 INT hreftype;
1062 UINT offset;
1063 struct list entry;
1064 } TLBGuid;
1065
1066 typedef struct tagTLBCustData
1067 {
1068 TLBGuid *guid;
1069 VARIANT data;
1070 struct list entry;
1071 } TLBCustData;
1072
1073 /* data structure for import typelibs */
1074 typedef struct tagTLBImpLib
1075 {
1076 int offset; /* offset in the file (MSFT)
1077 offset in nametable (SLTG)
1078 just used to identify library while reading
1079 data from file */
1080 TLBGuid *guid; /* libid */
1081 BSTR name; /* name */
1082
1083 LCID lcid; /* lcid of imported typelib */
1084
1085 WORD wVersionMajor; /* major version number */
1086 WORD wVersionMinor; /* minor version number */
1087
1088 struct tagITypeLibImpl *pImpTypeLib; /* pointer to loaded typelib, or
1089 NULL if not yet loaded */
1090 struct list entry;
1091 } TLBImpLib;
1092
1093 typedef struct tagTLBString {
1094 BSTR str;
1095 UINT offset;
1096 struct list entry;
1097 } TLBString;
1098
1099 /* internal ITypeLib data */
1100 typedef struct tagITypeLibImpl
1101 {
1102 ITypeLib2 ITypeLib2_iface;
1103 ITypeComp ITypeComp_iface;
1104 ICreateTypeLib2 ICreateTypeLib2_iface;
1105 LONG ref;
1106 TLBGuid *guid;
1107 LCID lcid;
1108 SYSKIND syskind;
1109 int ptr_size;
1110 WORD ver_major;
1111 WORD ver_minor;
1112 WORD libflags;
1113 LCID set_lcid;
1114
1115 /* strings can be stored in tlb as multibyte strings BUT they are *always*
1116 * exported to the application as a UNICODE string.
1117 */
1118 struct list string_list;
1119 struct list name_list;
1120 struct list guid_list;
1121
1122 const TLBString *Name;
1123 const TLBString *DocString;
1124 const TLBString *HelpFile;
1125 const TLBString *HelpStringDll;
1126 DWORD dwHelpContext;
1127 int TypeInfoCount; /* nr of typeinfo's in librarry */
1128 struct tagITypeInfoImpl **typeinfos;
1129 struct list custdata_list;
1130 struct list implib_list;
1131 int ctTypeDesc; /* number of items in type desc array */
1132 TYPEDESC * pTypeDesc; /* array of TypeDescriptions found in the
1133 library. Only used while reading MSFT
1134 typelibs */
1135 struct list ref_list; /* list of ref types in this typelib */
1136 HREFTYPE dispatch_href; /* reference to IDispatch, -1 if unused */
1137
1138
1139 /* typelibs are cached, keyed by path and index, so store the linked list info within them */
1140 struct list entry;
1141 WCHAR *path;
1142 INT index;
1143 } ITypeLibImpl;
1144
1145 static const ITypeLib2Vtbl tlbvt;
1146 static const ITypeCompVtbl tlbtcvt;
1147 static const ICreateTypeLib2Vtbl CreateTypeLib2Vtbl;
1148
1149 static inline ITypeLibImpl *impl_from_ITypeLib2(ITypeLib2 *iface)
1150 {
1151 return CONTAINING_RECORD(iface, ITypeLibImpl, ITypeLib2_iface);
1152 }
1153
1154 static inline ITypeLibImpl *impl_from_ITypeLib(ITypeLib *iface)
1155 {
1156 return impl_from_ITypeLib2((ITypeLib2*)iface);
1157 }
1158
1159 static inline ITypeLibImpl *impl_from_ITypeComp( ITypeComp *iface )
1160 {
1161 return CONTAINING_RECORD(iface, ITypeLibImpl, ITypeComp_iface);
1162 }
1163
1164 static inline ITypeLibImpl *impl_from_ICreateTypeLib2( ICreateTypeLib2 *iface )
1165 {
1166 return CONTAINING_RECORD(iface, ITypeLibImpl, ICreateTypeLib2_iface);
1167 }
1168
1169 /* ITypeLib methods */
1170 static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength);
1171 static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength);
1172
1173 /*======================= ITypeInfo implementation =======================*/
1174
1175 /* data for referenced types */
1176 typedef struct tagTLBRefType
1177 {
1178 INT index; /* Type index for internal ref or for external ref
1179 it the format is SLTG. -2 indicates to
1180 use guid */
1181
1182 TYPEKIND tkind;
1183 TLBGuid *guid; /* guid of the referenced type */
1184 /* if index == TLB_REF_USE_GUID */
1185
1186 HREFTYPE reference; /* The href of this ref */
1187 TLBImpLib *pImpTLInfo; /* If ref is external ptr to library data
1188 TLB_REF_INTERNAL for internal refs
1189 TLB_REF_NOT_FOUND for broken refs */
1190
1191 struct list entry;
1192 } TLBRefType;
1193
1194 #define TLB_REF_USE_GUID -2
1195
1196 #define TLB_REF_INTERNAL (void*)-2
1197 #define TLB_REF_NOT_FOUND (void*)-1
1198
1199 /* internal Parameter data */
1200 typedef struct tagTLBParDesc
1201 {
1202 const TLBString *Name;
1203 struct list custdata_list;
1204 } TLBParDesc;
1205
1206 /* internal Function data */
1207 typedef struct tagTLBFuncDesc
1208 {
1209 FUNCDESC funcdesc; /* lots of info on the function and its attributes. */
1210 const TLBString *Name; /* the name of this function */
1211 TLBParDesc *pParamDesc; /* array with param names and custom data */
1212 int helpcontext;
1213 int HelpStringContext;
1214 const TLBString *HelpString;
1215 const TLBString *Entry; /* if IS_INTRESOURCE true, it's numeric; if -1 it isn't present */
1216 struct list custdata_list;
1217 } TLBFuncDesc;
1218
1219 /* internal Variable data */
1220 typedef struct tagTLBVarDesc
1221 {
1222 VARDESC vardesc; /* lots of info on the variable and its attributes. */
1223 VARDESC *vardesc_create; /* additional data needed for storing VARDESC */
1224 const TLBString *Name; /* the name of this variable */
1225 int HelpContext;
1226 int HelpStringContext;
1227 const TLBString *HelpString;
1228 struct list custdata_list;
1229 } TLBVarDesc;
1230
1231 /* internal implemented interface data */
1232 typedef struct tagTLBImplType
1233 {
1234 HREFTYPE hRef; /* hRef of interface */
1235 int implflags; /* IMPLFLAG_*s */
1236 struct list custdata_list;
1237 } TLBImplType;
1238
1239 /* internal TypeInfo data */
1240 typedef struct tagITypeInfoImpl
1241 {
1242 ITypeInfo2 ITypeInfo2_iface;
1243 ITypeComp ITypeComp_iface;
1244 ICreateTypeInfo2 ICreateTypeInfo2_iface;
1245 LONG ref;
1246 BOOL not_attached_to_typelib;
1247 BOOL needs_layout;
1248
1249 TLBGuid *guid;
1250 TYPEATTR typeattr;
1251 TYPEDESC *tdescAlias;
1252
1253 ITypeLibImpl * pTypeLib; /* back pointer to typelib */
1254 int index; /* index in this typelib; */
1255 HREFTYPE hreftype; /* hreftype for app object binding */
1256 /* type libs seem to store the doc strings in ascii
1257 * so why should we do it in unicode?
1258 */
1259 const TLBString *Name;
1260 const TLBString *DocString;
1261 const TLBString *DllName;
1262 const TLBString *Schema;
1263 DWORD dwHelpContext;
1264 DWORD dwHelpStringContext;
1265
1266 /* functions */
1267 TLBFuncDesc *funcdescs;
1268
1269 /* variables */
1270 TLBVarDesc *vardescs;
1271
1272 /* Implemented Interfaces */
1273 TLBImplType *impltypes;
1274
1275 struct list *pcustdata_list;
1276 struct list custdata_list;
1277 } ITypeInfoImpl;
1278
1279 static inline ITypeInfoImpl *info_impl_from_ITypeComp( ITypeComp *iface )
1280 {
1281 return CONTAINING_RECORD(iface, ITypeInfoImpl, ITypeComp_iface);
1282 }
1283
1284 static inline ITypeInfoImpl *impl_from_ITypeInfo2( ITypeInfo2 *iface )
1285 {
1286 return CONTAINING_RECORD(iface, ITypeInfoImpl, ITypeInfo2_iface);
1287 }
1288
1289 static inline ITypeInfoImpl *impl_from_ITypeInfo( ITypeInfo *iface )
1290 {
1291 return impl_from_ITypeInfo2((ITypeInfo2*)iface);
1292 }
1293
1294 static inline ITypeInfoImpl *info_impl_from_ICreateTypeInfo2( ICreateTypeInfo2 *iface )
1295 {
1296 return CONTAINING_RECORD(iface, ITypeInfoImpl, ICreateTypeInfo2_iface);
1297 }
1298
1299 static const ITypeInfo2Vtbl tinfvt;
1300 static const ITypeCompVtbl tcompvt;
1301 static const ICreateTypeInfo2Vtbl CreateTypeInfo2Vtbl;
1302
1303 static ITypeInfoImpl* ITypeInfoImpl_Constructor(void);
1304 static void ITypeInfoImpl_Destroy(ITypeInfoImpl *This);
1305
1306 typedef struct tagTLBContext
1307 {
1308 unsigned int oStart; /* start of TLB in file */
1309 unsigned int pos; /* current pos */
1310 unsigned int length; /* total length */
1311 void *mapping; /* memory mapping */
1312 MSFT_SegDir * pTblDir;
1313 ITypeLibImpl* pLibInfo;
1314 } TLBContext;
1315
1316
1317 static inline BSTR TLB_get_bstr(const TLBString *str)
1318 {
1319 return str != NULL ? str->str : NULL;
1320 }
1321
1322 static inline int TLB_str_memcmp(void *left, const TLBString *str, DWORD len)
1323 {
1324 if(!str)
1325 return 1;
1326 return memcmp(left, str->str, len);
1327 }
1328
1329 static inline const GUID *TLB_get_guidref(const TLBGuid *guid)
1330 {
1331 return guid != NULL ? &guid->guid : NULL;
1332 }
1333
1334 static inline const GUID *TLB_get_guid_null(const TLBGuid *guid)
1335 {
1336 return guid != NULL ? &guid->guid : &GUID_NULL;
1337 }
1338
1339 static int get_ptr_size(SYSKIND syskind)
1340 {
1341 switch(syskind){
1342 case SYS_WIN64:
1343 return 8;
1344 case SYS_WIN32:
1345 case SYS_MAC:
1346 case SYS_WIN16:
1347 return 4;
1348 }
1349 WARN("Unhandled syskind: 0x%x\n", syskind);
1350 return 4;
1351 }
1352
1353 /*
1354 debug
1355 */
1356 static void dump_TypeDesc(const TYPEDESC *pTD,char *szVarType) {
1357 if (pTD->vt & VT_RESERVED)
1358 szVarType += strlen(strcpy(szVarType, "reserved | "));
1359 if (pTD->vt & VT_BYREF)
1360 szVarType += strlen(strcpy(szVarType, "ref to "));
1361 if (pTD->vt & VT_ARRAY)
1362 szVarType += strlen(strcpy(szVarType, "array of "));
1363 if (pTD->vt & VT_VECTOR)
1364 szVarType += strlen(strcpy(szVarType, "vector of "));
1365 switch(pTD->vt & VT_TYPEMASK) {
1366 case VT_UI1: sprintf(szVarType, "VT_UI1"); break;
1367 case VT_I2: sprintf(szVarType, "VT_I2"); break;
1368 case VT_I4: sprintf(szVarType, "VT_I4"); break;
1369 case VT_R4: sprintf(szVarType, "VT_R4"); break;
1370 case VT_R8: sprintf(szVarType, "VT_R8"); break;
1371 case VT_BOOL: sprintf(szVarType, "VT_BOOL"); break;
1372 case VT_ERROR: sprintf(szVarType, "VT_ERROR"); break;
1373 case VT_CY: sprintf(szVarType, "VT_CY"); break;
1374 case VT_DATE: sprintf(szVarType, "VT_DATE"); break;
1375 case VT_BSTR: sprintf(szVarType, "VT_BSTR"); break;
1376 case VT_UNKNOWN: sprintf(szVarType, "VT_UNKNOWN"); break;
1377 case VT_DISPATCH: sprintf(szVarType, "VT_DISPATCH"); break;
1378 case VT_I1: sprintf(szVarType, "VT_I1"); break;
1379 case VT_UI2: sprintf(szVarType, "VT_UI2"); break;
1380 case VT_UI4: sprintf(szVarType, "VT_UI4"); break;
1381 case VT_INT: sprintf(szVarType, "VT_INT"); break;
1382 case VT_UINT: sprintf(szVarType, "VT_UINT"); break;
1383 case VT_VARIANT: sprintf(szVarType, "VT_VARIANT"); break;
1384 case VT_VOID: sprintf(szVarType, "VT_VOID"); break;
1385 case VT_HRESULT: sprintf(szVarType, "VT_HRESULT"); break;
1386 case VT_USERDEFINED: sprintf(szVarType, "VT_USERDEFINED ref = %x",
1387 pTD->u.hreftype); break;
1388 case VT_LPSTR: sprintf(szVarType, "VT_LPSTR"); break;
1389 case VT_LPWSTR: sprintf(szVarType, "VT_LPWSTR"); break;
1390 case VT_PTR: sprintf(szVarType, "ptr to ");
1391 dump_TypeDesc(pTD->u.lptdesc, szVarType + 7);
1392 break;
1393 case VT_SAFEARRAY: sprintf(szVarType, "safearray of ");
1394 dump_TypeDesc(pTD->u.lptdesc, szVarType + 13);
1395 break;
1396 case VT_CARRAY: sprintf(szVarType, "%d dim array of ",
1397 pTD->u.lpadesc->cDims); /* FIXME print out sizes */
1398 dump_TypeDesc(&pTD->u.lpadesc->tdescElem, szVarType + strlen(szVarType));
1399 break;
1400
1401 default: sprintf(szVarType, "unknown(%d)", pTD->vt & VT_TYPEMASK); break;
1402 }
1403 }
1404
1405 static void dump_ELEMDESC(const ELEMDESC *edesc) {
1406 char buf[200];
1407 USHORT flags = edesc->u.paramdesc.wParamFlags;
1408 dump_TypeDesc(&edesc->tdesc,buf);
1409 MESSAGE("\t\ttdesc.vartype %d (%s)\n",edesc->tdesc.vt,buf);
1410 MESSAGE("\t\tu.paramdesc.wParamFlags");
1411 if (!flags) MESSAGE(" PARAMFLAGS_NONE");
1412 if (flags & PARAMFLAG_FIN) MESSAGE(" PARAMFLAG_FIN");
1413 if (flags & PARAMFLAG_FOUT) MESSAGE(" PARAMFLAG_FOUT");
1414 if (flags & PARAMFLAG_FLCID) MESSAGE(" PARAMFLAG_FLCID");
1415 if (flags & PARAMFLAG_FRETVAL) MESSAGE(" PARAMFLAG_FRETVAL");
1416 if (flags & PARAMFLAG_FOPT) MESSAGE(" PARAMFLAG_FOPT");
1417 if (flags & PARAMFLAG_FHASDEFAULT) MESSAGE(" PARAMFLAG_FHASDEFAULT");
1418 if (flags & PARAMFLAG_FHASCUSTDATA) MESSAGE(" PARAMFLAG_FHASCUSTDATA");
1419 MESSAGE("\n\t\tu.paramdesc.lpex %p\n",edesc->u.paramdesc.pparamdescex);
1420 }
1421 static void dump_FUNCDESC(const FUNCDESC *funcdesc) {
1422 int i;
1423 MESSAGE("memid is %08x\n",funcdesc->memid);
1424 for (i=0;i<funcdesc->cParams;i++) {
1425 MESSAGE("Param %d:\n",i);
1426 dump_ELEMDESC(funcdesc->lprgelemdescParam+i);
1427 }
1428 MESSAGE("\tfunckind: %d (",funcdesc->funckind);
1429 switch (funcdesc->funckind) {
1430 case FUNC_VIRTUAL: MESSAGE("virtual");break;
1431 case FUNC_PUREVIRTUAL: MESSAGE("pure virtual");break;
1432 case FUNC_NONVIRTUAL: MESSAGE("nonvirtual");break;
1433 case FUNC_STATIC: MESSAGE("static");break;
1434 case FUNC_DISPATCH: MESSAGE("dispatch");break;
1435 default: MESSAGE("unknown");break;
1436 }
1437 MESSAGE(")\n\tinvkind: %d (",funcdesc->invkind);
1438 switch (funcdesc->invkind) {
1439 case INVOKE_FUNC: MESSAGE("func");break;
1440 case INVOKE_PROPERTYGET: MESSAGE("property get");break;
1441 case INVOKE_PROPERTYPUT: MESSAGE("property put");break;
1442 case INVOKE_PROPERTYPUTREF: MESSAGE("property put ref");break;
1443 }
1444 MESSAGE(")\n\tcallconv: %d (",funcdesc->callconv);
1445 switch (funcdesc->callconv) {
1446 case CC_CDECL: MESSAGE("cdecl");break;
1447 case CC_PASCAL: MESSAGE("pascal");break;
1448 case CC_STDCALL: MESSAGE("stdcall");break;
1449 case CC_SYSCALL: MESSAGE("syscall");break;
1450 default:break;
1451 }
1452 MESSAGE(")\n\toVft: %d\n", funcdesc->oVft);
1453 MESSAGE("\tcParamsOpt: %d\n", funcdesc->cParamsOpt);
1454 MESSAGE("\twFlags: %x\n", funcdesc->wFuncFlags);
1455
1456 MESSAGE("\telemdescFunc (return value type):\n");
1457 dump_ELEMDESC(&funcdesc->elemdescFunc);
1458 }
1459
1460 static const char * const typekind_desc[] =
1461 {
1462 "TKIND_ENUM",
1463 "TKIND_RECORD",
1464 "TKIND_MODULE",
1465 "TKIND_INTERFACE",
1466 "TKIND_DISPATCH",
1467 "TKIND_COCLASS",
1468 "TKIND_ALIAS",
1469 "TKIND_UNION",
1470 "TKIND_MAX"
1471 };
1472
1473 static void dump_TLBFuncDescOne(const TLBFuncDesc * pfd)
1474 {
1475 int i;
1476 MESSAGE("%s(%u)\n", debugstr_w(TLB_get_bstr(pfd->Name)), pfd->funcdesc.cParams);
1477 for (i=0;i<pfd->funcdesc.cParams;i++)
1478 MESSAGE("\tparm%d: %s\n",i,debugstr_w(TLB_get_bstr(pfd->pParamDesc[i].Name)));
1479
1480
1481 dump_FUNCDESC(&(pfd->funcdesc));
1482
1483 MESSAGE("\thelpstring: %s\n", debugstr_w(TLB_get_bstr(pfd->HelpString)));
1484 if(pfd->Entry == NULL)
1485 MESSAGE("\tentry: (null)\n");
1486 else if(pfd->Entry == (void*)-1)
1487 MESSAGE("\tentry: invalid\n");
1488 else if(IS_INTRESOURCE(pfd->Entry))
1489 MESSAGE("\tentry: %p\n", pfd->Entry);
1490 else
1491 MESSAGE("\tentry: %s\n", debugstr_w(TLB_get_bstr(pfd->Entry)));
1492 }
1493 static void dump_TLBFuncDesc(const TLBFuncDesc * pfd, UINT n)
1494 {
1495 while (n)
1496 {
1497 dump_TLBFuncDescOne(pfd);
1498 ++pfd;
1499 --n;
1500 }
1501 }
1502 static void dump_TLBVarDesc(const TLBVarDesc * pvd, UINT n)
1503 {
1504 while (n)
1505 {
1506 TRACE_(typelib)("%s\n", debugstr_w(TLB_get_bstr(pvd->Name)));
1507 ++pvd;
1508 --n;
1509 }
1510 }
1511
1512 static void dump_TLBImpLib(const TLBImpLib *import)
1513 {
1514 TRACE_(typelib)("%s %s\n", debugstr_guid(TLB_get_guidref(import->guid)),
1515 debugstr_w(import->name));
1516 TRACE_(typelib)("v%d.%d lcid=%x offset=%x\n", import->wVersionMajor,
1517 import->wVersionMinor, import->lcid, import->offset);
1518 }
1519
1520 static void dump_TLBRefType(const ITypeLibImpl *pTL)
1521 {
1522 TLBRefType *ref;
1523
1524 LIST_FOR_EACH_ENTRY(ref, &pTL->ref_list, TLBRefType, entry)
1525 {
1526 TRACE_(typelib)("href:0x%08x\n", ref->reference);
1527 if(ref->index == -1)
1528 TRACE_(typelib)("%s\n", debugstr_guid(TLB_get_guidref(ref->guid)));
1529 else
1530 TRACE_(typelib)("type no: %d\n", ref->index);
1531
1532 if(ref->pImpTLInfo != TLB_REF_INTERNAL && ref->pImpTLInfo != TLB_REF_NOT_FOUND)
1533 {
1534 TRACE_(typelib)("in lib\n");
1535 dump_TLBImpLib(ref->pImpTLInfo);
1536 }
1537 }
1538 }
1539
1540 static void dump_TLBImplType(const TLBImplType * impl, UINT n)
1541 {
1542 if(!impl)
1543 return;
1544 while (n) {
1545 TRACE_(typelib)("implementing/inheriting interface hRef = %x implflags %x\n",
1546 impl->hRef, impl->implflags);
1547 ++impl;
1548 --n;
1549 }
1550 }
1551
1552 static void dump_DispParms(const DISPPARAMS * pdp)
1553 {
1554 unsigned int index;
1555
1556 TRACE("args=%u named args=%u\n", pdp->cArgs, pdp->cNamedArgs);
1557
1558 if (pdp->cNamedArgs && pdp->rgdispidNamedArgs)
1559 {
1560 TRACE("named args:\n");
1561 for (index = 0; index < pdp->cNamedArgs; index++)
1562 TRACE( "\t0x%x\n", pdp->rgdispidNamedArgs[index] );
1563 }
1564
1565 if (pdp->cArgs && pdp->rgvarg)
1566 {
1567 TRACE("args:\n");
1568 for (index = 0; index < pdp->cArgs; index++)
1569 TRACE(" [%d] %s\n", index, debugstr_variant(pdp->rgvarg+index));
1570 }
1571 }
1572
1573 static void dump_TypeInfo(const ITypeInfoImpl * pty)
1574 {
1575 TRACE("%p ref=%u\n", pty, pty->ref);
1576 TRACE("%s %s\n", debugstr_w(TLB_get_bstr(pty->Name)), debugstr_w(TLB_get_bstr(pty->DocString)));
1577 TRACE("attr:%s\n", debugstr_guid(TLB_get_guidref(pty->guid)));
1578 TRACE("kind:%s\n", typekind_desc[pty->typeattr.typekind]);
1579 TRACE("fct:%u var:%u impl:%u\n", pty->typeattr.cFuncs, pty->typeattr.cVars, pty->typeattr.cImplTypes);
1580 TRACE("wTypeFlags: 0x%04x\n", pty->typeattr.wTypeFlags);
1581 TRACE("parent tlb:%p index in TLB:%u\n",pty->pTypeLib, pty->index);
1582 if (pty->typeattr.typekind == TKIND_MODULE) TRACE("dllname:%s\n", debugstr_w(TLB_get_bstr(pty->DllName)));
1583 if (TRACE_ON(ole))
1584 dump_TLBFuncDesc(pty->funcdescs, pty->typeattr.cFuncs);
1585 dump_TLBVarDesc(pty->vardescs, pty->typeattr.cVars);
1586 dump_TLBImplType(pty->impltypes, pty->typeattr.cImplTypes);
1587 }
1588
1589 static void dump_VARDESC(const VARDESC *v)
1590 {
1591 MESSAGE("memid %d\n",v->memid);
1592 MESSAGE("lpstrSchema %s\n",debugstr_w(v->lpstrSchema));
1593 MESSAGE("oInst %d\n",v->u.oInst);
1594 dump_ELEMDESC(&(v->elemdescVar));
1595 MESSAGE("wVarFlags %x\n",v->wVarFlags);
1596 MESSAGE("varkind %d\n",v->varkind);
1597 }
1598
1599 static TYPEDESC std_typedesc[VT_LPWSTR+1] =
1600 {
1601 /* VT_LPWSTR is largest type that, may appear in type description */
1602 {{0}, VT_EMPTY}, {{0}, VT_NULL}, {{0}, VT_I2}, {{0}, VT_I4},
1603 {{0}, VT_R4}, {{0}, VT_R8}, {{0}, VT_CY}, {{0}, VT_DATE},
1604 {{0}, VT_BSTR}, {{0}, VT_DISPATCH}, {{0}, VT_ERROR}, {{0}, VT_BOOL},
1605 {{0}, VT_VARIANT},{{0}, VT_UNKNOWN}, {{0}, VT_DECIMAL}, {{0}, 15}, /* unused in VARENUM */
1606 {{0}, VT_I1}, {{0}, VT_UI1}, {{0}, VT_UI2}, {{0}, VT_UI4},
1607 {{0}, VT_I8}, {{0}, VT_UI8}, {{0}, VT_INT}, {{0}, VT_UINT},
1608 {{0}, VT_VOID}, {{0}, VT_HRESULT}, {{0}, VT_PTR}, {{0}, VT_SAFEARRAY},
1609 {{0}, VT_CARRAY}, {{0}, VT_USERDEFINED}, {{0}, VT_LPSTR}, {{0}, VT_LPWSTR}
1610 };
1611
1612 static void TLB_abort(void)
1613 {
1614 DebugBreak();
1615 }
1616
1617 /* returns the size required for a deep copy of a typedesc into a
1618 * flat buffer */
1619 static SIZE_T TLB_SizeTypeDesc( const TYPEDESC *tdesc, BOOL alloc_initial_space )
1620 {
1621 SIZE_T size = 0;
1622
1623 if (alloc_initial_space)
1624 size += sizeof(TYPEDESC);
1625
1626 switch (tdesc->vt)
1627 {
1628 case VT_PTR:
1629 case VT_SAFEARRAY:
1630 size += TLB_SizeTypeDesc(tdesc->u.lptdesc, TRUE);
1631 break;
1632 case VT_CARRAY:
1633 size += FIELD_OFFSET(ARRAYDESC, rgbounds[tdesc->u.lpadesc->cDims]);
1634 size += TLB_SizeTypeDesc(&tdesc->u.lpadesc->tdescElem, FALSE);
1635 break;
1636 }
1637 return size;
1638 }
1639
1640 /* deep copy a typedesc into a flat buffer */
1641 static void *TLB_CopyTypeDesc( TYPEDESC *dest, const TYPEDESC *src, void *buffer )
1642 {
1643 if (!dest)
1644 {
1645 dest = buffer;
1646 buffer = (char *)buffer + sizeof(TYPEDESC);
1647 }
1648
1649 *dest = *src;
1650
1651 switch (src->vt)
1652 {
1653 case VT_PTR:
1654 case VT_SAFEARRAY:
1655 dest->u.lptdesc = buffer;
1656 buffer = TLB_CopyTypeDesc(NULL, src->u.lptdesc, buffer);
1657 break;
1658 case VT_CARRAY:
1659 dest->u.lpadesc = buffer;
1660 memcpy(dest->u.lpadesc, src->u.lpadesc, FIELD_OFFSET(ARRAYDESC, rgbounds[src->u.lpadesc->cDims]));
1661 buffer = (char *)buffer + FIELD_OFFSET(ARRAYDESC, rgbounds[src->u.lpadesc->cDims]);
1662 buffer = TLB_CopyTypeDesc(&dest->u.lpadesc->tdescElem, &src->u.lpadesc->tdescElem, buffer);
1663 break;
1664 }
1665 return buffer;
1666 }
1667
1668 /* free custom data allocated by MSFT_CustData */
1669 static inline void TLB_FreeCustData(struct list *custdata_list)
1670 {
1671 TLBCustData *cd, *cdn;
1672 LIST_FOR_EACH_ENTRY_SAFE(cd, cdn, custdata_list, TLBCustData, entry)
1673 {
1674 list_remove(&cd->entry);
1675 VariantClear(&cd->data);
1676 heap_free(cd);
1677 }
1678 }
1679
1680 static BSTR TLB_MultiByteToBSTR(const char *ptr)
1681 {
1682 DWORD len;
1683 BSTR ret;
1684
1685 len = MultiByteToWideChar(CP_ACP, 0, ptr, -1, NULL, 0);
1686 ret = SysAllocStringLen(NULL, len - 1);
1687 if (!ret) return ret;
1688 MultiByteToWideChar(CP_ACP, 0, ptr, -1, ret, len);
1689 return ret;
1690 }
1691
1692 static inline TLBFuncDesc *TLB_get_funcdesc_by_memberid(TLBFuncDesc *funcdescs,
1693 UINT n, MEMBERID memid)
1694 {
1695 while(n){
1696 if(funcdescs->funcdesc.memid == memid)
1697 return funcdescs;
1698 ++funcdescs;
1699 --n;
1700 }
1701 return NULL;
1702 }
1703
1704 static inline TLBVarDesc *TLB_get_vardesc_by_memberid(TLBVarDesc *vardescs,
1705 UINT n, MEMBERID memid)
1706 {
1707 while(n){
1708 if(vardescs->vardesc.memid == memid)
1709 return vardescs;
1710 ++vardescs;
1711 --n;
1712 }
1713 return NULL;
1714 }
1715
1716 static inline TLBVarDesc *TLB_get_vardesc_by_name(TLBVarDesc *vardescs,
1717 UINT n, const OLECHAR *name)
1718 {
1719 while(n){
1720 if(!lstrcmpiW(TLB_get_bstr(vardescs->Name), name))
1721 return vardescs;
1722 ++vardescs;
1723 --n;
1724 }
1725 return NULL;
1726 }
1727
1728 static inline TLBCustData *TLB_get_custdata_by_guid(struct list *custdata_list, REFGUID guid)
1729 {
1730 TLBCustData *cust_data;
1731 LIST_FOR_EACH_ENTRY(cust_data, custdata_list, TLBCustData, entry)
1732 if(IsEqualIID(TLB_get_guid_null(cust_data->guid), guid))
1733 return cust_data;
1734 return NULL;
1735 }
1736
1737 static inline ITypeInfoImpl *TLB_get_typeinfo_by_name(ITypeInfoImpl **typeinfos,
1738 UINT n, const OLECHAR *name)
1739 {
1740 while(n){
1741 if(!lstrcmpiW(TLB_get_bstr((*typeinfos)->Name), name))
1742 return *typeinfos;
1743 ++typeinfos;
1744 --n;
1745 }
1746 return NULL;
1747 }
1748
1749 static void TLBVarDesc_Constructor(TLBVarDesc *var_desc)
1750 {
1751 list_init(&var_desc->custdata_list);
1752 }
1753
1754 static TLBVarDesc *TLBVarDesc_Alloc(UINT n)
1755 {
1756 TLBVarDesc *ret;
1757
1758 ret = heap_alloc_zero(sizeof(TLBVarDesc) * n);
1759 if(!ret)
1760 return NULL;
1761
1762 while(n){
1763 TLBVarDesc_Constructor(&ret[n-1]);
1764 --n;
1765 }
1766
1767 return ret;
1768 }
1769
1770 static TLBParDesc *TLBParDesc_Constructor(UINT n)
1771 {
1772 TLBParDesc *ret;
1773
1774 ret = heap_alloc_zero(sizeof(TLBParDesc) * n);
1775 if(!ret)
1776 return NULL;
1777
1778 while(n){
1779 list_init(&ret[n-1].custdata_list);
1780 --n;
1781 }
1782
1783 return ret;
1784 }
1785
1786 static void TLBFuncDesc_Constructor(TLBFuncDesc *func_desc)
1787 {
1788 list_init(&func_desc->custdata_list);
1789 }
1790
1791 static TLBFuncDesc *TLBFuncDesc_Alloc(UINT n)
1792 {
1793 TLBFuncDesc *ret;
1794
1795 ret = heap_alloc_zero(sizeof(TLBFuncDesc) * n);
1796 if(!ret)
1797 return NULL;
1798
1799 while(n){
1800 TLBFuncDesc_Constructor(&ret[n-1]);
1801 --n;
1802 }
1803
1804 return ret;
1805 }
1806
1807 static void TLBImplType_Constructor(TLBImplType *impl)
1808 {
1809 list_init(&impl->custdata_list);
1810 }
1811
1812 static TLBImplType *TLBImplType_Alloc(UINT n)
1813 {
1814 TLBImplType *ret;
1815
1816 ret = heap_alloc_zero(sizeof(TLBImplType) * n);
1817 if(!ret)
1818 return NULL;
1819
1820 while(n){
1821 TLBImplType_Constructor(&ret[n-1]);
1822 --n;
1823 }
1824
1825 return ret;
1826 }
1827
1828 static TLBGuid *TLB_append_guid(struct list *guid_list,
1829 const GUID *new_guid, HREFTYPE hreftype)
1830 {
1831 TLBGuid *guid;
1832
1833 LIST_FOR_EACH_ENTRY(guid, guid_list, TLBGuid, entry) {
1834 if (IsEqualGUID(&guid->guid, new_guid))
1835 return guid;
1836 }
1837
1838 guid = heap_alloc(sizeof(TLBGuid));
1839 if (!guid)
1840 return NULL;
1841
1842 memcpy(&guid->guid, new_guid, sizeof(GUID));
1843 guid->hreftype = hreftype;
1844
1845 list_add_tail(guid_list, &guid->entry);
1846
1847 return guid;
1848 }
1849
1850 static HRESULT TLB_set_custdata(struct list *custdata_list, TLBGuid *tlbguid, VARIANT *var)
1851 {
1852 TLBCustData *cust_data;
1853
1854 switch(V_VT(var)){
1855 case VT_I4:
1856 case VT_R4:
1857 case VT_UI4:
1858 case VT_INT:
1859 case VT_UINT:
1860 case VT_HRESULT:
1861 case VT_BSTR:
1862 break;
1863 default:
1864 return DISP_E_BADVARTYPE;
1865 }
1866
1867 cust_data = TLB_get_custdata_by_guid(custdata_list, TLB_get_guid_null(tlbguid));
1868
1869 if (!cust_data) {
1870 cust_data = heap_alloc(sizeof(TLBCustData));
1871 if (!cust_data)
1872 return E_OUTOFMEMORY;
1873
1874 cust_data->guid = tlbguid;
1875 VariantInit(&cust_data->data);
1876
1877 list_add_tail(custdata_list, &cust_data->entry);
1878 }else
1879 VariantClear(&cust_data->data);
1880
1881 return VariantCopy(&cust_data->data, var);
1882 }
1883
1884 static TLBString *TLB_append_str(struct list *string_list, BSTR new_str)
1885 {
1886 TLBString *str;
1887
1888 if(!new_str)
1889 return NULL;
1890
1891 LIST_FOR_EACH_ENTRY(str, string_list, TLBString, entry) {
1892 if (wcscmp(str->str, new_str) == 0)
1893 return str;
1894 }
1895
1896 str = heap_alloc(sizeof(TLBString));
1897 if (!str)
1898 return NULL;
1899
1900 str->str = SysAllocString(new_str);
1901 if (!str->str) {
1902 heap_free(str);
1903 return NULL;
1904 }
1905
1906 list_add_tail(string_list, &str->entry);
1907
1908 return str;
1909 }
1910
1911 static HRESULT TLB_get_size_from_hreftype(ITypeInfoImpl *info, HREFTYPE href,
1912 ULONG *size, WORD *align)
1913 {
1914 ITypeInfo *other;
1915 TYPEATTR *attr;
1916 HRESULT hr;
1917
1918 hr = ITypeInfo2_GetRefTypeInfo(&info->ITypeInfo2_iface, href, &other);
1919 if(FAILED(hr))
1920 return hr;
1921
1922 hr = ITypeInfo_GetTypeAttr(other, &attr);
1923 if(FAILED(hr)){
1924 ITypeInfo_Release(other);
1925 return hr;
1926 }
1927
1928 if(size)
1929 *size = attr->cbSizeInstance;
1930 if(align)
1931 *align = attr->cbAlignment;
1932
1933 ITypeInfo_ReleaseTypeAttr(other, attr);
1934 ITypeInfo_Release(other);
1935
1936 return S_OK;
1937 }
1938
1939 static HRESULT TLB_size_instance(ITypeInfoImpl *info, SYSKIND sys,
1940 TYPEDESC *tdesc, ULONG *size, WORD *align)
1941 {
1942 ULONG i, sub, ptr_size;
1943 HRESULT hr;
1944
1945 ptr_size = get_ptr_size(sys);
1946
1947 switch(tdesc->vt){
1948 case VT_VOID:
1949 *size = 0;
1950 break;
1951 case VT_I1:
1952 case VT_UI1:
1953 *size = 1;
1954 break;
1955 case VT_I2:
1956 case VT_BOOL:
1957 case VT_UI2:
1958 *size = 2;
1959 break;
1960 case VT_I4:
1961 case VT_R4:
1962 case VT_ERROR:
1963 case VT_UI4:
1964 case VT_INT:
1965 case VT_UINT:
1966 case VT_HRESULT:
1967 *size = 4;
1968 break;
1969 case VT_R8:
1970 case VT_I8:
1971 case VT_UI8:
1972 *size = 8;
1973 break;
1974 case VT_BSTR:
1975 case VT_DISPATCH:
1976 case VT_UNKNOWN:
1977 case VT_PTR:
1978 case VT_SAFEARRAY:
1979 case VT_LPSTR:
1980 case VT_LPWSTR:
1981 *size = ptr_size;
1982 break;
1983 case VT_DATE:
1984 *size = sizeof(DATE);
1985 break;
1986 case VT_VARIANT:
1987 *size = sizeof(VARIANT);
1988 #ifdef _WIN64
1989 if(sys == SYS_WIN32)
1990 *size -= 8; /* 32-bit VARIANT is 8 bytes smaller than 64-bit VARIANT */
1991 #endif
1992 break;
1993 case VT_DECIMAL:
1994 *size = sizeof(DECIMAL);
1995 break;
1996 case VT_CY:
1997 *size = sizeof(CY);
1998 break;
1999 case VT_CARRAY:
2000 *size = 0;
2001 for(i = 0; i < tdesc->u.lpadesc->cDims; ++i)
2002 *size += tdesc->u.lpadesc->rgbounds[i].cElements;
2003 hr = TLB_size_instance(info, sys, &tdesc->u.lpadesc->tdescElem, &sub, align);
2004 if(FAILED(hr))
2005 return hr;
2006 *size *= sub;
2007 return S_OK;
2008 case VT_USERDEFINED:
2009 return TLB_get_size_from_hreftype(info, tdesc->u.hreftype, size, align);
2010 default:
2011 FIXME("Unsized VT: 0x%x\n", tdesc->vt);
2012 return E_FAIL;
2013 }
2014
2015 if(align){
2016 if(*size < 4)
2017 *align = *size;
2018 else
2019 *align = 4;
2020 }
2021
2022 return S_OK;
2023 }
2024
2025 /**********************************************************************
2026 *
2027 * Functions for reading MSFT typelibs (those created by CreateTypeLib2)
2028 */
2029
2030 static inline void MSFT_Seek(TLBContext *pcx, LONG where)
2031 {
2032 if (where != DO_NOT_SEEK)
2033 {
2034 where += pcx->oStart;
2035 if (where > pcx->length)
2036 {
2037 /* FIXME */
2038 ERR("seek beyond end (%d/%d)\n", where, pcx->length );
2039 TLB_abort();
2040 }
2041 pcx->pos = where;
2042 }
2043 }
2044
2045 /* read function */
2046 static DWORD MSFT_Read(void *buffer, DWORD count, TLBContext *pcx, LONG where )
2047 {
2048 TRACE_(typelib)("pos=0x%08x len=0x%08x 0x%08x 0x%08x 0x%08x\n",
2049 pcx->pos, count, pcx->oStart, pcx->length, where);
2050
2051 MSFT_Seek(pcx, where);
2052 if (pcx->pos + count > pcx->length) count = pcx->length - pcx->pos;
2053 memcpy( buffer, (char *)pcx->mapping + pcx->pos, count );
2054 pcx->pos += count;
2055 return count;
2056 }
2057
2058 static DWORD MSFT_ReadLEDWords(void *buffer, DWORD count, TLBContext *pcx,
2059 LONG where )
2060 {
2061 DWORD ret;
2062
2063 ret = MSFT_Read(buffer, count, pcx, where);
2064 FromLEDWords(buffer, ret);
2065
2066 return ret;
2067 }
2068
2069 static DWORD MSFT_ReadLEWords(void *buffer, DWORD count, TLBContext *pcx,
2070 LONG where )
2071 {
2072 DWORD ret;
2073
2074 ret = MSFT_Read(buffer, count, pcx, where);
2075 FromLEWords(buffer, ret);
2076
2077 return ret;
2078 }
2079
2080 static HRESULT MSFT_ReadAllGuids(TLBContext *pcx)
2081 {
2082 TLBGuid *guid;
2083 MSFT_GuidEntry entry;
2084 int offs = 0;
2085
2086 MSFT_Seek(pcx, pcx->pTblDir->pGuidTab.offset);
2087 while (1) {
2088 if (offs >= pcx->pTblDir->pGuidTab.length)
2089 return S_OK;
2090
2091 MSFT_ReadLEWords(&entry, sizeof(MSFT_GuidEntry), pcx, DO_NOT_SEEK);
2092
2093 guid = heap_alloc(sizeof(TLBGuid));
2094
2095 guid->offset = offs;
2096 guid->guid = entry.guid;
2097 guid->hreftype = entry.hreftype;
2098
2099 list_add_tail(&pcx->pLibInfo->guid_list, &guid->entry);
2100
2101 offs += sizeof(MSFT_GuidEntry);
2102 }
2103 }
2104
2105 static TLBGuid *MSFT_ReadGuid( int offset, TLBContext *pcx)
2106 {
2107 TLBGuid *ret;
2108
2109 LIST_FOR_EACH_ENTRY(ret, &pcx->pLibInfo->guid_list, TLBGuid, entry){
2110 if(ret->offset == offset){
2111 TRACE_(typelib)("%s\n", debugstr_guid(&ret->guid));
2112 return ret;
2113 }
2114 }
2115
2116 return NULL;
2117 }
2118
2119 static HREFTYPE MSFT_ReadHreftype( TLBContext *pcx, int offset )
2120 {
2121 MSFT_NameIntro niName;
2122
2123 if (offset < 0)
2124 {
2125 ERR_(typelib)("bad offset %d\n", offset);
2126 return -1;
2127 }
2128
2129 MSFT_ReadLEDWords(&niName, sizeof(niName), pcx,
2130 pcx->pTblDir->pNametab.offset+offset);
2131
2132 return niName.hreftype;
2133 }
2134
2135 static HRESULT MSFT_ReadAllNames(TLBContext *pcx)
2136 {
2137 char *string;
2138 MSFT_NameIntro intro;
2139 INT16 len_piece;
2140 int offs = 0, lengthInChars;
2141
2142 MSFT_Seek(pcx, pcx->pTblDir->pNametab.offset);
2143 while (1) {
2144 TLBString *tlbstr;
2145
2146 if (offs >= pcx->pTblDir->pNametab.length)
2147 return S_OK;
2148
2149 MSFT_ReadLEWords(&intro, sizeof(MSFT_NameIntro), pcx, DO_NOT_SEEK);
2150 intro.namelen &= 0xFF;
2151 len_piece = intro.namelen + sizeof(MSFT_NameIntro);
2152 if(len_piece % 4)
2153 len_piece = (len_piece + 4) & ~0x3;
2154 if(len_piece < 8)
2155 len_piece = 8;
2156
2157 string = heap_alloc(len_piece + 1);
2158 MSFT_Read(string, len_piece - sizeof(MSFT_NameIntro), pcx, DO_NOT_SEEK);
2159 string[intro.namelen] = '\0';
2160
2161 lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
2162 string, -1, NULL, 0);
2163 if (!lengthInChars) {
2164 heap_free(string);
2165 return E_UNEXPECTED;
2166 }
2167
2168 tlbstr = heap_alloc(sizeof(TLBString));
2169
2170 tlbstr->offset = offs;
2171 tlbstr->str = SysAllocStringByteLen(NULL, lengthInChars * sizeof(WCHAR));
2172 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, string, -1, tlbstr->str, lengthInChars);
2173
2174 heap_free(string);
2175
2176 list_add_tail(&pcx->pLibInfo->name_list, &tlbstr->entry);
2177
2178 offs += len_piece;
2179 }
2180 }
2181
2182 static TLBString *MSFT_ReadName( TLBContext *pcx, int offset)
2183 {
2184 TLBString *tlbstr;
2185
2186 LIST_FOR_EACH_ENTRY(tlbstr, &pcx->pLibInfo->name_list, TLBString, entry) {
2187 if (tlbstr->offset == offset) {
2188 TRACE_(typelib)("%s\n", debugstr_w(tlbstr->str));
2189 return tlbstr;
2190 }
2191 }
2192
2193 return NULL;
2194 }
2195
2196 static TLBString *MSFT_ReadString( TLBContext *pcx, int offset)
2197 {
2198 TLBString *tlbstr;
2199
2200 LIST_FOR_EACH_ENTRY(tlbstr, &pcx->pLibInfo->string_list, TLBString, entry) {
2201 if (tlbstr->offset == offset) {
2202 TRACE_(typelib)("%s\n", debugstr_w(tlbstr->str));
2203 return tlbstr;
2204 }
2205 }
2206
2207 return NULL;
2208 }
2209
2210 /*
2211 * read a value and fill a VARIANT structure
2212 */
2213 static void MSFT_ReadValue( VARIANT * pVar, int offset, TLBContext *pcx )
2214 {
2215 int size;
2216
2217 TRACE_(typelib)("\n");
2218
2219 if(offset <0) { /* data are packed in here */
2220 V_VT(pVar) = (offset & 0x7c000000 )>> 26;
2221 V_I4(pVar) = offset & 0x3ffffff;
2222 return;
2223 }
2224 MSFT_ReadLEWords(&(V_VT(pVar)), sizeof(VARTYPE), pcx,
2225 pcx->pTblDir->pCustData.offset + offset );
2226 TRACE_(typelib)("Vartype = %x\n", V_VT(pVar));
2227 switch (V_VT(pVar)){
2228 case VT_EMPTY: /* FIXME: is this right? */
2229 case VT_NULL: /* FIXME: is this right? */
2230 case VT_I2 : /* this should not happen */
2231 case VT_I4 :
2232 case VT_R4 :
2233 case VT_ERROR :
2234 case VT_BOOL :
2235 case VT_I1 :
2236 case VT_UI1 :
2237 case VT_UI2 :
2238 case VT_UI4 :
2239 case VT_INT :
2240 case VT_UINT :
2241 case VT_VOID : /* FIXME: is this right? */
2242 case VT_HRESULT :
2243 size=4; break;
2244 case VT_R8 :
2245 case VT_CY :
2246 case VT_DATE :
2247 case VT_I8 :
2248 case VT_UI8 :
2249 case VT_DECIMAL : /* FIXME: is this right? */
2250 case VT_FILETIME :
2251 size=8;break;
2252 /* pointer types with known behaviour */
2253 case VT_BSTR :{
2254 char * ptr;
2255 MSFT_ReadLEDWords(&size, sizeof(INT), pcx, DO_NOT_SEEK );
2256 if(size == -1){
2257 V_BSTR(pVar) = NULL;
2258 }else{
2259 ptr = heap_alloc_zero(size);
2260 MSFT_Read(ptr, size, pcx, DO_NOT_SEEK);
2261 V_BSTR(pVar)=SysAllocStringLen(NULL,size);
2262 /* FIXME: do we need a AtoW conversion here? */
2263 V_UNION(pVar, bstrVal[size])='\0';
2264 while(size--) V_UNION(pVar, bstrVal[size])=ptr[size];
2265 heap_free(ptr);
2266 }
2267 }
2268 size=-4; break;
2269 /* FIXME: this will not work AT ALL when the variant contains a pointer */
2270 case VT_DISPATCH :
2271 case VT_VARIANT :
2272 case VT_UNKNOWN :
2273 case VT_PTR :
2274 case VT_SAFEARRAY :
2275 case VT_CARRAY :
2276 case VT_USERDEFINED :
2277 case VT_LPSTR :
2278 case VT_LPWSTR :
2279 case VT_BLOB :
2280 case VT_STREAM :
2281 case VT_STORAGE :
2282 case VT_STREAMED_OBJECT :
2283 case VT_STORED_OBJECT :
2284 case VT_BLOB_OBJECT :
2285 case VT_CF :
2286 case VT_CLSID :
2287 default:
2288 size=0;
2289 FIXME("VARTYPE %d is not supported, setting pointer to NULL\n",
2290 V_VT(pVar));
2291 }
2292
2293 if(size>0) /* (big|small) endian correct? */
2294 MSFT_Read(&(V_I2(pVar)), size, pcx, DO_NOT_SEEK );
2295 return;
2296 }
2297 /*
2298 * create a linked list with custom data
2299 */
2300 static int MSFT_CustData( TLBContext *pcx, int offset, struct list *custdata_list)
2301 {
2302 MSFT_CDGuid entry;
2303 TLBCustData* pNew;
2304 int count=0;
2305
2306 TRACE_(typelib)("\n");
2307
2308 if (pcx->pTblDir->pCDGuids.offset < 0) return 0;
2309
2310 while(offset >=0){
2311 count++;
2312 pNew=heap_alloc_zero(sizeof(TLBCustData));
2313 MSFT_ReadLEDWords(&entry, sizeof(entry), pcx, pcx->pTblDir->pCDGuids.offset+offset);
2314 pNew->guid = MSFT_ReadGuid(entry.GuidOffset, pcx);
2315 MSFT_ReadValue(&(pNew->data), entry.DataOffset, pcx);
2316 list_add_head(custdata_list, &pNew->entry);
2317 offset = entry.next;
2318 }
2319 return count;
2320 }
2321
2322 static void MSFT_GetTdesc(TLBContext *pcx, INT type, TYPEDESC *pTd)
2323 {
2324 if(type <0)
2325 pTd->vt=type & VT_TYPEMASK;
2326 else
2327 *pTd=pcx->pLibInfo->pTypeDesc[type/(2*sizeof(INT))];
2328
2329 TRACE_(typelib)("vt type = %X\n", pTd->vt);
2330 }
2331
2332 static BOOL TLB_is_propgetput(INVOKEKIND invkind)
2333 {
2334 return (invkind == INVOKE_PROPERTYGET ||
2335 invkind == INVOKE_PROPERTYPUT ||
2336 invkind == INVOKE_PROPERTYPUTREF);
2337 }
2338
2339 static void
2340 MSFT_DoFuncs(TLBContext* pcx,
2341 ITypeInfoImpl* pTI,
2342 int cFuncs,
2343 int cVars,
2344 int offset,
2345 TLBFuncDesc** pptfd)
2346 {
2347 /*
2348 * member information is stored in a data structure at offset
2349 * indicated by the memoffset field of the typeinfo structure
2350 * There are several distinctive parts.
2351 * The first part starts with a field that holds the total length
2352 * of this (first) part excluding this field. Then follow the records,
2353 * for each member there is one record.
2354 *
2355 * The first entry is always the length of the record (including this
2356 * length word).
2357 * The rest of the record depends on the type of the member. If there is
2358 * a field indicating the member type (function, variable, interface, etc)
2359 * I have not found it yet. At this time we depend on the information
2360 * in the type info and the usual order how things are stored.
2361 *
2362 * Second follows an array sized nrMEM*sizeof(INT) with a member id
2363 * for each member;
2364 *
2365 * Third is an equal sized array with file offsets to the name entry
2366 * of each member.
2367 *
2368 * The fourth and last (?) part is an array with offsets to the records
2369 * in the first part of this file segment.
2370 */
2371
2372 int infolen, nameoffset, reclength, i;
2373 int recoffset = offset + sizeof(INT);
2374
2375 char *recbuf = heap_alloc(0xffff);
2376 MSFT_FuncRecord *pFuncRec = (MSFT_FuncRecord*)recbuf;
2377 TLBFuncDesc *ptfd_prev = NULL, *ptfd;
2378
2379 TRACE_(typelib)("\n");
2380
2381 MSFT_ReadLEDWords(&infolen, sizeof(INT), pcx, offset);
2382
2383 *pptfd = TLBFuncDesc_Alloc(cFuncs);
2384 ptfd = *pptfd;
2385 for ( i = 0; i < cFuncs ; i++ )
2386 {
2387 int optional;
2388
2389 /* name, eventually add to a hash table */
2390 MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx,
2391 offset + infolen + (cFuncs + cVars + i + 1) * sizeof(INT));
2392
2393 /* read the function information record */
2394 MSFT_ReadLEDWords(&reclength, sizeof(pFuncRec->Info), pcx, recoffset);
2395
2396 reclength &= 0xffff;
2397
2398 MSFT_ReadLEDWords(&pFuncRec->DataType, reclength - FIELD_OFFSET(MSFT_FuncRecord, DataType), pcx, DO_NOT_SEEK);
2399
2400 /* size without argument data */
2401 optional = reclength - pFuncRec->nrargs*sizeof(MSFT_ParameterInfo);
2402 if (pFuncRec->FKCCIC & 0x1000)
2403 optional -= pFuncRec->nrargs * sizeof(INT);
2404
2405 if (optional > FIELD_OFFSET(MSFT_FuncRecord, HelpContext))
2406 ptfd->helpcontext = pFuncRec->HelpContext;
2407
2408 if (optional > FIELD_OFFSET(MSFT_FuncRecord, oHelpString))
2409 ptfd->HelpString = MSFT_ReadString(pcx, pFuncRec->oHelpString);
2410
2411 if (optional > FIELD_OFFSET(MSFT_FuncRecord, oEntry))
2412 {
2413 if (pFuncRec->FKCCIC & 0x2000 )
2414 {
2415 if (!IS_INTRESOURCE(pFuncRec->oEntry))
2416 ERR("ordinal 0x%08x invalid, IS_INTRESOURCE is false\n", pFuncRec->oEntry);
2417 ptfd->Entry = (TLBString*)(DWORD_PTR)LOWORD(pFuncRec->oEntry);
2418 }
2419 else
2420 ptfd->Entry = MSFT_ReadString(pcx, pFuncRec->oEntry);
2421 }
2422 else
2423 ptfd->Entry = (TLBString*)-1;
2424
2425 if (optional > FIELD_OFFSET(MSFT_FuncRecord, HelpStringContext))
2426 ptfd->HelpStringContext = pFuncRec->HelpStringContext;
2427
2428 if (optional > FIELD_OFFSET(MSFT_FuncRecord, oCustData) && pFuncRec->FKCCIC & 0x80)
2429 MSFT_CustData(pcx, pFuncRec->oCustData, &ptfd->custdata_list);
2430
2431 /* fill the FuncDesc Structure */
2432 MSFT_ReadLEDWords( & ptfd->funcdesc.memid, sizeof(INT), pcx,
2433 offset + infolen + ( i + 1) * sizeof(INT));
2434
2435 ptfd->funcdesc.funckind = (pFuncRec->FKCCIC) & 0x7;
2436 ptfd->funcdesc.invkind = (pFuncRec->FKCCIC) >> 3 & 0xF;
2437 ptfd->funcdesc.callconv = (pFuncRec->FKCCIC) >> 8 & 0xF;
2438 ptfd->funcdesc.cParams = pFuncRec->nrargs ;
2439 ptfd->funcdesc.cParamsOpt = pFuncRec->nroargs ;
2440 ptfd->funcdesc.oVft = (pFuncRec->VtableOffset & ~1) * sizeof(void *) / pTI->pTypeLib->ptr_size;
2441 ptfd->funcdesc.wFuncFlags = LOWORD(pFuncRec->Flags) ;
2442
2443 /* nameoffset is sometimes -1 on the second half of a propget/propput
2444 * pair of functions */
2445 if ((nameoffset == -1) && (i > 0) &&
2446 TLB_is_propgetput(ptfd_prev->funcdesc.invkind) &&
2447 TLB_is_propgetput(ptfd->funcdesc.invkind))
2448 ptfd->Name = ptfd_prev->Name;
2449 else
2450 ptfd->Name = MSFT_ReadName(pcx, nameoffset);
2451
2452 MSFT_GetTdesc(pcx,
2453 pFuncRec->DataType,
2454 &ptfd->funcdesc.elemdescFunc.tdesc);
2455
2456 /* do the parameters/arguments */
2457 if(pFuncRec->nrargs)
2458 {
2459 int j = 0;
2460 MSFT_ParameterInfo paraminfo;
2461
2462 ptfd->funcdesc.lprgelemdescParam =
2463 heap_alloc_zero(pFuncRec->nrargs * (sizeof(ELEMDESC) + sizeof(PARAMDESCEX)));
2464
2465 ptfd->pParamDesc = TLBParDesc_Constructor(pFuncRec->nrargs);
2466
2467 MSFT_ReadLEDWords(&paraminfo, sizeof(paraminfo), pcx,
2468 recoffset + reclength - pFuncRec->nrargs * sizeof(MSFT_ParameterInfo));
2469
2470 for ( j = 0 ; j < pFuncRec->nrargs ; j++ )
2471 {
2472 ELEMDESC *elemdesc = &ptfd->funcdesc.lprgelemdescParam[j];
2473
2474 MSFT_GetTdesc(pcx,
2475 paraminfo.DataType,
2476 &elemdesc->tdesc);
2477
2478 elemdesc->u.paramdesc.wParamFlags = paraminfo.Flags;
2479
2480 /* name */
2481 if (paraminfo.oName != -1)
2482 ptfd->pParamDesc[j].Name =
2483 MSFT_ReadName( pcx, paraminfo.oName );
2484 TRACE_(typelib)("param[%d] = %s\n", j, debugstr_w(TLB_get_bstr(ptfd->pParamDesc[j].Name)));
2485
2486 /* default value */
2487 if ( (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) &&
2488 (pFuncRec->FKCCIC & 0x1000) )
2489 {
2490 INT* pInt = (INT *)((char *)pFuncRec +
2491 reclength -
2492 (pFuncRec->nrargs * 4) * sizeof(INT) );
2493
2494 PARAMDESC* pParamDesc = &elemdesc->u.paramdesc;
2495
2496 pParamDesc->pparamdescex = (PARAMDESCEX*)(ptfd->funcdesc.lprgelemdescParam+pFuncRec->nrargs)+j;
2497 pParamDesc->pparamdescex->cBytes = sizeof(PARAMDESCEX);
2498
2499 MSFT_ReadValue(&(pParamDesc->pparamdescex->varDefaultValue),
2500 pInt[j], pcx);
2501 }
2502 else
2503 elemdesc->u.paramdesc.pparamdescex = NULL;
2504
2505 /* custom info */
2506 if (optional > (FIELD_OFFSET(MSFT_FuncRecord, oArgCustData) +
2507 j*sizeof(pFuncRec->oArgCustData[0])) &&
2508 pFuncRec->FKCCIC & 0x80 )
2509 {
2510 MSFT_CustData(pcx,
2511 pFuncRec->oArgCustData[j],
2512 &ptfd->pParamDesc[j].custdata_list);
2513 }
2514
2515 /* SEEK value = jump to offset,
2516 * from there jump to the end of record,
2517 * go back by (j-1) arguments
2518 */
2519 MSFT_ReadLEDWords( &paraminfo ,
2520 sizeof(MSFT_ParameterInfo), pcx,
2521 recoffset + reclength - ((pFuncRec->nrargs - j - 1)
2522 * sizeof(MSFT_ParameterInfo)));
2523 }
2524 }
2525
2526 /* scode is not used: archaic win16 stuff FIXME: right? */
2527 ptfd->funcdesc.cScodes = 0 ;
2528 ptfd->funcdesc.lprgscode = NULL ;
2529
2530 ptfd_prev = ptfd;
2531 ++ptfd;
2532 recoffset += reclength;
2533 }
2534 heap_free(recbuf);
2535 }
2536
2537 static void MSFT_DoVars(TLBContext *pcx, ITypeInfoImpl *pTI, int cFuncs,
2538 int cVars, int offset, TLBVarDesc ** pptvd)
2539 {
2540 int infolen, nameoffset, reclength;
2541 char recbuf[256];
2542 MSFT_VarRecord *pVarRec = (MSFT_VarRecord*)recbuf;
2543 TLBVarDesc *ptvd;
2544 int i;
2545 int recoffset;
2546
2547 TRACE_(typelib)("\n");
2548
2549 ptvd = *pptvd = TLBVarDesc_Alloc(cVars);
2550 MSFT_ReadLEDWords(&infolen,sizeof(INT), pcx, offset);
2551 MSFT_ReadLEDWords(&recoffset,sizeof(INT), pcx, offset + infolen +
2552 ((cFuncs+cVars)*2+cFuncs + 1)*sizeof(INT));
2553 recoffset += offset+sizeof(INT);
2554 for(i=0;i<cVars;i++, ++ptvd){
2555 /* name, eventually add to a hash table */
2556 MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx,
2557 offset + infolen + (2*cFuncs + cVars + i + 1) * sizeof(INT));
2558 ptvd->Name=MSFT_ReadName(pcx, nameoffset);
2559 /* read the variable information record */
2560 MSFT_ReadLEDWords(&reclength, sizeof(pVarRec->Info), pcx, recoffset);
2561 reclength &= 0xff;
2562 MSFT_ReadLEDWords(&pVarRec->DataType, reclength - FIELD_OFFSET(MSFT_VarRecord, DataType), pcx, DO_NOT_SEEK);
2563
2564 /* optional data */
2565 if(reclength > FIELD_OFFSET(MSFT_VarRecord, HelpContext))
2566 ptvd->HelpContext = pVarRec->HelpContext;
2567
2568 if(reclength > FIELD_OFFSET(MSFT_VarRecord, HelpString))
2569 ptvd->HelpString = MSFT_ReadString(pcx, pVarRec->HelpString);
2570
2571 if(reclength > FIELD_OFFSET(MSFT_VarRecord, HelpStringContext))
2572 ptvd->HelpStringContext = pVarRec->HelpStringContext;
2573
2574 /* fill the VarDesc Structure */
2575 MSFT_ReadLEDWords(&ptvd->vardesc.memid, sizeof(INT), pcx,
2576 offset + infolen + (cFuncs + i + 1) * sizeof(INT));
2577 ptvd->vardesc.varkind = pVarRec->VarKind;
2578 ptvd->vardesc.wVarFlags = pVarRec->Flags;
2579 MSFT_GetTdesc(pcx, pVarRec->DataType,
2580 &ptvd->vardesc.elemdescVar.tdesc);
2581 /* ptvd->vardesc.lpstrSchema; is reserved (SDK) FIXME?? */
2582 if(pVarRec->VarKind == VAR_CONST ){
2583 ptvd->vardesc.u.lpvarValue = heap_alloc_zero(sizeof(VARIANT));
2584 MSFT_ReadValue(ptvd->vardesc.u.lpvarValue,
2585 pVarRec->OffsValue, pcx);
2586 } else
2587 ptvd->vardesc.u.oInst=pVarRec->OffsValue;
2588 recoffset += reclength;
2589 }
2590 }
2591
2592 /* process Implemented Interfaces of a com class */
2593 static void MSFT_DoImplTypes(TLBContext *pcx, ITypeInfoImpl *pTI, int count,
2594 int offset)
2595 {
2596 int i;
2597 MSFT_RefRecord refrec;
2598 TLBImplType *pImpl;
2599
2600 TRACE_(typelib)("\n");
2601
2602 pTI->impltypes = TLBImplType_Alloc(count);
2603 pImpl = pTI->impltypes;
2604 for(i=0;i<count;i++){
2605 if(offset<0) break; /* paranoia */
2606 MSFT_ReadLEDWords(&refrec,sizeof(refrec),pcx,offset+pcx->pTblDir->pRefTab.offset);
2607 pImpl->hRef = refrec.reftype;
2608 pImpl->implflags=refrec.flags;
2609 MSFT_CustData(pcx, refrec.oCustData, &pImpl->custdata_list);
2610 offset=refrec.onext;
2611 ++pImpl;
2612 }
2613 }
2614
2615 #ifdef _WIN64
2616 /* when a 32-bit typelib is loaded in 64-bit mode, we need to resize pointers
2617 * and some structures, and fix the alignment */
2618 static void TLB_fix_32on64_typeinfo(ITypeInfoImpl *info)
2619 {
2620 if(info->typeattr.typekind == TKIND_ALIAS){
2621 switch(info->tdescAlias->vt){
2622 case VT_BSTR:
2623 case VT_DISPATCH:
2624 case VT_UNKNOWN:
2625 case VT_PTR:
2626 case VT_SAFEARRAY:
2627 case VT_LPSTR:
2628 case VT_LPWSTR:
2629 info->typeattr.cbSizeInstance = sizeof(void*);
2630 info->typeattr.cbAlignment = sizeof(void*);
2631 break;
2632 case VT_CARRAY:
2633 case VT_USERDEFINED:
2634 TLB_size_instance(info, SYS_WIN64, info->tdescAlias, &info->typeattr.cbSizeInstance, &info->typeattr.cbAlignment);
2635 break;
2636 case VT_VARIANT:
2637 info->typeattr.cbSizeInstance = sizeof(VARIANT);
2638 info->typeattr.cbAlignment = 8;
2639 default:
2640 if(info->typeattr.cbSizeInstance < sizeof(void*))
2641 info->typeattr.cbAlignment = info->typeattr.cbSizeInstance;
2642 else
2643 info->typeattr.cbAlignment = sizeof(void*);
2644 break;
2645 }
2646 }else if(info->typeattr.typekind == TKIND_INTERFACE ||
2647 info->typeattr.typekind == TKIND_DISPATCH ||
2648 info->typeattr.typekind == TKIND_COCLASS){
2649 info->typeattr.cbSizeInstance = sizeof(void*);
2650 info->typeattr.cbAlignment = sizeof(void*);
2651 }
2652 }
2653 #endif
2654
2655 /*
2656 * process a typeinfo record
2657 */
2658 static ITypeInfoImpl * MSFT_DoTypeInfo(
2659 TLBContext *pcx,
2660 int count,
2661 ITypeLibImpl * pLibInfo)
2662 {
2663 MSFT_TypeInfoBase tiBase;
2664 ITypeInfoImpl *ptiRet;
2665
2666 TRACE_(typelib)("count=%u\n", count);
2667
2668 ptiRet = ITypeInfoImpl_Constructor();
2669 MSFT_ReadLEDWords(&tiBase, sizeof(tiBase) ,pcx ,
2670 pcx->pTblDir->pTypeInfoTab.offset+count*sizeof(tiBase));
2671
2672 /* this is where we are coming from */
2673 ptiRet->pTypeLib = pLibInfo;
2674 ptiRet->index=count;
2675
2676 ptiRet->guid = MSFT_ReadGuid(tiBase.posguid, pcx);
2677 ptiRet->typeattr.lcid = pLibInfo->set_lcid; /* FIXME: correct? */
2678 ptiRet->typeattr.lpstrSchema = NULL; /* reserved */
2679 ptiRet->typeattr.cbSizeInstance = tiBase.size;
2680 ptiRet->typeattr.typekind = tiBase.typekind & 0xF;
2681 ptiRet->typeattr.cFuncs = LOWORD(tiBase.cElement);
2682 ptiRet->typeattr.cVars = HIWORD(tiBase.cElement);
2683 ptiRet->typeattr.cbAlignment = (tiBase.typekind >> 11 )& 0x1F; /* there are more flags there */
2684 ptiRet->typeattr.wTypeFlags = tiBase.flags;
2685 ptiRet->typeattr.wMajorVerNum = LOWORD(tiBase.version);
2686 ptiRet->typeattr.wMinorVerNum = HIWORD(tiBase.version);
2687 ptiRet->typeattr.cImplTypes = tiBase.cImplTypes;
2688 ptiRet->typeattr.cbSizeVft = tiBase.cbSizeVft;
2689 if (ptiRet->typeattr.typekind == TKIND_ALIAS) {
2690 TYPEDESC tmp;
2691 MSFT_GetTdesc(pcx, tiBase.datatype1, &tmp);
2692 ptiRet->tdescAlias = heap_alloc(TLB_SizeTypeDesc(&tmp, TRUE));
2693 TLB_CopyTypeDesc(NULL, &tmp, ptiRet->tdescAlias);
2694 }
2695
2696 /* FIXME: */
2697 /* IDLDESC idldescType; *//* never saw this one != zero */
2698
2699 /* name, eventually add to a hash table */
2700 ptiRet->Name=MSFT_ReadName(pcx, tiBase.NameOffset);
2701 ptiRet->hreftype = MSFT_ReadHreftype(pcx, tiBase.NameOffset);
2702 TRACE_(typelib)("reading %s\n", debugstr_w(TLB_get_bstr(ptiRet->Name)));
2703 /* help info */
2704 ptiRet->DocString=MSFT_ReadString(pcx, tiBase.docstringoffs);
2705 ptiRet->dwHelpStringContext=tiBase.helpstringcontext;
2706 ptiRet->dwHelpContext=tiBase.helpcontext;
2707
2708 if (ptiRet->typeattr.typekind == TKIND_MODULE)
2709 ptiRet->DllName = MSFT_ReadString(pcx, tiBase.datatype1);
2710
2711 /* note: InfoType's Help file and HelpStringDll come from the containing
2712 * library. Further HelpString and Docstring appear to be the same thing :(
2713 */
2714 /* functions */
2715 if(ptiRet->typeattr.cFuncs >0 )
2716 MSFT_DoFuncs(pcx, ptiRet, ptiRet->typeattr.cFuncs,
2717 ptiRet->typeattr.cVars,
2718 tiBase.memoffset, &ptiRet->funcdescs);
2719 /* variables */
2720 if(ptiRet->typeattr.cVars >0 )
2721 MSFT_DoVars(pcx, ptiRet, ptiRet->typeattr.cFuncs,
2722 ptiRet->typeattr.cVars,
2723 tiBase.memoffset, &ptiRet->vardescs);
2724 if(ptiRet->typeattr.cImplTypes >0 ) {
2725 switch(ptiRet->typeattr.typekind)
2726 {
2727 case TKIND_COCLASS:
2728 MSFT_DoImplTypes(pcx, ptiRet, ptiRet->typeattr.cImplTypes,
2729 tiBase.datatype1);
2730 break;
2731 case TKIND_DISPATCH:
2732 /* This is not -1 when the interface is a non-base dual interface or
2733 when a dispinterface wraps an interface, i.e., the idl 'dispinterface x {interface y;};'.
2734 Note however that GetRefTypeOfImplType(0) always returns a ref to IDispatch and
2735 not this interface.
2736 */
2737
2738 if (tiBase.datatype1 != -1)
2739 {
2740 ptiRet->impltypes = TLBImplType_Alloc(1);
2741 ptiRet->impltypes[0].hRef = tiBase.datatype1;
2742 }
2743 break;
2744 default:
2745 ptiRet->impltypes = TLBImplType_Alloc(1);
2746 ptiRet->impltypes[0].hRef = tiBase.datatype1;
2747 break;
2748 }
2749 }
2750 MSFT_CustData(pcx, tiBase.oCustData, ptiRet->pcustdata_list);
2751
2752 TRACE_(typelib)("%s guid: %s kind:%s\n",
2753 debugstr_w(TLB_get_bstr(ptiRet->Name)),
2754 debugstr_guid(TLB_get_guidref(ptiRet->guid)),
2755 typekind_desc[ptiRet->typeattr.typekind]);
2756 if (TRACE_ON(typelib))
2757 dump_TypeInfo(ptiRet);
2758
2759 return ptiRet;
2760 }
2761
2762 static HRESULT MSFT_ReadAllStrings(TLBContext *pcx)
2763 {
2764 char *string;
2765 INT16 len_str, len_piece;
2766 int offs = 0, lengthInChars;
2767
2768 MSFT_Seek(pcx, pcx->pTblDir->pStringtab.offset);
2769 while (1) {
2770 TLBString *tlbstr;
2771
2772 if (offs >= pcx->pTblDir->pStringtab.length)
2773 return S_OK;
2774
2775 MSFT_ReadLEWords(&len_str, sizeof(INT16), pcx, DO_NOT_SEEK);
2776 len_piece = len_str + sizeof(INT16);
2777 if(len_piece % 4)
2778 len_piece = (len_piece + 4) & ~0x3;
2779 if(len_piece < 8)
2780 len_piece = 8;
2781
2782 string = heap_alloc(len_piece + 1);
2783 MSFT_Read(string, len_piece - sizeof(INT16), pcx, DO_NOT_SEEK);
2784 string[len_str] = '\0';
2785
2786 lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
2787 string, -1, NULL, 0);
2788 if (!lengthInChars) {
2789 heap_free(string);
2790 return E_UNEXPECTED;
2791 }
2792
2793 tlbstr = heap_alloc(sizeof(TLBString));
2794
2795 tlbstr->offset = offs;
2796 tlbstr->str = SysAllocStringByteLen(NULL, lengthInChars * sizeof(WCHAR));
2797 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, string, -1, tlbstr->str, lengthInChars);
2798
2799 heap_free(string);
2800
2801 list_add_tail(&pcx->pLibInfo->string_list, &tlbstr->entry);
2802
2803 offs += len_piece;
2804 }
2805 }
2806
2807 static HRESULT MSFT_ReadAllRefs(TLBContext *pcx)
2808 {
2809 TLBRefType *ref;
2810 int offs = 0;
2811
2812 MSFT_Seek(pcx, pcx->pTblDir->pImpInfo.offset);
2813 while (offs < pcx->pTblDir->pImpInfo.length) {
2814 MSFT_ImpInfo impinfo;
2815 TLBImpLib *pImpLib;
2816
2817 MSFT_ReadLEDWords(&impinfo, sizeof(impinfo), pcx, DO_NOT_SEEK);
2818
2819 ref = heap_alloc_zero(sizeof(TLBRefType));
2820 list_add_tail(&pcx->pLibInfo->ref_list, &ref->entry);
2821
2822 LIST_FOR_EACH_ENTRY(pImpLib, &pcx->pLibInfo->implib_list, TLBImpLib, entry)
2823 if(pImpLib->offset==impinfo.oImpFile)
2824 break;
2825
2826 if(&pImpLib->entry != &pcx->pLibInfo->implib_list){
2827 ref->reference = offs;
2828 ref->pImpTLInfo = pImpLib;
2829 if(impinfo.flags & MSFT_IMPINFO_OFFSET_IS_GUID) {
2830 ref->guid = MSFT_ReadGuid(impinfo.oGuid, pcx);
2831 TRACE("importing by guid %s\n", debugstr_guid(TLB_get_guidref(ref->guid)));
2832 ref->index = TLB_REF_USE_GUID;
2833 } else
2834 ref->index = impinfo.oGuid;
2835 }else{
2836 ERR("Cannot find a reference\n");
2837 ref->reference = -1;
2838 ref->pImpTLInfo = TLB_REF_NOT_FOUND;
2839 }
2840
2841 offs += sizeof(impinfo);
2842 }
2843
2844 return S_OK;
2845 }
2846
2847 /* Because type library parsing has some degree of overhead, and some apps repeatedly load the same
2848 * typelibs over and over, we cache them here. According to MSDN Microsoft have a similar scheme in
2849 * place. This will cause a deliberate memory leak, but generally losing RAM for cycles is an acceptable
2850 * tradeoff here.
2851 */
2852 static struct list tlb_cache = LIST_INIT(tlb_cache);
2853 static CRITICAL_SECTION cache_section;
2854 static CRITICAL_SECTION_DEBUG cache_section_debug =
2855 {
2856 0, 0, &cache_section,
2857 { &cache_section_debug.ProcessLocksList, &cache_section_debug.ProcessLocksList },
2858 0, 0, { (DWORD_PTR)(__FILE__ ": typelib loader cache") }
2859 };
2860 static CRITICAL_SECTION cache_section = { &cache_section_debug, -1, 0, 0, 0, 0 };
2861
2862
2863 typedef struct TLB_PEFile
2864 {
2865 IUnknown IUnknown_iface;
2866 LONG refs;
2867 HMODULE dll;
2868 HRSRC typelib_resource;
2869 HGLOBAL typelib_global;
2870 LPVOID typelib_base;
2871 } TLB_PEFile;
2872
2873 static inline TLB_PEFile *pefile_impl_from_IUnknown(IUnknown *iface)
2874 {
2875 return CONTAINING_RECORD(iface, TLB_PEFile, IUnknown_iface);
2876 }
2877
2878 static HRESULT WINAPI TLB_PEFile_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2879 {
2880 if (IsEqualIID(riid, &IID_IUnknown))
2881 {
2882 *ppv = iface;
2883 IUnknown_AddRef(iface);
2884 return S_OK;
2885 }
2886 *ppv = NULL;
2887 return E_NOINTERFACE;
2888 }
2889
2890 static ULONG WINAPI TLB_PEFile_AddRef(IUnknown *iface)
2891 {
2892 TLB_PEFile *This = pefile_impl_from_IUnknown(iface);
2893 return InterlockedIncrement(&This->refs);
2894 }
2895
2896 static ULONG WINAPI TLB_PEFile_Release(IUnknown *iface)
2897 {
2898 TLB_PEFile *This = pefile_impl_from_IUnknown(iface);
2899 ULONG refs = InterlockedDecrement(&This->refs);
2900 if (!refs)
2901 {
2902 if (This->typelib_global)
2903 FreeResource(This->typelib_global);
2904 if (This->dll)
2905 FreeLibrary(This->dll);
2906 heap_free(This);
2907 }
2908 return refs;
2909 }
2910
2911 static const IUnknownVtbl TLB_PEFile_Vtable =
2912 {
2913 TLB_PEFile_QueryInterface,
2914 TLB_PEFile_AddRef,
2915 TLB_PEFile_Release
2916 };
2917
2918 static HRESULT TLB_PEFile_Open(LPCWSTR path, INT index, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile)
2919 {
2920 TLB_PEFile *This;
2921 HRESULT hr = TYPE_E_CANTLOADLIBRARY;
2922
2923 This = heap_alloc(sizeof(TLB_PEFile));
2924 if (!This)
2925 return E_OUTOFMEMORY;
2926
2927 This->IUnknown_iface.lpVtbl = &TLB_PEFile_Vtable;
2928 This->refs = 1;
2929 This->dll = NULL;
2930 This->typelib_resource = NULL;
2931 This->typelib_global = NULL;
2932 This->typelib_base = NULL;
2933
2934 This->dll = LoadLibraryExW(path, 0, DONT_RESOLVE_DLL_REFERENCES |
2935 LOAD_LIBRARY_AS_DATAFILE | LOAD_WITH_ALTERED_SEARCH_PATH);
2936
2937 if (This->dll)
2938 {
2939 static const WCHAR TYPELIBW[] = {'T','Y','P','E','L','I','B',0};
2940 This->typelib_resource = FindResourceW(This->dll, MAKEINTRESOURCEW(index), TYPELIBW);
2941 if (This->typelib_resource)
2942 {
2943 This->typelib_global = LoadResource(This->dll, This->typelib_resource);
2944 if (This->typelib_global)
2945 {
2946 This->typelib_base = LockResource(This->typelib_global);
2947
2948 if (This->typelib_base)
2949 {
2950 *pdwTLBLength = SizeofResource(This->dll, This->typelib_resource);
2951 *ppBase = This->typelib_base;
2952 *ppFile = &This->IUnknown_iface;
2953 return S_OK;
2954 }
2955 }
2956 }
2957
2958 TRACE("No TYPELIB resource found\n");
2959 hr = E_FAIL;
2960 }
2961
2962 TLB_PEFile_Release(&This->IUnknown_iface);
2963 return hr;
2964 }
2965
2966 typedef struct TLB_NEFile
2967 {
2968 IUnknown IUnknown_iface;
2969 LONG refs;
2970 LPVOID typelib_base;
2971 } TLB_NEFile;
2972
2973 static inline TLB_NEFile *nefile_impl_from_IUnknown(IUnknown *iface)
2974 {
2975 return CONTAINING_RECORD(iface, TLB_NEFile, IUnknown_iface);
2976 }
2977
2978 static HRESULT WINAPI TLB_NEFile_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2979 {
2980 if (IsEqualIID(riid, &IID_IUnknown))
2981 {
2982 *ppv = iface;
2983 IUnknown_AddRef(iface);
2984 return S_OK;
2985 }
2986 *ppv = NULL;
2987 return E_NOINTERFACE;
2988 }
2989
2990 static ULONG WINAPI TLB_NEFile_AddRef(IUnknown *iface)
2991 {
2992 TLB_NEFile *This = nefile_impl_from_IUnknown(iface);
2993 return InterlockedIncrement(&This->refs);
2994 }
2995
2996 static ULONG WINAPI TLB_NEFile_Release(IUnknown *iface)
2997 {
2998 TLB_NEFile *This = nefile_impl_from_IUnknown(iface);
2999 ULONG refs = InterlockedDecrement(&This->refs);
3000 if (!refs)
3001 {
3002 heap_free(This->typelib_base);
3003 heap_free(This);
3004 }
3005 return refs;
3006 }
3007
3008 static const IUnknownVtbl TLB_NEFile_Vtable =
3009 {
3010 TLB_NEFile_QueryInterface,
3011 TLB_NEFile_AddRef,
3012 TLB_NEFile_Release
3013 };
3014
3015 /***********************************************************************
3016 * read_xx_header [internal]
3017 */
3018 static int read_xx_header( HFILE lzfd )
3019 {
3020 IMAGE_DOS_HEADER mzh;
3021 char magic[3];
3022
3023 LZSeek( lzfd, 0, SEEK_SET );
3024 if ( sizeof(mzh) != LZRead( lzfd, (LPSTR)&mzh, sizeof(mzh) ) )
3025 return 0;
3026 if ( mzh.e_magic != IMAGE_DOS_SIGNATURE )
3027 return 0;
3028
3029 LZSeek( lzfd, mzh.e_lfanew, SEEK_SET );
3030 if ( 2 != LZRead( lzfd, magic, 2 ) )
3031 return 0;
3032
3033 LZSeek( lzfd, mzh.e_lfanew, SEEK_SET );
3034
3035 if ( magic[0] == 'N' && magic[1] == 'E' )
3036 return IMAGE_OS2_SIGNATURE;
3037 if ( magic[0] == 'P' && magic[1] == 'E' )
3038 return IMAGE_NT_SIGNATURE;
3039
3040 magic[2] = '\0';
3041 WARN("Can't handle %s files.\n", magic );
3042 return 0;
3043 }
3044
3045
3046 /***********************************************************************
3047 * find_ne_resource [internal]
3048 */
3049 static BOOL find_ne_resource( HFILE lzfd, LPCSTR typeid, LPCSTR resid,
3050 DWORD *resLen, DWORD *resOff )
3051 {
3052 IMAGE_OS2_HEADER nehd;
3053 NE_TYPEINFO *typeInfo;
3054 NE_NAMEINFO *nameInfo;
3055 DWORD nehdoffset;
3056 LPBYTE resTab;
3057 DWORD resTabSize;
3058 int count;
3059
3060 /* Read in NE header */
3061 nehdoffset = LZSeek( lzfd, 0, SEEK_CUR );
3062 if ( sizeof(nehd) != LZRead( lzfd, (LPSTR)&nehd, sizeof(nehd) ) ) return FALSE;
3063
3064 resTabSize = nehd.ne_restab - nehd.ne_rsrctab;
3065 if ( !resTabSize )
3066 {
3067 TRACE("No resources in NE dll\n" );
3068 return FALSE;
3069 }
3070
3071 /* Read in resource table */
3072 resTab = heap_alloc( resTabSize );
3073 if ( !resTab ) return FALSE;
3074
3075 LZSeek( lzfd, nehd.ne_rsrctab + nehdoffset, SEEK_SET );
3076 if ( resTabSize != LZRead( lzfd, (char*)resTab, resTabSize ) )
3077 {
3078 heap_free( resTab );
3079 return FALSE;
3080 }
3081
3082 /* Find resource */
3083 typeInfo = (NE_TYPEINFO *)(resTab + 2);
3084
3085 if (!IS_INTRESOURCE(typeid)) /* named type */
3086 {
3087 BYTE len = strlen( typeid );
3088 while (typeInfo->type_id)
3089 {
3090 if (!(typeInfo->type_id & 0x8000))
3091 {
3092 BYTE *p = resTab + typeInfo->type_id;
3093 if ((*p == len) && !_strnicmp( (char*)p+1, typeid, len )) goto found_type;
3094 }
3095 typeInfo = (NE_TYPEINFO *)((char *)(typeInfo + 1) +
3096 typeInfo->count * sizeof(NE_NAMEINFO));
3097 }
3098 }
3099 else /* numeric type id */
3100 {
3101 WORD id = LOWORD(typeid) | 0x8000;
3102 while (typeInfo->type_id)
3103 {
3104 if (typeInfo->type_id == id) goto found_type;
3105 typeInfo = (NE_TYPEINFO *)((char *)(typeInfo + 1) +
3106 typeInfo->count * sizeof(NE_NAMEINFO));
3107 }
3108 }
3109 TRACE("No typeid entry found for %p\n", typeid );