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