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