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