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[] = {'{','','','','2','','4','2','4','-',
523 '','','','','-','','','','','-','C','','','','-',
524 '','','','','','','','','','','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 (SUCCEEDED(ITypeLib_GetDocumentation(ptlib, -1, NULL, &doc, NULL, NULL)))
556 {
557 if (RegSetValueExW(key, NULL, 0, REG_SZ,
558 (BYTE *)doc, (lstrlenW(doc)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS)
559 res = E_FAIL;
560
561 SysFreeString(doc);
562 }
563 else
564 res = E_FAIL;
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
934 /* strings can be stored in tlb as multibyte strings BUT they are *always*
935 * exported to the application as a UNICODE string.
936 */
937 BSTR Name;
938 BSTR DocString;
939 BSTR HelpFile;
940 BSTR HelpStringDll;
941 unsigned long dwHelpContext;
942 int TypeInfoCount; /* nr of typeinfo's in librarry */
943 struct tagITypeInfoImpl *pTypeInfo; /* linked list of type info data */
944 int ctCustData; /* number of items in cust data list */
945 TLBCustData * pCustData; /* linked list to cust data */
946 TLBImpLib * pImpLibs; /* linked list to all imported typelibs */
947 int ctTypeDesc; /* number of items in type desc array */
948 TYPEDESC * pTypeDesc; /* array of TypeDescriptions found in the
949 library. Only used while reading MSFT
950 typelibs */
951 struct list ref_list; /* list of ref types in this typelib */
952 HREFTYPE dispatch_href; /* reference to IDispatch, -1 if unused */
953
954
955 /* typelibs are cached, keyed by path and index, so store the linked list info within them */
956 struct tagITypeLibImpl *next, *prev;
957 WCHAR *path;
958 INT index;
959 } ITypeLibImpl;
960
961 static const ITypeLib2Vtbl tlbvt;
962 static const ITypeCompVtbl tlbtcvt;
963
964 static inline ITypeLibImpl *impl_from_ITypeComp( ITypeComp *iface )
965 {
966 return (ITypeLibImpl *)((char*)iface - FIELD_OFFSET(ITypeLibImpl, lpVtblTypeComp));
967 }
968
969 /* ITypeLib methods */
970 static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength);
971 static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength);
972
973 /*======================= ITypeInfo implementation =======================*/
974
975 /* data for referenced types */
976 typedef struct tagTLBRefType
977 {
978 INT index; /* Type index for internal ref or for external ref
979 it the format is SLTG. -2 indicates to
980 use guid */
981
982 GUID guid; /* guid of the referenced type */
983 /* if index == TLB_REF_USE_GUID */
984
985 HREFTYPE reference; /* The href of this ref */
986 TLBImpLib *pImpTLInfo; /* If ref is external ptr to library data
987 TLB_REF_INTERNAL for internal refs
988 TLB_REF_NOT_FOUND for broken refs */
989
990 struct list entry;
991 } TLBRefType;
992
993 #define TLB_REF_USE_GUID -2
994
995 #define TLB_REF_INTERNAL (void*)-2
996 #define TLB_REF_NOT_FOUND (void*)-1
997
998 /* internal Parameter data */
999 typedef struct tagTLBParDesc
1000 {
1001 BSTR Name;
1002 int ctCustData;
1003 TLBCustData * pCustData; /* linked list to cust data */
1004 } TLBParDesc;
1005
1006 /* internal Function data */
1007 typedef struct tagTLBFuncDesc
1008 {
1009 FUNCDESC funcdesc; /* lots of info on the function and its attributes. */
1010 BSTR Name; /* the name of this function */
1011 TLBParDesc *pParamDesc; /* array with param names and custom data */
1012 int helpcontext;
1013 int HelpStringContext;
1014 BSTR HelpString;
1015 BSTR Entry; /* if its Hiword==0, it numeric; -1 is not present*/
1016 int ctCustData;
1017 TLBCustData * pCustData; /* linked list to cust data; */
1018 struct tagTLBFuncDesc * next;
1019 } TLBFuncDesc;
1020
1021 /* internal Variable data */
1022 typedef struct tagTLBVarDesc
1023 {
1024 VARDESC vardesc; /* lots of info on the variable and its attributes. */
1025 BSTR Name; /* the name of this variable */
1026 int HelpContext;
1027 int HelpStringContext; /* FIXME: where? */
1028 BSTR HelpString;
1029 int ctCustData;
1030 TLBCustData * pCustData;/* linked list to cust data; */
1031 struct tagTLBVarDesc * next;
1032 } TLBVarDesc;
1033
1034 /* internal implemented interface data */
1035 typedef struct tagTLBImplType
1036 {
1037 HREFTYPE hRef; /* hRef of interface */
1038 int implflags; /* IMPLFLAG_*s */
1039 int ctCustData;
1040 TLBCustData * pCustData;/* linked list to custom data; */
1041 struct tagTLBImplType *next;
1042 } TLBImplType;
1043
1044 /* internal TypeInfo data */
1045 typedef struct tagITypeInfoImpl
1046 {
1047 const ITypeInfo2Vtbl *lpVtbl;
1048 const ITypeCompVtbl *lpVtblTypeComp;
1049 LONG ref;
1050 BOOL no_free_data; /* don't free data structures */
1051 TYPEATTR TypeAttr ; /* _lots_ of type information. */
1052 ITypeLibImpl * pTypeLib; /* back pointer to typelib */
1053 int index; /* index in this typelib; */
1054 HREFTYPE hreftype; /* hreftype for app object binding */
1055 /* type libs seem to store the doc strings in ascii
1056 * so why should we do it in unicode?
1057 */
1058 BSTR Name;
1059 BSTR DocString;
1060 BSTR DllName;
1061 unsigned long dwHelpContext;
1062 unsigned long dwHelpStringContext;
1063
1064 /* functions */
1065 TLBFuncDesc * funclist; /* linked list with function descriptions */
1066
1067 /* variables */
1068 TLBVarDesc * varlist; /* linked list with variable descriptions */
1069
1070 /* Implemented Interfaces */
1071 TLBImplType * impltypelist;
1072
1073 int ctCustData;
1074 TLBCustData * pCustData; /* linked list to cust data; */
1075 struct tagITypeInfoImpl * next;
1076 } ITypeInfoImpl;
1077
1078 static inline ITypeInfoImpl *info_impl_from_ITypeComp( ITypeComp *iface )
1079 {
1080 return (ITypeInfoImpl *)((char*)iface - FIELD_OFFSET(ITypeInfoImpl, lpVtblTypeComp));
1081 }
1082
1083 static const ITypeInfo2Vtbl tinfvt;
1084 static const ITypeCompVtbl tcompvt;
1085
1086 static ITypeInfo2 * ITypeInfo_Constructor(void);
1087
1088 typedef struct tagTLBContext
1089 {
1090 unsigned int oStart; /* start of TLB in file */
1091 unsigned int pos; /* current pos */
1092 unsigned int length; /* total length */
1093 void *mapping; /* memory mapping */
1094 MSFT_SegDir * pTblDir;
1095 ITypeLibImpl* pLibInfo;
1096 } TLBContext;
1097
1098
1099 static void MSFT_DoRefType(TLBContext *pcx, ITypeLibImpl *pTL, int offset);
1100
1101 /*
1102 debug
1103 */
1104 static void dump_TypeDesc(const TYPEDESC *pTD,char *szVarType) {
1105 if (pTD->vt & VT_RESERVED)
1106 szVarType += strlen(strcpy(szVarType, "reserved | "));
1107 if (pTD->vt & VT_BYREF)
1108 szVarType += strlen(strcpy(szVarType, "ref to "));
1109 if (pTD->vt & VT_ARRAY)
1110 szVarType += strlen(strcpy(szVarType, "array of "));
1111 if (pTD->vt & VT_VECTOR)
1112 szVarType += strlen(strcpy(szVarType, "vector of "));
1113 switch(pTD->vt & VT_TYPEMASK) {
1114 case VT_UI1: sprintf(szVarType, "VT_UI1"); break;
1115 case VT_I2: sprintf(szVarType, "VT_I2"); break;
1116 case VT_I4: sprintf(szVarType, "VT_I4"); break;
1117 case VT_R4: sprintf(szVarType, "VT_R4"); break;
1118 case VT_R8: sprintf(szVarType, "VT_R8"); break;
1119 case VT_BOOL: sprintf(szVarType, "VT_BOOL"); break;
1120 case VT_ERROR: sprintf(szVarType, "VT_ERROR"); break;
1121 case VT_CY: sprintf(szVarType, "VT_CY"); break;
1122 case VT_DATE: sprintf(szVarType, "VT_DATE"); break;
1123 case VT_BSTR: sprintf(szVarType, "VT_BSTR"); break;
1124 case VT_UNKNOWN: sprintf(szVarType, "VT_UNKNOWN"); break;
1125 case VT_DISPATCH: sprintf(szVarType, "VT_DISPATCH"); break;
1126 case VT_I1: sprintf(szVarType, "VT_I1"); break;
1127 case VT_UI2: sprintf(szVarType, "VT_UI2"); break;
1128 case VT_UI4: sprintf(szVarType, "VT_UI4"); break;
1129 case VT_INT: sprintf(szVarType, "VT_INT"); break;
1130 case VT_UINT: sprintf(szVarType, "VT_UINT"); break;
1131 case VT_VARIANT: sprintf(szVarType, "VT_VARIANT"); break;
1132 case VT_VOID: sprintf(szVarType, "VT_VOID"); break;
1133 case VT_HRESULT: sprintf(szVarType, "VT_HRESULT"); break;
1134 case VT_USERDEFINED: sprintf(szVarType, "VT_USERDEFINED ref = %x",
1135 pTD->u.hreftype); break;
1136 case VT_LPSTR: sprintf(szVarType, "VT_LPSTR"); break;
1137 case VT_LPWSTR: sprintf(szVarType, "VT_LPWSTR"); break;
1138 case VT_PTR: sprintf(szVarType, "ptr to ");
1139 dump_TypeDesc(pTD->u.lptdesc, szVarType + 7);
1140 break;
1141 case VT_SAFEARRAY: sprintf(szVarType, "safearray of ");
1142 dump_TypeDesc(pTD->u.lptdesc, szVarType + 13);
1143 break;
1144 case VT_CARRAY: sprintf(szVarType, "%d dim array of ",
1145 pTD->u.lpadesc->cDims); /* FIXME print out sizes */
1146 dump_TypeDesc(&pTD->u.lpadesc->tdescElem, szVarType + strlen(szVarType));
1147 break;
1148
1149 default: sprintf(szVarType, "unknown(%d)", pTD->vt & VT_TYPEMASK); break;
1150 }
1151 }
1152
1153 static void dump_ELEMDESC(const ELEMDESC *edesc) {
1154 char buf[200];
1155 USHORT flags = edesc->u.paramdesc.wParamFlags;
1156 dump_TypeDesc(&edesc->tdesc,buf);
1157 MESSAGE("\t\ttdesc.vartype %d (%s)\n",edesc->tdesc.vt,buf);
1158 MESSAGE("\t\tu.paramdesc.wParamFlags");
1159 if (!flags) MESSAGE(" PARAMFLAGS_NONE");
1160 if (flags & PARAMFLAG_FIN) MESSAGE(" PARAMFLAG_FIN");
1161 if (flags & PARAMFLAG_FOUT) MESSAGE(" PARAMFLAG_FOUT");
1162 if (flags & PARAMFLAG_FLCID) MESSAGE(" PARAMFLAG_FLCID");
1163 if (flags & PARAMFLAG_FRETVAL) MESSAGE(" PARAMFLAG_FRETVAL");
1164 if (flags & PARAMFLAG_FOPT) MESSAGE(" PARAMFLAG_FOPT");
1165 if (flags & PARAMFLAG_FHASDEFAULT) MESSAGE(" PARAMFLAG_FHASDEFAULT");
1166 if (flags & PARAMFLAG_FHASCUSTDATA) MESSAGE(" PARAMFLAG_FHASCUSTDATA");
1167 MESSAGE("\n\t\tu.paramdesc.lpex %p\n",edesc->u.paramdesc.pparamdescex);
1168 }
1169 static void dump_FUNCDESC(const FUNCDESC *funcdesc) {
1170 int i;
1171 MESSAGE("memid is %08x\n",funcdesc->memid);
1172 for (i=0;i<funcdesc->cParams;i++) {
1173 MESSAGE("Param %d:\n",i);
1174 dump_ELEMDESC(funcdesc->lprgelemdescParam+i);
1175 }
1176 MESSAGE("\tfunckind: %d (",funcdesc->funckind);
1177 switch (funcdesc->funckind) {
1178 case FUNC_VIRTUAL: MESSAGE("virtual");break;
1179 case FUNC_PUREVIRTUAL: MESSAGE("pure virtual");break;
1180 case FUNC_NONVIRTUAL: MESSAGE("nonvirtual");break;
1181 case FUNC_STATIC: MESSAGE("static");break;
1182 case FUNC_DISPATCH: MESSAGE("dispatch");break;
1183 default: MESSAGE("unknown");break;
1184 }
1185 MESSAGE(")\n\tinvkind: %d (",funcdesc->invkind);
1186 switch (funcdesc->invkind) {
1187 case INVOKE_FUNC: MESSAGE("func");break;
1188 case INVOKE_PROPERTYGET: MESSAGE("property get");break;
1189 case INVOKE_PROPERTYPUT: MESSAGE("property put");break;
1190 case INVOKE_PROPERTYPUTREF: MESSAGE("property put ref");break;
1191 }
1192 MESSAGE(")\n\tcallconv: %d (",funcdesc->callconv);
1193 switch (funcdesc->callconv) {
1194 case CC_CDECL: MESSAGE("cdecl");break;
1195 case CC_PASCAL: MESSAGE("pascal");break;
1196 case CC_STDCALL: MESSAGE("stdcall");break;
1197 case CC_SYSCALL: MESSAGE("syscall");break;
1198 default:break;
1199 }
1200 MESSAGE(")\n\toVft: %d\n", funcdesc->oVft);
1201 MESSAGE("\tcParamsOpt: %d\n", funcdesc->cParamsOpt);
1202 MESSAGE("\twFlags: %x\n", funcdesc->wFuncFlags);
1203
1204 MESSAGE("\telemdescFunc (return value type):\n");
1205 dump_ELEMDESC(&funcdesc->elemdescFunc);
1206 }
1207
1208 static const char * const typekind_desc[] =
1209 {
1210 "TKIND_ENUM",
1211 "TKIND_RECORD",
1212 "TKIND_MODULE",
1213 "TKIND_INTERFACE",
1214 "TKIND_DISPATCH",
1215 "TKIND_COCLASS",
1216 "TKIND_ALIAS",
1217 "TKIND_UNION",
1218 "TKIND_MAX"
1219 };
1220
1221 static void dump_TLBFuncDescOne(const TLBFuncDesc * pfd)
1222 {
1223 int i;
1224 MESSAGE("%s(%u)\n", debugstr_w(pfd->Name), pfd->funcdesc.cParams);
1225 for (i=0;i<pfd->funcdesc.cParams;i++)
1226 MESSAGE("\tparm%d: %s\n",i,debugstr_w(pfd->pParamDesc[i].Name));
1227
1228
1229 dump_FUNCDESC(&(pfd->funcdesc));
1230
1231 MESSAGE("\thelpstring: %s\n", debugstr_w(pfd->HelpString));
1232 MESSAGE("\tentry: %s\n", (pfd->Entry == (void *)-1) ? "invalid" : debugstr_w(pfd->Entry));
1233 }
1234 static void dump_TLBFuncDesc(const TLBFuncDesc * pfd)
1235 {
1236 while (pfd)
1237 {
1238 dump_TLBFuncDescOne(pfd);
1239 pfd = pfd->next;
1240 };
1241 }
1242 static void dump_TLBVarDesc(const TLBVarDesc * pvd)
1243 {
1244 while (pvd)
1245 {
1246 TRACE_(typelib)("%s\n", debugstr_w(pvd->Name));
1247 pvd = pvd->next;
1248 };
1249 }
1250
1251 static void dump_TLBImpLib(const TLBImpLib *import)
1252 {
1253 TRACE_(typelib)("%s %s\n", debugstr_guid(&(import->guid)),
1254 debugstr_w(import->name));
1255 TRACE_(typelib)("v%d.%d lcid=%x offset=%x\n", import->wVersionMajor,
1256 import->wVersionMinor, import->lcid, import->offset);
1257 }
1258
1259 static void dump_TLBRefType(const ITypeLibImpl *pTL)
1260 {
1261 TLBRefType *ref;
1262
1263 LIST_FOR_EACH_ENTRY(ref, &pTL->ref_list, TLBRefType, entry)
1264 {
1265 TRACE_(typelib)("href:0x%08x\n", ref->reference);
1266 if(ref->index == -1)
1267 TRACE_(typelib)("%s\n", debugstr_guid(&(ref->guid)));
1268 else
1269 TRACE_(typelib)("type no: %d\n", ref->index);
1270
1271 if(ref->pImpTLInfo != TLB_REF_INTERNAL && ref->pImpTLInfo != TLB_REF_NOT_FOUND)
1272 {
1273 TRACE_(typelib)("in lib\n");
1274 dump_TLBImpLib(ref->pImpTLInfo);
1275 }
1276 }
1277 }
1278
1279 static void dump_TLBImplType(const TLBImplType * impl)
1280 {
1281 while (impl) {
1282 TRACE_(typelib)(
1283 "implementing/inheriting interface hRef = %x implflags %x\n",
1284 impl->hRef, impl->implflags);
1285 impl = impl->next;
1286 }
1287 }
1288
1289 static void dump_Variant(const VARIANT * pvar)
1290 {
1291 SYSTEMTIME st;
1292
1293 TRACE("%p->{%s%s", pvar, debugstr_VT(pvar), debugstr_VF(pvar));
1294
1295 if (pvar)
1296 {
1297 if (V_ISBYREF(pvar) || V_TYPE(pvar) == VT_UNKNOWN ||
1298 V_TYPE(pvar) == VT_DISPATCH || V_TYPE(pvar) == VT_RECORD)
1299 {
1300 TRACE(",%p", V_BYREF(pvar));
1301 }
1302 else if (V_ISARRAY(pvar) || V_ISVECTOR(pvar))
1303 {
1304 TRACE(",%p", V_ARRAY(pvar));
1305 }
1306 else switch (V_TYPE(pvar))
1307 {
1308 case VT_I1: TRACE(",%d", V_I1(pvar)); break;
1309 case VT_UI1: TRACE(",%d", V_UI1(pvar)); break;
1310 case VT_I2: TRACE(",%d", V_I2(pvar)); break;
1311 case VT_UI2: TRACE(",%d", V_UI2(pvar)); break;
1312 case VT_INT:
1313 case VT_I4: TRACE(",%d", V_I4(pvar)); break;
1314 case VT_UINT:
1315 case VT_UI4: TRACE(",%d", V_UI4(pvar)); break;
1316 case VT_I8: TRACE(",0x%08x,0x%08x", (ULONG)(V_I8(pvar) >> 32),
1317 (ULONG)(V_I8(pvar) & 0xffffffff)); break;
1318 case VT_UI8: TRACE(",0x%08x,0x%08x", (ULONG)(V_UI8(pvar) >> 32),
1319 (ULONG)(V_UI8(pvar) & 0xffffffff)); break;
1320 case VT_R4: TRACE(",%3.3e", V_R4(pvar)); break;
1321 case VT_R8: TRACE(",%3.3e", V_R8(pvar)); break;
1322 case VT_BOOL: TRACE(",%s", V_BOOL(pvar) ? "TRUE" : "FALSE"); break;
1323 case VT_BSTR: TRACE(",%s", debugstr_w(V_BSTR(pvar))); break;
1324 case VT_CY: TRACE(",0x%08x,0x%08x", V_CY(pvar).s.Hi,
1325 V_CY(pvar).s.Lo); break;
1326 case VT_DATE:
1327 if(!VariantTimeToSystemTime(V_DATE(pvar), &st))
1328 TRACE(",<invalid>");
1329 else
1330 TRACE(",%04d/%02d/%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay,
1331 st.wHour, st.wMinute, st.wSecond);
1332 break;
1333 case VT_ERROR:
1334 case VT_VOID:
1335 case VT_USERDEFINED:
1336 case VT_EMPTY:
1337 case VT_NULL: break;
1338 default: TRACE(",?"); break;
1339 }
1340 }
1341 TRACE("}\n");
1342 }
1343
1344 static void dump_DispParms(const DISPPARAMS * pdp)
1345 {
1346 unsigned int index;
1347
1348 TRACE("args=%u named args=%u\n", pdp->cArgs, pdp->cNamedArgs);
1349
1350 if (pdp->cNamedArgs && pdp->rgdispidNamedArgs)
1351 {
1352 TRACE("named args:\n");
1353 for (index = 0; index < pdp->cNamedArgs; index++)
1354 TRACE( "\t0x%x\n", pdp->rgdispidNamedArgs[index] );
1355 }
1356
1357 if (pdp->cArgs && pdp->rgvarg)
1358 {
1359 TRACE("args:\n");
1360 for (index = 0; index < pdp->cArgs; index++)
1361 dump_Variant( &pdp->rgvarg[index] );
1362 }
1363 }
1364
1365 static void dump_TypeInfo(const ITypeInfoImpl * pty)
1366 {
1367 TRACE("%p ref=%u\n", pty, pty->ref);
1368 TRACE("%s %s\n", debugstr_w(pty->Name), debugstr_w(pty->DocString));
1369 TRACE("attr:%s\n", debugstr_guid(&(pty->TypeAttr.guid)));
1370 TRACE("kind:%s\n", typekind_desc[pty->TypeAttr.typekind]);
1371 TRACE("fct:%u var:%u impl:%u\n",
1372 pty->TypeAttr.cFuncs, pty->TypeAttr.cVars, pty->TypeAttr.cImplTypes);
1373 TRACE("wTypeFlags: 0x%04x\n", pty->TypeAttr.wTypeFlags);
1374 TRACE("parent tlb:%p index in TLB:%u\n",pty->pTypeLib, pty->index);
1375 if (pty->TypeAttr.typekind == TKIND_MODULE) TRACE("dllname:%s\n", debugstr_w(pty->DllName));
1376 if (TRACE_ON(ole))
1377 dump_TLBFuncDesc(pty->funclist);
1378 dump_TLBVarDesc(pty->varlist);
1379 dump_TLBImplType(pty->impltypelist);
1380 }
1381
1382 static void dump_VARDESC(const VARDESC *v)
1383 {
1384 MESSAGE("memid %d\n",v->memid);
1385 MESSAGE("lpstrSchema %s\n",debugstr_w(v->lpstrSchema));
1386 MESSAGE("oInst %d\n",v->u.oInst);
1387 dump_ELEMDESC(&(v->elemdescVar));
1388 MESSAGE("wVarFlags %x\n",v->wVarFlags);
1389 MESSAGE("varkind %d\n",v->varkind);
1390 }
1391
1392 static TYPEDESC stndTypeDesc[VT_LPWSTR+1]=
1393 {
1394 /* VT_LPWSTR is largest type that */
1395 /* may appear in type description*/
1396 {{0}, 0},{{0}, 1},{{0}, 2},{{0}, 3},{{0}, 4},
1397 {{0}, 5},{{0}, 6},{{0}, 7},{{0}, 8},{{0}, 9},
1398 {{0},10},{{0},11},{{0},12},{{0},13},{{0},14},
1399 {{0},15},{{0},16},{{0},17},{{0},18},{{0},19},
1400 {{0},20},{{0},21},{{0},22},{{0},23},{{0},24},
1401 {{0},25},{{0},26},{{0},27},{{0},28},{{0},29},
1402 {{0},30},{{0},31}
1403 };
1404
1405 static void TLB_abort(void)
1406 {
1407 DebugBreak();
1408 }
1409
1410 static void * TLB_Alloc(unsigned size) __WINE_ALLOC_SIZE(1);
1411 static void * TLB_Alloc(unsigned size)
1412 {
1413 void * ret;
1414 if((ret=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size))==NULL){
1415 /* FIXME */
1416 ERR("cannot allocate memory\n");
1417 }
1418 return ret;
1419 }
1420
1421 static void TLB_Free(void * ptr)
1422 {
1423 HeapFree(GetProcessHeap(), 0, ptr);
1424 }
1425
1426 /* returns the size required for a deep copy of a typedesc into a
1427 * flat buffer */
1428 static SIZE_T TLB_SizeTypeDesc( const TYPEDESC *tdesc, BOOL alloc_initial_space )
1429 {
1430 SIZE_T size = 0;
1431
1432 if (alloc_initial_space)
1433 size += sizeof(TYPEDESC);
1434
1435 switch (tdesc->vt)
1436 {
1437 case VT_PTR:
1438 case VT_SAFEARRAY:
1439 size += TLB_SizeTypeDesc(tdesc->u.lptdesc, TRUE);
1440 break;
1441 case VT_CARRAY:
1442 size += FIELD_OFFSET(ARRAYDESC, rgbounds[tdesc->u.lpadesc->cDims]);
1443 size += TLB_SizeTypeDesc(&tdesc->u.lpadesc->tdescElem, FALSE);
1444 break;
1445 }
1446 return size;
1447 }
1448
1449 /* deep copy a typedesc into a flat buffer */
1450 static void *TLB_CopyTypeDesc( TYPEDESC *dest, const TYPEDESC *src, void *buffer )
1451 {
1452 if (!dest)
1453 {
1454 dest = buffer;
1455 buffer = (char *)buffer + sizeof(TYPEDESC);
1456 }
1457
1458 *dest = *src;
1459
1460 switch (src->vt)
1461 {
1462 case VT_PTR:
1463 case VT_SAFEARRAY:
1464 dest->u.lptdesc = buffer;
1465 buffer = TLB_CopyTypeDesc(NULL, src->u.lptdesc, buffer);
1466 break;
1467 case VT_CARRAY:
1468 dest->u.lpadesc = buffer;
1469 memcpy(dest->u.lpadesc, src->u.lpadesc, FIELD_OFFSET(ARRAYDESC, rgbounds[src->u.lpadesc->cDims]));
1470 buffer = (char *)buffer + FIELD_OFFSET(ARRAYDESC, rgbounds[src->u.lpadesc->cDims]);
1471 buffer = TLB_CopyTypeDesc(&dest->u.lpadesc->tdescElem, &src->u.lpadesc->tdescElem, buffer);
1472 break;
1473 }
1474 return buffer;
1475 }
1476
1477 /* free custom data allocated by MSFT_CustData */
1478 static inline void TLB_FreeCustData(TLBCustData *pCustData)
1479 {
1480 TLBCustData *pCustDataNext;
1481 for (; pCustData; pCustData = pCustDataNext)
1482 {
1483 VariantClear(&pCustData->data);
1484
1485 pCustDataNext = pCustData->next;
1486 TLB_Free(pCustData);
1487 }
1488 }
1489
1490 static BSTR TLB_MultiByteToBSTR(const char *ptr)
1491 {
1492 DWORD len;
1493 BSTR ret;
1494
1495 len = MultiByteToWideChar(CP_ACP, 0, ptr, -1, NULL, 0);
1496 ret = SysAllocStringLen(NULL, len - 1);
1497 if (!ret) return ret;
1498 MultiByteToWideChar(CP_ACP, 0, ptr, -1, ret, len);
1499 return ret;
1500 }
1501
1502 /**********************************************************************
1503 *
1504 * Functions for reading MSFT typelibs (those created by CreateTypeLib2)
1505 */
1506 static inline unsigned int MSFT_Tell(const TLBContext *pcx)
1507 {
1508 return pcx->pos;
1509 }
1510
1511 static inline void MSFT_Seek(TLBContext *pcx, long where)
1512 {
1513 if (where != DO_NOT_SEEK)
1514 {
1515 where += pcx->oStart;
1516 if (where > pcx->length)
1517 {
1518 /* FIXME */
1519 ERR("seek beyond end (%ld/%d)\n", where, pcx->length );
1520 TLB_abort();
1521 }
1522 pcx->pos = where;
1523 }
1524 }
1525
1526 /* read function */
1527 static DWORD MSFT_Read(void *buffer, DWORD count, TLBContext *pcx, long where )
1528 {
1529 TRACE_(typelib)("pos=0x%08x len=0x%08x 0x%08x 0x%08x 0x%08lx\n",
1530 pcx->pos, count, pcx->oStart, pcx->length, where);
1531
1532 MSFT_Seek(pcx, where);
1533 if (pcx->pos + count > pcx->length) count = pcx->length - pcx->pos;
1534 memcpy( buffer, (char *)pcx->mapping + pcx->pos, count );
1535 pcx->pos += count;
1536 return count;
1537 }
1538
1539 static DWORD MSFT_ReadLEDWords(void *buffer, DWORD count, TLBContext *pcx,
1540 long where )
1541 {
1542 DWORD ret;
1543
1544 ret = MSFT_Read(buffer, count, pcx, where);
1545 FromLEDWords(buffer, ret);
1546
1547 return ret;
1548 }
1549
1550 static DWORD MSFT_ReadLEWords(void *buffer, DWORD count, TLBContext *pcx,
1551 long where )
1552 {
1553 DWORD ret;
1554
1555 ret = MSFT_Read(buffer, count, pcx, where);
1556 FromLEWords(buffer, ret);
1557
1558 return ret;
1559 }
1560
1561 static void MSFT_ReadGuid( GUID *pGuid, int offset, TLBContext *pcx)
1562 {
1563 if(offset<0 || pcx->pTblDir->pGuidTab.offset <0){
1564 memset(pGuid,0, sizeof(GUID));
1565 return;
1566 }
1567 MSFT_Read(pGuid, sizeof(GUID), pcx, pcx->pTblDir->pGuidTab.offset+offset );
1568 pGuid->Data1 = FromLEDWord(pGuid->Data1);
1569 pGuid->Data2 = FromLEWord(pGuid->Data2);
1570 pGuid->Data3 = FromLEWord(pGuid->Data3);
1571 TRACE_(typelib)("%s\n", debugstr_guid(pGuid));
1572 }
1573
1574 static HREFTYPE MSFT_ReadHreftype( TLBContext *pcx, int offset )
1575 {
1576 MSFT_NameIntro niName;
1577
1578 if (offset < 0)
1579 {
1580 ERR_(typelib)("bad offset %d\n", offset);
1581 return -1;
1582 }
1583
1584 MSFT_ReadLEDWords(&niName, sizeof(niName), pcx,
1585 pcx->pTblDir->pNametab.offset+offset);
1586
1587 return niName.hreftype;
1588 }
1589
1590 static BSTR MSFT_ReadName( TLBContext *pcx, int offset)
1591 {
1592 char * name;
1593 MSFT_NameIntro niName;
1594 int lengthInChars;
1595 BSTR bstrName = NULL;
1596
1597 if (offset < 0)
1598 {
1599 ERR_(typelib)("bad offset %d\n", offset);
1600 return NULL;
1601 }
1602 MSFT_ReadLEDWords(&niName, sizeof(niName), pcx,
1603 pcx->pTblDir->pNametab.offset+offset);
1604 niName.namelen &= 0xFF; /* FIXME: correct ? */
1605 name=TLB_Alloc((niName.namelen & 0xff) +1);
1606 MSFT_Read(name, (niName.namelen & 0xff), pcx, DO_NOT_SEEK);
1607 name[niName.namelen & 0xff]='\0';
1608
1609 lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
1610 name, -1, NULL, 0);
1611
1612 /* no invalid characters in string */
1613 if (lengthInChars)
1614 {
1615 bstrName = SysAllocStringByteLen(NULL, lengthInChars * sizeof(WCHAR));
1616
1617 /* don't check for invalid character since this has been done previously */
1618 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name, -1, bstrName, lengthInChars);
1619 }
1620 TLB_Free(name);
1621
1622 TRACE_(typelib)("%s %d\n", debugstr_w(bstrName), lengthInChars);
1623 return bstrName;
1624 }
1625
1626 static BSTR MSFT_ReadString( TLBContext *pcx, int offset)
1627 {
1628 char * string;
1629 INT16 length;
1630 int lengthInChars;
1631 BSTR bstr = NULL;
1632
1633 if(offset<0) return NULL;
1634 MSFT_ReadLEWords(&length, sizeof(INT16), pcx, pcx->pTblDir->pStringtab.offset+offset);
1635 if(length <= 0) return 0;
1636 string=TLB_Alloc(length +1);
1637 MSFT_Read(string, length, pcx, DO_NOT_SEEK);
1638 string[length]='\0';
1639
1640 lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
1641 string, -1, NULL, 0);
1642
1643 /* no invalid characters in string */
1644 if (lengthInChars)
1645 {
1646 bstr = SysAllocStringByteLen(NULL, lengthInChars * sizeof(WCHAR));
1647
1648 /* don't check for invalid character since this has been done previously */
1649 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, string, -1, bstr, lengthInChars);
1650 }
1651 TLB_Free(string);
1652
1653 TRACE_(typelib)("%s %d\n", debugstr_w(bstr), lengthInChars);
1654 return bstr;
1655 }
1656 /*
1657 * read a value and fill a VARIANT structure
1658 */
1659 static void MSFT_ReadValue( VARIANT * pVar, int offset, TLBContext *pcx )
1660 {
1661 int size;
1662
1663 TRACE_(typelib)("\n");
1664
1665 if(offset <0) { /* data are packed in here */
1666 V_VT(pVar) = (offset & 0x7c000000 )>> 26;
1667 V_I4(pVar) = offset & 0x3ffffff;
1668 return;
1669 }
1670 MSFT_ReadLEWords(&(V_VT(pVar)), sizeof(VARTYPE), pcx,
1671 pcx->pTblDir->pCustData.offset + offset );
1672 TRACE_(typelib)("Vartype = %x\n", V_VT(pVar));
1673 switch (V_VT(pVar)){
1674 case VT_EMPTY: /* FIXME: is this right? */
1675 case VT_NULL: /* FIXME: is this right? */
1676 case VT_I2 : /* this should not happen */
1677 case VT_I4 :
1678 case VT_R4 :
1679 case VT_ERROR :
1680 case VT_BOOL :
1681 case VT_I1 :
1682 case VT_UI1 :
1683 case VT_UI2 :
1684 case VT_UI4 :
1685 case VT_INT :
1686 case VT_UINT :
1687 case VT_VOID : /* FIXME: is this right? */
1688 case VT_HRESULT :
1689 size=4; break;
1690 case VT_R8 :
1691 case VT_CY :
1692 case VT_DATE :
1693 case VT_I8 :
1694 case VT_UI8 :
1695 case VT_DECIMAL : /* FIXME: is this right? */
1696 case VT_FILETIME :
1697 size=8;break;
1698 /* pointer types with known behaviour */
1699 case VT_BSTR :{
1700 char * ptr;
1701 MSFT_ReadLEDWords(&size, sizeof(INT), pcx, DO_NOT_SEEK );
1702 if(size < 0) {
1703 char next;
1704 DWORD origPos = MSFT_Tell(pcx), nullPos;
1705
1706 do {
1707 MSFT_Read(&next, 1, pcx, DO_NOT_SEEK);
1708 } while (next);
1709 nullPos = MSFT_Tell(pcx);
1710 size = nullPos - origPos;
1711 MSFT_Seek(pcx, origPos);
1712 }
1713 ptr=TLB_Alloc(size);/* allocate temp buffer */
1714 MSFT_Read(ptr, size, pcx, DO_NOT_SEEK);/* read string (ANSI) */
1715 V_BSTR(pVar)=SysAllocStringLen(NULL,size);
1716 /* FIXME: do we need a AtoW conversion here? */
1717 V_UNION(pVar, bstrVal[size])='\0';
1718 while(size--) V_UNION(pVar, bstrVal[size])=ptr[size];
1719 TLB_Free(ptr);
1720 }
1721 size=-4; break;
1722 /* FIXME: this will not work AT ALL when the variant contains a pointer */
1723 case VT_DISPATCH :
1724 case VT_VARIANT :
1725 case VT_UNKNOWN :
1726 case VT_PTR :
1727 case VT_SAFEARRAY :
1728 case VT_CARRAY :
1729 case VT_USERDEFINED :
1730 case VT_LPSTR :
1731 case VT_LPWSTR :
1732 case VT_BLOB :
1733 case VT_STREAM :
1734 case VT_STORAGE :
1735 case VT_STREAMED_OBJECT :
1736 case VT_STORED_OBJECT :
1737 case VT_BLOB_OBJECT :
1738 case VT_CF :
1739 case VT_CLSID :
1740 default:
1741 size=0;
1742 FIXME("VARTYPE %d is not supported, setting pointer to NULL\n",
1743 V_VT(pVar));
1744 }
1745
1746 if(size>0) /* (big|small) endian correct? */
1747 MSFT_Read(&(V_I2(pVar)), size, pcx, DO_NOT_SEEK );
1748 return;
1749 }
1750 /*
1751 * create a linked list with custom data
1752 */
1753 static int MSFT_CustData( TLBContext *pcx, int offset, TLBCustData** ppCustData )
1754 {
1755 MSFT_CDGuid entry;
1756 TLBCustData* pNew;
1757 int count=0;
1758
1759 TRACE_(typelib)("\n");
1760
1761 while(offset >=0){
1762 count++;
1763 pNew=TLB_Alloc(sizeof(TLBCustData));
1764 MSFT_ReadLEDWords(&entry, sizeof(entry), pcx, pcx->pTblDir->pCDGuids.offset+offset);
1765 MSFT_ReadGuid(&(pNew->guid), entry.GuidOffset , pcx);
1766 MSFT_ReadValue(&(pNew->data), entry.DataOffset, pcx);
1767 /* add new custom data at head of the list */
1768 pNew->next=*ppCustData;
1769 *ppCustData=pNew;
1770 offset = entry.next;
1771 }
1772 return count;
1773 }
1774
1775 static void MSFT_GetTdesc(TLBContext *pcx, INT type, TYPEDESC *pTd,
1776 ITypeInfoImpl *pTI)
1777 {
1778 if(type <0)
1779 pTd->vt=type & VT_TYPEMASK;
1780 else
1781 *pTd=pcx->pLibInfo->pTypeDesc[type/(2*sizeof(INT))];
1782
1783 if(pTd->vt == VT_USERDEFINED)
1784 MSFT_DoRefType(pcx, pTI->pTypeLib, pTd->u.hreftype);
1785
1786 TRACE_(typelib)("vt type = %X\n", pTd->vt);
1787 }
1788
1789 static void MSFT_ResolveReferencedTypes(TLBContext *pcx, ITypeInfoImpl *pTI, TYPEDESC *lpTypeDesc)
1790 {
1791 /* resolve referenced type if any */
1792 while (lpTypeDesc)
1793 {
1794 switch (lpTypeDesc->vt)
1795 {
1796 case VT_PTR:
1797 lpTypeDesc = lpTypeDesc->u.lptdesc;
1798 break;
1799
1800 case VT_CARRAY:
1801 lpTypeDesc = & (lpTypeDesc->u.lpadesc->tdescElem);
1802 break;
1803
1804 case VT_USERDEFINED:
1805 MSFT_DoRefType(pcx, pTI->pTypeLib,
1806 lpTypeDesc->u.hreftype);
1807
1808 lpTypeDesc = NULL;
1809 break;
1810
1811 default:
1812 lpTypeDesc = NULL;
1813 }
1814 }
1815 }
1816
1817 static void
1818 MSFT_DoFuncs(TLBContext* pcx,
1819 ITypeInfoImpl* pTI,
1820 int cFuncs,
1821 int cVars,
1822 int offset,
1823 TLBFuncDesc** pptfd)
1824 {
1825 /*
1826 * member information is stored in a data structure at offset
1827 * indicated by the memoffset field of the typeinfo structure
1828 * There are several distinctive parts.
1829 * The first part starts with a field that holds the total length
1830 * of this (first) part excluding this field. Then follow the records,
1831 * for each member there is one record.
1832 *
1833 * The first entry is always the length of the record (including this
1834 * length word).
1835 * The rest of the record depends on the type of the member. If there is
1836 * a field indicating the member type (function, variable, interface, etc)
1837 * I have not found it yet. At this time we depend on the information
1838 * in the type info and the usual order how things are stored.
1839 *
1840 * Second follows an array sized nrMEM*sizeof(INT) with a member id
1841 * for each member;
1842 *
1843 * Third is an equal sized array with file offsets to the name entry
1844 * of each member.
1845 *
1846 * The fourth and last (?) part is an array with offsets to the records
1847 * in the first part of this file segment.
1848 */
1849
1850 int infolen, nameoffset, reclength, nrattributes, i;
1851 int recoffset = offset + sizeof(INT);
1852
1853 char *recbuf = HeapAlloc(GetProcessHeap(), 0, 0xffff);
1854 MSFT_FuncRecord * pFuncRec=(MSFT_FuncRecord *) recbuf;
1855 TLBFuncDesc *ptfd_prev = NULL;
1856
1857 TRACE_(typelib)("\n");
1858
1859 MSFT_ReadLEDWords(&infolen, sizeof(INT), pcx, offset);
1860
1861 for ( i = 0; i < cFuncs ; i++ )
1862 {
1863 *pptfd = TLB_Alloc(sizeof(TLBFuncDesc));
1864
1865 /* name, eventually add to a hash table */
1866 MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx,
1867 offset + infolen + (cFuncs + cVars + i + 1) * sizeof(INT));
1868
1869 /* nameoffset is sometimes -1 on the second half of a propget/propput
1870 * pair of functions */
1871 if ((nameoffset == -1) && (i > 0))
1872 (*pptfd)->Name = SysAllocString(ptfd_prev->Name);
1873 else
1874 (*pptfd)->Name = MSFT_ReadName(pcx, nameoffset);
1875
1876 /* read the function information record */
1877 MSFT_ReadLEDWords(&reclength, sizeof(INT), pcx, recoffset);
1878
1879 reclength &= 0xffff;
1880
1881 MSFT_ReadLEDWords(pFuncRec, reclength - sizeof(INT), pcx, DO_NOT_SEEK);
1882
1883 /* do the attributes */
1884 nrattributes = (reclength - pFuncRec->nrargs * 3 * sizeof(int) - 0x18)
1885 / sizeof(int);
1886
1887 if ( nrattributes > 0 )
1888 {
1889 (*pptfd)->helpcontext = pFuncRec->OptAttr[0] ;
1890
1891 if ( nrattributes > 1 )
1892 {
1893 (*pptfd)->HelpString = MSFT_ReadString(pcx,
1894 pFuncRec->OptAttr[1]) ;
1895
1896 if ( nrattributes > 2 )
1897 {
1898 if ( pFuncRec->FKCCIC & 0x2000 )
1899 {
1900 if (HIWORD(pFuncRec->OptAttr[2]) != 0)
1901 ERR("ordinal 0x%08x invalid, HIWORD != 0\n", pFuncRec->OptAttr[2]);
1902 (*pptfd)->Entry = (BSTR)pFuncRec->OptAttr[2];
1903 }
1904 else
1905 {
1906 (*pptfd)->Entry = MSFT_ReadString(pcx,
1907 pFuncRec->OptAttr[2]);
1908 }
1909 if( nrattributes > 5 )
1910 {
1911 (*pptfd)->HelpStringContext = pFuncRec->OptAttr[5] ;
1912
1913 if ( nrattributes > 6 && pFuncRec->FKCCIC & 0x80 )
1914 {
1915 MSFT_CustData(pcx,
1916 pFuncRec->OptAttr[6],
1917 &(*pptfd)->pCustData);
1918 }
1919 }
1920 }
1921 else
1922 {
1923 (*pptfd)->Entry = (BSTR)-1;
1924 }
1925 }
1926 }
1927
1928 /* fill the FuncDesc Structure */
1929 MSFT_ReadLEDWords( & (*pptfd)->funcdesc.memid, sizeof(INT), pcx,
1930 offset + infolen + ( i + 1) * sizeof(INT));
1931
1932 (*pptfd)->funcdesc.funckind = (pFuncRec->FKCCIC) & 0x7;
1933 (*pptfd)->funcdesc.invkind = (pFuncRec->FKCCIC) >> 3 & 0xF;
1934 (*pptfd)->funcdesc.callconv = (pFuncRec->FKCCIC) >> 8 & 0xF;
1935 (*pptfd)->funcdesc.cParams = pFuncRec->nrargs ;
1936 (*pptfd)->funcdesc.cParamsOpt = pFuncRec->nroargs ;
1937 (*pptfd)->funcdesc.oVft = pFuncRec->VtableOffset;
1938 (*pptfd)->funcdesc.wFuncFlags = LOWORD(pFuncRec->Flags) ;
1939
1940 MSFT_GetTdesc(pcx,
1941 pFuncRec->DataType,
1942 &(*pptfd)->funcdesc.elemdescFunc.tdesc,
1943 pTI);
1944 MSFT_ResolveReferencedTypes(pcx, pTI, &(*pptfd)->funcdesc.elemdescFunc.tdesc);
1945
1946 /* do the parameters/arguments */
1947 if(pFuncRec->nrargs)
1948 {
1949 int j = 0;
1950 MSFT_ParameterInfo paraminfo;
1951
1952 (*pptfd)->funcdesc.lprgelemdescParam =
1953 TLB_Alloc(pFuncRec->nrargs * sizeof(ELEMDESC));
1954
1955 (*pptfd)->pParamDesc =
1956 TLB_Alloc(pFuncRec->nrargs * sizeof(TLBParDesc));
1957
1958 MSFT_ReadLEDWords(¶minfo, sizeof(paraminfo), pcx,
1959 recoffset + reclength - pFuncRec->nrargs * sizeof(MSFT_ParameterInfo));
1960
1961 for ( j = 0 ; j < pFuncRec->nrargs ; j++ )
1962 {
1963 ELEMDESC *elemdesc = &(*pptfd)->funcdesc.lprgelemdescParam[j];
1964
1965 MSFT_GetTdesc(pcx,
1966 paraminfo.DataType,
1967 &elemdesc->tdesc,
1968 pTI);
1969
1970 elemdesc->u.paramdesc.wParamFlags = paraminfo.Flags;
1971
1972 /* name */
1973 if (paraminfo.oName == -1)
1974 /* this occurs for [propput] or [propget] methods, so
1975 * we should just set the name of the parameter to the
1976 * name of the method. */
1977 (*pptfd)->pParamDesc[j].Name = SysAllocString((*pptfd)->Name);
1978 else
1979 (*pptfd)->pParamDesc[j].Name =
1980 MSFT_ReadName( pcx, paraminfo.oName );
1981 TRACE_(typelib)("param[%d] = %s\n", j, debugstr_w((*pptfd)->pParamDesc[j].Name));
1982
1983 MSFT_ResolveReferencedTypes(pcx, pTI, &elemdesc->tdesc);
1984
1985 /* default value */
1986 if ( (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) &&
1987 (pFuncRec->FKCCIC & 0x1000) )
1988 {
1989 INT* pInt = (INT *)((char *)pFuncRec +
1990 reclength -
1991 (pFuncRec->nrargs * 4 + 1) * sizeof(INT) );
1992
1993 PARAMDESC* pParamDesc = &elemdesc->u.paramdesc;
1994
1995 pParamDesc->pparamdescex = TLB_Alloc(sizeof(PARAMDESCEX));
1996 pParamDesc->pparamdescex->cBytes = sizeof(PARAMDESCEX);
1997
1998 MSFT_ReadValue(&(pParamDesc->pparamdescex->varDefaultValue),
1999 pInt[j], pcx);
2000 }
2001 else
2002 elemdesc->u.paramdesc.pparamdescex = NULL;
2003 /* custom info */
2004 if ( nrattributes > 7 + j && pFuncRec->FKCCIC & 0x80 )
2005 {
2006 MSFT_CustData(pcx,
2007 pFuncRec->OptAttr[7+j],
2008 &(*pptfd)->pParamDesc[j].pCustData);
2009 }
2010
2011 /* SEEK value = jump to offset,
2012 * from there jump to the end of record,
2013 * go back by (j-1) arguments
2014 */
2015 MSFT_ReadLEDWords( ¶minfo ,
2016 sizeof(MSFT_ParameterInfo), pcx,
2017 recoffset + reclength - ((pFuncRec->nrargs - j - 1)
2018 * sizeof(MSFT_ParameterInfo)));
2019 }
2020 }
2021
2022 /* scode is not used: archaic win16 stuff FIXME: right? */
2023 (*pptfd)->funcdesc.cScodes = 0 ;
2024 (*pptfd)->funcdesc.lprgscode = NULL ;
2025
2026 ptfd_prev = *pptfd;
2027 pptfd = & ((*pptfd)->next);
2028 recoffset += reclength;
2029 }
2030 HeapFree(GetProcessHeap(), 0, recbuf);
2031 }
2032
2033 static void MSFT_DoVars(TLBContext *pcx, ITypeInfoImpl *pTI, int cFuncs,
2034 int cVars, int offset, TLBVarDesc ** pptvd)
2035 {
2036 int infolen, nameoffset, reclength;
2037 char recbuf[256];
2038 MSFT_VarRecord * pVarRec=(MSFT_VarRecord *) recbuf;
2039 int i;
2040 int recoffset;
2041
2042 TRACE_(typelib)("\n");
2043
2044 MSFT_ReadLEDWords(&infolen,sizeof(INT), pcx, offset);
2045 MSFT_ReadLEDWords(&recoffset,sizeof(INT), pcx, offset + infolen +
2046 ((cFuncs+cVars)*2+cFuncs + 1)*sizeof(INT));
2047 recoffset += offset+sizeof(INT);
2048 for(i=0;i<cVars;i++){
2049 *pptvd=TLB_Alloc(sizeof(TLBVarDesc));
2050 /* name, eventually add to a hash table */
2051 MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx,
2052 offset + infolen + (2*cFuncs + cVars + i + 1) * sizeof(INT));
2053 (*pptvd)->Name=MSFT_ReadName(pcx, nameoffset);
2054 /* read the variable information record */
2055 MSFT_ReadLEDWords(&reclength, sizeof(INT), pcx, recoffset);
2056 reclength &=0xff;
2057 MSFT_ReadLEDWords(pVarRec, reclength - sizeof(INT), pcx, DO_NOT_SEEK);
2058 /* Optional data */
2059 if(reclength >(6*sizeof(INT)) )
2060 (*pptvd)->HelpContext=pVarRec->HelpContext;
2061 if(reclength >(7*sizeof(INT)) )
2062 (*pptvd)->HelpString = MSFT_ReadString(pcx, pVarRec->oHelpString) ;
2063 if(reclength >(8*sizeof(INT)) )
2064 if(reclength >(9*sizeof(INT)) )
2065 (*pptvd)->HelpStringContext=pVarRec->HelpStringContext;
2066 /* fill the VarDesc Structure */
2067 MSFT_ReadLEDWords(&(*pptvd)->vardesc.memid, sizeof(INT), pcx,
2068 offset + infolen + (cFuncs + i + 1) * sizeof(INT));
2069 (*pptvd)->vardesc.varkind = pVarRec->VarKind;
2070 (*pptvd)->vardesc.wVarFlags = pVarRec->Flags;
2071 MSFT_GetTdesc(pcx, pVarRec->DataType,
2072 &(*pptvd)->vardesc.elemdescVar.tdesc, pTI);
2073 /* (*pptvd)->vardesc.lpstrSchema; is reserved (SDK) FIXME?? */
2074 if(pVarRec->VarKind == VAR_CONST ){
2075 (*pptvd)->vardesc.u.lpvarValue=TLB_Alloc(sizeof(VARIANT));
2076 MSFT_ReadValue((*pptvd)->vardesc.u.lpvarValue,
2077 pVarRec->OffsValue, pcx);
2078 } else
2079 (*pptvd)->vardesc.u.oInst=pVarRec->OffsValue;
2080 MSFT_ResolveReferencedTypes(pcx, pTI, &(*pptvd)->vardesc.elemdescVar.tdesc);
2081 pptvd=&((*pptvd)->next);
2082 recoffset += reclength;
2083 }
2084 }
2085 /* fill in data for a hreftype (offset). When the referenced type is contained
2086 * in the typelib, it's just an (file) offset in the type info base dir.
2087 * If comes from import, it's an offset+1 in the ImpInfo table
2088 * */
2089 static void MSFT_DoRefType(TLBContext *pcx, ITypeLibImpl *pTL,
2090 int offset)
2091 {
2092 TLBRefType *ref;
2093
2094 TRACE_(typelib)("TLB context %p, TLB offset %x\n", pcx, offset);
2095
2096 LIST_FOR_EACH_ENTRY(ref, &pTL->ref_list, TLBRefType, entry)
2097 {
2098 if(ref->reference == offset) return;
2099 }
2100
2101 ref = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ref));
2102 list_add_tail(&pTL->ref_list, &ref->entry);
2103
2104 if(!MSFT_HREFTYPE_INTHISFILE( offset)) {
2105 /* external typelib */
2106 MSFT_ImpInfo impinfo;
2107 TLBImpLib *pImpLib=(pcx->pLibInfo->pImpLibs);
2108
2109 TRACE_(typelib)("offset %x, masked offset %x\n", offset, offset + (offset & 0xfffffffc));
2110
2111 MSFT_ReadLEDWords(&impinfo, sizeof(impinfo), pcx,
2112 pcx->pTblDir->pImpInfo.offset + (offset & 0xfffffffc));
2113 while (pImpLib){ /* search the known offsets of all import libraries */
2114 if(pImpLib->offset==impinfo.oImpFile) break;
2115 pImpLib=pImpLib->next;
2116 }
2117 if(pImpLib){
2118 ref->reference = offset;
2119 ref->pImpTLInfo = pImpLib;
2120 if(impinfo.flags & MSFT_IMPINFO_OFFSET_IS_GUID) {
2121 MSFT_ReadGuid(&ref->guid, impinfo.oGuid, pcx);
2122 TRACE("importing by guid %s\n", debugstr_guid(&ref->guid));
2123 ref->index = TLB_REF_USE_GUID;
2124 } else
2125 ref->index = impinfo.oGuid;
2126 }else{
2127 ERR("Cannot find a reference\n");
2128 ref->reference = -1;
2129 ref->pImpTLInfo = TLB_REF_NOT_FOUND;
2130 }
2131 }else{
2132 /* in this typelib */
2133 ref->index = MSFT_HREFTYPE_INDEX(offset);
2134 ref->reference = offset;
2135 ref->pImpTLInfo = TLB_REF_INTERNAL;
2136 }
2137 }
2138
2139 /* process Implemented Interfaces of a com class */
2140 static void MSFT_DoImplTypes(TLBContext *pcx, ITypeInfoImpl *pTI, int count,
2141 int offset)
2142 {
2143 int i;
2144 MSFT_RefRecord refrec;
2145 TLBImplType **ppImpl = &pTI->impltypelist;
2146
2147 TRACE_(typelib)("\n");
2148
2149 for(i=0;i<count;i++){
2150 if(offset<0) break; /* paranoia */
2151 *ppImpl=TLB_Alloc(sizeof(**ppImpl));
2152 MSFT_ReadLEDWords(&refrec,sizeof(refrec),pcx,offset+pcx->pTblDir->pRefTab.offset);
2153 MSFT_DoRefType(pcx, pTI->pTypeLib, refrec.reftype);
2154 (*ppImpl)->hRef = refrec.reftype;
2155 (*ppImpl)->implflags=refrec.flags;
2156 (*ppImpl)->ctCustData=
2157 MSFT_CustData(pcx, refrec.oCustData, &(*ppImpl)->pCustData);
2158 offset=refrec.onext;
2159 ppImpl=&((*ppImpl)->next);
2160 }
2161 }
2162 /*
2163 * process a typeinfo record
2164 */
2165 static ITypeInfoImpl * MSFT_DoTypeInfo(
2166 TLBContext *pcx,
2167 int count,
2168 ITypeLibImpl * pLibInfo)
2169 {
2170 MSFT_TypeInfoBase tiBase;
2171 ITypeInfoImpl *ptiRet;
2172
2173 TRACE_(typelib)("count=%u\n", count);
2174
2175 ptiRet = (ITypeInfoImpl*) ITypeInfo_Constructor();
2176 MSFT_ReadLEDWords(&tiBase, sizeof(tiBase) ,pcx ,
2177 pcx->pTblDir->pTypeInfoTab.offset+count*sizeof(tiBase));
2178
2179 /* this is where we are coming from */
2180 ptiRet->pTypeLib = pLibInfo;
2181 ptiRet->index=count;
2182 /* fill in the typeattr fields */
2183
2184 MSFT_ReadGuid(&ptiRet->TypeAttr.guid, tiBase.posguid, pcx);
2185 ptiRet->TypeAttr.lcid=pLibInfo->LibAttr.lcid; /* FIXME: correct? */
2186 ptiRet->TypeAttr.lpstrSchema=NULL; /* reserved */
2187 ptiRet->TypeAttr.cbSizeInstance=tiBase.size;
2188 ptiRet->TypeAttr.typekind=tiBase.typekind & 0xF;
2189 ptiRet->TypeAttr.cFuncs=LOWORD(tiBase.cElement);
2190 ptiRet->TypeAttr.cVars=HIWORD(tiBase.cElement);
2191 ptiRet->TypeAttr.cbAlignment=(tiBase.typekind >> 11 )& 0x1F; /* there are more flags there */
2192 ptiRet->TypeAttr.wTypeFlags=tiBase.flags;
2193 ptiRet->TypeAttr.wMajorVerNum=LOWORD(tiBase.version);
2194 ptiRet->TypeAttr.wMinorVerNum=HIWORD(tiBase.version);
2195 ptiRet->TypeAttr.cImplTypes=tiBase.cImplTypes;
2196 ptiRet->TypeAttr.cbSizeVft=tiBase.cbSizeVft; /* FIXME: this is only the non inherited part */
2197 if(ptiRet->TypeAttr.typekind == TKIND_ALIAS)
2198 MSFT_GetTdesc(pcx, tiBase.datatype1,
2199 &ptiRet->TypeAttr.tdescAlias, ptiRet);
2200
2201 /* FIXME: */
2202 /* IDLDESC idldescType; *//* never saw this one != zero */
2203
2204 /* name, eventually add to a hash table */
2205 ptiRet->Name=MSFT_ReadName(pcx, tiBase.NameOffset);
2206 ptiRet->hreftype = MSFT_ReadHreftype(pcx, tiBase.NameOffset);
2207 TRACE_(typelib)("reading %s\n", debugstr_w(ptiRet->Name));
2208 /* help info */
2209 ptiRet->DocString=MSFT_ReadString(pcx, tiBase.docstringoffs);
2210 ptiRet->dwHelpStringContext=tiBase.helpstringcontext;
2211 ptiRet->dwHelpContext=tiBase.helpcontext;
2212
2213 if (ptiRet->TypeAttr.typekind == TKIND_MODULE)
2214 ptiRet->DllName = MSFT_ReadString(pcx, tiBase.datatype1);
2215
2216 /* note: InfoType's Help file and HelpStringDll come from the containing
2217 * library. Further HelpString and Docstring appear to be the same thing :(
2218 */
2219 /* functions */
2220 if(ptiRet->TypeAttr.cFuncs >0 )
2221 MSFT_DoFuncs(pcx, ptiRet, ptiRet->TypeAttr.cFuncs,
2222 ptiRet->TypeAttr.cVars,
2223 tiBase.memoffset, & ptiRet->funclist);
2224 /* variables */
2225 if(ptiRet->TypeAttr.cVars >0 )
2226 MSFT_DoVars(pcx, ptiRet, ptiRet->TypeAttr.cFuncs,
2227 ptiRet->TypeAttr.cVars,
2228 tiBase.memoffset, & ptiRet->varlist);
2229 if(ptiRet->TypeAttr.cImplTypes >0 ) {
2230 switch(ptiRet->TypeAttr.typekind)
2231 {
2232 case TKIND_COCLASS:
2233 MSFT_DoImplTypes(pcx, ptiRet, ptiRet->TypeAttr.cImplTypes ,
2234 tiBase.datatype1);
2235 break;
2236 case TKIND_DISPATCH:
2237 /* This is not -1 when the interface is a non-base dual interface or
2238 when a dispinterface wraps an interface, i.e., the idl 'dispinterface x {interface y;};'.
2239 Note however that GetRefTypeOfImplType(0) always returns a ref to IDispatch and
2240 not this interface.
2241 */
2242
2243 if (tiBase.datatype1 != -1)
2244 {
2245 ptiRet->impltypelist = TLB_Alloc(sizeof(TLBImplType));
2246 ptiRet->impltypelist->hRef = tiBase.datatype1;
2247 MSFT_DoRefType(pcx, pLibInfo, tiBase.datatype1);
2248 }
2249 break;
2250 default:
2251 ptiRet->impltypelist=TLB_Alloc(sizeof(TLBImplType));
2252 MSFT_DoRefType(pcx, pLibInfo, tiBase.datatype1);
2253 ptiRet->impltypelist->hRef = tiBase.datatype1;
2254 break;
2255 }
2256 }
2257 ptiRet->ctCustData=
2258 MSFT_CustData(pcx, tiBase.oCustData, &ptiRet->pCustData);
2259
2260 TRACE_(typelib)("%s guid: %s kind:%s\n",
2261 debugstr_w(ptiRet->Name),
2262 debugstr_guid(&ptiRet->TypeAttr.guid),
2263 typekind_desc[ptiRet->TypeAttr.typekind]);
2264 if (TRACE_ON(typelib))
2265 dump_TypeInfo(ptiRet);
2266
2267 return ptiRet;
2268 }
2269
2270 /* Because type library parsing has some degree of overhead, and some apps repeatedly load the same
2271 * typelibs over and over, we cache them here. According to MSDN Microsoft have a similar scheme in
2272 * place. This will cause a deliberate memory leak, but generally losing RAM for cycles is an acceptable
2273 * tradeoff here.
2274 */
2275 static ITypeLibImpl *tlb_cache_first;
2276 static CRITICAL_SECTION cache_section;
2277 static CRITICAL_SECTION_DEBUG cache_section_debug =
2278 {
2279 0, 0, &cache_section,
2280 { &cache_section_debug.ProcessLocksList, &cache_section_debug.ProcessLocksList },
2281 0, 0, { (DWORD_PTR)(__FILE__ ": typelib loader cache") }
2282 };
2283 static CRITICAL_SECTION cache_section = { &cache_section_debug, -1, 0, 0, 0, 0 };
2284
2285
2286 typedef struct TLB_PEFile
2287 {
2288 const IUnknownVtbl *lpvtbl;
2289 LONG refs;
2290 HMODULE dll;
2291 HRSRC typelib_resource;
2292 HGLOBAL typelib_global;
2293 LPVOID typelib_base;
2294 } TLB_PEFile;
2295
2296 static HRESULT WINAPI TLB_PEFile_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2297 {
2298 if (IsEqualIID(riid, &IID_IUnknown))
2299 {
2300 *ppv = iface;
2301 IUnknown_AddRef(iface);
2302 return S_OK;
2303 }
2304 *ppv = NULL;
2305 return E_NOINTERFACE;
2306 }
2307
2308 static ULONG WINAPI TLB_PEFile_AddRef(IUnknown *iface)
2309 {
2310 TLB_PEFile *This = (TLB_PEFile *)iface;
2311 return InterlockedIncrement(&This->refs);
2312 }
2313
2314 static ULONG WINAPI TLB_PEFile_Release(IUnknown *iface)
2315 {
2316 TLB_PEFile *This = (TLB_PEFile *)iface;
2317 ULONG refs = InterlockedDecrement(&This->refs);
2318 if (!refs)
2319 {
2320 if (This->typelib_global)
2321 FreeResource(This->typelib_global);
2322 if (This->dll)
2323 FreeLibrary(This->dll);
2324 HeapFree(GetProcessHeap(), 0, This);
2325 }
2326 return refs;
2327 }
2328
2329 static const IUnknownVtbl TLB_PEFile_Vtable =
2330 {
2331 TLB_PEFile_QueryInterface,
2332 TLB_PEFile_AddRef,
2333 TLB_PEFile_Release
2334 };
2335
2336 static HRESULT TLB_PEFile_Open(LPCWSTR path, INT index, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile)
2337 {
2338 TLB_PEFile *This;
2339
2340 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
2341 if (!This)
2342 return E_OUTOFMEMORY;
2343
2344 This->lpvtbl = &TLB_PEFile_Vtable;
2345 This->refs = 1;
2346 This->dll = NULL;
2347 This->typelib_resource = NULL;
2348 This->typelib_global = NULL;
2349 This->typelib_base = NULL;
2350
2351 This->dll = LoadLibraryExW(path, 0, DONT_RESOLVE_DLL_REFERENCES |
2352 LOAD_LIBRARY_AS_DATAFILE | LOAD_WITH_ALTERED_SEARCH_PATH);
2353
2354 if (This->dll)
2355 {
2356 static const WCHAR TYPELIBW[] = {'T','Y','P','E','L','I','B',0};
2357 This->typelib_resource = FindResourceW(This->dll, MAKEINTRESOURCEW(index), TYPELIBW);
2358 if (This->typelib_resource)
2359 {
2360 This->typelib_global = LoadResource(This->dll, This->typelib_resource);
2361 if (This->typelib_global)
2362 {
2363 This->typelib_base = LockResource(This->typelib_global);
2364
2365 if (This->typelib_base)
2366 {
2367 *pdwTLBLength = SizeofResource(This->dll, This->typelib_resource);
2368 *ppBase = This->typelib_base;
2369 *ppFile = (IUnknown *)&This->lpvtbl;
2370 return S_OK;
2371 }
2372 }
2373 }
2374 }
2375
2376 TLB_PEFile_Release((IUnknown *)&This->lpvtbl);
2377 return TYPE_E_CANTLOADLIBRARY;
2378 }
2379
2380 typedef struct TLB_NEFile
2381 {
2382 const IUnknownVtbl *lpvtbl;
2383 LONG refs;
2384 LPVOID typelib_base;
2385 } TLB_NEFile;
2386
2387 static HRESULT WINAPI TLB_NEFile_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2388 {
2389 if (IsEqualIID(riid, &IID_IUnknown))
2390 {
2391 *ppv = iface;
2392 IUnknown_AddRef(iface);
2393 return S_OK;
2394 }
2395 *ppv = NULL;
2396 return E_NOINTERFACE;
2397 }
2398
2399 static ULONG WINAPI TLB_NEFile_AddRef(IUnknown *iface)
2400 {
2401 TLB_NEFile *This = (TLB_NEFile *)iface;
2402 return InterlockedIncrement(&This->refs);
2403 }
2404
2405 static ULONG WINAPI TLB_NEFile_Release(IUnknown *iface)
2406 {
2407 TLB_NEFile *This = (TLB_NEFile *)iface;
2408 ULONG refs = InterlockedDecrement(&This->refs);
2409 if (!refs)
2410 {
2411 HeapFree(GetProcessHeap(), 0, This->typelib_base);
2412 HeapFree(GetProcessHeap(), 0, This);
2413 }
2414 return refs;
2415 }
2416
2417 static const IUnknownVtbl TLB_NEFile_Vtable =
2418 {
2419 TLB_NEFile_QueryInterface,
2420 TLB_NEFile_AddRef,
2421 TLB_NEFile_Release
2422 };
2423
2424 /***********************************************************************
2425 * read_xx_header [internal]
2426 */
2427 static int read_xx_header( HFILE lzfd )
2428 {
2429 IMAGE_DOS_HEADER mzh;
2430 char magic[3];
2431
2432 LZSeek( lzfd, 0, SEEK_SET );
2433 if ( sizeof(mzh) != LZRead( lzfd, (LPSTR)&mzh, sizeof(mzh) ) )
2434 return 0;
2435 if ( mzh.e_magic != IMAGE_DOS_SIGNATURE )
2436 return 0;
2437
2438 LZSeek( lzfd, mzh.e_lfanew, SEEK_SET );
2439 if ( 2 != LZRead( lzfd, magic, 2 ) )
2440 return 0;
2441
2442 LZSeek( lzfd, mzh.e_lfanew, SEEK_SET );
2443
2444 if ( magic[0] == 'N' && magic[1] == 'E' )
2445 return IMAGE_OS2_SIGNATURE;
2446 if ( magic[0] == 'P' && magic[1] == 'E' )
2447 return IMAGE_NT_SIGNATURE;
2448
2449 magic[2] = '\0';
2450 WARN("Can't handle %s files.\n", magic );
2451 return 0;
2452 }
2453
2454
2455 /***********************************************************************
2456 * find_ne_resource [internal]
2457 */
2458 static BOOL find_ne_resource( HFILE lzfd, LPCSTR typeid, LPCSTR resid,
2459 DWORD *resLen, DWORD *resOff )
2460 {
2461 IMAGE_OS2_HEADER nehd;
2462 NE_TYPEINFO *typeInfo;
2463 NE_NAMEINFO *nameInfo;
2464 DWORD nehdoffset;
2465 LPBYTE resTab;
2466 DWORD resTabSize;
2467 int count;
2468
2469 /* Read in NE header */
2470 nehdoffset = LZSeek( lzfd, 0, SEEK_CUR );
2471 if ( sizeof(nehd) != LZRead( lzfd, (LPSTR)&nehd, sizeof(nehd) ) ) return 0;
2472
2473 resTabSize = nehd.ne_restab - nehd.ne_rsrctab;
2474 if ( !resTabSize )
2475 {
2476 TRACE("No resources in NE dll\n" );
2477 return FALSE;
2478 }
2479
2480 /* Read in resource table */
2481 resTab = HeapAlloc( GetProcessHeap(), 0, resTabSize );
2482 if ( !resTab ) return FALSE;
2483
2484 LZSeek( lzfd, nehd.ne_rsrctab + nehdoffset, SEEK_SET );
2485 if ( resTabSize != LZRead( lzfd, (char*)resTab, resTabSize ) )
2486 {
2487 HeapFree( GetProcessHeap(), 0, resTab );
2488 return FALSE;
2489 }
2490
2491 /* Find resource */
2492 typeInfo = (NE_TYPEINFO *)(resTab + 2);
2493
2494 if (HIWORD(typeid) != 0) /* named type */
2495 {
2496 BYTE len = strlen( typeid );
2497 while (typeInfo->type_id)
2498 {
2499 if (!(typeInfo->type_id & 0x8000))
2500 {
2501 BYTE *p = resTab + typeInfo->type_id;
2502 if ((*p == len) && !strncasecmp( (char*)p+1, typeid, len )) goto found_type;
2503 }
2504 typeInfo = (NE_TYPEINFO *)((char *)(typeInfo + 1) +
2505 typeInfo->count * sizeof(NE_NAMEINFO));
2506 }
2507 }
2508 else /* numeric type id */
2509 {
2510 WORD id = LOWORD(typeid) | 0x8000;
2511 while (typeInfo->type_id)
2512 {
2513 if (typeInfo->type_id == id) goto found_type;
2514 typeInfo = (NE_TYPEINFO *)((char *)(typeInfo + 1) +
2515 typeInfo->count * sizeof(NE_NAMEINFO));
2516 }
2517 }
2518 TRACE("No typeid entry found for %p\n", typeid );
2519 HeapFree( GetProcessHeap(), 0, resTab );
2520 return FALSE;
2521
2522 found_type:
2523 nameInfo = (NE_NAMEINFO *)(typeInfo + 1);
2524
2525 if (HIWORD(resid) != 0) /* named resource */
2526 {
2527 BYTE len = strlen( resid );
2528 for (count = typeInfo->count; count > 0; count--, nameInfo++)
2529 {
2530 BYTE *p = resTab + nameInfo->id;
2531 if (nameInfo->id & 0x8000) continue;
2532 if ((*p == len) && !strncasecmp( (char*)p+1, resid, len )) goto found_name;
2533 }
2534 }
2535 else /* numeric resource id */
2536 {
2537 WORD id = LOWORD(resid) | 0x8000;
2538 for (count = typeInfo->count; count > 0; count--, nameInfo++)
2539 if (nameInfo->id == id) goto found_name;
2540 }
2541 TRACE("No resid entry found for %p\n", typeid );
2542 HeapFree( GetProcessHeap(), 0, resTab );
2543 return FALSE;
2544
2545 found_name:
2546 /* Return resource data */
2547 if ( resLen ) *resLen = nameInfo->length << *(WORD *)resTab;
2548 if ( resOff ) *resOff = nameInfo->offset << *(WORD *)resTab;
2549
2550 HeapFree( GetProcessHeap(), 0, resTab );
2551 return TRUE;
2552 }
2553
2554 static HRESULT TLB_NEFile_Open(LPCWSTR path, INT index, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile){
2555
2556 HFILE lzfd = -1;
2557 OFSTRUCT ofs;
2558 HRESULT hr = TYPE_E_CANTLOADLIBRARY;
2559 TLB_NEFile *This = NULL;
2560
2561 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
2562 if (!This) return E_OUTOFMEMORY;
2563
2564 This->lpvtbl = &TLB_NEFile_Vtable;
2565 This->refs = 1;
2566 This->typelib_base = NULL;
2567
2568 lzfd = LZOpenFileW( (LPWSTR)path, &ofs, OF_READ );
2569 if ( lzfd >= 0 && read_xx_header( lzfd ) == IMAGE_OS2_SIGNATURE )
2570 {
2571 DWORD reslen, offset;
2572 if( find_ne_resource( lzfd, "TYPELIB", MAKEINTRESOURCEA(index), &reslen, &offset ) )
2573 {
2574 This->typelib_base = HeapAlloc(GetProcessHeap(), 0, reslen);
2575 if( !This->typelib_base )
2576 hr = E_OUTOFMEMORY;
2577 else
2578 {
2579 LZSeek( lzfd, offset, SEEK_SET );
2580 reslen = LZRead( lzfd, This->typelib_base, reslen );
2581 LZClose( lzfd );
2582 *ppBase = This->typelib_base;
2583 *pdwTLBLength = reslen;
2584 *ppFile = (IUnknown *)&This->lpvtbl;
2585 return S_OK;
2586 }
2587 }
2588 }
2589
2590 if( lzfd >= 0) LZClose( lzfd );
2591 TLB_NEFile_Release((IUnknown *)&This->lpvtbl);
2592 return hr;
2593 }
2594
2595 typedef struct TLB_Mapping
2596 {
2597 const IUnknownVtbl *lpvtbl;
2598 LONG refs;
2599 HANDLE file;
2600 HANDLE mapping;
2601 LPVOID typelib_base;
2602 } TLB_Mapping;
2603
2604 static HRESULT WINAPI TLB_Mapping_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2605 {
2606 if (IsEqualIID(riid, &IID_IUnknown))
2607 {
2608 *ppv = iface;
2609 IUnknown_AddRef(iface);
2610 return S_OK;
2611 }
2612 *ppv = NULL;
2613 return E_NOINTERFACE;
2614 }
2615
2616 static ULONG WINAPI TLB_Mapping_AddRef(IUnknown *iface)
2617 {
2618 TLB_Mapping *This = (TLB_Mapping *)iface;
2619 return InterlockedIncrement(&This->refs);
2620 }
2621
2622 static ULONG WINAPI TLB_Mapping_Release(IUnknown *iface)
2623 {
2624 TLB_Mapping *This = (TLB_Mapping *)iface;
2625 ULONG refs = InterlockedDecrement(&This->refs);
2626 if (!refs)
2627 {
2628 if (This->typelib_base)
2629 UnmapViewOfFile(This->typelib_base);
2630 if (This->mapping)
2631 CloseHandle(This->mapping);
2632 if (This->file != INVALID_HANDLE_VALUE)
2633 CloseHandle(This->file);
2634 HeapFree(GetProcessHeap(), 0, This);
2635 }
2636 return refs;
2637 }
2638
2639 static const IUnknownVtbl TLB_Mapping_Vtable =
2640 {
2641 TLB_Mapping_QueryInterface,
2642 TLB_Mapping_AddRef,
2643 TLB_Mapping_Release
2644 };
2645
2646 static HRESULT TLB_Mapping_Open(LPCWSTR path, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile)
2647 {
2648 TLB_Mapping *This;
2649
2650 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
2651 if (!This)
2652 return E_OUTOFMEMORY;
2653
2654 This->lpvtbl = &TLB_Mapping_Vtable;
2655 This->refs = 1;
2656 This->file = INVALID_HANDLE_VALUE;
2657 This->mapping = NULL;
2658 This->typelib_base = NULL;
2659
2660 This->file = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
2661 if (INVALID_HANDLE_VALUE != This->file)
2662 {
2663 This->mapping = CreateFileMappingW(This->file, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL);
2664 if (This->mapping)
2665 {
2666 This->typelib_base = MapViewOfFile(This->mapping, FILE_MAP_READ, 0, 0, 0);
2667 if(This->typelib_base)
2668 {
2669 /* retrieve file size */
2670 *pdwTLBLength = GetFileSize(This->file, NULL);
2671 *ppBase = This->typelib_base;
2672 *ppFile = (IUnknown *)&This->lpvtbl;
2673 return S_OK;
2674 }
2675 }
2676 }
2677
2678 IUnknown_Release((IUnknown *)&This->lpvtbl);
2679 return TYPE_E_CANTLOADLIBRARY;
2680 }
2681
2682 /****************************************************************************
2683 * TLB_ReadTypeLib
2684 *
2685 * find the type of the typelib file and map the typelib resource into
2686 * the memory
2687 */
2688 #define MSFT_SIGNATURE 0x5446534D /* "MSFT" */
2689 #define SLTG_SIGNATURE 0x47544c53 /* "SLTG" */
2690 static HRESULT TLB_ReadTypeLib(LPCWSTR pszFileName, LPWSTR pszPath, UINT cchPath, ITypeLib2 **ppTypeLib)
2691 {
2692 ITypeLibImpl *entry;
2693 HRESULT ret;
2694 INT index = 1;
2695 LPWSTR index_str, file = (LPWSTR)pszFileName;
2696 LPVOID pBase = NULL;
2697 DWORD dwTLBLength = 0;
2698 IUnknown *pFile = NULL;
2699
2700 *ppTypeLib = NULL;
2701
2702 index_str = strrchrW(pszFileName, '\\');
2703 if(index_str && *++index_str != '\0')
2704 {
2705 LPWSTR end_ptr;
2706 long idx = strtolW(index_str, &end_ptr, 10);
2707 if(*end_ptr == '\0')
2708 {
2709 int str_len = index_str - pszFileName - 1;
2710 index = idx;
2711 file = HeapAlloc(GetProcessHeap(), 0, (str_len + 1) * sizeof(WCHAR));
2712 memcpy(file, pszFileName, str_len * sizeof(WCHAR));
2713 file[str_len] = 0;
2714 }
2715 }
2716
2717 if(!SearchPathW(NULL, file, NULL, cchPath, pszPath, NULL))
2718 {
2719 if(strchrW(file, '\\'))
2720 {
2721 lstrcpyW(pszPath, file);
2722 }
2723 else
2724 {
2725 int len = GetSystemDirectoryW(pszPath, cchPath);
2726 pszPath[len] = '\\';
2727 memcpy(pszPath + len + 1, file, (strlenW(file) + 1) * sizeof(WCHAR));
2728 }
2729 }
2730
2731 if(file != pszFileName) HeapFree(GetProcessHeap(), 0, file);
2732
2733 TRACE_(typelib)("File %s index %d\n", debugstr_w(pszPath), index);
2734
2735 /* We look the path up in the typelib cache. If found, we just addref it, and return the pointer. */
2736 EnterCriticalSection(&cache_section);
2737 for (entry = tlb_cache_first; entry != NULL; entry = entry->next)
2738 {
2739 if (!strcmpiW(entry->path, pszPath) && entry->index == index)
2740 {
2741 TRACE("cache hit\n");
2742 *ppTypeLib = (ITypeLib2*)entry;
2743 ITypeLib_AddRef(*ppTypeLib);
2744 LeaveCriticalSection(&cache_section);
2745 return S_OK;
2746 }
2747 }
2748 LeaveCriticalSection(&cache_section);
2749
2750 /* now actually load and parse the typelib */
2751
2752 ret = TLB_PEFile_Open(pszPath, index, &pBase, &dwTLBLength, &pFile);
2753 if (ret == TYPE_E_CANTLOADLIBRARY)
2754 ret = TLB_NEFile_Open(pszPath, index, &pBase, &dwTLBLength, &pFile);
2755 if (ret == TYPE_E_CANTLOADLIBRARY)
2756 ret = TLB_Mapping_Open(pszPath, &pBase, &dwTLBLength, &pFile);
2757 if (SUCCEEDED(ret))
2758 {
2759 if (dwTLBLength >= 4)
2760 {
2761 DWORD dwSignature = FromLEDWord(*((DWORD*) pBase));
2762 if (dwSignature == MSFT_SIGNATURE)
2763 *ppTypeLib = ITypeLib2_Constructor_MSFT(pBase, dwTLBLength);
2764 else if (dwSignature == SLTG_SIGNATURE)
2765 *ppTypeLib = ITypeLib2_Constructor_SLTG(pBase, dwTLBLength);
2766 else
2767 {
2768 FIXME("Header type magic 0x%08x not supported.\n",dwSignature);
2769 ret = TYPE_E_CANTLOADLIBRARY;
2770 }
2771 }
2772 else
2773 ret = TYPE_E_CANTLOADLIBRARY;
2774 IUnknown_Release(pFile);
2775 }
2776
2777 if(*ppTypeLib) {
2778 ITypeLibImpl *impl = (ITypeLibImpl*)*ppTypeLib;
2779
2780 TRACE("adding to cache\n");
2781 impl->path = HeapAlloc(GetProcessHeap(), 0, (strlenW(pszPath)+1) * sizeof(WCHAR));
2782 lstrcpyW(impl->path, pszPath);
2783 /* We should really canonicalise the path here. */
2784 impl->index = index;
2785
2786 /* FIXME: check if it has added already in the meantime */
2787 EnterCriticalSection(&cache_section);
2788 if ((impl->next = tlb_cache_first) != NULL) impl->next->prev = impl;
2789 impl->prev = NULL;
2790 tlb_cache_first = impl;
2791 LeaveCriticalSection(&cache_section);
2792 ret = S_OK;
2793 } else
2794 ERR("Loading of typelib %s failed with error %d\n", debugstr_w(pszFileName), GetLastError());
2795
2796 return ret;
2797 }
2798
2799 /*================== ITypeLib(2) Methods ===================================*/
2800
2801 static ITypeLibImpl* TypeLibImpl_Constructor(void)
2802 {
2803 ITypeLibImpl* pTypeLibImpl;
2804
2805 pTypeLibImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeLibImpl));
2806 if (!pTypeLibImpl) return NULL;
2807
2808 pTypeLibImpl->lpVtbl = &tlbvt;
2809 pTypeLibImpl->lpVtblTypeComp = &tlbtcvt;
2810 pTypeLibImpl->ref = 1;
2811
2812 list_init(&pTypeLibImpl->ref_list);
2813 pTypeLibImpl->dispatch_href = -1;
2814
2815 return pTypeLibImpl;
2816 }
2817
2818 /****************************************************************************
2819 * ITypeLib2_Constructor_MSFT
2820 *
2821 * loading an MSFT typelib from an in-memory image
2822 */
2823 static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength)
2824 {
2825 TLBContext cx;
2826 long lPSegDir;
2827 MSFT_Header tlbHeader;
2828 MSFT_SegDir tlbSegDir;
2829 ITypeLibImpl * pTypeLibImpl;
2830
2831 TRACE("%p, TLB length = %d\n", pLib, dwTLBLength);
2832
2833 pTypeLibImpl = TypeLibImpl_Constructor();
2834 if (!pTypeLibImpl) return NULL;
2835
2836 /* get pointer to beginning of typelib data */
2837 cx.pos = 0;
2838 cx.oStart=0;
2839 cx.mapping = pLib;
2840 cx.pLibInfo = pTypeLibImpl;
2841 cx.length = dwTLBLength;
2842
2843 /* read header */
2844 MSFT_ReadLEDWords((void*)&tlbHeader, sizeof(tlbHeader), &cx, 0);
2845 TRACE_(typelib)("header:\n");
2846 TRACE_(typelib)("\tmagic1=0x%08x ,magic2=0x%08x\n",tlbHeader.magic1,tlbHeader.magic2 );
2847 if (tlbHeader.magic1 != MSFT_SIGNATURE) {
2848 FIXME("Header type magic 0x%08x not supported.\n",tlbHeader.magic1);
2849 return NULL;
2850 }
2851 TRACE_(typelib)("\tdispatchpos = 0x%x\n", tlbHeader.dispatchpos);
2852
2853 /* there is a small amount of information here until the next important
2854 * part:
2855 * the segment directory . Try to calculate the amount of data */
2856 lPSegDir = sizeof(tlbHeader) + (tlbHeader.nrtypeinfos)*4 + ((tlbHeader.varflags & HELPDLLFLAG)? 4 :0);
2857
2858 /* now read the segment directory */
2859 TRACE("read segment directory (at %ld)\n",lPSegDir);
2860 MSFT_ReadLEDWords(&tlbSegDir, sizeof(tlbSegDir), &cx, lPSegDir);
2861 cx.pTblDir = &tlbSegDir;
2862
2863 /* just check two entries */
2864 if ( tlbSegDir.pTypeInfoTab.res0c != 0x0F || tlbSegDir.pImpInfo.res0c != 0x0F)
2865 {
2866 ERR("cannot find the table directory, ptr=0x%lx\n",lPSegDir);
2867 HeapFree(GetProcessHeap(),0,pTypeLibImpl);
2868 return NULL;
2869 }
2870
2871 /* now fill our internal data */
2872 /* TLIBATTR fields */
2873 MSFT_ReadGuid(&pTypeLibImpl->LibAttr.guid, tlbHeader.posguid, &cx);
2874
2875 /* pTypeLibImpl->LibAttr.lcid = tlbHeader.lcid;*/
2876 /* Windows seems to have zero here, is this correct? */
2877 if(SUBLANGID(tlbHeader.lcid) == SUBLANG_NEUTRAL)
2878 pTypeLibImpl->LibAttr.lcid = MAKELCID(MAKELANGID(PRIMARYLANGID(tlbHeader.lcid),0),0);
2879 else
2880 pTypeLibImpl->LibAttr.lcid = 0;
2881
2882 pTypeLibImpl->LibAttr.syskind = tlbHeader.varflags & 0x0f; /* check the mask */
2883 pTypeLibImpl->LibAttr.wMajorVerNum = LOWORD(tlbHeader.version);
2884 pTypeLibImpl->LibAttr.wMinorVerNum = HIWORD(tlbHeader.version);
2885 pTypeLibImpl->LibAttr.wLibFlags = (WORD) tlbHeader.flags & 0xffff;/* check mask */
2886
2887 /* name, eventually add to a hash table */
2888 pTypeLibImpl->Name = MSFT_ReadName(&cx, tlbHeader.NameOffset);
2889
2890 /* help info */
2891 pTypeLibImpl->DocString = MSFT_ReadString(&cx, tlbHeader.helpstring);
2892 pTypeLibImpl->HelpFile = MSFT_ReadString(&cx, tlbHeader.helpfile);
2893
2894 if( tlbHeader.varflags & HELPDLLFLAG)
2895 {
2896 int offset;
2897 MSFT_ReadLEDWords(&offset, sizeof(offset), &cx, sizeof(tlbHeader));
2898 pTypeLibImpl->HelpStringDll = MSFT_ReadString(&cx, offset);
2899 }
2900
2901 pTypeLibImpl->dwHelpContext = tlbHeader.helpstringcontext;
2902
2903 /* custom data */
2904 if(tlbHeader.CustomDataOffset >= 0)
2905 {
2906 pTypeLibImpl->ctCustData = MSFT_CustData(&cx, tlbHeader.CustomDataOffset, &pTypeLibImpl->pCustData);
2907 }
2908
2909 /* fill in type descriptions */
2910 if(tlbSegDir.pTypdescTab.length > 0)
2911 {
2912 int i, j, cTD = tlbSegDir.pTypdescTab.length / (2*sizeof(INT));
2913 INT16 td[4];
2914 pTypeLibImpl->ctTypeDesc = cTD;
2915 pTypeLibImpl->pTypeDesc = TLB_Alloc( cTD * sizeof(TYPEDESC));
2916 MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pTypdescTab.offset);
2917 for(i=0; i<cTD; )
2918 {
2919 /* FIXME: add several sanity checks here */
2920 pTypeLibImpl->pTypeDesc[i].vt = td[0] & VT_TYPEMASK;
2921 if(td[0] == VT_PTR || td[0] == VT_SAFEARRAY)
2922 {
2923 /* FIXME: check safearray */
2924 if(td[3] < 0)
2925 pTypeLibImpl->pTypeDesc[i].u.lptdesc= & stndTypeDesc[td[2]];
2926 else
2927 pTypeLibImpl->pTypeDesc[i].u.lptdesc= & pTypeLibImpl->pTypeDesc[td[2]/8];
2928 }
2929 else if(td[0] == VT_CARRAY)
2930 {
2931 /* array descr table here */
2932 pTypeLibImpl->pTypeDesc[i].u.lpadesc = (void *)((int) td[2]); /* temp store offset in*/
2933 }
2934 else if(td[0] == VT_USERDEFINED)
2935 {
2936 pTypeLibImpl->pTypeDesc[i].u.hreftype = MAKELONG(td[2],td[3]);
2937 }
2938 if(++i<cTD) MSFT_ReadLEWords(td, sizeof(td), &cx, DO_NOT_SEEK);
2939 }
2940
2941 /* second time around to fill the array subscript info */
2942 for(i=0;i<cTD;i++)
2943 {
2944 if(pTypeLibImpl->pTypeDesc[i].vt != VT_CARRAY) continue;
2945 if(tlbSegDir.pArrayDescriptions.offset>0)
2946 {
2947 MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pArrayDescriptions.offset + (int) pTypeLibImpl->pTypeDesc[i].u.lpadesc);
2948 pTypeLibImpl->pTypeDesc[i].u.lpadesc = TLB_Alloc(sizeof(ARRAYDESC)+sizeof(SAFEARRAYBOUND)*(td[3]-1));
2949
2950 if(td[1]<0)
2951 pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem.vt = td[0] & VT_TYPEMASK;
2952 else
2953 pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem = stndTypeDesc[td[0]/8];
2954
2955 pTypeLibImpl->pTypeDesc[i].u.lpadesc->cDims = td[2];
2956
2957 for(j = 0; j<td[2]; j++)
2958 {
2959 MSFT_ReadLEDWords(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].cElements,
2960 sizeof(INT), &cx, DO_NOT_SEEK);
2961 MSFT_ReadLEDWords(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].lLbound,
2962 sizeof(INT), &cx, DO_NOT_SEEK);
2963 }
2964 }
2965 else
2966 {
2967 pTypeLibImpl->pTypeDesc[i].u.lpadesc = NULL;
2968 ERR("didn't find array description data\n");
2969 }
2970 }
2971 }
2972
2973 /* imported type libs */
2974 if(tlbSegDir.pImpFiles.offset>0)
2975 {
2976 TLBImpLib **ppImpLib = &(pTypeLibImpl->pImpLibs);
2977 int oGuid, offset = tlbSegDir.pImpFiles.offset;
2978 UINT16 size;
2979
2980 while(offset < tlbSegDir.pImpFiles.offset +tlbSegDir.pImpFiles.length)
2981 {
2982 char *name;
2983
2984 *ppImpLib = TLB_Alloc(sizeof(TLBImpLib));
2985 (*ppImpLib)->offset = offset - tlbSegDir.pImpFiles.offset;
2986 MSFT_ReadLEDWords(&oGuid, sizeof(INT), &cx, offset);
2987
2988 MSFT_ReadLEDWords(&(*ppImpLib)->lcid, sizeof(LCID), &cx, DO_NOT_SEEK);
2989 MSFT_ReadLEWords(&(*ppImpLib)->wVersionMajor, sizeof(WORD), &cx, DO_NOT_SEEK);
2990 MSFT_ReadLEWords(&(*ppImpLib)->wVersionMinor, sizeof(WORD), &cx, DO_NOT_SEEK);
2991 MSFT_ReadLEWords(& size, sizeof(UINT16), &cx, DO_NOT_SEEK);
2992
2993 size >>= 2;
2994 name = TLB_Alloc(size+1);
2995 MSFT_Read(name, size, &cx, DO_NOT_SEEK);
2996 (*ppImpLib)->name = TLB_MultiByteToBSTR(name);
2997
2998 MSFT_ReadGuid(&(*ppImpLib)->guid, oGuid, &cx);
2999 offset = (offset + sizeof(INT) + sizeof(DWORD) + sizeof(LCID) + sizeof(UINT16) + size + 3) & ~3;
3000
3001 ppImpLib = &(*ppImpLib)->next;
3002 }
3003 }
3004
3005 pTypeLibImpl->dispatch_href = tlbHeader.dispatchpos;
3006 if(pTypeLibImpl->dispatch_href != -1)
3007 MSFT_DoRefType(&cx, pTypeLibImpl, pTypeLibImpl->dispatch_href);
3008
3009 /* type info's */
3010 if(tlbHeader.nrtypeinfos >= 0 )
3011 {
3012 /*pTypeLibImpl->TypeInfoCount=tlbHeader.nrtypeinfos; */
3013 ITypeInfoImpl **ppTI = &(pTypeLibImpl->pTypeInfo);
3014 int i;
3015
3016 for(i = 0; i < tlbHeader.nrtypeinfos; i++)
3017 {
3018 *ppTI = MSFT_DoTypeInfo(&cx, i, pTypeLibImpl);
3019
3020 ppTI = &((*ppTI)->next);
3021 (pTypeLibImpl->TypeInfoCount)++;
3022 }
3023 }
3024
3025 TRACE("(%p)\n", pTypeLibImpl);
3026 return (ITypeLib2*) pTypeLibImpl;
3027 }
3028
3029
3030 static BOOL TLB_GUIDFromString(const char *str, GUID *guid)
3031 {
3032 char b[3];
3033 int i;
3034 short s;
3035
3036 if(sscanf(str, "%x-%hx-%hx-%hx", &guid->Data1, &guid->Data2, &guid->Data3, &s) != 4) {
3037 FIXME("Can't parse guid %s\n", debugstr_guid(guid));
3038 return FALSE;
3039 }
3040
3041 guid->Data4[0] = s >> 8;
3042 guid->Data4[1] = s & 0xff;
3043
3044 b[2] = '\0';
3045 for(i = 0; i < 6; i++) {
3046 memcpy(b, str + 24 + 2 * i, 2);
3047 guid->Data4[i + 2] = strtol(b, NULL, 16);
3048 }
3049 return TRUE;
3050 }
3051
3052 static WORD SLTG_ReadString(const char *ptr, BSTR *pBstr)
3053 {
3054 WORD bytelen;
3055 DWORD len;
3056
3057 *pBstr = NULL;
3058 bytelen = *(const WORD*)ptr;
3059 if(bytelen == 0xffff) return 2;
3060 len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, NULL, 0);
3061 *pBstr = SysAllocStringLen(NULL, len - 1);
3062 if (*pBstr)
3063 len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, *pBstr, len);
3064 return bytelen + 2;
3065 }
3066
3067 static WORD SLTG_ReadStringA(const char *ptr, char **str)
3068 {
3069 WORD bytelen;
3070
3071 *str = NULL;
3072 bytelen = *(const WORD*)ptr;
3073 if(bytelen == 0xffff) return 2;
3074 *str = HeapAlloc(GetProcessHeap(), 0, bytelen + 1);
3075 memcpy(*str, ptr + 2, bytelen);
3076 (*str)[bytelen] = '\0';
3077 return bytelen + 2;
3078 }
3079
3080 static DWORD SLTG_ReadLibBlk(LPVOID pLibBlk, ITypeLibImpl *pTypeLibImpl)
3081 {
3082 char *ptr = pLibBlk;
3083 WORD w;
3084
3085 if((w = *(WORD*)ptr) != SLTG_LIBBLK_MAGIC) {
3086 FIXME("libblk magic = %04x\n", w);
3087 return 0;
3088 }
3089
3090 ptr += 6;
3091 if((w = *(WORD*)ptr) != 0xffff) {
3092 FIXME("LibBlk.res06 = %04x. Assumung string and skipping\n", w);
3093 ptr += w;
3094 }
3095 ptr += 2;
3096
3097 ptr += SLTG_ReadString(ptr, &pTypeLibImpl->DocString);
3098
3099 ptr += SLTG_ReadString(ptr, &pTypeLibImpl->HelpFile);
3100
3101 pTypeLibImpl->dwHelpContext = *(DWORD*)ptr;
3102 ptr += 4;
3103
3104 pTypeLibImpl->LibAttr.syskind = *(WORD*)ptr;
3105 ptr += 2;
3106
3107 if(SUBLANGID(*(WORD*)ptr) == SUBLANG_NEUTRAL)
3108 pTypeLibImpl->LibAttr.lcid = MAKELCID(MAKELANGID(PRIMARYLANGID(*(WORD*)ptr),0),0);
3109 else
3110 pTypeLibImpl->LibAttr.lcid = 0;
3111 ptr += 2;
3112
3113 ptr += 4; /* skip res12 */
3114
3115 pTypeLibImpl->LibAttr.wLibFlags = *(WORD*)ptr;
3116 ptr += 2;
3117
3118 pTypeLibImpl->LibAttr.wMajorVerNum = *(WORD*)ptr;
3119 ptr += 2;
3120
3121 pTypeLibImpl->LibAttr.wMinorVerNum = *(WORD*)ptr;
3122 ptr += 2;
3123
3124 memcpy(&pTypeLibImpl->LibAttr.guid, ptr, sizeof(GUID));
3125 ptr += sizeof(GUID);
3126
3127 return ptr - (char*)pLibBlk;
3128 }
3129
3130 /* stores a mapping between the sltg typeinfo's references and the typelib's HREFTYPEs */
3131 typedef struct
3132 {
3133 unsigned int num;
3134 HREFTYPE refs[1];
3135 } sltg_ref_lookup_t;
3136
3137 static HRESULT sltg_get_typelib_ref(const sltg_ref_lookup_t *table, DWORD typeinfo_ref,
3138 HREFTYPE *typelib_ref)
3139 {
3140 if(typeinfo_ref < table->num)
3141 {
3142 *typelib_ref = table->refs[typeinfo_ref];
3143 return S_OK;
3144 }
3145
3146 ERR_(typelib)("Unable to find reference\n");
3147 *typelib_ref = -1;
3148 return E_FAIL;
3149 }
3150
3151 static WORD *SLTG_DoType(WORD *pType, char *pBlk, TYPEDESC *pTD, const sltg_ref_lookup_t *ref_lookup)
3152 {
3153 BOOL done = FALSE;
3154
3155 while(!done) {
3156 if((*pType & 0xe00) == 0xe00) {
3157 pTD->vt = VT_PTR;
3158 pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3159 sizeof(TYPEDESC));
3160 pTD = pTD->u.lptdesc;
3161 }
3162 switch(*pType & 0x3f) {
3163 case VT_PTR:
3164 pTD->vt = VT_PTR;
3165 pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3166 sizeof(TYPEDESC));
3167 pTD = pTD->u.lptdesc;
3168 break;
3169
3170 case VT_USERDEFINED:
3171 pTD->vt = VT_USERDEFINED;
3172 sltg_get_typelib_ref(ref_lookup, *(++pType) / 4, &pTD->u.hreftype);
3173 done = TRUE;
3174 break;
3175
3176 case VT_CARRAY:
3177 {
3178 /* *(pType+1) is offset to a SAFEARRAY, *(pType+2) is type of
3179 array */
3180
3181 SAFEARRAY *pSA = (SAFEARRAY *)(pBlk + *(++pType));
3182
3183 pTD->vt = VT_CARRAY;
3184 pTD->u.lpadesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3185 sizeof(ARRAYDESC) +
3186 (pSA->cDims - 1) * sizeof(SAFEARRAYBOUND));
3187 pTD->u.lpadesc->cDims = pSA->cDims;
3188 memcpy(pTD->u.lpadesc->rgbounds, pSA->rgsabound,
3189 pSA->cDims * sizeof(SAFEARRAYBOUND));
3190
3191 pTD = &pTD->u.lpadesc->tdescElem;
3192 break;
3193 }
3194
3195 case VT_SAFEARRAY:
3196 {
3197 /* FIXME: *(pType+1) gives an offset to SAFEARRAY, is this
3198 useful? */
3199
3200 pType++;
3201 pTD->vt = VT_SAFEARRAY;
3202 pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3203 sizeof(TYPEDESC));
3204 pTD = pTD->u.lptdesc;
3205 break;
3206 }
3207 default:
3208 pTD->vt = *pType & 0x3f;
3209 done = TRUE;
3210 break;
3211 }
3212 pType++;
3213 }
3214 return pType;
3215 }
3216
3217 static WORD *SLTG_DoElem(WORD *pType, char *pBlk,
3218 ELEMDESC *pElem, const sltg_ref_lookup_t *ref_lookup)
3219 {
3220 /* Handle [in/out] first */
3221 if((*pType & 0xc000) == 0xc000)
3222 pElem->u.paramdesc.wParamFlags = PARAMFLAG_NONE;
3223 else if(*pType & 0x8000)
3224 pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN | PARAMFLAG_FOUT;
3225 else if(*pType & 0x4000)
3226 pElem->u.paramdesc.wParamFlags = PARAMFLAG_FOUT;
3227 else
3228 pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN;
3229
3230 if(*pType & 0x2000)
3231 pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FLCID;
3232
3233 if(*pType & 0x80)
3234 pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FRETVAL;
3235
3236 return SLTG_DoType(pType, pBlk, &pElem->tdesc, ref_lookup);
3237 }
3238
3239
3240 static sltg_ref_lookup_t *SLTG_DoRefs(SLTG_RefInfo *pRef, ITypeLibImpl *pTL,
3241 char *pNameTable)
3242 {
3243 unsigned int ref;
3244 char *name;
3245 TLBRefType *ref_type;
3246 sltg_ref_lookup_t *table;
3247 HREFTYPE typelib_ref;
3248
3249 if(pRef->magic != SLTG_REF_MAGIC) {
3250 FIXME("Ref magic = %x\n", pRef->magic);
3251 return NULL;
3252 }
3253 name = ( (char*)pRef->names + pRef->number);
3254
3255 table = HeapAlloc(GetProcessHeap(), 0, sizeof(*table) + ((pRef->number >> 3) - 1) * sizeof(table->refs[0]));
3256 table->num = pRef->number >> 3;
3257
3258 /* FIXME should scan the existing list and reuse matching refs added by previous typeinfos */
3259
3260 /* We don't want the first href to be 0 */
3261 typelib_ref = (list_count(&pTL->ref_list) + 1) << 2;
3262
3263 for(ref = 0; ref < pRef->number >> 3; ref++) {
3264 char *refname;
3265 unsigned int lib_offs, type_num;
3266
3267 ref_type = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ref_type));
3268
3269 name += SLTG_ReadStringA(name, &refname);
3270 if(sscanf(refname, "*\\R%x*#%x", &lib_offs, &type_num) != 2)
3271 FIXME_(typelib)("Can't sscanf ref\n");
3272 if(lib_offs != 0xffff) {
3273 TLBImpLib **import = &pTL->pImpLibs;
3274
3275 while(*import) {
3276 if((*import)->offset == lib_offs)
3277 break;
3278 import = &(*import)->next;
3279 }
3280 if(!*import) {
3281 char fname[MAX_PATH+1];
3282 int len;
3283
3284 *import = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3285 sizeof(**import));
3286 (*import)->offset = lib_offs;
3287 TLB_GUIDFromString( pNameTable + lib_offs + 4,
3288 &(*import)->guid);
3289 if(sscanf(pNameTable + lib_offs + 40, "}#%hd.%hd#%x#%s",
3290 &(*import)->wVersionMajor,
3291 &(*import)->wVersionMinor,
3292 &(*import)->lcid, fname) != 4) {
3293 FIXME_(typelib)("can't sscanf ref %s\n",
3294 pNameTable + lib_offs + 40);
3295 }
3296 len = strlen(fname);
3297 if(fname[len-1] != '#')
3298 FIXME("fname = %s\n", fname);
3299 fname[len-1] = '\0';
3300 (*import)->name = TLB_MultiByteToBSTR(fname);
3301 }
3302 ref_type->pImpTLInfo = *import;
3303
3304 /* Store a reference to IDispatch */
3305 if(pTL->dispatch_href == -1 && IsEqualGUID(&(*import)->guid, &IID_StdOle) && type_num == 4)
3306 pTL->dispatch_href = typelib_ref;
3307
3308 } else { /* internal ref */
3309 ref_type->pImpTLInfo = TLB_REF_INTERNAL;
3310 }
3311 ref_type->reference = typelib_ref;
3312 ref_type->index = type_num;
3313
3314 HeapFree(GetProcessHeap(), 0, refname);
3315 list_add_tail(&pTL->ref_list, &ref_type->entry);
3316
3317 table->refs[ref] = typelib_ref;
3318 typelib_ref += 4;
3319 }
3320 if((BYTE)*name != SLTG_REF_MAGIC)
3321 FIXME_(typelib)("End of ref block magic = %x\n", *name);
3322 dump_TLBRefType(pTL);
3323 return table;
3324 }
3325
3326 static char *SLTG_DoImpls(char *pBlk, ITypeInfoImpl *pTI,
3327 BOOL OneOnly, const sltg_ref_lookup_t *ref_lookup)
3328 {
3329 SLTG_ImplInfo *info;
3330 TLBImplType **ppImplType = &pTI->impltypelist;
3331 /* I don't really get this structure, usually it's 0x16 bytes
3332 long, but iuser.tlb contains some that are 0x18 bytes long.
3333 That's ok because we can use the next ptr to jump to the next
3334 one. But how do we know the length of the last one? The WORD
3335 at offs 0x8 might be the clue. For now I'm just assuming that
3336 the last one is the regular 0x16 bytes. */
3337
3338 info = (SLTG_ImplInfo*)pBlk;
3339 while(1) {
3340 *ppImplType = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3341 sizeof(**ppImplType));
3342 sltg_get_typelib_ref(ref_lookup, info->ref, &(*ppImplType)->hRef);
3343 (*ppImplType)->implflags = info->impltypeflags;
3344 pTI->TypeAttr.cImplTypes++;
3345 ppImplType = &(*ppImplType)->next;
3346
3347 if(info->next == 0xffff)
3348 break;
3349 if(OneOnly)
3350 FIXME_(typelib)("Interface inheriting more than one interface\n");
3351 info = (SLTG_ImplInfo*)(pBlk + info->next);
3352 }
3353 info++; /* see comment at top of function */
3354 return (char*)info;
3355 }
3356
3357 static void SLTG_DoVars(char *pBlk, char *pFirstItem, ITypeInfoImpl *pTI, unsigned short cVars,
3358 const char *pNameTable, const sltg_ref_lookup_t *ref_lookup)
3359 {
3360 TLBVarDesc **ppVarDesc = &pTI->varlist;
3361 BSTR bstrPrevName = NULL;
3362 SLTG_Variable *pItem;
3363 unsigned short i;
3364 WORD *pType;
3365
3366 for(pItem = (SLTG_Variable *)pFirstItem, i = 0; i < cVars;
3367 pItem = (SLTG_Variable *)(pBlk + pItem->next), i++) {
3368
3369 *ppVarDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3370 sizeof(**ppVarDesc));
3371 (*ppVarDesc)->vardesc.memid = pItem->memid;
3372
3373 if (pItem->magic != SLTG_VAR_MAGIC &&
3374 pItem->magic != SLTG_VAR_WITH_FLAGS_MAGIC) {