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