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