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