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