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