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