d3dx9/tests: Add UpdateSemantics test.
[wine/multimedia.git] / dlls / oleaut32 / typelib.c
blob2e286b4259648e4706480787f56e0d01d5f40778
1 /*
2 * TYPELIB
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
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.
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.
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
24 * --------------------------------------------------------------------------------------
25 * Known problems (2000, Francois Jacques)
27 * - Tested using OLEVIEW (Platform SDK tool) only.
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.
33 * - locale stuff is partially implemented but hasn't been tested.
35 * - typelib file is still read in its entirety, but it is released now.
37 * --------------------------------------------------------------------------------------
38 * Known problems left from previous implementation (1999, Rein Klazes) :
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
48 #include "config.h"
49 #include "wine/port.h"
51 #include <stdlib.h>
52 #include <string.h>
53 #include <stdarg.h>
54 #include <stdio.h>
55 #include <ctype.h>
57 #define COBJMACROS
58 #define NONAMELESSUNION
59 #define NONAMELESSSTRUCT
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"
69 #include "wine/unicode.h"
70 #include "objbase.h"
71 #include "typelib.h"
72 #include "wine/debug.h"
73 #include "variant.h"
74 #include "wine/list.h"
76 WINE_DEFAULT_DEBUG_CHANNEL(ole);
77 WINE_DECLARE_DEBUG_CHANNEL(typelib);
79 typedef struct
81 WORD offset;
82 WORD length;
83 WORD flags;
84 WORD id;
85 WORD handle;
86 WORD usage;
87 } NE_NAMEINFO;
89 typedef struct
91 WORD type_id; /* Type identifier */
92 WORD count; /* Number of resources of this type */
93 DWORD resloader; /* SetResourceHandler() */
95 * Name info array.
97 } NE_TYPEINFO;
99 static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt);
100 static HRESULT TLB_AllocAndInitVarDesc(const VARDESC *src, VARDESC **dest_ptr);
102 /****************************************************************************
103 * FromLExxx
105 * Takes p_iVal (which is in little endian) and returns it
106 * in the host machine's byte order.
108 #ifdef WORDS_BIGENDIAN
109 static WORD FromLEWord(WORD p_iVal)
111 return (((p_iVal & 0x00FF) << 8) |
112 ((p_iVal & 0xFF00) >> 8));
116 static DWORD FromLEDWord(DWORD p_iVal)
118 return (((p_iVal & 0x000000FF) << 24) |
119 ((p_iVal & 0x0000FF00) << 8) |
120 ((p_iVal & 0x00FF0000) >> 8) |
121 ((p_iVal & 0xFF000000) >> 24));
123 #else
124 #define FromLEWord(X) (X)
125 #define FromLEDWord(X) (X)
126 #endif
128 #define DISPATCH_HREF_OFFSET 0x01000000
129 #define DISPATCH_HREF_MASK 0xff000000
131 /****************************************************************************
132 * FromLExxx
134 * Fix byte order in any structure if necessary
136 #ifdef WORDS_BIGENDIAN
137 static void FromLEWords(void *p_Val, int p_iSize)
139 WORD *Val = p_Val;
141 p_iSize /= sizeof(WORD);
143 while (p_iSize) {
144 *Val = FromLEWord(*Val);
145 Val++;
146 p_iSize--;
151 static void FromLEDWords(void *p_Val, int p_iSize)
153 DWORD *Val = p_Val;
155 p_iSize /= sizeof(DWORD);
157 while (p_iSize) {
158 *Val = FromLEDWord(*Val);
159 Val++;
160 p_iSize--;
163 #else
164 #define FromLEWords(X,Y) /*nothing*/
165 #define FromLEDWords(X,Y) /*nothing*/
166 #endif
169 * Find a typelib key which matches a requested maj.min version.
171 static BOOL find_typelib_key( REFGUID guid, WORD *wMaj, WORD *wMin )
173 static const WCHAR typelibW[] = {'T','y','p','e','l','i','b','\\',0};
174 WCHAR buffer[60];
175 char key_name[16];
176 DWORD len, i;
177 INT best_maj = -1, best_min = -1;
178 HKEY hkey;
180 memcpy( buffer, typelibW, sizeof(typelibW) );
181 StringFromGUID2( guid, buffer + strlenW(buffer), 40 );
183 if (RegOpenKeyExW( HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hkey ) != ERROR_SUCCESS)
184 return FALSE;
186 len = sizeof(key_name);
187 i = 0;
188 while (RegEnumKeyExA(hkey, i++, key_name, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
190 INT v_maj, v_min;
192 if (sscanf(key_name, "%x.%x", &v_maj, &v_min) == 2)
194 TRACE("found %s: %x.%x\n", debugstr_w(buffer), v_maj, v_min);
196 if (*wMaj == 0xffff && *wMin == 0xffff)
198 if (v_maj > best_maj) best_maj = v_maj;
199 if (v_min > best_min) best_min = v_min;
201 else if (*wMaj == v_maj)
203 best_maj = v_maj;
205 if (*wMin == v_min)
207 best_min = v_min;
208 break; /* exact match */
210 if (*wMin != 0xffff && v_min > best_min) best_min = v_min;
213 len = sizeof(key_name);
215 RegCloseKey( hkey );
217 TRACE("found best_maj %d, best_min %d\n", best_maj, best_min);
219 if (*wMaj == 0xffff && *wMin == 0xffff)
221 if (best_maj >= 0 && best_min >= 0)
223 *wMaj = best_maj;
224 *wMin = best_min;
225 return TRUE;
229 if (*wMaj == best_maj && best_min >= 0)
231 *wMin = best_min;
232 return TRUE;
234 return FALSE;
237 /* get the path of a typelib key, in the form "Typelib\\<guid>\\<maj>.<min>" */
238 /* buffer must be at least 60 characters long */
239 static WCHAR *get_typelib_key( REFGUID guid, WORD wMaj, WORD wMin, WCHAR *buffer )
241 static const WCHAR TypelibW[] = {'T','y','p','e','l','i','b','\\',0};
242 static const WCHAR VersionFormatW[] = {'\\','%','x','.','%','x',0};
244 memcpy( buffer, TypelibW, sizeof(TypelibW) );
245 StringFromGUID2( guid, buffer + strlenW(buffer), 40 );
246 sprintfW( buffer + strlenW(buffer), VersionFormatW, wMaj, wMin );
247 return buffer;
250 /* get the path of an interface key, in the form "Interface\\<guid>" */
251 /* buffer must be at least 50 characters long */
252 static WCHAR *get_interface_key( REFGUID guid, WCHAR *buffer )
254 static const WCHAR InterfaceW[] = {'I','n','t','e','r','f','a','c','e','\\',0};
256 memcpy( buffer, InterfaceW, sizeof(InterfaceW) );
257 StringFromGUID2( guid, buffer + strlenW(buffer), 40 );
258 return buffer;
261 /* get the lcid subkey for a typelib, in the form "<lcid>\\<syskind>" */
262 /* buffer must be at least 16 characters long */
263 static WCHAR *get_lcid_subkey( LCID lcid, SYSKIND syskind, WCHAR *buffer )
265 static const WCHAR LcidFormatW[] = {'%','l','x','\\',0};
266 static const WCHAR win16W[] = {'w','i','n','1','6',0};
267 static const WCHAR win32W[] = {'w','i','n','3','2',0};
268 static const WCHAR win64W[] = {'w','i','n','6','4',0};
270 sprintfW( buffer, LcidFormatW, lcid );
271 switch(syskind)
273 case SYS_WIN16: strcatW( buffer, win16W ); break;
274 case SYS_WIN32: strcatW( buffer, win32W ); break;
275 case SYS_WIN64: strcatW( buffer, win64W ); break;
276 default:
277 TRACE("Typelib is for unsupported syskind %i\n", syskind);
278 return NULL;
280 return buffer;
283 static HRESULT TLB_ReadTypeLib(LPCWSTR pszFileName, LPWSTR pszPath, UINT cchPath, ITypeLib2 **ppTypeLib);
286 /* Get the path to a registered type library. Helper for QueryPathOfRegTypeLib. */
287 static HRESULT query_typelib_path( REFGUID guid, WORD wMaj, WORD wMin,
288 SYSKIND syskind, LCID lcid, LPBSTR path )
290 HRESULT hr = TYPE_E_LIBNOTREGISTERED;
291 LCID myLCID = lcid;
292 HKEY hkey;
293 WCHAR buffer[60];
294 WCHAR Path[MAX_PATH];
295 LONG res;
297 TRACE_(typelib)("(%s, %x.%x, 0x%x, %p)\n", debugstr_guid(guid), wMaj, wMin, lcid, path);
299 if (!find_typelib_key( guid, &wMaj, &wMin )) return TYPE_E_LIBNOTREGISTERED;
300 get_typelib_key( guid, wMaj, wMin, buffer );
302 res = RegOpenKeyExW( HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hkey );
303 if (res == ERROR_FILE_NOT_FOUND)
305 TRACE_(typelib)("%s not found\n", debugstr_w(buffer));
306 return TYPE_E_LIBNOTREGISTERED;
308 else if (res != ERROR_SUCCESS)
310 TRACE_(typelib)("failed to open %s for read access\n", debugstr_w(buffer));
311 return TYPE_E_REGISTRYACCESS;
314 while (hr != S_OK)
316 LONG dwPathLen = sizeof(Path);
318 get_lcid_subkey( myLCID, syskind, buffer );
320 if (RegQueryValueW(hkey, buffer, Path, &dwPathLen))
322 if (!lcid)
323 break;
324 else if (myLCID == lcid)
326 /* try with sub-langid */
327 myLCID = SUBLANGID(lcid);
329 else if ((myLCID == SUBLANGID(lcid)) && myLCID)
331 /* try with system langid */
332 myLCID = 0;
334 else
336 break;
339 else
341 *path = SysAllocString( Path );
342 hr = S_OK;
345 RegCloseKey( hkey );
346 TRACE_(typelib)("-- 0x%08x\n", hr);
347 return hr;
350 /****************************************************************************
351 * QueryPathOfRegTypeLib [OLEAUT32.164]
353 * Gets the path to a registered type library.
355 * PARAMS
356 * guid [I] referenced guid
357 * wMaj [I] major version
358 * wMin [I] minor version
359 * lcid [I] locale id
360 * path [O] path of typelib
362 * RETURNS
363 * Success: S_OK.
364 * Failure: If the type library is not registered then TYPE_E_LIBNOTREGISTERED
365 * or TYPE_E_REGISTRYACCESS if the type library registration key couldn't be
366 * opened.
368 HRESULT WINAPI QueryPathOfRegTypeLib( REFGUID guid, WORD wMaj, WORD wMin, LCID lcid, LPBSTR path )
370 #ifdef _WIN64
371 HRESULT hres = query_typelib_path( guid, wMaj, wMin, SYS_WIN64, lcid, path );
372 if(SUCCEEDED(hres))
373 return hres;
374 #endif
375 return query_typelib_path( guid, wMaj, wMin, SYS_WIN32, lcid, path );
378 /******************************************************************************
379 * CreateTypeLib [OLEAUT32.160] creates a typelib
381 * RETURNS
382 * Success: S_OK
383 * Failure: Status
385 HRESULT WINAPI CreateTypeLib(
386 SYSKIND syskind, LPCOLESTR szFile, ICreateTypeLib** ppctlib
388 FIXME("(%d,%s,%p), stub!\n",syskind,debugstr_w(szFile),ppctlib);
389 return E_FAIL;
392 /******************************************************************************
393 * LoadTypeLib [OLEAUT32.161]
395 * Loads a type library
397 * PARAMS
398 * szFile [I] Name of file to load from.
399 * pptLib [O] Pointer that receives ITypeLib object on success.
401 * RETURNS
402 * Success: S_OK
403 * Failure: Status
405 * SEE
406 * LoadTypeLibEx, LoadRegTypeLib, CreateTypeLib.
408 HRESULT WINAPI LoadTypeLib(const OLECHAR *szFile, ITypeLib * *pptLib)
410 TRACE("(%s,%p)\n",debugstr_w(szFile), pptLib);
411 return LoadTypeLibEx(szFile, REGKIND_DEFAULT, pptLib);
414 /******************************************************************************
415 * LoadTypeLibEx [OLEAUT32.183]
417 * Loads and optionally registers a type library
419 * RETURNS
420 * Success: S_OK
421 * Failure: Status
423 HRESULT WINAPI LoadTypeLibEx(
424 LPCOLESTR szFile, /* [in] Name of file to load from */
425 REGKIND regkind, /* [in] Specify kind of registration */
426 ITypeLib **pptLib) /* [out] Pointer to pointer to loaded type library */
428 WCHAR szPath[MAX_PATH+1];
429 HRESULT res;
431 TRACE("(%s,%d,%p)\n",debugstr_w(szFile), regkind, pptLib);
433 *pptLib = NULL;
435 res = TLB_ReadTypeLib(szFile, szPath, MAX_PATH + 1, (ITypeLib2**)pptLib);
437 if (SUCCEEDED(res))
438 switch(regkind)
440 case REGKIND_DEFAULT:
441 /* don't register typelibs supplied with full path. Experimentation confirms the following */
442 if (((szFile[0] == '\\') && (szFile[1] == '\\')) ||
443 (szFile[0] && (szFile[1] == ':'))) break;
444 /* else fall-through */
446 case REGKIND_REGISTER:
447 if (FAILED(res = RegisterTypeLib(*pptLib, szPath, NULL)))
449 IUnknown_Release(*pptLib);
450 *pptLib = 0;
452 break;
453 case REGKIND_NONE:
454 break;
457 TRACE(" returns %08x\n",res);
458 return res;
461 /******************************************************************************
462 * LoadRegTypeLib [OLEAUT32.162]
464 * Loads a registered type library.
466 * PARAMS
467 * rguid [I] GUID of the registered type library.
468 * wVerMajor [I] major version.
469 * wVerMinor [I] minor version.
470 * lcid [I] locale ID.
471 * ppTLib [O] pointer that receives an ITypeLib object on success.
473 * RETURNS
474 * Success: S_OK.
475 * Failure: Any HRESULT code returned from QueryPathOfRegTypeLib or
476 * LoadTypeLib.
478 HRESULT WINAPI LoadRegTypeLib(
479 REFGUID rguid,
480 WORD wVerMajor,
481 WORD wVerMinor,
482 LCID lcid,
483 ITypeLib **ppTLib)
485 BSTR bstr=NULL;
486 HRESULT res;
488 *ppTLib = NULL;
490 res = QueryPathOfRegTypeLib( rguid, wVerMajor, wVerMinor, lcid, &bstr);
492 if(SUCCEEDED(res))
494 res= LoadTypeLib(bstr, ppTLib);
495 SysFreeString(bstr);
498 TRACE("(IID: %s) load %s (%p)\n",debugstr_guid(rguid), SUCCEEDED(res)? "SUCCESS":"FAILED", *ppTLib);
500 return res;
504 /* some string constants shared between RegisterTypeLib and UnRegisterTypeLib */
505 static const WCHAR TypeLibW[] = {'T','y','p','e','L','i','b',0};
506 static const WCHAR FLAGSW[] = {'F','L','A','G','S',0};
507 static const WCHAR HELPDIRW[] = {'H','E','L','P','D','I','R',0};
508 static const WCHAR ProxyStubClsidW[] = {'P','r','o','x','y','S','t','u','b','C','l','s','i','d',0};
509 static const WCHAR ProxyStubClsid32W[] = {'P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
511 /******************************************************************************
512 * RegisterTypeLib [OLEAUT32.163]
513 * Adds information about a type library to the System Registry
514 * NOTES
515 * Docs: ITypeLib FAR * ptlib
516 * Docs: OLECHAR FAR* szFullPath
517 * Docs: OLECHAR FAR* szHelpDir
519 * RETURNS
520 * Success: S_OK
521 * Failure: Status
523 HRESULT WINAPI RegisterTypeLib(
524 ITypeLib * ptlib, /* [in] Pointer to the library*/
525 OLECHAR * szFullPath, /* [in] full Path of the library*/
526 OLECHAR * szHelpDir) /* [in] dir to the helpfile for the library,
527 may be NULL*/
529 static const WCHAR PSOA[] = {'{','0','0','0','2','0','4','2','4','-',
530 '0','0','0','0','-','0','0','0','0','-','C','0','0','0','-',
531 '0','0','0','0','0','0','0','0','0','0','4','6','}',0};
532 HRESULT res;
533 TLIBATTR *attr;
534 WCHAR keyName[60];
535 WCHAR tmp[16];
536 HKEY key, subKey;
537 UINT types, tidx;
538 TYPEKIND kind;
539 DWORD disposition;
541 if (ptlib == NULL || szFullPath == NULL)
542 return E_INVALIDARG;
544 if (FAILED(ITypeLib_GetLibAttr(ptlib, &attr)))
545 return E_FAIL;
547 #ifdef _WIN64
548 if (attr->syskind != SYS_WIN64) return TYPE_E_BADMODULEKIND;
549 #else
550 if (attr->syskind != SYS_WIN32 && attr->syskind != SYS_WIN16) return TYPE_E_BADMODULEKIND;
551 #endif
553 get_typelib_key( &attr->guid, attr->wMajorVerNum, attr->wMinorVerNum, keyName );
555 res = S_OK;
556 if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0,
557 KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS)
559 LPOLESTR doc;
561 /* Set the human-readable name of the typelib */
562 if (FAILED(ITypeLib_GetDocumentation(ptlib, -1, NULL, &doc, NULL, NULL)))
563 res = E_FAIL;
564 else if (doc)
566 if (RegSetValueExW(key, NULL, 0, REG_SZ,
567 (BYTE *)doc, (lstrlenW(doc)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS)
568 res = E_FAIL;
570 SysFreeString(doc);
573 /* Make up the name of the typelib path subkey */
574 if (!get_lcid_subkey( attr->lcid, attr->syskind, tmp )) res = E_FAIL;
576 /* Create the typelib path subkey */
577 if (res == S_OK && RegCreateKeyExW(key, tmp, 0, NULL, 0,
578 KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
580 if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
581 (BYTE *)szFullPath, (lstrlenW(szFullPath)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS)
582 res = E_FAIL;
584 RegCloseKey(subKey);
586 else
587 res = E_FAIL;
589 /* Create the flags subkey */
590 if (res == S_OK && RegCreateKeyExW(key, FLAGSW, 0, NULL, 0,
591 KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
593 /* FIXME: is %u correct? */
594 static const WCHAR formatW[] = {'%','u',0};
595 WCHAR buf[20];
596 sprintfW(buf, formatW, attr->wLibFlags);
597 if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
598 (BYTE *)buf, (strlenW(buf) + 1)*sizeof(WCHAR) ) != ERROR_SUCCESS)
599 res = E_FAIL;
601 RegCloseKey(subKey);
603 else
604 res = E_FAIL;
606 /* create the helpdir subkey */
607 if (res == S_OK && RegCreateKeyExW(key, HELPDIRW, 0, NULL, 0,
608 KEY_WRITE, NULL, &subKey, &disposition) == ERROR_SUCCESS)
610 BOOL freeHelpDir = FALSE;
611 OLECHAR* pIndexStr;
613 /* if we created a new key, and helpDir was null, set the helpdir
614 to the directory which contains the typelib. However,
615 if we just opened an existing key, we leave the helpdir alone */
616 if ((disposition == REG_CREATED_NEW_KEY) && (szHelpDir == NULL)) {
617 szHelpDir = SysAllocString(szFullPath);
618 pIndexStr = strrchrW(szHelpDir, '\\');
619 if (pIndexStr) {
620 *pIndexStr = 0;
622 freeHelpDir = TRUE;
625 /* if we have an szHelpDir, set it! */
626 if (szHelpDir != NULL) {
627 if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
628 (BYTE *)szHelpDir, (lstrlenW(szHelpDir)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS) {
629 res = E_FAIL;
633 /* tidy up */
634 if (freeHelpDir) SysFreeString(szHelpDir);
635 RegCloseKey(subKey);
637 } else {
638 res = E_FAIL;
641 RegCloseKey(key);
643 else
644 res = E_FAIL;
646 /* register OLE Automation-compatible interfaces for this typelib */
647 types = ITypeLib_GetTypeInfoCount(ptlib);
648 for (tidx=0; tidx<types; tidx++) {
649 if (SUCCEEDED(ITypeLib_GetTypeInfoType(ptlib, tidx, &kind))) {
650 LPOLESTR name = NULL;
651 ITypeInfo *tinfo = NULL;
653 ITypeLib_GetDocumentation(ptlib, tidx, &name, NULL, NULL, NULL);
655 switch (kind) {
656 case TKIND_INTERFACE:
657 TRACE_(typelib)("%d: interface %s\n", tidx, debugstr_w(name));
658 ITypeLib_GetTypeInfo(ptlib, tidx, &tinfo);
659 break;
661 case TKIND_DISPATCH:
662 TRACE_(typelib)("%d: dispinterface %s\n", tidx, debugstr_w(name));
663 ITypeLib_GetTypeInfo(ptlib, tidx, &tinfo);
664 break;
666 default:
667 TRACE_(typelib)("%d: %s\n", tidx, debugstr_w(name));
668 break;
671 if (tinfo) {
672 TYPEATTR *tattr = NULL;
673 ITypeInfo_GetTypeAttr(tinfo, &tattr);
675 if (tattr) {
676 TRACE_(typelib)("guid=%s, flags=%04x (",
677 debugstr_guid(&tattr->guid),
678 tattr->wTypeFlags);
680 if (TRACE_ON(typelib)) {
681 #define XX(x) if (TYPEFLAG_##x & tattr->wTypeFlags) MESSAGE(#x"|");
682 XX(FAPPOBJECT);
683 XX(FCANCREATE);
684 XX(FLICENSED);
685 XX(FPREDECLID);
686 XX(FHIDDEN);
687 XX(FCONTROL);
688 XX(FDUAL);
689 XX(FNONEXTENSIBLE);
690 XX(FOLEAUTOMATION);
691 XX(FRESTRICTED);
692 XX(FAGGREGATABLE);
693 XX(FREPLACEABLE);
694 XX(FDISPATCHABLE);
695 XX(FREVERSEBIND);
696 XX(FPROXY);
697 #undef XX
698 MESSAGE("\n");
701 /* Register all dispinterfaces (which includes dual interfaces) and
702 oleautomation interfaces */
703 if ((kind == TKIND_INTERFACE && (tattr->wTypeFlags & TYPEFLAG_FOLEAUTOMATION)) ||
704 kind == TKIND_DISPATCH)
706 /* register interface<->typelib coupling */
707 get_interface_key( &tattr->guid, keyName );
708 if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0,
709 KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS)
711 if (name)
712 RegSetValueExW(key, NULL, 0, REG_SZ,
713 (BYTE *)name, (strlenW(name)+1) * sizeof(OLECHAR));
715 if (RegCreateKeyExW(key, ProxyStubClsidW, 0, NULL, 0,
716 KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) {
717 RegSetValueExW(subKey, NULL, 0, REG_SZ,
718 (const BYTE *)PSOA, sizeof PSOA);
719 RegCloseKey(subKey);
722 if (RegCreateKeyExW(key, ProxyStubClsid32W, 0, NULL, 0,
723 KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) {
724 RegSetValueExW(subKey, NULL, 0, REG_SZ,
725 (const BYTE *)PSOA, sizeof PSOA);
726 RegCloseKey(subKey);
729 if (RegCreateKeyExW(key, TypeLibW, 0, NULL, 0,
730 KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
732 WCHAR buffer[40];
733 static const WCHAR fmtver[] = {'%','x','.','%','x',0 };
734 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
736 StringFromGUID2(&attr->guid, buffer, 40);
737 RegSetValueExW(subKey, NULL, 0, REG_SZ,
738 (BYTE *)buffer, (strlenW(buffer)+1) * sizeof(WCHAR));
739 sprintfW(buffer, fmtver, attr->wMajorVerNum, attr->wMinorVerNum);
740 RegSetValueExW(subKey, VersionW, 0, REG_SZ,
741 (BYTE*)buffer, (strlenW(buffer)+1) * sizeof(WCHAR));
742 RegCloseKey(subKey);
745 RegCloseKey(key);
749 ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
752 ITypeInfo_Release(tinfo);
755 SysFreeString(name);
759 ITypeLib_ReleaseTLibAttr(ptlib, attr);
761 return res;
765 /******************************************************************************
766 * UnRegisterTypeLib [OLEAUT32.186]
767 * Removes information about a type library from the System Registry
768 * NOTES
770 * RETURNS
771 * Success: S_OK
772 * Failure: Status
774 HRESULT WINAPI UnRegisterTypeLib(
775 REFGUID libid, /* [in] Guid of the library */
776 WORD wVerMajor, /* [in] major version */
777 WORD wVerMinor, /* [in] minor version */
778 LCID lcid, /* [in] locale id */
779 SYSKIND syskind)
781 BSTR tlibPath = NULL;
782 DWORD tmpLength;
783 WCHAR keyName[60];
784 WCHAR subKeyName[50];
785 int result = S_OK;
786 DWORD i = 0;
787 BOOL deleteOtherStuff;
788 HKEY key = NULL;
789 HKEY subKey = NULL;
790 TYPEATTR* typeAttr = NULL;
791 TYPEKIND kind;
792 ITypeInfo* typeInfo = NULL;
793 ITypeLib* typeLib = NULL;
794 int numTypes;
796 TRACE("(IID: %s)\n",debugstr_guid(libid));
798 /* Create the path to the key */
799 get_typelib_key( libid, wVerMajor, wVerMinor, keyName );
801 if (syskind != SYS_WIN16 && syskind != SYS_WIN32 && syskind != SYS_WIN64)
803 TRACE("Unsupported syskind %i\n", syskind);
804 result = E_INVALIDARG;
805 goto end;
808 /* get the path to the typelib on disk */
809 if (query_typelib_path(libid, wVerMajor, wVerMinor, syskind, lcid, &tlibPath) != S_OK) {
810 result = E_INVALIDARG;
811 goto end;
814 /* Try and open the key to the type library. */
815 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, keyName, 0, KEY_READ | KEY_WRITE, &key) != ERROR_SUCCESS) {
816 result = E_INVALIDARG;
817 goto end;
820 /* Try and load the type library */
821 if (LoadTypeLibEx(tlibPath, REGKIND_NONE, &typeLib) != S_OK) {
822 result = TYPE_E_INVALIDSTATE;
823 goto end;
826 /* remove any types registered with this typelib */
827 numTypes = ITypeLib_GetTypeInfoCount(typeLib);
828 for (i=0; i<numTypes; i++) {
829 /* get the kind of type */
830 if (ITypeLib_GetTypeInfoType(typeLib, i, &kind) != S_OK) {
831 goto enddeleteloop;
834 /* skip non-interfaces, and get type info for the type */
835 if ((kind != TKIND_INTERFACE) && (kind != TKIND_DISPATCH)) {
836 goto enddeleteloop;
838 if (ITypeLib_GetTypeInfo(typeLib, i, &typeInfo) != S_OK) {
839 goto enddeleteloop;
841 if (ITypeInfo_GetTypeAttr(typeInfo, &typeAttr) != S_OK) {
842 goto enddeleteloop;
845 if ((kind == TKIND_INTERFACE && (typeAttr->wTypeFlags & TYPEFLAG_FOLEAUTOMATION)) ||
846 kind == TKIND_DISPATCH)
848 /* the path to the type */
849 get_interface_key( &typeAttr->guid, subKeyName );
851 /* Delete its bits */
852 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, subKeyName, 0, KEY_WRITE, &subKey) != ERROR_SUCCESS)
853 goto enddeleteloop;
855 RegDeleteKeyW(subKey, ProxyStubClsidW);
856 RegDeleteKeyW(subKey, ProxyStubClsid32W);
857 RegDeleteKeyW(subKey, TypeLibW);
858 RegCloseKey(subKey);
859 subKey = NULL;
860 RegDeleteKeyW(HKEY_CLASSES_ROOT, subKeyName);
863 enddeleteloop:
864 if (typeAttr) ITypeInfo_ReleaseTypeAttr(typeInfo, typeAttr);
865 typeAttr = NULL;
866 if (typeInfo) ITypeInfo_Release(typeInfo);
867 typeInfo = NULL;
870 /* Now, delete the type library path subkey */
871 get_lcid_subkey( lcid, syskind, subKeyName );
872 RegDeleteKeyW(key, subKeyName);
873 *strrchrW( subKeyName, '\\' ) = 0; /* remove last path component */
874 RegDeleteKeyW(key, subKeyName);
876 /* check if there is anything besides the FLAGS/HELPDIR keys.
877 If there is, we don't delete them */
878 tmpLength = sizeof(subKeyName)/sizeof(WCHAR);
879 deleteOtherStuff = TRUE;
880 i = 0;
881 while(RegEnumKeyExW(key, i++, subKeyName, &tmpLength, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
882 tmpLength = sizeof(subKeyName)/sizeof(WCHAR);
884 /* if its not FLAGS or HELPDIR, then we must keep the rest of the key */
885 if (!strcmpW(subKeyName, FLAGSW)) continue;
886 if (!strcmpW(subKeyName, HELPDIRW)) continue;
887 deleteOtherStuff = FALSE;
888 break;
891 /* only delete the other parts of the key if we're absolutely sure */
892 if (deleteOtherStuff) {
893 RegDeleteKeyW(key, FLAGSW);
894 RegDeleteKeyW(key, HELPDIRW);
895 RegCloseKey(key);
896 key = NULL;
898 RegDeleteKeyW(HKEY_CLASSES_ROOT, keyName);
899 *strrchrW( keyName, '\\' ) = 0; /* remove last path component */
900 RegDeleteKeyW(HKEY_CLASSES_ROOT, keyName);
903 end:
904 SysFreeString(tlibPath);
905 if (typeLib) ITypeLib_Release(typeLib);
906 if (subKey) RegCloseKey(subKey);
907 if (key) RegCloseKey(key);
908 return result;
911 /******************************************************************************
912 * RegisterTypeLibForUser [OLEAUT32.442]
913 * Adds information about a type library to the user registry
914 * NOTES
915 * Docs: ITypeLib FAR * ptlib
916 * Docs: OLECHAR FAR* szFullPath
917 * Docs: OLECHAR FAR* szHelpDir
919 * RETURNS
920 * Success: S_OK
921 * Failure: Status
923 HRESULT WINAPI RegisterTypeLibForUser(
924 ITypeLib * ptlib, /* [in] Pointer to the library*/
925 OLECHAR * szFullPath, /* [in] full Path of the library*/
926 OLECHAR * szHelpDir) /* [in] dir to the helpfile for the library,
927 may be NULL*/
929 FIXME("(%p, %s, %s) registering the typelib system-wide\n", ptlib,
930 debugstr_w(szFullPath), debugstr_w(szHelpDir));
931 return RegisterTypeLib(ptlib, szFullPath, szHelpDir);
934 /******************************************************************************
935 * UnRegisterTypeLibForUser [OLEAUT32.443]
936 * Removes information about a type library from the user registry
938 * RETURNS
939 * Success: S_OK
940 * Failure: Status
942 HRESULT WINAPI UnRegisterTypeLibForUser(
943 REFGUID libid, /* [in] GUID of the library */
944 WORD wVerMajor, /* [in] major version */
945 WORD wVerMinor, /* [in] minor version */
946 LCID lcid, /* [in] locale id */
947 SYSKIND syskind)
949 FIXME("(%s, %u, %u, %u, %u) unregistering the typelib system-wide\n",
950 debugstr_guid(libid), wVerMajor, wVerMinor, lcid, syskind);
951 return UnRegisterTypeLib(libid, wVerMajor, wVerMinor, lcid, syskind);
954 /*======================= ITypeLib implementation =======================*/
956 typedef struct tagTLBCustData
958 GUID guid;
959 VARIANT data;
960 struct list entry;
961 } TLBCustData;
963 /* data structure for import typelibs */
964 typedef struct tagTLBImpLib
966 int offset; /* offset in the file (MSFT)
967 offset in nametable (SLTG)
968 just used to identify library while reading
969 data from file */
970 GUID guid; /* libid */
971 BSTR name; /* name */
973 LCID lcid; /* lcid of imported typelib */
975 WORD wVersionMajor; /* major version number */
976 WORD wVersionMinor; /* minor version number */
978 struct tagITypeLibImpl *pImpTypeLib; /* pointer to loaded typelib, or
979 NULL if not yet loaded */
980 struct list entry;
981 } TLBImpLib;
983 /* internal ITypeLib data */
984 typedef struct tagITypeLibImpl
986 const ITypeLib2Vtbl *lpVtbl;
987 const ITypeCompVtbl *lpVtblTypeComp;
988 LONG ref;
989 TLIBATTR LibAttr; /* guid,lcid,syskind,version,flags */
990 LCID lcid;
992 /* strings can be stored in tlb as multibyte strings BUT they are *always*
993 * exported to the application as a UNICODE string.
995 BSTR Name;
996 BSTR DocString;
997 BSTR HelpFile;
998 BSTR HelpStringDll;
999 DWORD dwHelpContext;
1000 int TypeInfoCount; /* nr of typeinfo's in librarry */
1001 struct tagITypeInfoImpl **typeinfos;
1002 struct list custdata_list;
1003 struct list implib_list;
1004 int ctTypeDesc; /* number of items in type desc array */
1005 TYPEDESC * pTypeDesc; /* array of TypeDescriptions found in the
1006 library. Only used while reading MSFT
1007 typelibs */
1008 struct list ref_list; /* list of ref types in this typelib */
1009 HREFTYPE dispatch_href; /* reference to IDispatch, -1 if unused */
1012 /* typelibs are cached, keyed by path and index, so store the linked list info within them */
1013 struct list entry;
1014 WCHAR *path;
1015 INT index;
1016 } ITypeLibImpl;
1018 static const ITypeLib2Vtbl tlbvt;
1019 static const ITypeCompVtbl tlbtcvt;
1021 static inline ITypeLibImpl *impl_from_ITypeComp( ITypeComp *iface )
1023 return (ITypeLibImpl *)((char*)iface - FIELD_OFFSET(ITypeLibImpl, lpVtblTypeComp));
1026 /* ITypeLib methods */
1027 static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength);
1028 static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength);
1030 /*======================= ITypeInfo implementation =======================*/
1032 /* data for referenced types */
1033 typedef struct tagTLBRefType
1035 INT index; /* Type index for internal ref or for external ref
1036 it the format is SLTG. -2 indicates to
1037 use guid */
1039 GUID guid; /* guid of the referenced type */
1040 /* if index == TLB_REF_USE_GUID */
1042 HREFTYPE reference; /* The href of this ref */
1043 TLBImpLib *pImpTLInfo; /* If ref is external ptr to library data
1044 TLB_REF_INTERNAL for internal refs
1045 TLB_REF_NOT_FOUND for broken refs */
1047 struct list entry;
1048 } TLBRefType;
1050 #define TLB_REF_USE_GUID -2
1052 #define TLB_REF_INTERNAL (void*)-2
1053 #define TLB_REF_NOT_FOUND (void*)-1
1055 /* internal Parameter data */
1056 typedef struct tagTLBParDesc
1058 BSTR Name;
1059 struct list custdata_list;
1060 } TLBParDesc;
1062 /* internal Function data */
1063 typedef struct tagTLBFuncDesc
1065 FUNCDESC funcdesc; /* lots of info on the function and its attributes. */
1066 BSTR Name; /* the name of this function */
1067 TLBParDesc *pParamDesc; /* array with param names and custom data */
1068 int helpcontext;
1069 int HelpStringContext;
1070 BSTR HelpString;
1071 BSTR Entry; /* if IS_INTRESOURCE true, it's numeric; if -1 it isn't present */
1072 struct list custdata_list;
1073 } TLBFuncDesc;
1075 /* internal Variable data */
1076 typedef struct tagTLBVarDesc
1078 VARDESC vardesc; /* lots of info on the variable and its attributes. */
1079 BSTR Name; /* the name of this variable */
1080 int HelpContext;
1081 int HelpStringContext;
1082 BSTR HelpString;
1083 struct list custdata_list;
1084 } TLBVarDesc;
1086 /* internal implemented interface data */
1087 typedef struct tagTLBImplType
1089 HREFTYPE hRef; /* hRef of interface */
1090 int implflags; /* IMPLFLAG_*s */
1091 struct list custdata_list;
1092 } TLBImplType;
1094 /* internal TypeInfo data */
1095 typedef struct tagITypeInfoImpl
1097 const ITypeInfo2Vtbl *lpVtbl;
1098 const ITypeCompVtbl *lpVtblTypeComp;
1099 LONG ref;
1100 BOOL not_attached_to_typelib;
1101 TYPEATTR TypeAttr ; /* _lots_ of type information. */
1102 ITypeLibImpl * pTypeLib; /* back pointer to typelib */
1103 int index; /* index in this typelib; */
1104 HREFTYPE hreftype; /* hreftype for app object binding */
1105 /* type libs seem to store the doc strings in ascii
1106 * so why should we do it in unicode?
1108 BSTR Name;
1109 BSTR DocString;
1110 BSTR DllName;
1111 DWORD dwHelpContext;
1112 DWORD dwHelpStringContext;
1114 /* functions */
1115 TLBFuncDesc *funcdescs;
1117 /* variables */
1118 TLBVarDesc *vardescs;
1120 /* Implemented Interfaces */
1121 TLBImplType *impltypes;
1123 struct list custdata_list;
1124 } ITypeInfoImpl;
1126 static inline ITypeInfoImpl *info_impl_from_ITypeComp( ITypeComp *iface )
1128 return (ITypeInfoImpl *)((char*)iface - FIELD_OFFSET(ITypeInfoImpl, lpVtblTypeComp));
1131 static const ITypeInfo2Vtbl tinfvt;
1132 static const ITypeCompVtbl tcompvt;
1134 static ITypeInfoImpl* ITypeInfoImpl_Constructor(void);
1135 static void ITypeInfoImpl_Destroy(ITypeInfoImpl *This);
1137 typedef struct tagTLBContext
1139 unsigned int oStart; /* start of TLB in file */
1140 unsigned int pos; /* current pos */
1141 unsigned int length; /* total length */
1142 void *mapping; /* memory mapping */
1143 MSFT_SegDir * pTblDir;
1144 ITypeLibImpl* pLibInfo;
1145 } TLBContext;
1148 static void MSFT_DoRefType(TLBContext *pcx, ITypeLibImpl *pTL, int offset);
1151 debug
1153 static void dump_TypeDesc(const TYPEDESC *pTD,char *szVarType) {
1154 if (pTD->vt & VT_RESERVED)
1155 szVarType += strlen(strcpy(szVarType, "reserved | "));
1156 if (pTD->vt & VT_BYREF)
1157 szVarType += strlen(strcpy(szVarType, "ref to "));
1158 if (pTD->vt & VT_ARRAY)
1159 szVarType += strlen(strcpy(szVarType, "array of "));
1160 if (pTD->vt & VT_VECTOR)
1161 szVarType += strlen(strcpy(szVarType, "vector of "));
1162 switch(pTD->vt & VT_TYPEMASK) {
1163 case VT_UI1: sprintf(szVarType, "VT_UI1"); break;
1164 case VT_I2: sprintf(szVarType, "VT_I2"); break;
1165 case VT_I4: sprintf(szVarType, "VT_I4"); break;
1166 case VT_R4: sprintf(szVarType, "VT_R4"); break;
1167 case VT_R8: sprintf(szVarType, "VT_R8"); break;
1168 case VT_BOOL: sprintf(szVarType, "VT_BOOL"); break;
1169 case VT_ERROR: sprintf(szVarType, "VT_ERROR"); break;
1170 case VT_CY: sprintf(szVarType, "VT_CY"); break;
1171 case VT_DATE: sprintf(szVarType, "VT_DATE"); break;
1172 case VT_BSTR: sprintf(szVarType, "VT_BSTR"); break;
1173 case VT_UNKNOWN: sprintf(szVarType, "VT_UNKNOWN"); break;
1174 case VT_DISPATCH: sprintf(szVarType, "VT_DISPATCH"); break;
1175 case VT_I1: sprintf(szVarType, "VT_I1"); break;
1176 case VT_UI2: sprintf(szVarType, "VT_UI2"); break;
1177 case VT_UI4: sprintf(szVarType, "VT_UI4"); break;
1178 case VT_INT: sprintf(szVarType, "VT_INT"); break;
1179 case VT_UINT: sprintf(szVarType, "VT_UINT"); break;
1180 case VT_VARIANT: sprintf(szVarType, "VT_VARIANT"); break;
1181 case VT_VOID: sprintf(szVarType, "VT_VOID"); break;
1182 case VT_HRESULT: sprintf(szVarType, "VT_HRESULT"); break;
1183 case VT_USERDEFINED: sprintf(szVarType, "VT_USERDEFINED ref = %x",
1184 pTD->u.hreftype); break;
1185 case VT_LPSTR: sprintf(szVarType, "VT_LPSTR"); break;
1186 case VT_LPWSTR: sprintf(szVarType, "VT_LPWSTR"); break;
1187 case VT_PTR: sprintf(szVarType, "ptr to ");
1188 dump_TypeDesc(pTD->u.lptdesc, szVarType + 7);
1189 break;
1190 case VT_SAFEARRAY: sprintf(szVarType, "safearray of ");
1191 dump_TypeDesc(pTD->u.lptdesc, szVarType + 13);
1192 break;
1193 case VT_CARRAY: sprintf(szVarType, "%d dim array of ",
1194 pTD->u.lpadesc->cDims); /* FIXME print out sizes */
1195 dump_TypeDesc(&pTD->u.lpadesc->tdescElem, szVarType + strlen(szVarType));
1196 break;
1198 default: sprintf(szVarType, "unknown(%d)", pTD->vt & VT_TYPEMASK); break;
1202 static void dump_ELEMDESC(const ELEMDESC *edesc) {
1203 char buf[200];
1204 USHORT flags = edesc->u.paramdesc.wParamFlags;
1205 dump_TypeDesc(&edesc->tdesc,buf);
1206 MESSAGE("\t\ttdesc.vartype %d (%s)\n",edesc->tdesc.vt,buf);
1207 MESSAGE("\t\tu.paramdesc.wParamFlags");
1208 if (!flags) MESSAGE(" PARAMFLAGS_NONE");
1209 if (flags & PARAMFLAG_FIN) MESSAGE(" PARAMFLAG_FIN");
1210 if (flags & PARAMFLAG_FOUT) MESSAGE(" PARAMFLAG_FOUT");
1211 if (flags & PARAMFLAG_FLCID) MESSAGE(" PARAMFLAG_FLCID");
1212 if (flags & PARAMFLAG_FRETVAL) MESSAGE(" PARAMFLAG_FRETVAL");
1213 if (flags & PARAMFLAG_FOPT) MESSAGE(" PARAMFLAG_FOPT");
1214 if (flags & PARAMFLAG_FHASDEFAULT) MESSAGE(" PARAMFLAG_FHASDEFAULT");
1215 if (flags & PARAMFLAG_FHASCUSTDATA) MESSAGE(" PARAMFLAG_FHASCUSTDATA");
1216 MESSAGE("\n\t\tu.paramdesc.lpex %p\n",edesc->u.paramdesc.pparamdescex);
1218 static void dump_FUNCDESC(const FUNCDESC *funcdesc) {
1219 int i;
1220 MESSAGE("memid is %08x\n",funcdesc->memid);
1221 for (i=0;i<funcdesc->cParams;i++) {
1222 MESSAGE("Param %d:\n",i);
1223 dump_ELEMDESC(funcdesc->lprgelemdescParam+i);
1225 MESSAGE("\tfunckind: %d (",funcdesc->funckind);
1226 switch (funcdesc->funckind) {
1227 case FUNC_VIRTUAL: MESSAGE("virtual");break;
1228 case FUNC_PUREVIRTUAL: MESSAGE("pure virtual");break;
1229 case FUNC_NONVIRTUAL: MESSAGE("nonvirtual");break;
1230 case FUNC_STATIC: MESSAGE("static");break;
1231 case FUNC_DISPATCH: MESSAGE("dispatch");break;
1232 default: MESSAGE("unknown");break;
1234 MESSAGE(")\n\tinvkind: %d (",funcdesc->invkind);
1235 switch (funcdesc->invkind) {
1236 case INVOKE_FUNC: MESSAGE("func");break;
1237 case INVOKE_PROPERTYGET: MESSAGE("property get");break;
1238 case INVOKE_PROPERTYPUT: MESSAGE("property put");break;
1239 case INVOKE_PROPERTYPUTREF: MESSAGE("property put ref");break;
1241 MESSAGE(")\n\tcallconv: %d (",funcdesc->callconv);
1242 switch (funcdesc->callconv) {
1243 case CC_CDECL: MESSAGE("cdecl");break;
1244 case CC_PASCAL: MESSAGE("pascal");break;
1245 case CC_STDCALL: MESSAGE("stdcall");break;
1246 case CC_SYSCALL: MESSAGE("syscall");break;
1247 default:break;
1249 MESSAGE(")\n\toVft: %d\n", funcdesc->oVft);
1250 MESSAGE("\tcParamsOpt: %d\n", funcdesc->cParamsOpt);
1251 MESSAGE("\twFlags: %x\n", funcdesc->wFuncFlags);
1253 MESSAGE("\telemdescFunc (return value type):\n");
1254 dump_ELEMDESC(&funcdesc->elemdescFunc);
1257 static const char * const typekind_desc[] =
1259 "TKIND_ENUM",
1260 "TKIND_RECORD",
1261 "TKIND_MODULE",
1262 "TKIND_INTERFACE",
1263 "TKIND_DISPATCH",
1264 "TKIND_COCLASS",
1265 "TKIND_ALIAS",
1266 "TKIND_UNION",
1267 "TKIND_MAX"
1270 static void dump_TLBFuncDescOne(const TLBFuncDesc * pfd)
1272 int i;
1273 MESSAGE("%s(%u)\n", debugstr_w(pfd->Name), pfd->funcdesc.cParams);
1274 for (i=0;i<pfd->funcdesc.cParams;i++)
1275 MESSAGE("\tparm%d: %s\n",i,debugstr_w(pfd->pParamDesc[i].Name));
1278 dump_FUNCDESC(&(pfd->funcdesc));
1280 MESSAGE("\thelpstring: %s\n", debugstr_w(pfd->HelpString));
1281 MESSAGE("\tentry: %s\n", (pfd->Entry == (void *)-1) ? "invalid" : debugstr_w(pfd->Entry));
1283 static void dump_TLBFuncDesc(const TLBFuncDesc * pfd, UINT n)
1285 while (n)
1287 dump_TLBFuncDescOne(pfd);
1288 ++pfd;
1289 --n;
1292 static void dump_TLBVarDesc(const TLBVarDesc * pvd, UINT n)
1294 while (n)
1296 TRACE_(typelib)("%s\n", debugstr_w(pvd->Name));
1297 ++pvd;
1298 --n;
1302 static void dump_TLBImpLib(const TLBImpLib *import)
1304 TRACE_(typelib)("%s %s\n", debugstr_guid(&(import->guid)),
1305 debugstr_w(import->name));
1306 TRACE_(typelib)("v%d.%d lcid=%x offset=%x\n", import->wVersionMajor,
1307 import->wVersionMinor, import->lcid, import->offset);
1310 static void dump_TLBRefType(const ITypeLibImpl *pTL)
1312 TLBRefType *ref;
1314 LIST_FOR_EACH_ENTRY(ref, &pTL->ref_list, TLBRefType, entry)
1316 TRACE_(typelib)("href:0x%08x\n", ref->reference);
1317 if(ref->index == -1)
1318 TRACE_(typelib)("%s\n", debugstr_guid(&(ref->guid)));
1319 else
1320 TRACE_(typelib)("type no: %d\n", ref->index);
1322 if(ref->pImpTLInfo != TLB_REF_INTERNAL && ref->pImpTLInfo != TLB_REF_NOT_FOUND)
1324 TRACE_(typelib)("in lib\n");
1325 dump_TLBImpLib(ref->pImpTLInfo);
1330 static void dump_TLBImplType(const TLBImplType * impl, UINT n)
1332 if(!impl)
1333 return;
1334 while (n) {
1335 TRACE_(typelib)("implementing/inheriting interface hRef = %x implflags %x\n",
1336 impl->hRef, impl->implflags);
1337 ++impl;
1338 --n;
1342 static void dump_Variant(const VARIANT * pvar)
1344 SYSTEMTIME st;
1346 TRACE("%p->{%s%s", pvar, debugstr_VT(pvar), debugstr_VF(pvar));
1348 if (pvar)
1350 if (V_ISBYREF(pvar) || V_TYPE(pvar) == VT_UNKNOWN ||
1351 V_TYPE(pvar) == VT_DISPATCH || V_TYPE(pvar) == VT_RECORD)
1353 TRACE(",%p", V_BYREF(pvar));
1355 else if (V_ISARRAY(pvar) || V_ISVECTOR(pvar))
1357 TRACE(",%p", V_ARRAY(pvar));
1359 else switch (V_TYPE(pvar))
1361 case VT_I1: TRACE(",%d", V_I1(pvar)); break;
1362 case VT_UI1: TRACE(",%d", V_UI1(pvar)); break;
1363 case VT_I2: TRACE(",%d", V_I2(pvar)); break;
1364 case VT_UI2: TRACE(",%d", V_UI2(pvar)); break;
1365 case VT_INT:
1366 case VT_I4: TRACE(",%d", V_I4(pvar)); break;
1367 case VT_UINT:
1368 case VT_UI4: TRACE(",%d", V_UI4(pvar)); break;
1369 case VT_I8: TRACE(",0x%08x,0x%08x", (ULONG)(V_I8(pvar) >> 32),
1370 (ULONG)(V_I8(pvar) & 0xffffffff)); break;
1371 case VT_UI8: TRACE(",0x%08x,0x%08x", (ULONG)(V_UI8(pvar) >> 32),
1372 (ULONG)(V_UI8(pvar) & 0xffffffff)); break;
1373 case VT_R4: TRACE(",%3.3e", V_R4(pvar)); break;
1374 case VT_R8: TRACE(",%3.3e", V_R8(pvar)); break;
1375 case VT_BOOL: TRACE(",%s", V_BOOL(pvar) ? "TRUE" : "FALSE"); break;
1376 case VT_BSTR: TRACE(",%s", debugstr_w(V_BSTR(pvar))); break;
1377 case VT_CY: TRACE(",0x%08x,0x%08x", V_CY(pvar).s.Hi,
1378 V_CY(pvar).s.Lo); break;
1379 case VT_DATE:
1380 if(!VariantTimeToSystemTime(V_DATE(pvar), &st))
1381 TRACE(",<invalid>");
1382 else
1383 TRACE(",%04d/%02d/%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay,
1384 st.wHour, st.wMinute, st.wSecond);
1385 break;
1386 case VT_ERROR:
1387 case VT_VOID:
1388 case VT_USERDEFINED:
1389 case VT_EMPTY:
1390 case VT_NULL: break;
1391 default: TRACE(",?"); break;
1394 TRACE("}\n");
1397 static void dump_DispParms(const DISPPARAMS * pdp)
1399 unsigned int index;
1401 TRACE("args=%u named args=%u\n", pdp->cArgs, pdp->cNamedArgs);
1403 if (pdp->cNamedArgs && pdp->rgdispidNamedArgs)
1405 TRACE("named args:\n");
1406 for (index = 0; index < pdp->cNamedArgs; index++)
1407 TRACE( "\t0x%x\n", pdp->rgdispidNamedArgs[index] );
1410 if (pdp->cArgs && pdp->rgvarg)
1412 TRACE("args:\n");
1413 for (index = 0; index < pdp->cArgs; index++)
1414 dump_Variant( &pdp->rgvarg[index] );
1418 static void dump_TypeInfo(const ITypeInfoImpl * pty)
1420 TRACE("%p ref=%u\n", pty, pty->ref);
1421 TRACE("%s %s\n", debugstr_w(pty->Name), debugstr_w(pty->DocString));
1422 TRACE("attr:%s\n", debugstr_guid(&(pty->TypeAttr.guid)));
1423 TRACE("kind:%s\n", typekind_desc[pty->TypeAttr.typekind]);
1424 TRACE("fct:%u var:%u impl:%u\n",
1425 pty->TypeAttr.cFuncs, pty->TypeAttr.cVars, pty->TypeAttr.cImplTypes);
1426 TRACE("wTypeFlags: 0x%04x\n", pty->TypeAttr.wTypeFlags);
1427 TRACE("parent tlb:%p index in TLB:%u\n",pty->pTypeLib, pty->index);
1428 if (pty->TypeAttr.typekind == TKIND_MODULE) TRACE("dllname:%s\n", debugstr_w(pty->DllName));
1429 if (TRACE_ON(ole))
1430 dump_TLBFuncDesc(pty->funcdescs, pty->TypeAttr.cFuncs);
1431 dump_TLBVarDesc(pty->vardescs, pty->TypeAttr.cVars);
1432 dump_TLBImplType(pty->impltypes, pty->TypeAttr.cImplTypes);
1435 static void dump_VARDESC(const VARDESC *v)
1437 MESSAGE("memid %d\n",v->memid);
1438 MESSAGE("lpstrSchema %s\n",debugstr_w(v->lpstrSchema));
1439 MESSAGE("oInst %d\n",v->u.oInst);
1440 dump_ELEMDESC(&(v->elemdescVar));
1441 MESSAGE("wVarFlags %x\n",v->wVarFlags);
1442 MESSAGE("varkind %d\n",v->varkind);
1445 static TYPEDESC std_typedesc[VT_LPWSTR+1] =
1447 /* VT_LPWSTR is largest type that, may appear in type description */
1448 {{0}, VT_EMPTY}, {{0}, VT_NULL}, {{0}, VT_I2}, {{0}, VT_I4},
1449 {{0}, VT_R4}, {{0}, VT_R8}, {{0}, VT_CY}, {{0}, VT_DATE},
1450 {{0}, VT_BSTR}, {{0}, VT_DISPATCH}, {{0}, VT_ERROR}, {{0}, VT_BOOL},
1451 {{0}, VT_VARIANT},{{0}, VT_UNKNOWN}, {{0}, VT_DECIMAL}, {{0}, 15}, /* unused in VARENUM */
1452 {{0}, VT_I1}, {{0}, VT_UI1}, {{0}, VT_UI2}, {{0}, VT_UI4},
1453 {{0}, VT_I8}, {{0}, VT_UI8}, {{0}, VT_INT}, {{0}, VT_UINT},
1454 {{0}, VT_VOID}, {{0}, VT_HRESULT}, {{0}, VT_PTR}, {{0}, VT_SAFEARRAY},
1455 {{0}, VT_CARRAY}, {{0}, VT_USERDEFINED}, {{0}, VT_LPSTR}, {{0}, VT_LPWSTR}
1458 static void TLB_abort(void)
1460 DebugBreak();
1463 void* __WINE_ALLOC_SIZE(1) heap_alloc_zero(unsigned size)
1465 void *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
1466 if (!ret) ERR("cannot allocate memory\n");
1467 return ret;
1470 void* __WINE_ALLOC_SIZE(1) heap_alloc(unsigned size)
1472 void *ret = HeapAlloc(GetProcessHeap(), 0, size);
1473 if (!ret) ERR("cannot allocate memory\n");
1474 return ret;
1477 void* __WINE_ALLOC_SIZE(2) heap_realloc(void *ptr, unsigned size)
1479 return HeapReAlloc(GetProcessHeap(), 0, ptr, size);
1482 void heap_free(void *ptr)
1484 HeapFree(GetProcessHeap(), 0, ptr);
1487 /* returns the size required for a deep copy of a typedesc into a
1488 * flat buffer */
1489 static SIZE_T TLB_SizeTypeDesc( const TYPEDESC *tdesc, BOOL alloc_initial_space )
1491 SIZE_T size = 0;
1493 if (alloc_initial_space)
1494 size += sizeof(TYPEDESC);
1496 switch (tdesc->vt)
1498 case VT_PTR:
1499 case VT_SAFEARRAY:
1500 size += TLB_SizeTypeDesc(tdesc->u.lptdesc, TRUE);
1501 break;
1502 case VT_CARRAY:
1503 size += FIELD_OFFSET(ARRAYDESC, rgbounds[tdesc->u.lpadesc->cDims]);
1504 size += TLB_SizeTypeDesc(&tdesc->u.lpadesc->tdescElem, FALSE);
1505 break;
1507 return size;
1510 /* deep copy a typedesc into a flat buffer */
1511 static void *TLB_CopyTypeDesc( TYPEDESC *dest, const TYPEDESC *src, void *buffer )
1513 if (!dest)
1515 dest = buffer;
1516 buffer = (char *)buffer + sizeof(TYPEDESC);
1519 *dest = *src;
1521 switch (src->vt)
1523 case VT_PTR:
1524 case VT_SAFEARRAY:
1525 dest->u.lptdesc = buffer;
1526 buffer = TLB_CopyTypeDesc(NULL, src->u.lptdesc, buffer);
1527 break;
1528 case VT_CARRAY:
1529 dest->u.lpadesc = buffer;
1530 memcpy(dest->u.lpadesc, src->u.lpadesc, FIELD_OFFSET(ARRAYDESC, rgbounds[src->u.lpadesc->cDims]));
1531 buffer = (char *)buffer + FIELD_OFFSET(ARRAYDESC, rgbounds[src->u.lpadesc->cDims]);
1532 buffer = TLB_CopyTypeDesc(&dest->u.lpadesc->tdescElem, &src->u.lpadesc->tdescElem, buffer);
1533 break;
1535 return buffer;
1538 /* free custom data allocated by MSFT_CustData */
1539 static inline void TLB_FreeCustData(struct list *custdata_list)
1541 TLBCustData *cd, *cdn;
1542 LIST_FOR_EACH_ENTRY_SAFE(cd, cdn, custdata_list, TLBCustData, entry)
1544 list_remove(&cd->entry);
1545 VariantClear(&cd->data);
1546 heap_free(cd);
1550 static BSTR TLB_MultiByteToBSTR(const char *ptr)
1552 DWORD len;
1553 BSTR ret;
1555 len = MultiByteToWideChar(CP_ACP, 0, ptr, -1, NULL, 0);
1556 ret = SysAllocStringLen(NULL, len - 1);
1557 if (!ret) return ret;
1558 MultiByteToWideChar(CP_ACP, 0, ptr, -1, ret, len);
1559 return ret;
1562 static inline TLBFuncDesc *TLB_get_funcdesc_by_memberid(TLBFuncDesc *funcdescs,
1563 UINT n, MEMBERID memid)
1565 while(n){
1566 if(funcdescs->funcdesc.memid == memid)
1567 return funcdescs;
1568 ++funcdescs;
1569 --n;
1571 return NULL;
1574 static inline TLBFuncDesc *TLB_get_funcdesc_by_name(TLBFuncDesc *funcdescs,
1575 UINT n, const OLECHAR *name)
1577 while(n){
1578 if(!lstrcmpiW(funcdescs->Name, name))
1579 return funcdescs;
1580 ++funcdescs;
1581 --n;
1583 return NULL;
1586 static inline TLBVarDesc *TLB_get_vardesc_by_memberid(TLBVarDesc *vardescs,
1587 UINT n, MEMBERID memid)
1589 while(n){
1590 if(vardescs->vardesc.memid == memid)
1591 return vardescs;
1592 ++vardescs;
1593 --n;
1595 return NULL;
1598 static inline TLBVarDesc *TLB_get_vardesc_by_name(TLBVarDesc *vardescs,
1599 UINT n, const OLECHAR *name)
1601 while(n){
1602 if(!lstrcmpiW(vardescs->Name, name))
1603 return vardescs;
1604 ++vardescs;
1605 --n;
1607 return NULL;
1610 static inline TLBCustData *TLB_get_custdata_by_guid(struct list *custdata_list, REFGUID guid)
1612 TLBCustData *cust_data;
1613 LIST_FOR_EACH_ENTRY(cust_data, custdata_list, TLBCustData, entry)
1614 if(IsEqualIID(&cust_data->guid, guid))
1615 return cust_data;
1616 return NULL;
1619 static TLBVarDesc *TLBVarDesc_Constructor(UINT n)
1621 TLBVarDesc *ret;
1623 ret = heap_alloc_zero(sizeof(TLBVarDesc) * n);
1624 if(!ret)
1625 return NULL;
1627 while(n){
1628 list_init(&ret[n-1].custdata_list);
1629 --n;
1632 return ret;
1635 static TLBParDesc *TLBParDesc_Constructor(UINT n)
1637 TLBParDesc *ret;
1639 ret = heap_alloc_zero(sizeof(TLBParDesc) * n);
1640 if(!ret)
1641 return NULL;
1643 while(n){
1644 list_init(&ret[n-1].custdata_list);
1645 --n;
1648 return ret;
1651 static TLBFuncDesc *TLBFuncDesc_Constructor(UINT n)
1653 TLBFuncDesc *ret;
1655 ret = heap_alloc_zero(sizeof(TLBFuncDesc) * n);
1656 if(!ret)
1657 return NULL;
1659 while(n){
1660 list_init(&ret[n-1].custdata_list);
1661 --n;
1664 return ret;
1667 static TLBImplType *TLBImplType_Constructor(UINT n)
1669 TLBImplType *ret;
1671 ret = heap_alloc_zero(sizeof(TLBImplType) * n);
1672 if(!ret)
1673 return NULL;
1675 while(n){
1676 list_init(&ret[n-1].custdata_list);
1677 --n;
1680 return ret;
1683 /**********************************************************************
1685 * Functions for reading MSFT typelibs (those created by CreateTypeLib2)
1687 static inline unsigned int MSFT_Tell(const TLBContext *pcx)
1689 return pcx->pos;
1692 static inline void MSFT_Seek(TLBContext *pcx, LONG where)
1694 if (where != DO_NOT_SEEK)
1696 where += pcx->oStart;
1697 if (where > pcx->length)
1699 /* FIXME */
1700 ERR("seek beyond end (%d/%d)\n", where, pcx->length );
1701 TLB_abort();
1703 pcx->pos = where;
1707 /* read function */
1708 static DWORD MSFT_Read(void *buffer, DWORD count, TLBContext *pcx, LONG where )
1710 TRACE_(typelib)("pos=0x%08x len=0x%08x 0x%08x 0x%08x 0x%08x\n",
1711 pcx->pos, count, pcx->oStart, pcx->length, where);
1713 MSFT_Seek(pcx, where);
1714 if (pcx->pos + count > pcx->length) count = pcx->length - pcx->pos;
1715 memcpy( buffer, (char *)pcx->mapping + pcx->pos, count );
1716 pcx->pos += count;
1717 return count;
1720 static DWORD MSFT_ReadLEDWords(void *buffer, DWORD count, TLBContext *pcx,
1721 LONG where )
1723 DWORD ret;
1725 ret = MSFT_Read(buffer, count, pcx, where);
1726 FromLEDWords(buffer, ret);
1728 return ret;
1731 static DWORD MSFT_ReadLEWords(void *buffer, DWORD count, TLBContext *pcx,
1732 LONG where )
1734 DWORD ret;
1736 ret = MSFT_Read(buffer, count, pcx, where);
1737 FromLEWords(buffer, ret);
1739 return ret;
1742 static void MSFT_ReadGuid( GUID *pGuid, int offset, TLBContext *pcx)
1744 if(offset<0 || pcx->pTblDir->pGuidTab.offset <0){
1745 memset(pGuid,0, sizeof(GUID));
1746 return;
1748 MSFT_Read(pGuid, sizeof(GUID), pcx, pcx->pTblDir->pGuidTab.offset+offset );
1749 pGuid->Data1 = FromLEDWord(pGuid->Data1);
1750 pGuid->Data2 = FromLEWord(pGuid->Data2);
1751 pGuid->Data3 = FromLEWord(pGuid->Data3);
1752 TRACE_(typelib)("%s\n", debugstr_guid(pGuid));
1755 static HREFTYPE MSFT_ReadHreftype( TLBContext *pcx, int offset )
1757 MSFT_NameIntro niName;
1759 if (offset < 0)
1761 ERR_(typelib)("bad offset %d\n", offset);
1762 return -1;
1765 MSFT_ReadLEDWords(&niName, sizeof(niName), pcx,
1766 pcx->pTblDir->pNametab.offset+offset);
1768 return niName.hreftype;
1771 static BSTR MSFT_ReadName( TLBContext *pcx, int offset)
1773 char * name;
1774 MSFT_NameIntro niName;
1775 int lengthInChars;
1776 BSTR bstrName = NULL;
1778 if (offset < 0)
1780 ERR_(typelib)("bad offset %d\n", offset);
1781 return NULL;
1783 MSFT_ReadLEDWords(&niName, sizeof(niName), pcx,
1784 pcx->pTblDir->pNametab.offset+offset);
1785 niName.namelen &= 0xFF; /* FIXME: correct ? */
1786 name = heap_alloc_zero((niName.namelen & 0xff) +1);
1787 MSFT_Read(name, (niName.namelen & 0xff), pcx, DO_NOT_SEEK);
1788 name[niName.namelen & 0xff]='\0';
1790 lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
1791 name, -1, NULL, 0);
1793 /* no invalid characters in string */
1794 if (lengthInChars)
1796 bstrName = SysAllocStringByteLen(NULL, lengthInChars * sizeof(WCHAR));
1798 /* don't check for invalid character since this has been done previously */
1799 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name, -1, bstrName, lengthInChars);
1801 heap_free(name);
1803 TRACE_(typelib)("%s %d\n", debugstr_w(bstrName), lengthInChars);
1804 return bstrName;
1807 static BSTR MSFT_ReadString( TLBContext *pcx, int offset)
1809 char * string;
1810 INT16 length;
1811 int lengthInChars;
1812 BSTR bstr = NULL;
1814 if(offset<0) return NULL;
1815 MSFT_ReadLEWords(&length, sizeof(INT16), pcx, pcx->pTblDir->pStringtab.offset+offset);
1816 if(length <= 0) return 0;
1817 string = heap_alloc_zero(length +1);
1818 MSFT_Read(string, length, pcx, DO_NOT_SEEK);
1819 string[length]='\0';
1821 lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
1822 string, -1, NULL, 0);
1824 /* no invalid characters in string */
1825 if (lengthInChars)
1827 bstr = SysAllocStringByteLen(NULL, lengthInChars * sizeof(WCHAR));
1829 /* don't check for invalid character since this has been done previously */
1830 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, string, -1, bstr, lengthInChars);
1832 heap_free(string);
1834 TRACE_(typelib)("%s %d\n", debugstr_w(bstr), lengthInChars);
1835 return bstr;
1838 * read a value and fill a VARIANT structure
1840 static void MSFT_ReadValue( VARIANT * pVar, int offset, TLBContext *pcx )
1842 int size;
1844 TRACE_(typelib)("\n");
1846 if(offset <0) { /* data are packed in here */
1847 V_VT(pVar) = (offset & 0x7c000000 )>> 26;
1848 V_I4(pVar) = offset & 0x3ffffff;
1849 return;
1851 MSFT_ReadLEWords(&(V_VT(pVar)), sizeof(VARTYPE), pcx,
1852 pcx->pTblDir->pCustData.offset + offset );
1853 TRACE_(typelib)("Vartype = %x\n", V_VT(pVar));
1854 switch (V_VT(pVar)){
1855 case VT_EMPTY: /* FIXME: is this right? */
1856 case VT_NULL: /* FIXME: is this right? */
1857 case VT_I2 : /* this should not happen */
1858 case VT_I4 :
1859 case VT_R4 :
1860 case VT_ERROR :
1861 case VT_BOOL :
1862 case VT_I1 :
1863 case VT_UI1 :
1864 case VT_UI2 :
1865 case VT_UI4 :
1866 case VT_INT :
1867 case VT_UINT :
1868 case VT_VOID : /* FIXME: is this right? */
1869 case VT_HRESULT :
1870 size=4; break;
1871 case VT_R8 :
1872 case VT_CY :
1873 case VT_DATE :
1874 case VT_I8 :
1875 case VT_UI8 :
1876 case VT_DECIMAL : /* FIXME: is this right? */
1877 case VT_FILETIME :
1878 size=8;break;
1879 /* pointer types with known behaviour */
1880 case VT_BSTR :{
1881 char * ptr;
1882 MSFT_ReadLEDWords(&size, sizeof(INT), pcx, DO_NOT_SEEK );
1883 if(size < 0) {
1884 char next;
1885 DWORD origPos = MSFT_Tell(pcx), nullPos;
1887 do {
1888 MSFT_Read(&next, 1, pcx, DO_NOT_SEEK);
1889 } while (next);
1890 nullPos = MSFT_Tell(pcx);
1891 size = nullPos - origPos;
1892 MSFT_Seek(pcx, origPos);
1894 ptr = heap_alloc_zero(size);/* allocate temp buffer */
1895 MSFT_Read(ptr, size, pcx, DO_NOT_SEEK);/* read string (ANSI) */
1896 V_BSTR(pVar)=SysAllocStringLen(NULL,size);
1897 /* FIXME: do we need a AtoW conversion here? */
1898 V_UNION(pVar, bstrVal[size])='\0';
1899 while(size--) V_UNION(pVar, bstrVal[size])=ptr[size];
1900 heap_free(ptr);
1902 size=-4; break;
1903 /* FIXME: this will not work AT ALL when the variant contains a pointer */
1904 case VT_DISPATCH :
1905 case VT_VARIANT :
1906 case VT_UNKNOWN :
1907 case VT_PTR :
1908 case VT_SAFEARRAY :
1909 case VT_CARRAY :
1910 case VT_USERDEFINED :
1911 case VT_LPSTR :
1912 case VT_LPWSTR :
1913 case VT_BLOB :
1914 case VT_STREAM :
1915 case VT_STORAGE :
1916 case VT_STREAMED_OBJECT :
1917 case VT_STORED_OBJECT :
1918 case VT_BLOB_OBJECT :
1919 case VT_CF :
1920 case VT_CLSID :
1921 default:
1922 size=0;
1923 FIXME("VARTYPE %d is not supported, setting pointer to NULL\n",
1924 V_VT(pVar));
1927 if(size>0) /* (big|small) endian correct? */
1928 MSFT_Read(&(V_I2(pVar)), size, pcx, DO_NOT_SEEK );
1929 return;
1932 * create a linked list with custom data
1934 static int MSFT_CustData( TLBContext *pcx, int offset, struct list *custdata_list)
1936 MSFT_CDGuid entry;
1937 TLBCustData* pNew;
1938 int count=0;
1940 TRACE_(typelib)("\n");
1942 while(offset >=0){
1943 count++;
1944 pNew=heap_alloc_zero(sizeof(TLBCustData));
1945 MSFT_ReadLEDWords(&entry, sizeof(entry), pcx, pcx->pTblDir->pCDGuids.offset+offset);
1946 MSFT_ReadGuid(&(pNew->guid), entry.GuidOffset , pcx);
1947 MSFT_ReadValue(&(pNew->data), entry.DataOffset, pcx);
1948 list_add_head(custdata_list, &pNew->entry);
1949 offset = entry.next;
1951 return count;
1954 static void MSFT_GetTdesc(TLBContext *pcx, INT type, TYPEDESC *pTd,
1955 ITypeInfoImpl *pTI)
1957 if(type <0)
1958 pTd->vt=type & VT_TYPEMASK;
1959 else
1960 *pTd=pcx->pLibInfo->pTypeDesc[type/(2*sizeof(INT))];
1962 if(pTd->vt == VT_USERDEFINED)
1963 MSFT_DoRefType(pcx, pTI->pTypeLib, pTd->u.hreftype);
1965 TRACE_(typelib)("vt type = %X\n", pTd->vt);
1968 static void MSFT_ResolveReferencedTypes(TLBContext *pcx, ITypeInfoImpl *pTI, TYPEDESC *lpTypeDesc)
1970 /* resolve referenced type if any */
1971 while (lpTypeDesc)
1973 switch (lpTypeDesc->vt)
1975 case VT_PTR:
1976 lpTypeDesc = lpTypeDesc->u.lptdesc;
1977 break;
1979 case VT_CARRAY:
1980 lpTypeDesc = & (lpTypeDesc->u.lpadesc->tdescElem);
1981 break;
1983 case VT_USERDEFINED:
1984 MSFT_DoRefType(pcx, pTI->pTypeLib,
1985 lpTypeDesc->u.hreftype);
1987 lpTypeDesc = NULL;
1988 break;
1990 default:
1991 lpTypeDesc = NULL;
1996 static void
1997 MSFT_DoFuncs(TLBContext* pcx,
1998 ITypeInfoImpl* pTI,
1999 int cFuncs,
2000 int cVars,
2001 int offset,
2002 TLBFuncDesc** pptfd)
2005 * member information is stored in a data structure at offset
2006 * indicated by the memoffset field of the typeinfo structure
2007 * There are several distinctive parts.
2008 * The first part starts with a field that holds the total length
2009 * of this (first) part excluding this field. Then follow the records,
2010 * for each member there is one record.
2012 * The first entry is always the length of the record (including this
2013 * length word).
2014 * The rest of the record depends on the type of the member. If there is
2015 * a field indicating the member type (function, variable, interface, etc)
2016 * I have not found it yet. At this time we depend on the information
2017 * in the type info and the usual order how things are stored.
2019 * Second follows an array sized nrMEM*sizeof(INT) with a member id
2020 * for each member;
2022 * Third is an equal sized array with file offsets to the name entry
2023 * of each member.
2025 * The fourth and last (?) part is an array with offsets to the records
2026 * in the first part of this file segment.
2029 int infolen, nameoffset, reclength, i;
2030 int recoffset = offset + sizeof(INT);
2032 char *recbuf = heap_alloc(0xffff);
2033 MSFT_FuncRecord *pFuncRec = (MSFT_FuncRecord*)recbuf;
2034 TLBFuncDesc *ptfd_prev = NULL, *ptfd;
2036 TRACE_(typelib)("\n");
2038 MSFT_ReadLEDWords(&infolen, sizeof(INT), pcx, offset);
2040 *pptfd = TLBFuncDesc_Constructor(cFuncs);
2041 ptfd = *pptfd;
2042 for ( i = 0; i < cFuncs ; i++ )
2044 int optional;
2046 /* name, eventually add to a hash table */
2047 MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx,
2048 offset + infolen + (cFuncs + cVars + i + 1) * sizeof(INT));
2050 /* nameoffset is sometimes -1 on the second half of a propget/propput
2051 * pair of functions */
2052 if ((nameoffset == -1) && (i > 0))
2053 ptfd->Name = SysAllocString(ptfd_prev->Name);
2054 else
2055 ptfd->Name = MSFT_ReadName(pcx, nameoffset);
2057 /* read the function information record */
2058 MSFT_ReadLEDWords(&reclength, sizeof(pFuncRec->Info), pcx, recoffset);
2060 reclength &= 0xffff;
2062 MSFT_ReadLEDWords(&pFuncRec->DataType, reclength - FIELD_OFFSET(MSFT_FuncRecord, DataType), pcx, DO_NOT_SEEK);
2064 /* size without argument data */
2065 optional = reclength - pFuncRec->nrargs*sizeof(MSFT_ParameterInfo);
2067 if (optional > FIELD_OFFSET(MSFT_FuncRecord, HelpContext))
2068 ptfd->helpcontext = pFuncRec->HelpContext;
2070 if (optional > FIELD_OFFSET(MSFT_FuncRecord, oHelpString))
2071 ptfd->HelpString = MSFT_ReadString(pcx, pFuncRec->oHelpString);
2073 if (optional > FIELD_OFFSET(MSFT_FuncRecord, oEntry))
2075 if (pFuncRec->FKCCIC & 0x2000 )
2077 if (!IS_INTRESOURCE(pFuncRec->oEntry))
2078 ERR("ordinal 0x%08x invalid, IS_INTRESOURCE is false\n", pFuncRec->oEntry);
2079 ptfd->Entry = (BSTR)(DWORD_PTR)LOWORD(pFuncRec->oEntry);
2081 else
2082 ptfd->Entry = MSFT_ReadString(pcx, pFuncRec->oEntry);
2084 else
2085 ptfd->Entry = (BSTR)-1;
2087 if (optional > FIELD_OFFSET(MSFT_FuncRecord, HelpStringContext))
2088 ptfd->HelpStringContext = pFuncRec->HelpStringContext;
2090 if (optional > FIELD_OFFSET(MSFT_FuncRecord, oCustData) && pFuncRec->FKCCIC & 0x80)
2091 MSFT_CustData(pcx, pFuncRec->oCustData, &ptfd->custdata_list);
2093 /* fill the FuncDesc Structure */
2094 MSFT_ReadLEDWords( & ptfd->funcdesc.memid, sizeof(INT), pcx,
2095 offset + infolen + ( i + 1) * sizeof(INT));
2097 ptfd->funcdesc.funckind = (pFuncRec->FKCCIC) & 0x7;
2098 ptfd->funcdesc.invkind = (pFuncRec->FKCCIC) >> 3 & 0xF;
2099 ptfd->funcdesc.callconv = (pFuncRec->FKCCIC) >> 8 & 0xF;
2100 ptfd->funcdesc.cParams = pFuncRec->nrargs ;
2101 ptfd->funcdesc.cParamsOpt = pFuncRec->nroargs ;
2102 ptfd->funcdesc.oVft = pFuncRec->VtableOffset & ~1;
2103 ptfd->funcdesc.wFuncFlags = LOWORD(pFuncRec->Flags) ;
2105 MSFT_GetTdesc(pcx,
2106 pFuncRec->DataType,
2107 &ptfd->funcdesc.elemdescFunc.tdesc,
2108 pTI);
2109 MSFT_ResolveReferencedTypes(pcx, pTI, &ptfd->funcdesc.elemdescFunc.tdesc);
2111 /* do the parameters/arguments */
2112 if(pFuncRec->nrargs)
2114 int j = 0;
2115 MSFT_ParameterInfo paraminfo;
2117 ptfd->funcdesc.lprgelemdescParam =
2118 heap_alloc_zero(pFuncRec->nrargs * sizeof(ELEMDESC));
2120 ptfd->pParamDesc = TLBParDesc_Constructor(pFuncRec->nrargs);
2122 MSFT_ReadLEDWords(&paraminfo, sizeof(paraminfo), pcx,
2123 recoffset + reclength - pFuncRec->nrargs * sizeof(MSFT_ParameterInfo));
2125 for ( j = 0 ; j < pFuncRec->nrargs ; j++ )
2127 ELEMDESC *elemdesc = &ptfd->funcdesc.lprgelemdescParam[j];
2129 MSFT_GetTdesc(pcx,
2130 paraminfo.DataType,
2131 &elemdesc->tdesc,
2132 pTI);
2134 elemdesc->u.paramdesc.wParamFlags = paraminfo.Flags;
2136 /* name */
2137 if (paraminfo.oName == -1)
2138 /* this occurs for [propput] or [propget] methods, so
2139 * we should just set the name of the parameter to the
2140 * name of the method. */
2141 ptfd->pParamDesc[j].Name = SysAllocString(ptfd->Name);
2142 else
2143 ptfd->pParamDesc[j].Name =
2144 MSFT_ReadName( pcx, paraminfo.oName );
2145 TRACE_(typelib)("param[%d] = %s\n", j, debugstr_w(ptfd->pParamDesc[j].Name));
2147 MSFT_ResolveReferencedTypes(pcx, pTI, &elemdesc->tdesc);
2149 /* default value */
2150 if ( (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) &&
2151 (pFuncRec->FKCCIC & 0x1000) )
2153 INT* pInt = (INT *)((char *)pFuncRec +
2154 reclength -
2155 (pFuncRec->nrargs * 4) * sizeof(INT) );
2157 PARAMDESC* pParamDesc = &elemdesc->u.paramdesc;
2159 pParamDesc->pparamdescex = heap_alloc_zero(sizeof(PARAMDESCEX));
2160 pParamDesc->pparamdescex->cBytes = sizeof(PARAMDESCEX);
2162 MSFT_ReadValue(&(pParamDesc->pparamdescex->varDefaultValue),
2163 pInt[j], pcx);
2165 else
2166 elemdesc->u.paramdesc.pparamdescex = NULL;
2168 /* custom info */
2169 if (optional > (FIELD_OFFSET(MSFT_FuncRecord, oArgCustData) +
2170 j*sizeof(pFuncRec->oArgCustData[0])) &&
2171 pFuncRec->FKCCIC & 0x80 )
2173 MSFT_CustData(pcx,
2174 pFuncRec->oArgCustData[j],
2175 &ptfd->pParamDesc[j].custdata_list);
2178 /* SEEK value = jump to offset,
2179 * from there jump to the end of record,
2180 * go back by (j-1) arguments
2182 MSFT_ReadLEDWords( &paraminfo ,
2183 sizeof(MSFT_ParameterInfo), pcx,
2184 recoffset + reclength - ((pFuncRec->nrargs - j - 1)
2185 * sizeof(MSFT_ParameterInfo)));
2189 /* scode is not used: archaic win16 stuff FIXME: right? */
2190 ptfd->funcdesc.cScodes = 0 ;
2191 ptfd->funcdesc.lprgscode = NULL ;
2193 ptfd_prev = ptfd;
2194 ++ptfd;
2195 recoffset += reclength;
2197 heap_free(recbuf);
2200 static void MSFT_DoVars(TLBContext *pcx, ITypeInfoImpl *pTI, int cFuncs,
2201 int cVars, int offset, TLBVarDesc ** pptvd)
2203 int infolen, nameoffset, reclength;
2204 char recbuf[256];
2205 MSFT_VarRecord *pVarRec = (MSFT_VarRecord*)recbuf;
2206 TLBVarDesc *ptvd;
2207 int i;
2208 int recoffset;
2210 TRACE_(typelib)("\n");
2212 ptvd = *pptvd = TLBVarDesc_Constructor(cVars);
2213 MSFT_ReadLEDWords(&infolen,sizeof(INT), pcx, offset);
2214 MSFT_ReadLEDWords(&recoffset,sizeof(INT), pcx, offset + infolen +
2215 ((cFuncs+cVars)*2+cFuncs + 1)*sizeof(INT));
2216 recoffset += offset+sizeof(INT);
2217 for(i=0;i<cVars;i++, ++ptvd){
2218 /* name, eventually add to a hash table */
2219 MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx,
2220 offset + infolen + (2*cFuncs + cVars + i + 1) * sizeof(INT));
2221 ptvd->Name=MSFT_ReadName(pcx, nameoffset);
2222 /* read the variable information record */
2223 MSFT_ReadLEDWords(&reclength, sizeof(pVarRec->Info), pcx, recoffset);
2224 reclength &= 0xff;
2225 MSFT_ReadLEDWords(&pVarRec->DataType, reclength - FIELD_OFFSET(MSFT_VarRecord, DataType), pcx, DO_NOT_SEEK);
2227 /* optional data */
2228 if(reclength > FIELD_OFFSET(MSFT_VarRecord, HelpContext))
2229 ptvd->HelpContext = pVarRec->HelpContext;
2231 if(reclength > FIELD_OFFSET(MSFT_VarRecord, HelpString))
2232 ptvd->HelpString = MSFT_ReadString(pcx, pVarRec->HelpString);
2234 if(reclength > FIELD_OFFSET(MSFT_VarRecord, HelpStringContext))
2235 ptvd->HelpStringContext = pVarRec->HelpStringContext;
2237 /* fill the VarDesc Structure */
2238 MSFT_ReadLEDWords(&ptvd->vardesc.memid, sizeof(INT), pcx,
2239 offset + infolen + (cFuncs + i + 1) * sizeof(INT));
2240 ptvd->vardesc.varkind = pVarRec->VarKind;
2241 ptvd->vardesc.wVarFlags = pVarRec->Flags;
2242 MSFT_GetTdesc(pcx, pVarRec->DataType,
2243 &ptvd->vardesc.elemdescVar.tdesc, pTI);
2244 /* ptvd->vardesc.lpstrSchema; is reserved (SDK) FIXME?? */
2245 if(pVarRec->VarKind == VAR_CONST ){
2246 ptvd->vardesc.u.lpvarValue = heap_alloc_zero(sizeof(VARIANT));
2247 MSFT_ReadValue(ptvd->vardesc.u.lpvarValue,
2248 pVarRec->OffsValue, pcx);
2249 } else
2250 ptvd->vardesc.u.oInst=pVarRec->OffsValue;
2251 MSFT_ResolveReferencedTypes(pcx, pTI, &ptvd->vardesc.elemdescVar.tdesc);
2252 recoffset += reclength;
2256 /* fill in data for a hreftype (offset). When the referenced type is contained
2257 * in the typelib, it's just an (file) offset in the type info base dir.
2258 * If comes from import, it's an offset+1 in the ImpInfo table
2259 * */
2260 static void MSFT_DoRefType(TLBContext *pcx, ITypeLibImpl *pTL,
2261 int offset)
2263 TLBRefType *ref;
2265 TRACE_(typelib)("TLB context %p, TLB offset %x\n", pcx, offset);
2267 LIST_FOR_EACH_ENTRY(ref, &pTL->ref_list, TLBRefType, entry)
2269 if(ref->reference == offset) return;
2272 ref = heap_alloc_zero(sizeof(TLBRefType));
2273 list_add_tail(&pTL->ref_list, &ref->entry);
2275 if(!MSFT_HREFTYPE_INTHISFILE( offset)) {
2276 /* external typelib */
2277 MSFT_ImpInfo impinfo;
2278 TLBImpLib *pImpLib;
2280 TRACE_(typelib)("offset %x, masked offset %x\n", offset, offset + (offset & 0xfffffffc));
2282 MSFT_ReadLEDWords(&impinfo, sizeof(impinfo), pcx,
2283 pcx->pTblDir->pImpInfo.offset + (offset & 0xfffffffc));
2285 LIST_FOR_EACH_ENTRY(pImpLib, &pcx->pLibInfo->implib_list, TLBImpLib, entry)
2286 if(pImpLib->offset==impinfo.oImpFile)
2287 break;
2289 if(&pImpLib->entry != &pcx->pLibInfo->implib_list){
2290 ref->reference = offset;
2291 ref->pImpTLInfo = pImpLib;
2292 if(impinfo.flags & MSFT_IMPINFO_OFFSET_IS_GUID) {
2293 MSFT_ReadGuid(&ref->guid, impinfo.oGuid, pcx);
2294 TRACE("importing by guid %s\n", debugstr_guid(&ref->guid));
2295 ref->index = TLB_REF_USE_GUID;
2296 } else
2297 ref->index = impinfo.oGuid;
2298 }else{
2299 ERR("Cannot find a reference\n");
2300 ref->reference = -1;
2301 ref->pImpTLInfo = TLB_REF_NOT_FOUND;
2303 }else{
2304 /* in this typelib */
2305 ref->index = MSFT_HREFTYPE_INDEX(offset);
2306 ref->reference = offset;
2307 ref->pImpTLInfo = TLB_REF_INTERNAL;
2311 /* process Implemented Interfaces of a com class */
2312 static void MSFT_DoImplTypes(TLBContext *pcx, ITypeInfoImpl *pTI, int count,
2313 int offset)
2315 int i;
2316 MSFT_RefRecord refrec;
2317 TLBImplType *pImpl;
2319 TRACE_(typelib)("\n");
2321 pTI->impltypes = TLBImplType_Constructor(count);
2322 pImpl = pTI->impltypes;
2323 for(i=0;i<count;i++){
2324 if(offset<0) break; /* paranoia */
2325 MSFT_ReadLEDWords(&refrec,sizeof(refrec),pcx,offset+pcx->pTblDir->pRefTab.offset);
2326 MSFT_DoRefType(pcx, pTI->pTypeLib, refrec.reftype);
2327 pImpl->hRef = refrec.reftype;
2328 pImpl->implflags=refrec.flags;
2329 MSFT_CustData(pcx, refrec.oCustData, &pImpl->custdata_list);
2330 offset=refrec.onext;
2331 ++pImpl;
2335 * process a typeinfo record
2337 static ITypeInfoImpl * MSFT_DoTypeInfo(
2338 TLBContext *pcx,
2339 int count,
2340 ITypeLibImpl * pLibInfo)
2342 MSFT_TypeInfoBase tiBase;
2343 ITypeInfoImpl *ptiRet;
2345 TRACE_(typelib)("count=%u\n", count);
2347 ptiRet = ITypeInfoImpl_Constructor();
2348 MSFT_ReadLEDWords(&tiBase, sizeof(tiBase) ,pcx ,
2349 pcx->pTblDir->pTypeInfoTab.offset+count*sizeof(tiBase));
2351 /* this is where we are coming from */
2352 ptiRet->pTypeLib = pLibInfo;
2353 ptiRet->index=count;
2354 /* fill in the typeattr fields */
2356 MSFT_ReadGuid(&ptiRet->TypeAttr.guid, tiBase.posguid, pcx);
2357 ptiRet->TypeAttr.lcid=pLibInfo->LibAttr.lcid; /* FIXME: correct? */
2358 ptiRet->TypeAttr.lpstrSchema=NULL; /* reserved */
2359 ptiRet->TypeAttr.cbSizeInstance=tiBase.size;
2360 ptiRet->TypeAttr.typekind=tiBase.typekind & 0xF;
2361 ptiRet->TypeAttr.cFuncs=LOWORD(tiBase.cElement);
2362 ptiRet->TypeAttr.cVars=HIWORD(tiBase.cElement);
2363 ptiRet->TypeAttr.cbAlignment=(tiBase.typekind >> 11 )& 0x1F; /* there are more flags there */
2364 ptiRet->TypeAttr.wTypeFlags=tiBase.flags;
2365 ptiRet->TypeAttr.wMajorVerNum=LOWORD(tiBase.version);
2366 ptiRet->TypeAttr.wMinorVerNum=HIWORD(tiBase.version);
2367 ptiRet->TypeAttr.cImplTypes=tiBase.cImplTypes;
2368 ptiRet->TypeAttr.cbSizeVft=tiBase.cbSizeVft; /* FIXME: this is only the non inherited part */
2369 if(ptiRet->TypeAttr.typekind == TKIND_ALIAS)
2370 MSFT_GetTdesc(pcx, tiBase.datatype1,
2371 &ptiRet->TypeAttr.tdescAlias, ptiRet);
2373 /* FIXME: */
2374 /* IDLDESC idldescType; *//* never saw this one != zero */
2376 /* name, eventually add to a hash table */
2377 ptiRet->Name=MSFT_ReadName(pcx, tiBase.NameOffset);
2378 ptiRet->hreftype = MSFT_ReadHreftype(pcx, tiBase.NameOffset);
2379 TRACE_(typelib)("reading %s\n", debugstr_w(ptiRet->Name));
2380 /* help info */
2381 ptiRet->DocString=MSFT_ReadString(pcx, tiBase.docstringoffs);
2382 ptiRet->dwHelpStringContext=tiBase.helpstringcontext;
2383 ptiRet->dwHelpContext=tiBase.helpcontext;
2385 if (ptiRet->TypeAttr.typekind == TKIND_MODULE)
2386 ptiRet->DllName = MSFT_ReadString(pcx, tiBase.datatype1);
2388 /* note: InfoType's Help file and HelpStringDll come from the containing
2389 * library. Further HelpString and Docstring appear to be the same thing :(
2391 /* functions */
2392 if(ptiRet->TypeAttr.cFuncs >0 )
2393 MSFT_DoFuncs(pcx, ptiRet, ptiRet->TypeAttr.cFuncs,
2394 ptiRet->TypeAttr.cVars,
2395 tiBase.memoffset, &ptiRet->funcdescs);
2396 /* variables */
2397 if(ptiRet->TypeAttr.cVars >0 )
2398 MSFT_DoVars(pcx, ptiRet, ptiRet->TypeAttr.cFuncs,
2399 ptiRet->TypeAttr.cVars,
2400 tiBase.memoffset, &ptiRet->vardescs);
2401 if(ptiRet->TypeAttr.cImplTypes >0 ) {
2402 switch(ptiRet->TypeAttr.typekind)
2404 case TKIND_COCLASS:
2405 MSFT_DoImplTypes(pcx, ptiRet, ptiRet->TypeAttr.cImplTypes ,
2406 tiBase.datatype1);
2407 break;
2408 case TKIND_DISPATCH:
2409 /* This is not -1 when the interface is a non-base dual interface or
2410 when a dispinterface wraps an interface, i.e., the idl 'dispinterface x {interface y;};'.
2411 Note however that GetRefTypeOfImplType(0) always returns a ref to IDispatch and
2412 not this interface.
2415 if (tiBase.datatype1 != -1)
2417 ptiRet->impltypes = TLBImplType_Constructor(1);
2418 ptiRet->impltypes[0].hRef = tiBase.datatype1;
2419 MSFT_DoRefType(pcx, pLibInfo, tiBase.datatype1);
2421 break;
2422 default:
2423 ptiRet->impltypes = TLBImplType_Constructor(1);
2424 MSFT_DoRefType(pcx, pLibInfo, tiBase.datatype1);
2425 ptiRet->impltypes[0].hRef = tiBase.datatype1;
2426 break;
2429 MSFT_CustData(pcx, tiBase.oCustData, &ptiRet->custdata_list);
2431 TRACE_(typelib)("%s guid: %s kind:%s\n",
2432 debugstr_w(ptiRet->Name),
2433 debugstr_guid(&ptiRet->TypeAttr.guid),
2434 typekind_desc[ptiRet->TypeAttr.typekind]);
2435 if (TRACE_ON(typelib))
2436 dump_TypeInfo(ptiRet);
2438 return ptiRet;
2441 /* Because type library parsing has some degree of overhead, and some apps repeatedly load the same
2442 * typelibs over and over, we cache them here. According to MSDN Microsoft have a similar scheme in
2443 * place. This will cause a deliberate memory leak, but generally losing RAM for cycles is an acceptable
2444 * tradeoff here.
2446 static struct list tlb_cache = LIST_INIT(tlb_cache);
2447 static CRITICAL_SECTION cache_section;
2448 static CRITICAL_SECTION_DEBUG cache_section_debug =
2450 0, 0, &cache_section,
2451 { &cache_section_debug.ProcessLocksList, &cache_section_debug.ProcessLocksList },
2452 0, 0, { (DWORD_PTR)(__FILE__ ": typelib loader cache") }
2454 static CRITICAL_SECTION cache_section = { &cache_section_debug, -1, 0, 0, 0, 0 };
2457 typedef struct TLB_PEFile
2459 const IUnknownVtbl *lpvtbl;
2460 LONG refs;
2461 HMODULE dll;
2462 HRSRC typelib_resource;
2463 HGLOBAL typelib_global;
2464 LPVOID typelib_base;
2465 } TLB_PEFile;
2467 static HRESULT WINAPI TLB_PEFile_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2469 if (IsEqualIID(riid, &IID_IUnknown))
2471 *ppv = iface;
2472 IUnknown_AddRef(iface);
2473 return S_OK;
2475 *ppv = NULL;
2476 return E_NOINTERFACE;
2479 static ULONG WINAPI TLB_PEFile_AddRef(IUnknown *iface)
2481 TLB_PEFile *This = (TLB_PEFile *)iface;
2482 return InterlockedIncrement(&This->refs);
2485 static ULONG WINAPI TLB_PEFile_Release(IUnknown *iface)
2487 TLB_PEFile *This = (TLB_PEFile *)iface;
2488 ULONG refs = InterlockedDecrement(&This->refs);
2489 if (!refs)
2491 if (This->typelib_global)
2492 FreeResource(This->typelib_global);
2493 if (This->dll)
2494 FreeLibrary(This->dll);
2495 heap_free(This);
2497 return refs;
2500 static const IUnknownVtbl TLB_PEFile_Vtable =
2502 TLB_PEFile_QueryInterface,
2503 TLB_PEFile_AddRef,
2504 TLB_PEFile_Release
2507 static HRESULT TLB_PEFile_Open(LPCWSTR path, INT index, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile)
2509 TLB_PEFile *This;
2511 This = heap_alloc(sizeof(TLB_PEFile));
2512 if (!This)
2513 return E_OUTOFMEMORY;
2515 This->lpvtbl = &TLB_PEFile_Vtable;
2516 This->refs = 1;
2517 This->dll = NULL;
2518 This->typelib_resource = NULL;
2519 This->typelib_global = NULL;
2520 This->typelib_base = NULL;
2522 This->dll = LoadLibraryExW(path, 0, DONT_RESOLVE_DLL_REFERENCES |
2523 LOAD_LIBRARY_AS_DATAFILE | LOAD_WITH_ALTERED_SEARCH_PATH);
2525 if (This->dll)
2527 static const WCHAR TYPELIBW[] = {'T','Y','P','E','L','I','B',0};
2528 This->typelib_resource = FindResourceW(This->dll, MAKEINTRESOURCEW(index), TYPELIBW);
2529 if (This->typelib_resource)
2531 This->typelib_global = LoadResource(This->dll, This->typelib_resource);
2532 if (This->typelib_global)
2534 This->typelib_base = LockResource(This->typelib_global);
2536 if (This->typelib_base)
2538 *pdwTLBLength = SizeofResource(This->dll, This->typelib_resource);
2539 *ppBase = This->typelib_base;
2540 *ppFile = (IUnknown *)&This->lpvtbl;
2541 return S_OK;
2547 TLB_PEFile_Release((IUnknown *)&This->lpvtbl);
2548 return TYPE_E_CANTLOADLIBRARY;
2551 typedef struct TLB_NEFile
2553 const IUnknownVtbl *lpvtbl;
2554 LONG refs;
2555 LPVOID typelib_base;
2556 } TLB_NEFile;
2558 static HRESULT WINAPI TLB_NEFile_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2560 if (IsEqualIID(riid, &IID_IUnknown))
2562 *ppv = iface;
2563 IUnknown_AddRef(iface);
2564 return S_OK;
2566 *ppv = NULL;
2567 return E_NOINTERFACE;
2570 static ULONG WINAPI TLB_NEFile_AddRef(IUnknown *iface)
2572 TLB_NEFile *This = (TLB_NEFile *)iface;
2573 return InterlockedIncrement(&This->refs);
2576 static ULONG WINAPI TLB_NEFile_Release(IUnknown *iface)
2578 TLB_NEFile *This = (TLB_NEFile *)iface;
2579 ULONG refs = InterlockedDecrement(&This->refs);
2580 if (!refs)
2582 heap_free(This->typelib_base);
2583 heap_free(This);
2585 return refs;
2588 static const IUnknownVtbl TLB_NEFile_Vtable =
2590 TLB_NEFile_QueryInterface,
2591 TLB_NEFile_AddRef,
2592 TLB_NEFile_Release
2595 /***********************************************************************
2596 * read_xx_header [internal]
2598 static int read_xx_header( HFILE lzfd )
2600 IMAGE_DOS_HEADER mzh;
2601 char magic[3];
2603 LZSeek( lzfd, 0, SEEK_SET );
2604 if ( sizeof(mzh) != LZRead( lzfd, (LPSTR)&mzh, sizeof(mzh) ) )
2605 return 0;
2606 if ( mzh.e_magic != IMAGE_DOS_SIGNATURE )
2607 return 0;
2609 LZSeek( lzfd, mzh.e_lfanew, SEEK_SET );
2610 if ( 2 != LZRead( lzfd, magic, 2 ) )
2611 return 0;
2613 LZSeek( lzfd, mzh.e_lfanew, SEEK_SET );
2615 if ( magic[0] == 'N' && magic[1] == 'E' )
2616 return IMAGE_OS2_SIGNATURE;
2617 if ( magic[0] == 'P' && magic[1] == 'E' )
2618 return IMAGE_NT_SIGNATURE;
2620 magic[2] = '\0';
2621 WARN("Can't handle %s files.\n", magic );
2622 return 0;
2626 /***********************************************************************
2627 * find_ne_resource [internal]
2629 static BOOL find_ne_resource( HFILE lzfd, LPCSTR typeid, LPCSTR resid,
2630 DWORD *resLen, DWORD *resOff )
2632 IMAGE_OS2_HEADER nehd;
2633 NE_TYPEINFO *typeInfo;
2634 NE_NAMEINFO *nameInfo;
2635 DWORD nehdoffset;
2636 LPBYTE resTab;
2637 DWORD resTabSize;
2638 int count;
2640 /* Read in NE header */
2641 nehdoffset = LZSeek( lzfd, 0, SEEK_CUR );
2642 if ( sizeof(nehd) != LZRead( lzfd, (LPSTR)&nehd, sizeof(nehd) ) ) return 0;
2644 resTabSize = nehd.ne_restab - nehd.ne_rsrctab;
2645 if ( !resTabSize )
2647 TRACE("No resources in NE dll\n" );
2648 return FALSE;
2651 /* Read in resource table */
2652 resTab = heap_alloc( resTabSize );
2653 if ( !resTab ) return FALSE;
2655 LZSeek( lzfd, nehd.ne_rsrctab + nehdoffset, SEEK_SET );
2656 if ( resTabSize != LZRead( lzfd, (char*)resTab, resTabSize ) )
2658 heap_free( resTab );
2659 return FALSE;
2662 /* Find resource */
2663 typeInfo = (NE_TYPEINFO *)(resTab + 2);
2665 if (!IS_INTRESOURCE(typeid)) /* named type */
2667 BYTE len = strlen( typeid );
2668 while (typeInfo->type_id)
2670 if (!(typeInfo->type_id & 0x8000))
2672 BYTE *p = resTab + typeInfo->type_id;
2673 if ((*p == len) && !strncasecmp( (char*)p+1, typeid, len )) goto found_type;
2675 typeInfo = (NE_TYPEINFO *)((char *)(typeInfo + 1) +
2676 typeInfo->count * sizeof(NE_NAMEINFO));
2679 else /* numeric type id */
2681 WORD id = LOWORD(typeid) | 0x8000;
2682 while (typeInfo->type_id)
2684 if (typeInfo->type_id == id) goto found_type;
2685 typeInfo = (NE_TYPEINFO *)((char *)(typeInfo + 1) +
2686 typeInfo->count * sizeof(NE_NAMEINFO));
2689 TRACE("No typeid entry found for %p\n", typeid );
2690 heap_free( resTab );
2691 return FALSE;
2693 found_type:
2694 nameInfo = (NE_NAMEINFO *)(typeInfo + 1);
2696 if (!IS_INTRESOURCE(resid)) /* named resource */
2698 BYTE len = strlen( resid );
2699 for (count = typeInfo->count; count > 0; count--, nameInfo++)
2701 BYTE *p = resTab + nameInfo->id;
2702 if (nameInfo->id & 0x8000) continue;
2703 if ((*p == len) && !strncasecmp( (char*)p+1, resid, len )) goto found_name;
2706 else /* numeric resource id */
2708 WORD id = LOWORD(resid) | 0x8000;
2709 for (count = typeInfo->count; count > 0; count--, nameInfo++)
2710 if (nameInfo->id == id) goto found_name;
2712 TRACE("No resid entry found for %p\n", typeid );
2713 heap_free( resTab );
2714 return FALSE;
2716 found_name:
2717 /* Return resource data */
2718 if ( resLen ) *resLen = nameInfo->length << *(WORD *)resTab;
2719 if ( resOff ) *resOff = nameInfo->offset << *(WORD *)resTab;
2721 heap_free( resTab );
2722 return TRUE;
2725 static HRESULT TLB_NEFile_Open(LPCWSTR path, INT index, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile){
2727 HFILE lzfd = -1;
2728 OFSTRUCT ofs;
2729 HRESULT hr = TYPE_E_CANTLOADLIBRARY;
2730 TLB_NEFile *This;
2732 This = heap_alloc(sizeof(TLB_NEFile));
2733 if (!This) return E_OUTOFMEMORY;
2735 This->lpvtbl = &TLB_NEFile_Vtable;
2736 This->refs = 1;
2737 This->typelib_base = NULL;
2739 lzfd = LZOpenFileW( (LPWSTR)path, &ofs, OF_READ );
2740 if ( lzfd >= 0 && read_xx_header( lzfd ) == IMAGE_OS2_SIGNATURE )
2742 DWORD reslen, offset;
2743 if( find_ne_resource( lzfd, "TYPELIB", MAKEINTRESOURCEA(index), &reslen, &offset ) )
2745 This->typelib_base = heap_alloc(reslen);
2746 if( !This->typelib_base )
2747 hr = E_OUTOFMEMORY;
2748 else
2750 LZSeek( lzfd, offset, SEEK_SET );
2751 reslen = LZRead( lzfd, This->typelib_base, reslen );
2752 LZClose( lzfd );
2753 *ppBase = This->typelib_base;
2754 *pdwTLBLength = reslen;
2755 *ppFile = (IUnknown *)&This->lpvtbl;
2756 return S_OK;
2761 if( lzfd >= 0) LZClose( lzfd );
2762 TLB_NEFile_Release((IUnknown *)&This->lpvtbl);
2763 return hr;
2766 typedef struct TLB_Mapping
2768 const IUnknownVtbl *lpvtbl;
2769 LONG refs;
2770 HANDLE file;
2771 HANDLE mapping;
2772 LPVOID typelib_base;
2773 } TLB_Mapping;
2775 static HRESULT WINAPI TLB_Mapping_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2777 if (IsEqualIID(riid, &IID_IUnknown))
2779 *ppv = iface;
2780 IUnknown_AddRef(iface);
2781 return S_OK;
2783 *ppv = NULL;
2784 return E_NOINTERFACE;
2787 static ULONG WINAPI TLB_Mapping_AddRef(IUnknown *iface)
2789 TLB_Mapping *This = (TLB_Mapping *)iface;
2790 return InterlockedIncrement(&This->refs);
2793 static ULONG WINAPI TLB_Mapping_Release(IUnknown *iface)
2795 TLB_Mapping *This = (TLB_Mapping *)iface;
2796 ULONG refs = InterlockedDecrement(&This->refs);
2797 if (!refs)
2799 if (This->typelib_base)
2800 UnmapViewOfFile(This->typelib_base);
2801 if (This->mapping)
2802 CloseHandle(This->mapping);
2803 if (This->file != INVALID_HANDLE_VALUE)
2804 CloseHandle(This->file);
2805 heap_free(This);
2807 return refs;
2810 static const IUnknownVtbl TLB_Mapping_Vtable =
2812 TLB_Mapping_QueryInterface,
2813 TLB_Mapping_AddRef,
2814 TLB_Mapping_Release
2817 static HRESULT TLB_Mapping_Open(LPCWSTR path, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile)
2819 TLB_Mapping *This;
2821 This = heap_alloc(sizeof(TLB_Mapping));
2822 if (!This)
2823 return E_OUTOFMEMORY;
2825 This->lpvtbl = &TLB_Mapping_Vtable;
2826 This->refs = 1;
2827 This->file = INVALID_HANDLE_VALUE;
2828 This->mapping = NULL;
2829 This->typelib_base = NULL;
2831 This->file = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
2832 if (INVALID_HANDLE_VALUE != This->file)
2834 This->mapping = CreateFileMappingW(This->file, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL);
2835 if (This->mapping)
2837 This->typelib_base = MapViewOfFile(This->mapping, FILE_MAP_READ, 0, 0, 0);
2838 if(This->typelib_base)
2840 /* retrieve file size */
2841 *pdwTLBLength = GetFileSize(This->file, NULL);
2842 *ppBase = This->typelib_base;
2843 *ppFile = (IUnknown *)&This->lpvtbl;
2844 return S_OK;
2849 IUnknown_Release((IUnknown *)&This->lpvtbl);
2850 return TYPE_E_CANTLOADLIBRARY;
2853 /****************************************************************************
2854 * TLB_ReadTypeLib
2856 * find the type of the typelib file and map the typelib resource into
2857 * the memory
2860 #define SLTG_SIGNATURE 0x47544c53 /* "SLTG" */
2861 static HRESULT TLB_ReadTypeLib(LPCWSTR pszFileName, LPWSTR pszPath, UINT cchPath, ITypeLib2 **ppTypeLib)
2863 ITypeLibImpl *entry;
2864 HRESULT ret;
2865 INT index = 1;
2866 LPWSTR index_str, file = (LPWSTR)pszFileName;
2867 LPVOID pBase = NULL;
2868 DWORD dwTLBLength = 0;
2869 IUnknown *pFile = NULL;
2871 *ppTypeLib = NULL;
2873 index_str = strrchrW(pszFileName, '\\');
2874 if(index_str && *++index_str != '\0')
2876 LPWSTR end_ptr;
2877 LONG idx = strtolW(index_str, &end_ptr, 10);
2878 if(*end_ptr == '\0')
2880 int str_len = index_str - pszFileName - 1;
2881 index = idx;
2882 file = heap_alloc((str_len + 1) * sizeof(WCHAR));
2883 memcpy(file, pszFileName, str_len * sizeof(WCHAR));
2884 file[str_len] = 0;
2888 if(!SearchPathW(NULL, file, NULL, cchPath, pszPath, NULL))
2890 if(strchrW(file, '\\'))
2892 lstrcpyW(pszPath, file);
2894 else
2896 int len = GetSystemDirectoryW(pszPath, cchPath);
2897 pszPath[len] = '\\';
2898 memcpy(pszPath + len + 1, file, (strlenW(file) + 1) * sizeof(WCHAR));
2902 if(file != pszFileName) heap_free(file);
2904 TRACE_(typelib)("File %s index %d\n", debugstr_w(pszPath), index);
2906 /* We look the path up in the typelib cache. If found, we just addref it, and return the pointer. */
2907 EnterCriticalSection(&cache_section);
2908 LIST_FOR_EACH_ENTRY(entry, &tlb_cache, ITypeLibImpl, entry)
2910 if (!strcmpiW(entry->path, pszPath) && entry->index == index)
2912 TRACE("cache hit\n");
2913 *ppTypeLib = (ITypeLib2*)entry;
2914 ITypeLib_AddRef(*ppTypeLib);
2915 LeaveCriticalSection(&cache_section);
2916 return S_OK;
2919 LeaveCriticalSection(&cache_section);
2921 /* now actually load and parse the typelib */
2923 ret = TLB_PEFile_Open(pszPath, index, &pBase, &dwTLBLength, &pFile);
2924 if (ret == TYPE_E_CANTLOADLIBRARY)
2925 ret = TLB_NEFile_Open(pszPath, index, &pBase, &dwTLBLength, &pFile);
2926 if (ret == TYPE_E_CANTLOADLIBRARY)
2927 ret = TLB_Mapping_Open(pszPath, &pBase, &dwTLBLength, &pFile);
2928 if (SUCCEEDED(ret))
2930 if (dwTLBLength >= 4)
2932 DWORD dwSignature = FromLEDWord(*((DWORD*) pBase));
2933 if (dwSignature == MSFT_SIGNATURE)
2934 *ppTypeLib = ITypeLib2_Constructor_MSFT(pBase, dwTLBLength);
2935 else if (dwSignature == SLTG_SIGNATURE)
2936 *ppTypeLib = ITypeLib2_Constructor_SLTG(pBase, dwTLBLength);
2937 else
2939 FIXME("Header type magic 0x%08x not supported.\n",dwSignature);
2940 ret = TYPE_E_CANTLOADLIBRARY;
2943 else
2944 ret = TYPE_E_CANTLOADLIBRARY;
2945 IUnknown_Release(pFile);
2948 if(*ppTypeLib) {
2949 ITypeLibImpl *impl = (ITypeLibImpl*)*ppTypeLib;
2951 TRACE("adding to cache\n");
2952 impl->path = heap_alloc((strlenW(pszPath)+1) * sizeof(WCHAR));
2953 lstrcpyW(impl->path, pszPath);
2954 /* We should really canonicalise the path here. */
2955 impl->index = index;
2957 /* FIXME: check if it has added already in the meantime */
2958 EnterCriticalSection(&cache_section);
2959 list_add_head(&tlb_cache, &impl->entry);
2960 LeaveCriticalSection(&cache_section);
2961 ret = S_OK;
2962 } else
2963 ERR("Loading of typelib %s failed with error %d\n", debugstr_w(pszFileName), GetLastError());
2965 return ret;
2968 /*================== ITypeLib(2) Methods ===================================*/
2970 static ITypeLibImpl* TypeLibImpl_Constructor(void)
2972 ITypeLibImpl* pTypeLibImpl;
2974 pTypeLibImpl = heap_alloc_zero(sizeof(ITypeLibImpl));
2975 if (!pTypeLibImpl) return NULL;
2977 pTypeLibImpl->lpVtbl = &tlbvt;
2978 pTypeLibImpl->lpVtblTypeComp = &tlbtcvt;
2979 pTypeLibImpl->ref = 1;
2981 list_init(&pTypeLibImpl->implib_list);
2982 list_init(&pTypeLibImpl->custdata_list);
2983 list_init(&pTypeLibImpl->ref_list);
2984 pTypeLibImpl->dispatch_href = -1;
2986 return pTypeLibImpl;
2989 /****************************************************************************
2990 * ITypeLib2_Constructor_MSFT
2992 * loading an MSFT typelib from an in-memory image
2994 static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength)
2996 TLBContext cx;
2997 LONG lPSegDir;
2998 MSFT_Header tlbHeader;
2999 MSFT_SegDir tlbSegDir;
3000 ITypeLibImpl * pTypeLibImpl;
3002 TRACE("%p, TLB length = %d\n", pLib, dwTLBLength);
3004 pTypeLibImpl = TypeLibImpl_Constructor();
3005 if (!pTypeLibImpl) return NULL;
3007 /* get pointer to beginning of typelib data */
3008 cx.pos = 0;
3009 cx.oStart=0;
3010 cx.mapping = pLib;
3011 cx.pLibInfo = pTypeLibImpl;
3012 cx.length = dwTLBLength;
3014 /* read header */
3015 MSFT_ReadLEDWords((void*)&tlbHeader, sizeof(tlbHeader), &cx, 0);
3016 TRACE_(typelib)("header:\n");
3017 TRACE_(typelib)("\tmagic1=0x%08x ,magic2=0x%08x\n",tlbHeader.magic1,tlbHeader.magic2 );
3018 if (tlbHeader.magic1 != MSFT_SIGNATURE) {
3019 FIXME("Header type magic 0x%08x not supported.\n",tlbHeader.magic1);
3020 return NULL;
3022 TRACE_(typelib)("\tdispatchpos = 0x%x\n", tlbHeader.dispatchpos);
3024 /* there is a small amount of information here until the next important
3025 * part:
3026 * the segment directory . Try to calculate the amount of data */
3027 lPSegDir = sizeof(tlbHeader) + (tlbHeader.nrtypeinfos)*4 + ((tlbHeader.varflags & HELPDLLFLAG)? 4 :0);
3029 /* now read the segment directory */
3030 TRACE("read segment directory (at %d)\n",lPSegDir);
3031 MSFT_ReadLEDWords(&tlbSegDir, sizeof(tlbSegDir), &cx, lPSegDir);
3032 cx.pTblDir = &tlbSegDir;
3034 /* just check two entries */
3035 if ( tlbSegDir.pTypeInfoTab.res0c != 0x0F || tlbSegDir.pImpInfo.res0c != 0x0F)
3037 ERR("cannot find the table directory, ptr=0x%x\n",lPSegDir);
3038 heap_free(pTypeLibImpl);
3039 return NULL;
3042 /* now fill our internal data */
3043 /* TLIBATTR fields */
3044 MSFT_ReadGuid(&pTypeLibImpl->LibAttr.guid, tlbHeader.posguid, &cx);
3046 pTypeLibImpl->LibAttr.lcid = tlbHeader.lcid2;
3047 pTypeLibImpl->LibAttr.syskind = tlbHeader.varflags & 0x0f; /* check the mask */
3048 pTypeLibImpl->LibAttr.wMajorVerNum = LOWORD(tlbHeader.version);
3049 pTypeLibImpl->LibAttr.wMinorVerNum = HIWORD(tlbHeader.version);
3050 pTypeLibImpl->LibAttr.wLibFlags = (WORD) tlbHeader.flags & 0xffff;/* check mask */
3052 pTypeLibImpl->lcid = tlbHeader.lcid;
3054 /* name, eventually add to a hash table */
3055 pTypeLibImpl->Name = MSFT_ReadName(&cx, tlbHeader.NameOffset);
3057 /* help info */
3058 pTypeLibImpl->DocString = MSFT_ReadString(&cx, tlbHeader.helpstring);
3059 pTypeLibImpl->HelpFile = MSFT_ReadString(&cx, tlbHeader.helpfile);
3061 if( tlbHeader.varflags & HELPDLLFLAG)
3063 int offset;
3064 MSFT_ReadLEDWords(&offset, sizeof(offset), &cx, sizeof(tlbHeader));
3065 pTypeLibImpl->HelpStringDll = MSFT_ReadString(&cx, offset);
3068 pTypeLibImpl->dwHelpContext = tlbHeader.helpstringcontext;
3070 /* custom data */
3071 if(tlbHeader.CustomDataOffset >= 0)
3073 MSFT_CustData(&cx, tlbHeader.CustomDataOffset, &pTypeLibImpl->custdata_list);
3076 /* fill in type descriptions */
3077 if(tlbSegDir.pTypdescTab.length > 0)
3079 int i, j, cTD = tlbSegDir.pTypdescTab.length / (2*sizeof(INT));
3080 INT16 td[4];
3081 pTypeLibImpl->ctTypeDesc = cTD;
3082 pTypeLibImpl->pTypeDesc = heap_alloc_zero( cTD * sizeof(TYPEDESC));
3083 MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pTypdescTab.offset);
3084 for(i=0; i<cTD; )
3086 /* FIXME: add several sanity checks here */
3087 pTypeLibImpl->pTypeDesc[i].vt = td[0] & VT_TYPEMASK;
3088 if(td[0] == VT_PTR || td[0] == VT_SAFEARRAY)
3090 /* FIXME: check safearray */
3091 if(td[3] < 0)
3092 pTypeLibImpl->pTypeDesc[i].u.lptdesc = &std_typedesc[td[2]];
3093 else
3094 pTypeLibImpl->pTypeDesc[i].u.lptdesc = &pTypeLibImpl->pTypeDesc[td[2]/8];
3096 else if(td[0] == VT_CARRAY)
3098 /* array descr table here */
3099 pTypeLibImpl->pTypeDesc[i].u.lpadesc = (void *)(INT_PTR)td[2]; /* temp store offset in*/
3101 else if(td[0] == VT_USERDEFINED)
3103 pTypeLibImpl->pTypeDesc[i].u.hreftype = MAKELONG(td[2],td[3]);
3105 if(++i<cTD) MSFT_ReadLEWords(td, sizeof(td), &cx, DO_NOT_SEEK);
3108 /* second time around to fill the array subscript info */
3109 for(i=0;i<cTD;i++)
3111 if(pTypeLibImpl->pTypeDesc[i].vt != VT_CARRAY) continue;
3112 if(tlbSegDir.pArrayDescriptions.offset>0)
3114 MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pArrayDescriptions.offset + (INT_PTR)pTypeLibImpl->pTypeDesc[i].u.lpadesc);
3115 pTypeLibImpl->pTypeDesc[i].u.lpadesc = heap_alloc_zero(sizeof(ARRAYDESC)+sizeof(SAFEARRAYBOUND)*(td[3]-1));
3117 if(td[1]<0)
3118 pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem.vt = td[0] & VT_TYPEMASK;
3119 else
3120 pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem = cx.pLibInfo->pTypeDesc[td[0]/(2*sizeof(INT))];
3122 pTypeLibImpl->pTypeDesc[i].u.lpadesc->cDims = td[2];
3124 for(j = 0; j<td[2]; j++)
3126 MSFT_ReadLEDWords(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].cElements,
3127 sizeof(INT), &cx, DO_NOT_SEEK);
3128 MSFT_ReadLEDWords(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].lLbound,
3129 sizeof(INT), &cx, DO_NOT_SEEK);
3132 else
3134 pTypeLibImpl->pTypeDesc[i].u.lpadesc = NULL;
3135 ERR("didn't find array description data\n");
3140 /* imported type libs */
3141 if(tlbSegDir.pImpFiles.offset>0)
3143 TLBImpLib *pImpLib;
3144 int oGuid, offset = tlbSegDir.pImpFiles.offset;
3145 UINT16 size;
3147 while(offset < tlbSegDir.pImpFiles.offset +tlbSegDir.pImpFiles.length)
3149 char *name;
3151 pImpLib = heap_alloc_zero(sizeof(TLBImpLib));
3152 pImpLib->offset = offset - tlbSegDir.pImpFiles.offset;
3153 MSFT_ReadLEDWords(&oGuid, sizeof(INT), &cx, offset);
3155 MSFT_ReadLEDWords(&pImpLib->lcid, sizeof(LCID), &cx, DO_NOT_SEEK);
3156 MSFT_ReadLEWords(&pImpLib->wVersionMajor, sizeof(WORD), &cx, DO_NOT_SEEK);
3157 MSFT_ReadLEWords(&pImpLib->wVersionMinor, sizeof(WORD), &cx, DO_NOT_SEEK);
3158 MSFT_ReadLEWords(& size, sizeof(UINT16), &cx, DO_NOT_SEEK);
3160 size >>= 2;
3161 name = heap_alloc_zero(size+1);
3162 MSFT_Read(name, size, &cx, DO_NOT_SEEK);
3163 pImpLib->name = TLB_MultiByteToBSTR(name);
3164 heap_free(name);
3166 MSFT_ReadGuid(&pImpLib->guid, oGuid, &cx);
3167 offset = (offset + sizeof(INT) + sizeof(DWORD) + sizeof(LCID) + sizeof(UINT16) + size + 3) & ~3;
3169 list_add_tail(&pTypeLibImpl->implib_list, &pImpLib->entry);
3173 pTypeLibImpl->dispatch_href = tlbHeader.dispatchpos;
3174 if(pTypeLibImpl->dispatch_href != -1)
3175 MSFT_DoRefType(&cx, pTypeLibImpl, pTypeLibImpl->dispatch_href);
3177 /* type infos */
3178 if(tlbHeader.nrtypeinfos >= 0 )
3180 ITypeInfoImpl **ppTI;
3181 int i;
3183 ppTI = pTypeLibImpl->typeinfos = heap_alloc_zero(sizeof(ITypeInfoImpl*) * tlbHeader.nrtypeinfos);
3185 for(i = 0; i < tlbHeader.nrtypeinfos; i++)
3187 *ppTI = MSFT_DoTypeInfo(&cx, i, pTypeLibImpl);
3189 ++ppTI;
3190 (pTypeLibImpl->TypeInfoCount)++;
3194 TRACE("(%p)\n", pTypeLibImpl);
3195 return (ITypeLib2*) pTypeLibImpl;
3199 static BOOL TLB_GUIDFromString(const char *str, GUID *guid)
3201 char b[3];
3202 int i;
3203 short s;
3205 if(sscanf(str, "%x-%hx-%hx-%hx", &guid->Data1, &guid->Data2, &guid->Data3, &s) != 4) {
3206 FIXME("Can't parse guid %s\n", debugstr_guid(guid));
3207 return FALSE;
3210 guid->Data4[0] = s >> 8;
3211 guid->Data4[1] = s & 0xff;
3213 b[2] = '\0';
3214 for(i = 0; i < 6; i++) {
3215 memcpy(b, str + 24 + 2 * i, 2);
3216 guid->Data4[i + 2] = strtol(b, NULL, 16);
3218 return TRUE;
3221 static WORD SLTG_ReadString(const char *ptr, BSTR *pBstr)
3223 WORD bytelen;
3224 DWORD len;
3226 *pBstr = NULL;
3227 bytelen = *(const WORD*)ptr;
3228 if(bytelen == 0xffff) return 2;
3229 len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, NULL, 0);
3230 *pBstr = SysAllocStringLen(NULL, len);
3231 if (*pBstr)
3232 len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, *pBstr, len);
3233 return bytelen + 2;
3236 static WORD SLTG_ReadStringA(const char *ptr, char **str)
3238 WORD bytelen;
3240 *str = NULL;
3241 bytelen = *(const WORD*)ptr;
3242 if(bytelen == 0xffff) return 2;
3243 *str = heap_alloc(bytelen + 1);
3244 memcpy(*str, ptr + 2, bytelen);
3245 (*str)[bytelen] = '\0';
3246 return bytelen + 2;
3249 static DWORD SLTG_ReadLibBlk(LPVOID pLibBlk, ITypeLibImpl *pTypeLibImpl)
3251 char *ptr = pLibBlk;
3252 WORD w;
3254 if((w = *(WORD*)ptr) != SLTG_LIBBLK_MAGIC) {
3255 FIXME("libblk magic = %04x\n", w);
3256 return 0;
3259 ptr += 6;
3260 if((w = *(WORD*)ptr) != 0xffff) {
3261 FIXME("LibBlk.res06 = %04x. Assumung string and skipping\n", w);
3262 ptr += w;
3264 ptr += 2;
3266 ptr += SLTG_ReadString(ptr, &pTypeLibImpl->DocString);
3268 ptr += SLTG_ReadString(ptr, &pTypeLibImpl->HelpFile);
3270 pTypeLibImpl->dwHelpContext = *(DWORD*)ptr;
3271 ptr += 4;
3273 pTypeLibImpl->LibAttr.syskind = *(WORD*)ptr;
3274 ptr += 2;
3276 if(SUBLANGID(*(WORD*)ptr) == SUBLANG_NEUTRAL)
3277 pTypeLibImpl->lcid = pTypeLibImpl->LibAttr.lcid = MAKELCID(MAKELANGID(PRIMARYLANGID(*(WORD*)ptr),0),0);
3278 else
3279 pTypeLibImpl->lcid = pTypeLibImpl->LibAttr.lcid = 0;
3280 ptr += 2;
3282 ptr += 4; /* skip res12 */
3284 pTypeLibImpl->LibAttr.wLibFlags = *(WORD*)ptr;
3285 ptr += 2;
3287 pTypeLibImpl->LibAttr.wMajorVerNum = *(WORD*)ptr;
3288 ptr += 2;
3290 pTypeLibImpl->LibAttr.wMinorVerNum = *(WORD*)ptr;
3291 ptr += 2;
3293 memcpy(&pTypeLibImpl->LibAttr.guid, ptr, sizeof(GUID));
3294 ptr += sizeof(GUID);
3296 return ptr - (char*)pLibBlk;
3299 /* stores a mapping between the sltg typeinfo's references and the typelib's HREFTYPEs */
3300 typedef struct
3302 unsigned int num;
3303 HREFTYPE refs[1];
3304 } sltg_ref_lookup_t;
3306 static HRESULT sltg_get_typelib_ref(const sltg_ref_lookup_t *table, DWORD typeinfo_ref,
3307 HREFTYPE *typelib_ref)
3309 if(table && typeinfo_ref < table->num)
3311 *typelib_ref = table->refs[typeinfo_ref];
3312 return S_OK;
3315 ERR_(typelib)("Unable to find reference\n");
3316 *typelib_ref = -1;
3317 return E_FAIL;
3320 static WORD *SLTG_DoType(WORD *pType, char *pBlk, TYPEDESC *pTD, const sltg_ref_lookup_t *ref_lookup)
3322 BOOL done = FALSE;
3324 while(!done) {
3325 if((*pType & 0xe00) == 0xe00) {
3326 pTD->vt = VT_PTR;
3327 pTD->u.lptdesc = heap_alloc_zero(sizeof(TYPEDESC));
3328 pTD = pTD->u.lptdesc;
3330 switch(*pType & 0x3f) {
3331 case VT_PTR:
3332 pTD->vt = VT_PTR;
3333 pTD->u.lptdesc = heap_alloc_zero(sizeof(TYPEDESC));
3334 pTD = pTD->u.lptdesc;
3335 break;
3337 case VT_USERDEFINED:
3338 pTD->vt = VT_USERDEFINED;
3339 sltg_get_typelib_ref(ref_lookup, *(++pType) / 4, &pTD->u.hreftype);
3340 done = TRUE;
3341 break;
3343 case VT_CARRAY:
3345 /* *(pType+1) is offset to a SAFEARRAY, *(pType+2) is type of
3346 array */
3348 SAFEARRAY *pSA = (SAFEARRAY *)(pBlk + *(++pType));
3350 pTD->vt = VT_CARRAY;
3351 pTD->u.lpadesc = heap_alloc_zero(sizeof(ARRAYDESC) + (pSA->cDims - 1) * sizeof(SAFEARRAYBOUND));
3352 pTD->u.lpadesc->cDims = pSA->cDims;
3353 memcpy(pTD->u.lpadesc->rgbounds, pSA->rgsabound,
3354 pSA->cDims * sizeof(SAFEARRAYBOUND));
3356 pTD = &pTD->u.lpadesc->tdescElem;
3357 break;
3360 case VT_SAFEARRAY:
3362 /* FIXME: *(pType+1) gives an offset to SAFEARRAY, is this
3363 useful? */
3365 pType++;
3366 pTD->vt = VT_SAFEARRAY;
3367 pTD->u.lptdesc = heap_alloc_zero(sizeof(TYPEDESC));
3368 pTD = pTD->u.lptdesc;
3369 break;
3371 default:
3372 pTD->vt = *pType & 0x3f;
3373 done = TRUE;
3374 break;
3376 pType++;
3378 return pType;
3381 static WORD *SLTG_DoElem(WORD *pType, char *pBlk,
3382 ELEMDESC *pElem, const sltg_ref_lookup_t *ref_lookup)
3384 /* Handle [in/out] first */
3385 if((*pType & 0xc000) == 0xc000)
3386 pElem->u.paramdesc.wParamFlags = PARAMFLAG_NONE;
3387 else if(*pType & 0x8000)
3388 pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN | PARAMFLAG_FOUT;
3389 else if(*pType & 0x4000)
3390 pElem->u.paramdesc.wParamFlags = PARAMFLAG_FOUT;
3391 else
3392 pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN;
3394 if(*pType & 0x2000)
3395 pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FLCID;
3397 if(*pType & 0x80)
3398 pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FRETVAL;
3400 return SLTG_DoType(pType, pBlk, &pElem->tdesc, ref_lookup);
3404 static sltg_ref_lookup_t *SLTG_DoRefs(SLTG_RefInfo *pRef, ITypeLibImpl *pTL,
3405 char *pNameTable)
3407 unsigned int ref;
3408 char *name;
3409 TLBRefType *ref_type;
3410 sltg_ref_lookup_t *table;
3411 HREFTYPE typelib_ref;
3413 if(pRef->magic != SLTG_REF_MAGIC) {
3414 FIXME("Ref magic = %x\n", pRef->magic);
3415 return NULL;
3417 name = ( (char*)pRef->names + pRef->number);
3419 table = heap_alloc(sizeof(*table) + ((pRef->number >> 3) - 1) * sizeof(table->refs[0]));
3420 table->num = pRef->number >> 3;
3422 /* FIXME should scan the existing list and reuse matching refs added by previous typeinfos */
3424 /* We don't want the first href to be 0 */
3425 typelib_ref = (list_count(&pTL->ref_list) + 1) << 2;
3427 for(ref = 0; ref < pRef->number >> 3; ref++) {
3428 char *refname;
3429 unsigned int lib_offs, type_num;
3431 ref_type = heap_alloc_zero(sizeof(TLBRefType));
3433 name += SLTG_ReadStringA(name, &refname);
3434 if(sscanf(refname, "*\\R%x*#%x", &lib_offs, &type_num) != 2)
3435 FIXME_(typelib)("Can't sscanf ref\n");
3436 if(lib_offs != 0xffff) {
3437 TLBImpLib *import;
3439 LIST_FOR_EACH_ENTRY(import, &pTL->implib_list, TLBImpLib, entry)
3440 if(import->offset == lib_offs)
3441 break;
3443 if(&import->entry == &pTL->implib_list) {
3444 char fname[MAX_PATH+1];
3445 int len;
3447 import = heap_alloc_zero(sizeof(*import));
3448 import->offset = lib_offs;
3449 TLB_GUIDFromString( pNameTable + lib_offs + 4,
3450 &import->guid);
3451 if(sscanf(pNameTable + lib_offs + 40, "}#%hd.%hd#%x#%s",
3452 &import->wVersionMajor,
3453 &import->wVersionMinor,
3454 &import->lcid, fname) != 4) {
3455 FIXME_(typelib)("can't sscanf ref %s\n",
3456 pNameTable + lib_offs + 40);
3458 len = strlen(fname);
3459 if(fname[len-1] != '#')
3460 FIXME("fname = %s\n", fname);
3461 fname[len-1] = '\0';
3462 import->name = TLB_MultiByteToBSTR(fname);
3463 list_add_tail(&pTL->implib_list, &import->entry);
3465 ref_type->pImpTLInfo = import;
3467 /* Store a reference to IDispatch */
3468 if(pTL->dispatch_href == -1 && IsEqualGUID(&import->guid, &IID_StdOle) && type_num == 4)
3469 pTL->dispatch_href = typelib_ref;
3471 } else { /* internal ref */
3472 ref_type->pImpTLInfo = TLB_REF_INTERNAL;
3474 ref_type->reference = typelib_ref;
3475 ref_type->index = type_num;
3477 heap_free(refname);
3478 list_add_tail(&pTL->ref_list, &ref_type->entry);
3480 table->refs[ref] = typelib_ref;
3481 typelib_ref += 4;
3483 if((BYTE)*name != SLTG_REF_MAGIC)
3484 FIXME_(typelib)("End of ref block magic = %x\n", *name);
3485 dump_TLBRefType(pTL);
3486 return table;
3489 static char *SLTG_DoImpls(char *pBlk, ITypeInfoImpl *pTI,
3490 BOOL OneOnly, const sltg_ref_lookup_t *ref_lookup)
3492 SLTG_ImplInfo *info;
3493 TLBImplType *pImplType;
3494 /* I don't really get this structure, usually it's 0x16 bytes
3495 long, but iuser.tlb contains some that are 0x18 bytes long.
3496 That's ok because we can use the next ptr to jump to the next
3497 one. But how do we know the length of the last one? The WORD
3498 at offs 0x8 might be the clue. For now I'm just assuming that
3499 the last one is the regular 0x16 bytes. */
3501 info = (SLTG_ImplInfo*)pBlk;
3502 while(1){
3503 pTI->TypeAttr.cImplTypes++;
3504 if(info->next == 0xffff)
3505 break;
3506 info = (SLTG_ImplInfo*)(pBlk + info->next);
3509 info = (SLTG_ImplInfo*)pBlk;
3510 pTI->impltypes = TLBImplType_Constructor(pTI->TypeAttr.cImplTypes);
3511 pImplType = pTI->impltypes;
3512 while(1) {
3513 sltg_get_typelib_ref(ref_lookup, info->ref, &pImplType->hRef);
3514 pImplType->implflags = info->impltypeflags;
3515 ++pImplType;
3517 if(info->next == 0xffff)
3518 break;
3519 if(OneOnly)
3520 FIXME_(typelib)("Interface inheriting more than one interface\n");
3521 info = (SLTG_ImplInfo*)(pBlk + info->next);
3523 info++; /* see comment at top of function */
3524 return (char*)info;
3527 static void SLTG_DoVars(char *pBlk, char *pFirstItem, ITypeInfoImpl *pTI, unsigned short cVars,
3528 const char *pNameTable, const sltg_ref_lookup_t *ref_lookup)
3530 TLBVarDesc *pVarDesc;
3531 BSTR bstrPrevName = NULL;
3532 SLTG_Variable *pItem;
3533 unsigned short i;
3534 WORD *pType;
3536 pVarDesc = pTI->vardescs = TLBVarDesc_Constructor(cVars);
3538 for(pItem = (SLTG_Variable *)pFirstItem, i = 0; i < cVars;
3539 pItem = (SLTG_Variable *)(pBlk + pItem->next), i++, ++pVarDesc) {
3541 pVarDesc->vardesc.memid = pItem->memid;
3543 if (pItem->magic != SLTG_VAR_MAGIC &&
3544 pItem->magic != SLTG_VAR_WITH_FLAGS_MAGIC) {
3545 FIXME_(typelib)("var magic = %02x\n", pItem->magic);
3546 return;
3549 if (pItem->name == 0xfffe)
3550 pVarDesc->Name = SysAllocString(bstrPrevName);
3551 else
3552 pVarDesc->Name = TLB_MultiByteToBSTR(pItem->name + pNameTable);
3554 TRACE_(typelib)("name: %s\n", debugstr_w(pVarDesc->Name));
3555 TRACE_(typelib)("byte_offs = 0x%x\n", pItem->byte_offs);
3556 TRACE_(typelib)("memid = 0x%x\n", pItem->memid);
3558 if(pItem->flags & 0x02)
3559 pType = &pItem->type;
3560 else
3561 pType = (WORD*)(pBlk + pItem->type);
3563 if (pItem->flags & ~0xda)
3564 FIXME_(typelib)("unhandled flags = %02x\n", pItem->flags & ~0xda);
3566 SLTG_DoElem(pType, pBlk,
3567 &pVarDesc->vardesc.elemdescVar, ref_lookup);
3569 if (TRACE_ON(typelib)) {
3570 char buf[300];
3571 dump_TypeDesc(&pVarDesc->vardesc.elemdescVar.tdesc, buf);
3572 TRACE_(typelib)("elemdescVar: %s\n", buf);
3575 if (pItem->flags & 0x40) {
3576 TRACE_(typelib)("VAR_DISPATCH\n");
3577 pVarDesc->vardesc.varkind = VAR_DISPATCH;
3579 else if (pItem->flags & 0x10) {
3580 TRACE_(typelib)("VAR_CONST\n");
3581 pVarDesc->vardesc.varkind = VAR_CONST;
3582 pVarDesc->vardesc.u.lpvarValue = heap_alloc(sizeof(VARIANT));
3583 V_VT(pVarDesc->vardesc.u.lpvarValue) = VT_INT;
3584 if (pItem->flags & 0x08)
3585 V_INT(pVarDesc->vardesc.u.lpvarValue) = pItem->byte_offs;
3586 else {
3587 switch (pVarDesc->vardesc.elemdescVar.tdesc.vt)
3589 case VT_LPSTR:
3590 case VT_LPWSTR:
3591 case VT_BSTR:
3593 WORD len = *(WORD *)(pBlk + pItem->byte_offs);
3594 BSTR str;
3595 TRACE_(typelib)("len = %u\n", len);
3596 if (len == 0xffff) {
3597 str = NULL;
3598 } else {
3599 INT alloc_len = MultiByteToWideChar(CP_ACP, 0, pBlk + pItem->byte_offs + 2, len, NULL, 0);
3600 str = SysAllocStringLen(NULL, alloc_len);
3601 MultiByteToWideChar(CP_ACP, 0, pBlk + pItem->byte_offs + 2, len, str, alloc_len);
3603 V_VT(pVarDesc->vardesc.u.lpvarValue) = VT_BSTR;
3604 V_BSTR(pVarDesc->vardesc.u.lpvarValue) = str;
3605 break;
3607 case VT_I2:
3608 case VT_UI2:
3609 case VT_I4:
3610 case VT_UI4:
3611 case VT_INT:
3612 case VT_UINT:
3613 V_INT(pVarDesc->vardesc.u.lpvarValue) =
3614 *(INT*)(pBlk + pItem->byte_offs);
3615 break;
3616 default:
3617 FIXME_(typelib)("VAR_CONST unimplemented for type %d\n", pVarDesc->vardesc.elemdescVar.tdesc.vt);
3621 else {
3622 TRACE_(typelib)("VAR_PERINSTANCE\n");
3623 pVarDesc->vardesc.u.oInst = pItem->byte_offs;
3624 pVarDesc->vardesc.varkind = VAR_PERINSTANCE;
3627 if (pItem->magic == SLTG_VAR_WITH_FLAGS_MAGIC)
3628 pVarDesc->vardesc.wVarFlags = pItem->varflags;
3630 if (pItem->flags & 0x80)
3631 pVarDesc->vardesc.wVarFlags |= VARFLAG_FREADONLY;
3633 bstrPrevName = pVarDesc->Name;
3635 pTI->TypeAttr.cVars = cVars;
3638 static void SLTG_DoFuncs(char *pBlk, char *pFirstItem, ITypeInfoImpl *pTI,
3639 unsigned short cFuncs, char *pNameTable, const sltg_ref_lookup_t *ref_lookup)
3641 SLTG_Function *pFunc;
3642 unsigned short i;
3643 TLBFuncDesc *pFuncDesc;
3645 pTI->funcdescs = TLBFuncDesc_Constructor(cFuncs);
3647 pFuncDesc = pTI->funcdescs;
3648 for(pFunc = (SLTG_Function*)pFirstItem, i = 0; i < cFuncs && pFunc != (SLTG_Function*)0xFFFF;
3649 pFunc = (SLTG_Function*)(pBlk + pFunc->next), i++, ++pFuncDesc) {
3651 int param;
3652 WORD *pType, *pArg;
3654 switch (pFunc->magic & ~SLTG_FUNCTION_FLAGS_PRESENT) {
3655 case SLTG_FUNCTION_MAGIC:
3656 pFuncDesc->funcdesc.funckind = FUNC_PUREVIRTUAL;
3657 break;
3658 case SLTG_DISPATCH_FUNCTION_MAGIC:
3659 pFuncDesc->funcdesc.funckind = FUNC_DISPATCH;
3660 break;
3661 case SLTG_STATIC_FUNCTION_MAGIC:
3662 pFuncDesc->funcdesc.funckind = FUNC_STATIC;
3663 break;
3664 default:
3665 FIXME("unimplemented func magic = %02x\n", pFunc->magic & ~SLTG_FUNCTION_FLAGS_PRESENT);
3666 continue;
3668 pFuncDesc->Name = TLB_MultiByteToBSTR(pFunc->name + pNameTable);
3670 pFuncDesc->funcdesc.memid = pFunc->dispid;
3671 pFuncDesc->funcdesc.invkind = pFunc->inv >> 4;
3672 pFuncDesc->funcdesc.callconv = pFunc->nacc & 0x7;
3673 pFuncDesc->funcdesc.cParams = pFunc->nacc >> 3;
3674 pFuncDesc->funcdesc.cParamsOpt = (pFunc->retnextopt & 0x7e) >> 1;
3675 pFuncDesc->funcdesc.oVft = pFunc->vtblpos & ~1;
3677 if(pFunc->magic & SLTG_FUNCTION_FLAGS_PRESENT)
3678 pFuncDesc->funcdesc.wFuncFlags = pFunc->funcflags;
3680 if(pFunc->retnextopt & 0x80)
3681 pType = &pFunc->rettype;
3682 else
3683 pType = (WORD*)(pBlk + pFunc->rettype);
3685 SLTG_DoElem(pType, pBlk, &pFuncDesc->funcdesc.elemdescFunc, ref_lookup);
3687 pFuncDesc->funcdesc.lprgelemdescParam =
3688 heap_alloc_zero(pFuncDesc->funcdesc.cParams * sizeof(ELEMDESC));
3689 pFuncDesc->pParamDesc = TLBParDesc_Constructor(pFuncDesc->funcdesc.cParams);
3691 pArg = (WORD*)(pBlk + pFunc->arg_off);
3693 for(param = 0; param < pFuncDesc->funcdesc.cParams; param++) {
3694 char *paramName = pNameTable + *pArg;
3695 BOOL HaveOffs;
3696 /* If arg type follows then paramName points to the 2nd
3697 letter of the name, else the next WORD is an offset to
3698 the arg type and paramName points to the first letter.
3699 So let's take one char off paramName and see if we're
3700 pointing at an alpha-numeric char. However if *pArg is
3701 0xffff or 0xfffe then the param has no name, the former
3702 meaning that the next WORD is the type, the latter
3703 meaning that the next WORD is an offset to the type. */
3705 HaveOffs = FALSE;
3706 if(*pArg == 0xffff)
3707 paramName = NULL;
3708 else if(*pArg == 0xfffe) {
3709 paramName = NULL;
3710 HaveOffs = TRUE;
3712 else if(paramName[-1] && !isalnum(paramName[-1]))
3713 HaveOffs = TRUE;
3715 pArg++;
3717 if(HaveOffs) { /* the next word is an offset to type */
3718 pType = (WORD*)(pBlk + *pArg);
3719 SLTG_DoElem(pType, pBlk,
3720 &pFuncDesc->funcdesc.lprgelemdescParam[param], ref_lookup);
3721 pArg++;
3722 } else {
3723 if(paramName)
3724 paramName--;
3725 pArg = SLTG_DoElem(pArg, pBlk,
3726 &pFuncDesc->funcdesc.lprgelemdescParam[param], ref_lookup);
3729 /* Are we an optional param ? */
3730 if(pFuncDesc->funcdesc.cParams - param <=
3731 pFuncDesc->funcdesc.cParamsOpt)
3732 pFuncDesc->funcdesc.lprgelemdescParam[param].u.paramdesc.wParamFlags |= PARAMFLAG_FOPT;
3734 if(paramName) {
3735 pFuncDesc->pParamDesc[param].Name =
3736 TLB_MultiByteToBSTR(paramName);
3737 } else {
3738 pFuncDesc->pParamDesc[param].Name =
3739 SysAllocString(pFuncDesc->Name);
3743 pTI->TypeAttr.cFuncs = cFuncs;
3746 static void SLTG_ProcessCoClass(char *pBlk, ITypeInfoImpl *pTI,
3747 char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3748 SLTG_TypeInfoTail *pTITail)
3750 char *pFirstItem;
3751 sltg_ref_lookup_t *ref_lookup = NULL;
3753 if(pTIHeader->href_table != 0xffffffff) {
3754 ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3755 pNameTable);
3758 pFirstItem = pBlk;
3760 if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
3761 SLTG_DoImpls(pFirstItem, pTI, FALSE, ref_lookup);
3763 heap_free(ref_lookup);
3767 static void SLTG_ProcessInterface(char *pBlk, ITypeInfoImpl *pTI,
3768 char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3769 const SLTG_TypeInfoTail *pTITail)
3771 char *pFirstItem;
3772 sltg_ref_lookup_t *ref_lookup = NULL;
3774 if(pTIHeader->href_table != 0xffffffff) {
3775 ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3776 pNameTable);
3779 pFirstItem = pBlk;
3781 if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
3782 SLTG_DoImpls(pFirstItem, pTI, TRUE, ref_lookup);
3785 if (pTITail->funcs_off != 0xffff)
3786 SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup);
3788 heap_free(ref_lookup);
3790 if (TRACE_ON(typelib))
3791 dump_TLBFuncDesc(pTI->funcdescs, pTI->TypeAttr.cFuncs);
3794 static void SLTG_ProcessRecord(char *pBlk, ITypeInfoImpl *pTI,
3795 const char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3796 const SLTG_TypeInfoTail *pTITail)
3798 SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, NULL);
3801 static void SLTG_ProcessAlias(char *pBlk, ITypeInfoImpl *pTI,
3802 char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3803 const SLTG_TypeInfoTail *pTITail)
3805 WORD *pType;
3806 sltg_ref_lookup_t *ref_lookup = NULL;
3808 if (pTITail->simple_alias) {
3809 /* if simple alias, no more processing required */
3810 pTI->TypeAttr.tdescAlias.vt = pTITail->tdescalias_vt;
3811 return;
3814 if(pTIHeader->href_table != 0xffffffff) {
3815 ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3816 pNameTable);
3819 /* otherwise it is an offset to a type */
3820 pType = (WORD *)(pBlk + pTITail->tdescalias_vt);
3822 SLTG_DoType(pType, pBlk, &pTI->TypeAttr.tdescAlias, ref_lookup);
3824 heap_free(ref_lookup);
3827 static void SLTG_ProcessDispatch(char *pBlk, ITypeInfoImpl *pTI,
3828 char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3829 const SLTG_TypeInfoTail *pTITail)
3831 sltg_ref_lookup_t *ref_lookup = NULL;
3832 if (pTIHeader->href_table != 0xffffffff)
3833 ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3834 pNameTable);
3836 if (pTITail->vars_off != 0xffff)
3837 SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, ref_lookup);
3839 if (pTITail->funcs_off != 0xffff)
3840 SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup);
3842 if (pTITail->impls_off != 0xffff)
3843 SLTG_DoImpls(pBlk + pTITail->impls_off, pTI, FALSE, ref_lookup);
3845 /* this is necessary to cope with MSFT typelibs that set cFuncs to the number
3846 * of dispinterface functions including the IDispatch ones, so
3847 * ITypeInfo::GetFuncDesc takes the real value for cFuncs from cbSizeVft */
3848 pTI->TypeAttr.cbSizeVft = pTI->TypeAttr.cFuncs * sizeof(void *);
3850 heap_free(ref_lookup);
3851 if (TRACE_ON(typelib))
3852 dump_TLBFuncDesc(pTI->funcdescs, pTI->TypeAttr.cFuncs);
3855 static void SLTG_ProcessEnum(char *pBlk, ITypeInfoImpl *pTI,
3856 const char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3857 const SLTG_TypeInfoTail *pTITail)
3859 SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, NULL);
3862 static void SLTG_ProcessModule(char *pBlk, ITypeInfoImpl *pTI,
3863 char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3864 const SLTG_TypeInfoTail *pTITail)
3866 sltg_ref_lookup_t *ref_lookup = NULL;
3867 if (pTIHeader->href_table != 0xffffffff)
3868 ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3869 pNameTable);
3871 if (pTITail->vars_off != 0xffff)
3872 SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, ref_lookup);
3874 if (pTITail->funcs_off != 0xffff)
3875 SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup);
3876 heap_free(ref_lookup);
3877 if (TRACE_ON(typelib))
3878 dump_TypeInfo(pTI);
3881 /* Because SLTG_OtherTypeInfo is such a painful struct, we make a more
3882 managable copy of it into this */
3883 typedef struct {
3884 WORD small_no;
3885 char *index_name;
3886 char *other_name;
3887 WORD res1a;
3888 WORD name_offs;
3889 WORD more_bytes;
3890 char *extra;
3891 WORD res20;
3892 DWORD helpcontext;
3893 WORD res26;
3894 GUID uuid;
3895 } SLTG_InternalOtherTypeInfo;
3897 /****************************************************************************
3898 * ITypeLib2_Constructor_SLTG
3900 * loading a SLTG typelib from an in-memory image
3902 static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength)
3904 ITypeLibImpl *pTypeLibImpl;
3905 SLTG_Header *pHeader;
3906 SLTG_BlkEntry *pBlkEntry;
3907 SLTG_Magic *pMagic;
3908 SLTG_Index *pIndex;
3909 SLTG_Pad9 *pPad9;
3910 LPVOID pBlk, pFirstBlk;
3911 SLTG_LibBlk *pLibBlk;
3912 SLTG_InternalOtherTypeInfo *pOtherTypeInfoBlks;
3913 char *pAfterOTIBlks = NULL;
3914 char *pNameTable, *ptr;
3915 int i;
3916 DWORD len, order;
3917 ITypeInfoImpl **ppTypeInfoImpl;
3919 TRACE_(typelib)("%p, TLB length = %d\n", pLib, dwTLBLength);
3922 pTypeLibImpl = TypeLibImpl_Constructor();
3923 if (!pTypeLibImpl) return NULL;
3925 pHeader = pLib;
3927 TRACE_(typelib)("header:\n");
3928 TRACE_(typelib)("\tmagic=0x%08x, file blocks = %d\n", pHeader->SLTG_magic,
3929 pHeader->nrOfFileBlks );
3930 if (pHeader->SLTG_magic != SLTG_SIGNATURE) {
3931 FIXME_(typelib)("Header type magic 0x%08x not supported.\n",
3932 pHeader->SLTG_magic);
3933 return NULL;
3936 /* There are pHeader->nrOfFileBlks - 2 TypeInfo records in this typelib */
3937 pTypeLibImpl->TypeInfoCount = pHeader->nrOfFileBlks - 2;
3939 /* This points to pHeader->nrOfFileBlks - 1 of SLTG_BlkEntry */
3940 pBlkEntry = (SLTG_BlkEntry*)(pHeader + 1);
3942 /* Next we have a magic block */
3943 pMagic = (SLTG_Magic*)(pBlkEntry + pHeader->nrOfFileBlks - 1);
3945 /* Let's see if we're still in sync */
3946 if(memcmp(pMagic->CompObj_magic, SLTG_COMPOBJ_MAGIC,
3947 sizeof(SLTG_COMPOBJ_MAGIC))) {
3948 FIXME_(typelib)("CompObj magic = %s\n", pMagic->CompObj_magic);
3949 return NULL;
3951 if(memcmp(pMagic->dir_magic, SLTG_DIR_MAGIC,
3952 sizeof(SLTG_DIR_MAGIC))) {
3953 FIXME_(typelib)("dir magic = %s\n", pMagic->dir_magic);
3954 return NULL;
3957 pIndex = (SLTG_Index*)(pMagic+1);
3959 pPad9 = (SLTG_Pad9*)(pIndex + pTypeLibImpl->TypeInfoCount);
3961 pFirstBlk = pPad9 + 1;
3963 /* We'll set up a ptr to the main library block, which is the last one. */
3965 for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0;
3966 pBlkEntry[order].next != 0;
3967 order = pBlkEntry[order].next - 1, i++) {
3968 pBlk = (char*)pBlk + pBlkEntry[order].len;
3970 pLibBlk = pBlk;
3972 len = SLTG_ReadLibBlk(pLibBlk, pTypeLibImpl);
3974 /* Now there's 0x40 bytes of 0xffff with the numbers 0 to TypeInfoCount
3975 interspersed */
3977 len += 0x40;
3979 /* And now TypeInfoCount of SLTG_OtherTypeInfo */
3981 pOtherTypeInfoBlks = heap_alloc_zero(sizeof(*pOtherTypeInfoBlks) * pTypeLibImpl->TypeInfoCount);
3984 ptr = (char*)pLibBlk + len;
3986 for(i = 0; i < pTypeLibImpl->TypeInfoCount; i++) {
3987 WORD w, extra;
3988 len = 0;
3990 pOtherTypeInfoBlks[i].small_no = *(WORD*)ptr;
3992 w = *(WORD*)(ptr + 2);
3993 if(w != 0xffff) {
3994 len += w;
3995 pOtherTypeInfoBlks[i].index_name = heap_alloc(w+1);
3996 memcpy(pOtherTypeInfoBlks[i].index_name, ptr + 4, w);
3997 pOtherTypeInfoBlks[i].index_name[w] = '\0';
3999 w = *(WORD*)(ptr + 4 + len);
4000 if(w != 0xffff) {
4001 TRACE_(typelib)("\twith %s\n", debugstr_an(ptr + 6 + len, w));
4002 len += w;
4003 pOtherTypeInfoBlks[i].other_name = heap_alloc(w+1);
4004 memcpy(pOtherTypeInfoBlks[i].other_name, ptr + 6 + len, w);
4005 pOtherTypeInfoBlks[i].other_name[w] = '\0';
4007 pOtherTypeInfoBlks[i].res1a = *(WORD*)(ptr + len + 6);
4008 pOtherTypeInfoBlks[i].name_offs = *(WORD*)(ptr + len + 8);
4009 extra = pOtherTypeInfoBlks[i].more_bytes = *(WORD*)(ptr + 10 + len);
4010 if(extra) {
4011 pOtherTypeInfoBlks[i].extra = heap_alloc(extra);
4012 memcpy(pOtherTypeInfoBlks[i].extra, ptr + 12, extra);
4013 len += extra;
4015 pOtherTypeInfoBlks[i].res20 = *(WORD*)(ptr + 12 + len);
4016 pOtherTypeInfoBlks[i].helpcontext = *(DWORD*)(ptr + 14 + len);
4017 pOtherTypeInfoBlks[i].res26 = *(WORD*)(ptr + 18 + len);
4018 memcpy(&pOtherTypeInfoBlks[i].uuid, ptr + 20 + len, sizeof(GUID));
4019 len += sizeof(SLTG_OtherTypeInfo);
4020 ptr += len;
4023 pAfterOTIBlks = ptr;
4025 /* Skip this WORD and get the next DWORD */
4026 len = *(DWORD*)(pAfterOTIBlks + 2);
4028 /* Now add this to pLibBLk look at what we're pointing at and
4029 possibly add 0x20, then add 0x216, sprinkle a bit a magic
4030 dust and we should be pointing at the beginning of the name
4031 table */
4033 pNameTable = (char*)pLibBlk + len;
4035 switch(*(WORD*)pNameTable) {
4036 case 0xffff:
4037 break;
4038 case 0x0200:
4039 pNameTable += 0x20;
4040 break;
4041 default:
4042 FIXME_(typelib)("pNameTable jump = %x\n", *(WORD*)pNameTable);
4043 break;
4046 pNameTable += 0x216;
4048 pNameTable += 2;
4050 TRACE_(typelib)("Library name is %s\n", pNameTable + pLibBlk->name);
4052 pTypeLibImpl->Name = TLB_MultiByteToBSTR(pNameTable + pLibBlk->name);
4055 /* Hopefully we now have enough ptrs set up to actually read in
4056 some TypeInfos. It's not clear which order to do them in, so
4057 I'll just follow the links along the BlkEntry chain and read
4058 them in the order in which they are in the file */
4060 pTypeLibImpl->typeinfos = heap_alloc_zero(pTypeLibImpl->TypeInfoCount * sizeof(ITypeInfoImpl*));
4061 ppTypeInfoImpl = pTypeLibImpl->typeinfos;
4063 for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0;
4064 pBlkEntry[order].next != 0;
4065 order = pBlkEntry[order].next - 1, i++) {
4067 SLTG_TypeInfoHeader *pTIHeader;
4068 SLTG_TypeInfoTail *pTITail;
4069 SLTG_MemberHeader *pMemHeader;
4071 if(strcmp(pBlkEntry[order].index_string + (char*)pMagic,
4072 pOtherTypeInfoBlks[i].index_name)) {
4073 FIXME_(typelib)("Index strings don't match\n");
4074 return NULL;
4077 pTIHeader = pBlk;
4078 if(pTIHeader->magic != SLTG_TIHEADER_MAGIC) {
4079 FIXME_(typelib)("TypeInfoHeader magic = %04x\n", pTIHeader->magic);
4080 return NULL;
4082 TRACE_(typelib)("pTIHeader->res06 = %x, pTIHeader->res0e = %x, "
4083 "pTIHeader->res16 = %x, pTIHeader->res1e = %x\n",
4084 pTIHeader->res06, pTIHeader->res0e, pTIHeader->res16, pTIHeader->res1e);
4086 *ppTypeInfoImpl = ITypeInfoImpl_Constructor();
4087 (*ppTypeInfoImpl)->pTypeLib = pTypeLibImpl;
4088 (*ppTypeInfoImpl)->index = i;
4089 (*ppTypeInfoImpl)->Name = TLB_MultiByteToBSTR(
4090 pOtherTypeInfoBlks[i].name_offs +
4091 pNameTable);
4092 (*ppTypeInfoImpl)->dwHelpContext = pOtherTypeInfoBlks[i].helpcontext;
4093 (*ppTypeInfoImpl)->TypeAttr.guid = pOtherTypeInfoBlks[i].uuid;
4094 (*ppTypeInfoImpl)->TypeAttr.typekind = pTIHeader->typekind;
4095 (*ppTypeInfoImpl)->TypeAttr.wMajorVerNum = pTIHeader->major_version;
4096 (*ppTypeInfoImpl)->TypeAttr.wMinorVerNum = pTIHeader->minor_version;
4097 (*ppTypeInfoImpl)->TypeAttr.wTypeFlags =
4098 (pTIHeader->typeflags1 >> 3) | (pTIHeader->typeflags2 << 5);
4100 if((*ppTypeInfoImpl)->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL)
4101 (*ppTypeInfoImpl)->TypeAttr.typekind = TKIND_DISPATCH;
4103 if((pTIHeader->typeflags1 & 7) != 2)
4104 FIXME_(typelib)("typeflags1 = %02x\n", pTIHeader->typeflags1);
4105 if(pTIHeader->typeflags3 != 2)
4106 FIXME_(typelib)("typeflags3 = %02x\n", pTIHeader->typeflags3);
4108 TRACE_(typelib)("TypeInfo %s of kind %s guid %s typeflags %04x\n",
4109 debugstr_w((*ppTypeInfoImpl)->Name),
4110 typekind_desc[pTIHeader->typekind],
4111 debugstr_guid(&(*ppTypeInfoImpl)->TypeAttr.guid),
4112 (*ppTypeInfoImpl)->TypeAttr.wTypeFlags);
4114 pMemHeader = (SLTG_MemberHeader*)((char *)pBlk + pTIHeader->elem_table);
4116 pTITail = (SLTG_TypeInfoTail*)((char *)(pMemHeader + 1) + pMemHeader->cbExtra);
4118 (*ppTypeInfoImpl)->TypeAttr.cbAlignment = pTITail->cbAlignment;
4119 (*ppTypeInfoImpl)->TypeAttr.cbSizeInstance = pTITail->cbSizeInstance;
4120 (*ppTypeInfoImpl)->TypeAttr.cbSizeVft = pTITail->cbSizeVft;
4122 switch(pTIHeader->typekind) {
4123 case TKIND_ENUM:
4124 SLTG_ProcessEnum((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
4125 pTIHeader, pTITail);
4126 break;
4128 case TKIND_RECORD:
4129 SLTG_ProcessRecord((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
4130 pTIHeader, pTITail);
4131 break;
4133 case TKIND_INTERFACE:
4134 SLTG_ProcessInterface((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
4135 pTIHeader, pTITail);
4136 break;
4138 case TKIND_COCLASS:
4139 SLTG_ProcessCoClass((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
4140 pTIHeader, pTITail);
4141 break;
4143 case TKIND_ALIAS:
4144 SLTG_ProcessAlias((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
4145 pTIHeader, pTITail);
4146 break;
4148 case TKIND_DISPATCH:
4149 SLTG_ProcessDispatch((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
4150 pTIHeader, pTITail);
4151 break;
4153 case TKIND_MODULE:
4154 SLTG_ProcessModule((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
4155 pTIHeader, pTITail);
4156 break;
4158 default:
4159 FIXME("Not processing typekind %d\n", pTIHeader->typekind);
4160 break;
4164 /* could get cFuncs, cVars and cImplTypes from here
4165 but we've already set those */
4166 #define X(x) TRACE_(typelib)("tt "#x": %x\n",pTITail->res##x);
4167 X(06);
4168 X(16);
4169 X(18);
4170 X(1a);
4171 X(1e);
4172 X(24);
4173 X(26);
4174 X(2a);
4175 X(2c);
4176 X(2e);
4177 X(30);
4178 X(32);
4179 X(34);
4180 #undef X
4181 ++ppTypeInfoImpl;
4182 pBlk = (char*)pBlk + pBlkEntry[order].len;
4185 if(i != pTypeLibImpl->TypeInfoCount) {
4186 FIXME("Somehow processed %d TypeInfos\n", i);
4187 return NULL;
4190 heap_free(pOtherTypeInfoBlks);
4191 return (ITypeLib2*)pTypeLibImpl;
4194 /* ITypeLib::QueryInterface
4196 static HRESULT WINAPI ITypeLib2_fnQueryInterface(
4197 ITypeLib2 * iface,
4198 REFIID riid,
4199 VOID **ppvObject)
4201 ITypeLibImpl *This = (ITypeLibImpl *)iface;
4203 TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
4205 *ppvObject=NULL;
4206 if(IsEqualIID(riid, &IID_IUnknown) ||
4207 IsEqualIID(riid,&IID_ITypeLib)||
4208 IsEqualIID(riid,&IID_ITypeLib2))
4210 *ppvObject = This;
4213 if(*ppvObject)
4215 ITypeLib2_AddRef(iface);
4216 TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
4217 return S_OK;
4219 TRACE("-- Interface: E_NOINTERFACE\n");
4220 return E_NOINTERFACE;
4223 /* ITypeLib::AddRef
4225 static ULONG WINAPI ITypeLib2_fnAddRef( ITypeLib2 *iface)
4227 ITypeLibImpl *This = (ITypeLibImpl *)iface;
4228 ULONG ref = InterlockedIncrement(&This->ref);
4230 TRACE("(%p)->ref was %u\n",This, ref - 1);
4232 return ref;
4235 /* ITypeLib::Release
4237 static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface)
4239 ITypeLibImpl *This = (ITypeLibImpl *)iface;
4240 ULONG ref = InterlockedDecrement(&This->ref);
4242 TRACE("(%p)->(%u)\n",This, ref);
4244 if (!ref)
4246 TLBImpLib *pImpLib, *pImpLibNext;
4247 TLBRefType *ref_type;
4248 void *cursor2;
4249 int i;
4251 /* remove cache entry */
4252 if(This->path)
4254 TRACE("removing from cache list\n");
4255 EnterCriticalSection(&cache_section);
4256 if(This->entry.next)
4257 list_remove(&This->entry);
4258 LeaveCriticalSection(&cache_section);
4259 heap_free(This->path);
4261 TRACE(" destroying ITypeLib(%p)\n",This);
4263 SysFreeString(This->Name);
4264 This->Name = NULL;
4266 SysFreeString(This->DocString);
4267 This->DocString = NULL;
4269 SysFreeString(This->HelpFile);
4270 This->HelpFile = NULL;
4272 SysFreeString(This->HelpStringDll);
4273 This->HelpStringDll = NULL;
4275 TLB_FreeCustData(&This->custdata_list);
4277 for (i = 0; i < This->ctTypeDesc; i++)
4278 if (This->pTypeDesc[i].vt == VT_CARRAY)
4279 heap_free(This->pTypeDesc[i].u.lpadesc);
4281 heap_free(This->pTypeDesc);
4283 LIST_FOR_EACH_ENTRY_SAFE(pImpLib, pImpLibNext, &This->implib_list, TLBImpLib, entry)
4285 if (pImpLib->pImpTypeLib)
4286 ITypeLib_Release((ITypeLib *)pImpLib->pImpTypeLib);
4287 SysFreeString(pImpLib->name);
4289 list_remove(&pImpLib->entry);
4290 heap_free(pImpLib);
4293 LIST_FOR_EACH_ENTRY_SAFE(ref_type, cursor2, &This->ref_list, TLBRefType, entry)
4295 list_remove(&ref_type->entry);
4296 heap_free(ref_type);
4299 for (i = 0; i < This->TypeInfoCount; ++i)
4300 ITypeInfoImpl_Destroy(This->typeinfos[i]);
4301 heap_free(This->typeinfos);
4302 heap_free(This);
4303 return 0;
4306 return ref;
4309 /* ITypeLib::GetTypeInfoCount
4311 * Returns the number of type descriptions in the type library
4313 static UINT WINAPI ITypeLib2_fnGetTypeInfoCount( ITypeLib2 *iface)
4315 ITypeLibImpl *This = (ITypeLibImpl *)iface;
4316 TRACE("(%p)->count is %d\n",This, This->TypeInfoCount);
4317 return This->TypeInfoCount;
4320 /* ITypeLib::GetTypeInfo
4322 * retrieves the specified type description in the library.
4324 static HRESULT WINAPI ITypeLib2_fnGetTypeInfo(
4325 ITypeLib2 *iface,
4326 UINT index,
4327 ITypeInfo **ppTInfo)
4329 ITypeLibImpl *This = (ITypeLibImpl*)iface;
4331 TRACE("%p %u %p\n", This, index, ppTInfo);
4333 if(!ppTInfo)
4334 return E_INVALIDARG;
4336 if(index >= This->TypeInfoCount)
4337 return TYPE_E_ELEMENTNOTFOUND;
4339 *ppTInfo = (ITypeInfo*)This->typeinfos[index];
4340 ITypeInfo_AddRef(*ppTInfo);
4342 return S_OK;
4346 /* ITypeLibs::GetTypeInfoType
4348 * Retrieves the type of a type description.
4350 static HRESULT WINAPI ITypeLib2_fnGetTypeInfoType(
4351 ITypeLib2 *iface,
4352 UINT index,
4353 TYPEKIND *pTKind)
4355 ITypeLibImpl *This = (ITypeLibImpl *)iface;
4357 TRACE("(%p, %d, %p)\n", This, index, pTKind);
4359 if(!pTKind)
4360 return E_INVALIDARG;
4362 if(index >= This->TypeInfoCount)
4363 return TYPE_E_ELEMENTNOTFOUND;
4365 *pTKind = This->typeinfos[index]->TypeAttr.typekind;
4367 return S_OK;
4370 /* ITypeLib::GetTypeInfoOfGuid
4372 * Retrieves the type description that corresponds to the specified GUID.
4375 static HRESULT WINAPI ITypeLib2_fnGetTypeInfoOfGuid(
4376 ITypeLib2 *iface,
4377 REFGUID guid,
4378 ITypeInfo **ppTInfo)
4380 ITypeLibImpl *This = (ITypeLibImpl *)iface;
4381 UINT i;
4383 TRACE("%p %s %p\n", This, debugstr_guid(guid), ppTInfo);
4385 for(i = 0; i < This->TypeInfoCount; ++i){
4386 if(IsEqualIID(&This->typeinfos[i]->TypeAttr.guid, guid)){
4387 *ppTInfo = (ITypeInfo*)This->typeinfos[i];
4388 ITypeInfo_AddRef(*ppTInfo);
4389 return S_OK;
4393 return TYPE_E_ELEMENTNOTFOUND;
4396 /* ITypeLib::GetLibAttr
4398 * Retrieves the structure that contains the library's attributes.
4401 static HRESULT WINAPI ITypeLib2_fnGetLibAttr(
4402 ITypeLib2 *iface,
4403 LPTLIBATTR *attr)
4405 ITypeLibImpl *This = (ITypeLibImpl *)iface;
4407 TRACE("(%p, %p)\n", This, attr);
4409 if (!attr) return E_INVALIDARG;
4411 *attr = heap_alloc(sizeof(**attr));
4412 if (!*attr) return E_OUTOFMEMORY;
4414 **attr = This->LibAttr;
4415 return S_OK;
4418 /* ITypeLib::GetTypeComp
4420 * Enables a client compiler to bind to a library's types, variables,
4421 * constants, and global functions.
4424 static HRESULT WINAPI ITypeLib2_fnGetTypeComp(
4425 ITypeLib2 *iface,
4426 ITypeComp **ppTComp)
4428 ITypeLibImpl *This = (ITypeLibImpl *)iface;
4430 TRACE("(%p)->(%p)\n",This,ppTComp);
4431 *ppTComp = (ITypeComp *)&This->lpVtblTypeComp;
4432 ITypeComp_AddRef(*ppTComp);
4434 return S_OK;
4437 /* ITypeLib::GetDocumentation
4439 * Retrieves the library's documentation string, the complete Help file name
4440 * and path, and the context identifier for the library Help topic in the Help
4441 * file.
4443 * On a successful return all non-null BSTR pointers will have been set,
4444 * possibly to NULL.
4446 static HRESULT WINAPI ITypeLib2_fnGetDocumentation(
4447 ITypeLib2 *iface,
4448 INT index,
4449 BSTR *pBstrName,
4450 BSTR *pBstrDocString,
4451 DWORD *pdwHelpContext,
4452 BSTR *pBstrHelpFile)
4454 ITypeLibImpl *This = (ITypeLibImpl *)iface;
4456 HRESULT result = E_INVALIDARG;
4458 ITypeInfo *pTInfo;
4461 TRACE("(%p) index %d Name(%p) DocString(%p) HelpContext(%p) HelpFile(%p)\n",
4462 This, index,
4463 pBstrName, pBstrDocString,
4464 pdwHelpContext, pBstrHelpFile);
4466 if(index<0)
4468 /* documentation for the typelib */
4469 if(pBstrName)
4471 if (This->Name)
4473 if(!(*pBstrName = SysAllocString(This->Name)))
4474 goto memerr1;
4476 else
4477 *pBstrName = NULL;
4479 if(pBstrDocString)
4481 if (This->DocString)
4483 if(!(*pBstrDocString = SysAllocString(This->DocString)))
4484 goto memerr2;
4486 else if (This->Name)
4488 if(!(*pBstrDocString = SysAllocString(This->Name)))
4489 goto memerr2;
4491 else
4492 *pBstrDocString = NULL;
4494 if(pdwHelpContext)
4496 *pdwHelpContext = This->dwHelpContext;
4498 if(pBstrHelpFile)
4500 if (This->HelpFile)
4502 if(!(*pBstrHelpFile = SysAllocString(This->HelpFile)))
4503 goto memerr3;
4505 else
4506 *pBstrHelpFile = NULL;
4509 result = S_OK;
4511 else
4513 /* for a typeinfo */
4514 result = ITypeLib2_fnGetTypeInfo(iface, index, &pTInfo);
4516 if(SUCCEEDED(result))
4518 result = ITypeInfo_GetDocumentation(pTInfo,
4519 MEMBERID_NIL,
4520 pBstrName,
4521 pBstrDocString,
4522 pdwHelpContext, pBstrHelpFile);
4524 ITypeInfo_Release(pTInfo);
4527 return result;
4528 memerr3:
4529 if (pBstrDocString) SysFreeString (*pBstrDocString);
4530 memerr2:
4531 if (pBstrName) SysFreeString (*pBstrName);
4532 memerr1:
4533 return STG_E_INSUFFICIENTMEMORY;
4536 /* ITypeLib::IsName
4538 * Indicates whether a passed-in string contains the name of a type or member
4539 * described in the library.
4542 static HRESULT WINAPI ITypeLib2_fnIsName(
4543 ITypeLib2 *iface,
4544 LPOLESTR szNameBuf,
4545 ULONG lHashVal,
4546 BOOL *pfName)
4548 ITypeLibImpl *This = (ITypeLibImpl *)iface;
4549 UINT nNameBufLen = (lstrlenW(szNameBuf)+1)*sizeof(WCHAR), tic, fdc, vrc, pc;
4551 TRACE("(%p)->(%s,%08x,%p)\n", This, debugstr_w(szNameBuf), lHashVal,
4552 pfName);
4554 *pfName=TRUE;
4555 for(tic = 0; tic < This->TypeInfoCount; ++tic){
4556 ITypeInfoImpl *pTInfo = This->typeinfos[tic];
4557 if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
4558 for(fdc = 0; fdc < pTInfo->TypeAttr.cFuncs; ++fdc) {
4559 TLBFuncDesc *pFInfo = &pTInfo->funcdescs[fdc];
4560 if(!memcmp(szNameBuf,pFInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
4561 for(pc=0; pc < pFInfo->funcdesc.cParams; pc++)
4562 if(!memcmp(szNameBuf,pFInfo->pParamDesc[pc].Name, nNameBufLen))
4563 goto ITypeLib2_fnIsName_exit;
4565 for(vrc = 0; vrc < pTInfo->TypeAttr.cVars; ++vrc){
4566 TLBVarDesc *pVInfo = &pTInfo->vardescs[vrc];
4567 if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
4571 *pfName=FALSE;
4573 ITypeLib2_fnIsName_exit:
4574 TRACE("(%p)slow! search for %s: %s found!\n", This,
4575 debugstr_w(szNameBuf), *pfName?"NOT":"");
4577 return S_OK;
4580 /* ITypeLib::FindName
4582 * Finds occurrences of a type description in a type library. This may be used
4583 * to quickly verify that a name exists in a type library.
4586 static HRESULT WINAPI ITypeLib2_fnFindName(
4587 ITypeLib2 *iface,
4588 LPOLESTR szNameBuf,
4589 ULONG lHashVal,
4590 ITypeInfo **ppTInfo,
4591 MEMBERID *rgMemId,
4592 UINT16 *pcFound)
4594 ITypeLibImpl *This = (ITypeLibImpl *)iface;
4595 TLBVarDesc *pVInfo;
4596 UINT tic, fdc, pc, count = 0;
4597 UINT nNameBufLen = (lstrlenW(szNameBuf)+1)*sizeof(WCHAR);
4599 for(tic = 0; tic < This->TypeInfoCount; ++tic){
4600 ITypeInfoImpl *pTInfo = This->typeinfos[tic];
4601 if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit;
4602 for(fdc = 0; fdc < pTInfo->TypeAttr.cFuncs; ++fdc) {
4603 TLBFuncDesc *pFInfo = &pTInfo->funcdescs[fdc];
4604 if(!memcmp(szNameBuf,pFInfo->Name,nNameBufLen)) goto ITypeLib2_fnFindName_exit;
4605 for(pc = 0;pc < pFInfo->funcdesc.cParams; pc++) {
4606 if(!memcmp(szNameBuf,pFInfo->pParamDesc[pc].Name,nNameBufLen))
4607 goto ITypeLib2_fnFindName_exit;
4611 pVInfo = TLB_get_vardesc_by_name(pTInfo->vardescs, pTInfo->TypeAttr.cVars, szNameBuf);
4612 if(pVInfo)
4613 goto ITypeLib2_fnFindName_exit;
4615 continue;
4616 ITypeLib2_fnFindName_exit:
4617 ITypeInfo_AddRef((ITypeInfo*)pTInfo);
4618 ppTInfo[count]=(LPTYPEINFO)pTInfo;
4619 count++;
4621 TRACE("(%p)slow! search for %d with %s: found %d TypeInfos!\n",
4622 This, *pcFound, debugstr_w(szNameBuf), count);
4624 *pcFound = count;
4626 return S_OK;
4629 /* ITypeLib::ReleaseTLibAttr
4631 * Releases the TLIBATTR originally obtained from ITypeLib::GetLibAttr.
4634 static VOID WINAPI ITypeLib2_fnReleaseTLibAttr(
4635 ITypeLib2 *iface,
4636 TLIBATTR *pTLibAttr)
4638 ITypeLibImpl *This = (ITypeLibImpl *)iface;
4639 TRACE("freeing (%p)\n",This);
4640 heap_free(pTLibAttr);
4644 /* ITypeLib2::GetCustData
4646 * gets the custom data
4648 static HRESULT WINAPI ITypeLib2_fnGetCustData(
4649 ITypeLib2 * iface,
4650 REFGUID guid,
4651 VARIANT *pVarVal)
4653 ITypeLibImpl *This = (ITypeLibImpl *)iface;
4654 TLBCustData *pCData;
4656 TRACE("%p %s %p\n", This, debugstr_guid(guid), pVarVal);
4658 pCData = TLB_get_custdata_by_guid(&This->custdata_list, guid);
4659 if(!pCData)
4660 return TYPE_E_ELEMENTNOTFOUND;
4662 VariantInit(pVarVal);
4663 VariantCopy(pVarVal, &pCData->data);
4665 return S_OK;
4668 /* ITypeLib2::GetLibStatistics
4670 * Returns statistics about a type library that are required for efficient
4671 * sizing of hash tables.
4674 static HRESULT WINAPI ITypeLib2_fnGetLibStatistics(
4675 ITypeLib2 * iface,
4676 ULONG *pcUniqueNames,
4677 ULONG *pcchUniqueNames)
4679 ITypeLibImpl *This = (ITypeLibImpl *)iface;
4681 FIXME("(%p): stub!\n", This);
4683 if(pcUniqueNames) *pcUniqueNames=1;
4684 if(pcchUniqueNames) *pcchUniqueNames=1;
4685 return S_OK;
4688 /* ITypeLib2::GetDocumentation2
4690 * Retrieves the library's documentation string, the complete Help file name
4691 * and path, the localization context to use, and the context ID for the
4692 * library Help topic in the Help file.
4695 static HRESULT WINAPI ITypeLib2_fnGetDocumentation2(
4696 ITypeLib2 * iface,
4697 INT index,
4698 LCID lcid,
4699 BSTR *pbstrHelpString,
4700 DWORD *pdwHelpStringContext,
4701 BSTR *pbstrHelpStringDll)
4703 ITypeLibImpl *This = (ITypeLibImpl *)iface;
4704 HRESULT result;
4705 ITypeInfo *pTInfo;
4707 FIXME("(%p) index %d lcid %d half implemented stub!\n", This, index, lcid);
4709 /* the help string should be obtained from the helpstringdll,
4710 * using the _DLLGetDocumentation function, based on the supplied
4711 * lcid. Nice to do sometime...
4713 if(index<0)
4715 /* documentation for the typelib */
4716 if(pbstrHelpString)
4717 *pbstrHelpString=SysAllocString(This->DocString);
4718 if(pdwHelpStringContext)
4719 *pdwHelpStringContext=This->dwHelpContext;
4720 if(pbstrHelpStringDll)
4721 *pbstrHelpStringDll=SysAllocString(This->HelpStringDll);
4723 result = S_OK;
4725 else
4727 /* for a typeinfo */
4728 result=ITypeLib2_GetTypeInfo(iface, index, &pTInfo);
4730 if(SUCCEEDED(result))
4732 ITypeInfo2 * pTInfo2;
4733 result = ITypeInfo_QueryInterface(pTInfo,
4734 &IID_ITypeInfo2,
4735 (LPVOID*) &pTInfo2);
4737 if(SUCCEEDED(result))
4739 result = ITypeInfo2_GetDocumentation2(pTInfo2,
4740 MEMBERID_NIL,
4741 lcid,
4742 pbstrHelpString,
4743 pdwHelpStringContext,
4744 pbstrHelpStringDll);
4746 ITypeInfo2_Release(pTInfo2);
4749 ITypeInfo_Release(pTInfo);
4752 return result;
4755 static HRESULT TLB_copy_all_custdata(struct list *custdata_list, CUSTDATA *pCustData)
4757 TLBCustData *pCData;
4758 unsigned int ct;
4759 CUSTDATAITEM *cdi;
4761 ct = list_count(custdata_list);
4763 pCustData->prgCustData = heap_alloc_zero(ct * sizeof(CUSTDATAITEM));
4764 if(!pCustData->prgCustData)
4765 return E_OUTOFMEMORY;
4767 pCustData->cCustData = ct;
4769 cdi = pCustData->prgCustData;
4770 LIST_FOR_EACH_ENTRY(pCData, custdata_list, TLBCustData, entry){
4771 cdi->guid = pCData->guid;
4772 VariantCopy(&cdi->varValue, &pCData->data);
4773 ++cdi;
4776 return S_OK;
4780 /* ITypeLib2::GetAllCustData
4782 * Gets all custom data items for the library.
4785 static HRESULT WINAPI ITypeLib2_fnGetAllCustData(
4786 ITypeLib2 * iface,
4787 CUSTDATA *pCustData)
4789 ITypeLibImpl *This = (ITypeLibImpl *)iface;
4790 TRACE("%p %p\n", iface, pCustData);
4791 return TLB_copy_all_custdata(&This->custdata_list, pCustData);
4794 static const ITypeLib2Vtbl tlbvt = {
4795 ITypeLib2_fnQueryInterface,
4796 ITypeLib2_fnAddRef,
4797 ITypeLib2_fnRelease,
4798 ITypeLib2_fnGetTypeInfoCount,
4799 ITypeLib2_fnGetTypeInfo,
4800 ITypeLib2_fnGetTypeInfoType,
4801 ITypeLib2_fnGetTypeInfoOfGuid,
4802 ITypeLib2_fnGetLibAttr,
4803 ITypeLib2_fnGetTypeComp,
4804 ITypeLib2_fnGetDocumentation,
4805 ITypeLib2_fnIsName,
4806 ITypeLib2_fnFindName,
4807 ITypeLib2_fnReleaseTLibAttr,
4809 ITypeLib2_fnGetCustData,
4810 ITypeLib2_fnGetLibStatistics,
4811 ITypeLib2_fnGetDocumentation2,
4812 ITypeLib2_fnGetAllCustData
4816 static HRESULT WINAPI ITypeLibComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
4818 ITypeLibImpl *This = impl_from_ITypeComp(iface);
4820 return ITypeLib2_QueryInterface((ITypeLib *)This, riid, ppv);
4823 static ULONG WINAPI ITypeLibComp_fnAddRef(ITypeComp * iface)
4825 ITypeLibImpl *This = impl_from_ITypeComp(iface);
4827 return ITypeLib2_AddRef((ITypeLib2 *)This);
4830 static ULONG WINAPI ITypeLibComp_fnRelease(ITypeComp * iface)
4832 ITypeLibImpl *This = impl_from_ITypeComp(iface);
4834 return ITypeLib2_Release((ITypeLib2 *)This);
4837 static HRESULT WINAPI ITypeLibComp_fnBind(
4838 ITypeComp * iface,
4839 OLECHAR * szName,
4840 ULONG lHash,
4841 WORD wFlags,
4842 ITypeInfo ** ppTInfo,
4843 DESCKIND * pDescKind,
4844 BINDPTR * pBindPtr)
4846 ITypeLibImpl *This = impl_from_ITypeComp(iface);
4847 int typemismatch=0, i;
4849 TRACE("(%s, 0x%x, 0x%x, %p, %p, %p)\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
4851 *pDescKind = DESCKIND_NONE;
4852 pBindPtr->lptcomp = NULL;
4853 *ppTInfo = NULL;
4855 for(i = 0; i < This->TypeInfoCount; ++i){
4856 ITypeInfoImpl *pTypeInfo = This->typeinfos[i];
4857 TRACE("testing %s\n", debugstr_w(pTypeInfo->Name));
4859 /* FIXME: check wFlags here? */
4860 /* FIXME: we should use a hash table to look this info up using lHash
4861 * instead of an O(n) search */
4862 if ((pTypeInfo->TypeAttr.typekind == TKIND_ENUM) ||
4863 (pTypeInfo->TypeAttr.typekind == TKIND_MODULE))
4865 if (pTypeInfo->Name && !strcmpW(pTypeInfo->Name, szName))
4867 *pDescKind = DESCKIND_TYPECOMP;
4868 pBindPtr->lptcomp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4869 ITypeComp_AddRef(pBindPtr->lptcomp);
4870 TRACE("module or enum: %s\n", debugstr_w(szName));
4871 return S_OK;
4875 if ((pTypeInfo->TypeAttr.typekind == TKIND_MODULE) ||
4876 (pTypeInfo->TypeAttr.typekind == TKIND_ENUM))
4878 ITypeComp *pSubTypeComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4879 HRESULT hr;
4881 hr = ITypeComp_Bind(pSubTypeComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
4882 if (SUCCEEDED(hr) && (*pDescKind != DESCKIND_NONE))
4884 TRACE("found in module or in enum: %s\n", debugstr_w(szName));
4885 return S_OK;
4887 else if (hr == TYPE_E_TYPEMISMATCH)
4888 typemismatch = 1;
4891 if ((pTypeInfo->TypeAttr.typekind == TKIND_COCLASS) &&
4892 (pTypeInfo->TypeAttr.wTypeFlags & TYPEFLAG_FAPPOBJECT))
4894 ITypeComp *pSubTypeComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
4895 HRESULT hr;
4896 ITypeInfo *subtypeinfo;
4897 BINDPTR subbindptr;
4898 DESCKIND subdesckind;
4900 hr = ITypeComp_Bind(pSubTypeComp, szName, lHash, wFlags,
4901 &subtypeinfo, &subdesckind, &subbindptr);
4902 if (SUCCEEDED(hr) && (subdesckind != DESCKIND_NONE))
4904 TYPEDESC tdesc_appobject;
4905 const VARDESC vardesc_appobject =
4907 -2, /* memid */
4908 NULL, /* lpstrSchema */
4910 0 /* oInst */
4913 /* ELEMDESC */
4915 /* TYPEDESC */
4917 &tdesc_appobject
4919 VT_PTR
4922 0, /* wVarFlags */
4923 VAR_STATIC /* varkind */
4926 tdesc_appobject.u.hreftype = pTypeInfo->hreftype;
4927 tdesc_appobject.vt = VT_USERDEFINED;
4929 TRACE("found in implicit app object: %s\n", debugstr_w(szName));
4931 /* cleanup things filled in by Bind call so we can put our
4932 * application object data in there instead */
4933 switch (subdesckind)
4935 case DESCKIND_FUNCDESC:
4936 ITypeInfo_ReleaseFuncDesc(subtypeinfo, subbindptr.lpfuncdesc);
4937 break;
4938 case DESCKIND_VARDESC:
4939 ITypeInfo_ReleaseVarDesc(subtypeinfo, subbindptr.lpvardesc);
4940 break;
4941 default:
4942 break;
4944 if (subtypeinfo) ITypeInfo_Release(subtypeinfo);
4946 if (pTypeInfo->hreftype == -1)
4947 FIXME("no hreftype for interface %p\n", pTypeInfo);
4949 hr = TLB_AllocAndInitVarDesc(&vardesc_appobject, &pBindPtr->lpvardesc);
4950 if (FAILED(hr))
4951 return hr;
4953 *pDescKind = DESCKIND_IMPLICITAPPOBJ;
4954 *ppTInfo = (ITypeInfo *)pTypeInfo;
4955 ITypeInfo_AddRef(*ppTInfo);
4956 return S_OK;
4958 else if (hr == TYPE_E_TYPEMISMATCH)
4959 typemismatch = 1;
4963 if (typemismatch)
4965 TRACE("type mismatch %s\n", debugstr_w(szName));
4966 return TYPE_E_TYPEMISMATCH;
4968 else
4970 TRACE("name not found %s\n", debugstr_w(szName));
4971 return S_OK;
4975 static HRESULT WINAPI ITypeLibComp_fnBindType(
4976 ITypeComp * iface,
4977 OLECHAR * szName,
4978 ULONG lHash,
4979 ITypeInfo ** ppTInfo,
4980 ITypeComp ** ppTComp)
4982 ITypeLibImpl *This = impl_from_ITypeComp(iface);
4983 UINT i;
4985 TRACE("(%s, %x, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
4987 if(!szName || !ppTInfo || !ppTComp)
4988 return E_INVALIDARG;
4990 for(i = 0; i < This->TypeInfoCount; ++i)
4992 ITypeInfoImpl *pTypeInfo = This->typeinfos[i];
4993 /* FIXME: should use lHash to do the search */
4994 if (pTypeInfo->Name && !strcmpiW(pTypeInfo->Name, szName))
4996 TRACE("returning %p\n", pTypeInfo);
4997 *ppTInfo = (ITypeInfo *)&pTypeInfo->lpVtbl;
4998 ITypeInfo_AddRef(*ppTInfo);
4999 *ppTComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
5000 ITypeComp_AddRef(*ppTComp);
5001 return S_OK;
5005 TRACE("not found\n");
5006 *ppTInfo = NULL;
5007 *ppTComp = NULL;
5008 return S_OK;
5011 static const ITypeCompVtbl tlbtcvt =
5014 ITypeLibComp_fnQueryInterface,
5015 ITypeLibComp_fnAddRef,
5016 ITypeLibComp_fnRelease,
5018 ITypeLibComp_fnBind,
5019 ITypeLibComp_fnBindType
5022 /*================== ITypeInfo(2) Methods ===================================*/
5023 static ITypeInfoImpl* ITypeInfoImpl_Constructor(void)
5025 ITypeInfoImpl *pTypeInfoImpl;
5027 pTypeInfoImpl = heap_alloc_zero(sizeof(ITypeInfoImpl));
5028 if (pTypeInfoImpl)
5030 pTypeInfoImpl->lpVtbl = &tinfvt;
5031 pTypeInfoImpl->lpVtblTypeComp = &tcompvt;
5032 pTypeInfoImpl->ref = 0;
5033 pTypeInfoImpl->hreftype = -1;
5034 pTypeInfoImpl->TypeAttr.memidConstructor = MEMBERID_NIL;
5035 pTypeInfoImpl->TypeAttr.memidDestructor = MEMBERID_NIL;
5036 list_init(&pTypeInfoImpl->custdata_list);
5038 TRACE("(%p)\n", pTypeInfoImpl);
5039 return pTypeInfoImpl;
5042 /* ITypeInfo::QueryInterface
5044 static HRESULT WINAPI ITypeInfo_fnQueryInterface(
5045 ITypeInfo2 *iface,
5046 REFIID riid,
5047 VOID **ppvObject)
5049 ITypeLibImpl *This = (ITypeLibImpl *)iface;
5051 TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
5053 *ppvObject=NULL;
5054 if(IsEqualIID(riid, &IID_IUnknown) ||
5055 IsEqualIID(riid,&IID_ITypeInfo)||
5056 IsEqualIID(riid,&IID_ITypeInfo2))
5057 *ppvObject = This;
5059 if(*ppvObject){
5060 ITypeInfo_AddRef(iface);
5061 TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
5062 return S_OK;
5064 TRACE("-- Interface: E_NOINTERFACE\n");
5065 return E_NOINTERFACE;
5068 /* ITypeInfo::AddRef
5070 static ULONG WINAPI ITypeInfo_fnAddRef( ITypeInfo2 *iface)
5072 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5073 ULONG ref = InterlockedIncrement(&This->ref);
5075 TRACE("(%p)->ref is %u\n",This, ref);
5077 if (ref == 1 /* incremented from 0 */)
5078 ITypeLib2_AddRef((ITypeLib2*)This->pTypeLib);
5080 return ref;
5083 static void ITypeInfoImpl_Destroy(ITypeInfoImpl *This)
5085 UINT i, j;
5087 TRACE("destroying ITypeInfo(%p)\n",This);
5089 SysFreeString(This->Name);
5090 This->Name = NULL;
5092 SysFreeString(This->DocString);
5093 This->DocString = NULL;
5095 SysFreeString(This->DllName);
5096 This->DllName = NULL;
5098 for (i = 0; i < This->TypeAttr.cFuncs; ++i)
5100 TLBFuncDesc *pFInfo = &This->funcdescs[i];
5101 for(j = 0; j < pFInfo->funcdesc.cParams; j++)
5103 ELEMDESC *elemdesc = &pFInfo->funcdesc.lprgelemdescParam[j];
5104 if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
5106 VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue);
5107 heap_free(elemdesc->u.paramdesc.pparamdescex);
5109 TLB_FreeCustData(&pFInfo->pParamDesc[j].custdata_list);
5110 SysFreeString(pFInfo->pParamDesc[j].Name);
5112 heap_free(pFInfo->funcdesc.lprgelemdescParam);
5113 heap_free(pFInfo->pParamDesc);
5114 TLB_FreeCustData(&pFInfo->custdata_list);
5115 if (!IS_INTRESOURCE(pFInfo->Entry) && pFInfo->Entry != (BSTR)-1)
5116 SysFreeString(pFInfo->Entry);
5117 SysFreeString(pFInfo->HelpString);
5118 SysFreeString(pFInfo->Name);
5120 heap_free(This->funcdescs);
5122 for(i = 0; i < This->TypeAttr.cVars; ++i)
5124 TLBVarDesc *pVInfo = &This->vardescs[i];
5125 if (pVInfo->vardesc.varkind == VAR_CONST)
5127 VariantClear(pVInfo->vardesc.u.lpvarValue);
5128 heap_free(pVInfo->vardesc.u.lpvarValue);
5130 TLB_FreeCustData(&pVInfo->custdata_list);
5131 SysFreeString(pVInfo->Name);
5132 SysFreeString(pVInfo->HelpString);
5134 heap_free(This->vardescs);
5136 if(This->impltypes){
5137 for (i = 0; i < This->TypeAttr.cImplTypes; ++i){
5138 TLBImplType *pImpl = &This->impltypes[i];
5139 TLB_FreeCustData(&pImpl->custdata_list);
5141 heap_free(This->impltypes);
5144 TLB_FreeCustData(&This->custdata_list);
5146 heap_free(This);
5149 /* ITypeInfo::Release
5151 static ULONG WINAPI ITypeInfo_fnRelease(ITypeInfo2 *iface)
5153 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5154 ULONG ref = InterlockedDecrement(&This->ref);
5156 TRACE("(%p)->(%u)\n",This, ref);
5158 if (!ref)
5160 BOOL not_attached_to_typelib = This->not_attached_to_typelib;
5161 ITypeLib2_Release((ITypeLib2*)This->pTypeLib);
5162 if (not_attached_to_typelib)
5163 heap_free(This);
5164 /* otherwise This will be freed when typelib is freed */
5167 return ref;
5170 /* ITypeInfo::GetTypeAttr
5172 * Retrieves a TYPEATTR structure that contains the attributes of the type
5173 * description.
5176 static HRESULT WINAPI ITypeInfo_fnGetTypeAttr( ITypeInfo2 *iface,
5177 LPTYPEATTR *ppTypeAttr)
5179 const ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5180 SIZE_T size;
5182 TRACE("(%p)\n",This);
5184 size = sizeof(**ppTypeAttr);
5185 if (This->TypeAttr.typekind == TKIND_ALIAS)
5186 size += TLB_SizeTypeDesc(&This->TypeAttr.tdescAlias, FALSE);
5188 *ppTypeAttr = heap_alloc(size);
5189 if (!*ppTypeAttr)
5190 return E_OUTOFMEMORY;
5192 **ppTypeAttr = This->TypeAttr;
5194 if (This->TypeAttr.typekind == TKIND_ALIAS)
5195 TLB_CopyTypeDesc(&(*ppTypeAttr)->tdescAlias,
5196 &This->TypeAttr.tdescAlias, *ppTypeAttr + 1);
5198 if((*ppTypeAttr)->typekind == TKIND_DISPATCH) {
5199 /* This should include all the inherited funcs */
5200 (*ppTypeAttr)->cFuncs = (*ppTypeAttr)->cbSizeVft / sizeof(void *);
5201 /* This is always the size of IDispatch's vtbl */
5202 (*ppTypeAttr)->cbSizeVft = sizeof(IDispatchVtbl);
5203 (*ppTypeAttr)->wTypeFlags &= ~TYPEFLAG_FOLEAUTOMATION;
5205 return S_OK;
5208 /* ITypeInfo::GetTypeComp
5210 * Retrieves the ITypeComp interface for the type description, which enables a
5211 * client compiler to bind to the type description's members.
5214 static HRESULT WINAPI ITypeInfo_fnGetTypeComp( ITypeInfo2 *iface,
5215 ITypeComp * *ppTComp)
5217 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5219 TRACE("(%p)->(%p)\n", This, ppTComp);
5221 *ppTComp = (ITypeComp *)&This->lpVtblTypeComp;
5222 ITypeComp_AddRef(*ppTComp);
5223 return S_OK;
5226 static SIZE_T TLB_SizeElemDesc( const ELEMDESC *elemdesc )
5228 SIZE_T size = TLB_SizeTypeDesc(&elemdesc->tdesc, FALSE);
5229 if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
5230 size += sizeof(*elemdesc->u.paramdesc.pparamdescex);
5231 return size;
5234 static HRESULT TLB_CopyElemDesc( const ELEMDESC *src, ELEMDESC *dest, char **buffer )
5236 *dest = *src;
5237 *buffer = TLB_CopyTypeDesc(&dest->tdesc, &src->tdesc, *buffer);
5238 if (src->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
5240 const PARAMDESCEX *pparamdescex_src = src->u.paramdesc.pparamdescex;
5241 PARAMDESCEX *pparamdescex_dest = dest->u.paramdesc.pparamdescex = (PARAMDESCEX *)*buffer;
5242 *buffer += sizeof(PARAMDESCEX);
5243 *pparamdescex_dest = *pparamdescex_src;
5244 VariantInit(&pparamdescex_dest->varDefaultValue);
5245 return VariantCopy(&pparamdescex_dest->varDefaultValue,
5246 (VARIANTARG *)&pparamdescex_src->varDefaultValue);
5248 else
5249 dest->u.paramdesc.pparamdescex = NULL;
5250 return S_OK;
5253 static void TLB_FreeElemDesc( ELEMDESC *elemdesc )
5255 if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
5256 VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue);
5259 static HRESULT TLB_AllocAndInitFuncDesc( const FUNCDESC *src, FUNCDESC **dest_ptr, BOOL dispinterface )
5261 FUNCDESC *dest;
5262 char *buffer;
5263 SIZE_T size = sizeof(*src);
5264 SHORT i;
5265 HRESULT hr;
5267 size += sizeof(*src->lprgscode) * src->cScodes;
5268 size += TLB_SizeElemDesc(&src->elemdescFunc);
5269 for (i = 0; i < src->cParams; i++)
5271 size += sizeof(ELEMDESC);
5272 size += TLB_SizeElemDesc(&src->lprgelemdescParam[i]);
5275 dest = (FUNCDESC *)SysAllocStringByteLen(NULL, size);
5276 if (!dest) return E_OUTOFMEMORY;
5278 *dest = *src;
5279 if (dispinterface) /* overwrite funckind */
5280 dest->funckind = FUNC_DISPATCH;
5281 buffer = (char *)(dest + 1);
5283 dest->lprgscode = (SCODE *)buffer;
5284 memcpy(dest->lprgscode, src->lprgscode, sizeof(*src->lprgscode) * src->cScodes);
5285 buffer += sizeof(*src->lprgscode) * src->cScodes;
5287 hr = TLB_CopyElemDesc(&src->elemdescFunc, &dest->elemdescFunc, &buffer);
5288 if (FAILED(hr))
5290 SysFreeString((BSTR)dest);
5291 return hr;
5294 dest->lprgelemdescParam = (ELEMDESC *)buffer;
5295 buffer += sizeof(ELEMDESC) * src->cParams;
5296 for (i = 0; i < src->cParams; i++)
5298 hr = TLB_CopyElemDesc(&src->lprgelemdescParam[i], &dest->lprgelemdescParam[i], &buffer);
5299 if (FAILED(hr))
5300 break;
5302 if (FAILED(hr))
5304 /* undo the above actions */
5305 for (i = i - 1; i >= 0; i--)
5306 TLB_FreeElemDesc(&dest->lprgelemdescParam[i]);
5307 TLB_FreeElemDesc(&dest->elemdescFunc);
5308 SysFreeString((BSTR)dest);
5309 return hr;
5312 /* special treatment for dispinterfaces: this makes functions appear
5313 * to return their [retval] value when it is really returning an
5314 * HRESULT */
5315 if (dispinterface && dest->elemdescFunc.tdesc.vt == VT_HRESULT)
5317 if (dest->cParams &&
5318 (dest->lprgelemdescParam[dest->cParams - 1].u.paramdesc.wParamFlags & PARAMFLAG_FRETVAL))
5320 ELEMDESC *elemdesc = &dest->lprgelemdescParam[dest->cParams - 1];
5321 if (elemdesc->tdesc.vt != VT_PTR)
5323 ERR("elemdesc should have started with VT_PTR instead of:\n");
5324 if (ERR_ON(ole))
5325 dump_ELEMDESC(elemdesc);
5326 return E_UNEXPECTED;
5329 /* copy last parameter to the return value. we are using a flat
5330 * buffer so there is no danger of leaking memory in
5331 * elemdescFunc */
5332 dest->elemdescFunc.tdesc = *elemdesc->tdesc.u.lptdesc;
5334 /* remove the last parameter */
5335 dest->cParams--;
5337 else
5338 /* otherwise this function is made to appear to have no return
5339 * value */
5340 dest->elemdescFunc.tdesc.vt = VT_VOID;
5344 *dest_ptr = dest;
5345 return S_OK;
5348 HRESULT ITypeInfoImpl_GetInternalFuncDesc( ITypeInfo *iface, UINT index, const FUNCDESC **ppFuncDesc )
5350 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5352 if (index >= This->TypeAttr.cFuncs)
5353 return TYPE_E_ELEMENTNOTFOUND;
5355 *ppFuncDesc = &This->funcdescs[index].funcdesc;
5356 return S_OK;
5359 /* internal function to make the inherited interfaces' methods appear
5360 * part of the interface */
5361 static HRESULT ITypeInfoImpl_GetInternalDispatchFuncDesc( ITypeInfo *iface,
5362 UINT index, const FUNCDESC **ppFuncDesc, UINT *funcs, UINT *hrefoffset)
5364 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5365 HRESULT hr;
5366 UINT implemented_funcs = 0;
5368 if (funcs)
5369 *funcs = 0;
5370 else
5371 *hrefoffset = DISPATCH_HREF_OFFSET;
5373 if(This->impltypes)
5375 ITypeInfo *pSubTypeInfo;
5376 UINT sub_funcs;
5378 hr = ITypeInfo_GetRefTypeInfo(iface, This->impltypes[0].hRef, &pSubTypeInfo);
5379 if (FAILED(hr))
5380 return hr;
5382 hr = ITypeInfoImpl_GetInternalDispatchFuncDesc(pSubTypeInfo,
5383 index,
5384 ppFuncDesc,
5385 &sub_funcs, hrefoffset);
5386 implemented_funcs += sub_funcs;
5387 ITypeInfo_Release(pSubTypeInfo);
5388 if (SUCCEEDED(hr))
5389 return hr;
5390 *hrefoffset += DISPATCH_HREF_OFFSET;
5393 if (funcs)
5394 *funcs = implemented_funcs + This->TypeAttr.cFuncs;
5395 else
5396 *hrefoffset = 0;
5398 if (index < implemented_funcs)
5399 return E_INVALIDARG;
5400 return ITypeInfoImpl_GetInternalFuncDesc(iface, index - implemented_funcs,
5401 ppFuncDesc);
5404 static inline void ITypeInfoImpl_ElemDescAddHrefOffset( LPELEMDESC pElemDesc, UINT hrefoffset)
5406 TYPEDESC *pTypeDesc = &pElemDesc->tdesc;
5407 while (TRUE)
5409 switch (pTypeDesc->vt)
5411 case VT_USERDEFINED:
5412 pTypeDesc->u.hreftype += hrefoffset;
5413 return;
5414 case VT_PTR:
5415 case VT_SAFEARRAY:
5416 pTypeDesc = pTypeDesc->u.lptdesc;
5417 break;
5418 case VT_CARRAY:
5419 pTypeDesc = &pTypeDesc->u.lpadesc->tdescElem;
5420 break;
5421 default:
5422 return;
5427 static inline void ITypeInfoImpl_FuncDescAddHrefOffset( LPFUNCDESC pFuncDesc, UINT hrefoffset)
5429 SHORT i;
5430 for (i = 0; i < pFuncDesc->cParams; i++)
5431 ITypeInfoImpl_ElemDescAddHrefOffset(&pFuncDesc->lprgelemdescParam[i], hrefoffset);
5432 ITypeInfoImpl_ElemDescAddHrefOffset(&pFuncDesc->elemdescFunc, hrefoffset);
5435 /* ITypeInfo::GetFuncDesc
5437 * Retrieves the FUNCDESC structure that contains information about a
5438 * specified function.
5441 static HRESULT WINAPI ITypeInfo_fnGetFuncDesc( ITypeInfo2 *iface, UINT index,
5442 LPFUNCDESC *ppFuncDesc)
5444 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5445 const FUNCDESC *internal_funcdesc;
5446 HRESULT hr;
5447 UINT hrefoffset = 0;
5449 TRACE("(%p) index %d\n", This, index);
5451 if (This->TypeAttr.typekind == TKIND_DISPATCH)
5452 hr = ITypeInfoImpl_GetInternalDispatchFuncDesc((ITypeInfo *)iface, index,
5453 &internal_funcdesc, NULL,
5454 &hrefoffset);
5455 else
5456 hr = ITypeInfoImpl_GetInternalFuncDesc((ITypeInfo *)iface, index,
5457 &internal_funcdesc);
5458 if (FAILED(hr))
5460 WARN("description for function %d not found\n", index);
5461 return hr;
5464 hr = TLB_AllocAndInitFuncDesc(
5465 internal_funcdesc,
5466 ppFuncDesc,
5467 This->TypeAttr.typekind == TKIND_DISPATCH);
5469 if ((This->TypeAttr.typekind == TKIND_DISPATCH) && hrefoffset)
5470 ITypeInfoImpl_FuncDescAddHrefOffset(*ppFuncDesc, hrefoffset);
5472 TRACE("-- 0x%08x\n", hr);
5473 return hr;
5476 static HRESULT TLB_AllocAndInitVarDesc( const VARDESC *src, VARDESC **dest_ptr )
5478 VARDESC *dest;
5479 char *buffer;
5480 SIZE_T size = sizeof(*src);
5481 HRESULT hr;
5483 if (src->lpstrSchema) size += (strlenW(src->lpstrSchema) + 1) * sizeof(WCHAR);
5484 if (src->varkind == VAR_CONST)
5485 size += sizeof(VARIANT);
5486 size += TLB_SizeElemDesc(&src->elemdescVar);
5488 dest = (VARDESC *)SysAllocStringByteLen(NULL, size);
5489 if (!dest) return E_OUTOFMEMORY;
5491 *dest = *src;
5492 buffer = (char *)(dest + 1);
5493 if (src->lpstrSchema)
5495 int len;
5496 dest->lpstrSchema = (LPOLESTR)buffer;
5497 len = strlenW(src->lpstrSchema);
5498 memcpy(dest->lpstrSchema, src->lpstrSchema, (len + 1) * sizeof(WCHAR));
5499 buffer += (len + 1) * sizeof(WCHAR);
5502 if (src->varkind == VAR_CONST)
5504 HRESULT hr;
5506 dest->u.lpvarValue = (VARIANT *)buffer;
5507 *dest->u.lpvarValue = *src->u.lpvarValue;
5508 buffer += sizeof(VARIANT);
5509 VariantInit(dest->u.lpvarValue);
5510 hr = VariantCopy(dest->u.lpvarValue, src->u.lpvarValue);
5511 if (FAILED(hr))
5513 SysFreeString((BSTR)dest);
5514 return hr;
5517 hr = TLB_CopyElemDesc(&src->elemdescVar, &dest->elemdescVar, &buffer);
5518 if (FAILED(hr))
5520 if (src->varkind == VAR_CONST)
5521 VariantClear(dest->u.lpvarValue);
5522 SysFreeString((BSTR)dest);
5523 return hr;
5525 *dest_ptr = dest;
5526 return S_OK;
5529 /* ITypeInfo::GetVarDesc
5531 * Retrieves a VARDESC structure that describes the specified variable.
5534 static HRESULT WINAPI ITypeInfo_fnGetVarDesc( ITypeInfo2 *iface, UINT index,
5535 LPVARDESC *ppVarDesc)
5537 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5538 const TLBVarDesc *pVDesc = &This->vardescs[index];
5540 TRACE("(%p) index %d\n", This, index);
5542 if(index >= This->TypeAttr.cVars)
5543 return TYPE_E_ELEMENTNOTFOUND;
5545 return TLB_AllocAndInitVarDesc(&pVDesc->vardesc, ppVarDesc);
5548 /* ITypeInfo_GetNames
5550 * Retrieves the variable with the specified member ID (or the name of the
5551 * property or method and its parameters) that correspond to the specified
5552 * function ID.
5554 static HRESULT WINAPI ITypeInfo_fnGetNames( ITypeInfo2 *iface, MEMBERID memid,
5555 BSTR *rgBstrNames, UINT cMaxNames, UINT *pcNames)
5557 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5558 const TLBFuncDesc *pFDesc;
5559 const TLBVarDesc *pVDesc;
5560 int i;
5561 TRACE("(%p) memid=0x%08x Maxname=%d\n", This, memid, cMaxNames);
5562 pFDesc = TLB_get_funcdesc_by_memberid(This->funcdescs, This->TypeAttr.cFuncs, memid);
5563 if(pFDesc)
5565 /* function found, now return function and parameter names */
5566 for(i=0; i<cMaxNames && i <= pFDesc->funcdesc.cParams; i++)
5568 if(!i)
5569 *rgBstrNames=SysAllocString(pFDesc->Name);
5570 else
5571 rgBstrNames[i]=SysAllocString(pFDesc->pParamDesc[i-1].Name);
5573 *pcNames=i;
5575 else
5577 pVDesc = TLB_get_vardesc_by_memberid(This->vardescs, This->TypeAttr.cVars, memid);
5578 if(pVDesc)
5580 *rgBstrNames=SysAllocString(pVDesc->Name);
5581 *pcNames=1;
5583 else
5585 if(This->impltypes &&
5586 (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
5587 /* recursive search */
5588 ITypeInfo *pTInfo;
5589 HRESULT result;
5590 result=ITypeInfo_GetRefTypeInfo(iface, This->impltypes[0].hRef,
5591 &pTInfo);
5592 if(SUCCEEDED(result))
5594 result=ITypeInfo_GetNames(pTInfo, memid, rgBstrNames, cMaxNames, pcNames);
5595 ITypeInfo_Release(pTInfo);
5596 return result;
5598 WARN("Could not search inherited interface!\n");
5600 else
5602 WARN("no names found\n");
5604 *pcNames=0;
5605 return TYPE_E_ELEMENTNOTFOUND;
5608 return S_OK;
5612 /* ITypeInfo::GetRefTypeOfImplType
5614 * If a type description describes a COM class, it retrieves the type
5615 * description of the implemented interface types. For an interface,
5616 * GetRefTypeOfImplType returns the type information for inherited interfaces,
5617 * if any exist.
5620 static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType(
5621 ITypeInfo2 *iface,
5622 UINT index,
5623 HREFTYPE *pRefType)
5625 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5626 HRESULT hr = S_OK;
5628 TRACE("(%p) index %d\n", This, index);
5629 if (TRACE_ON(ole)) dump_TypeInfo(This);
5631 if(index==(UINT)-1)
5633 /* only valid on dual interfaces;
5634 retrieve the associated TKIND_INTERFACE handle for the current TKIND_DISPATCH
5636 if( This->TypeAttr.typekind != TKIND_DISPATCH) return E_INVALIDARG;
5638 if (This->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL)
5640 *pRefType = -1;
5642 else
5644 hr = TYPE_E_ELEMENTNOTFOUND;
5647 else if(index == 0 && This->TypeAttr.typekind == TKIND_DISPATCH)
5649 /* All TKIND_DISPATCHs are made to look like they inherit from IDispatch */
5650 *pRefType = This->pTypeLib->dispatch_href;
5652 else
5654 if(index >= This->TypeAttr.cImplTypes)
5655 hr = TYPE_E_ELEMENTNOTFOUND;
5656 else
5657 *pRefType = This->impltypes[index].hRef;
5660 if(TRACE_ON(ole))
5662 if(SUCCEEDED(hr))
5663 TRACE("SUCCESS -- hRef = 0x%08x\n", *pRefType );
5664 else
5665 TRACE("FAILURE -- hresult = 0x%08x\n", hr);
5668 return hr;
5671 /* ITypeInfo::GetImplTypeFlags
5673 * Retrieves the IMPLTYPEFLAGS enumeration for one implemented interface
5674 * or base interface in a type description.
5676 static HRESULT WINAPI ITypeInfo_fnGetImplTypeFlags( ITypeInfo2 *iface,
5677 UINT index, INT *pImplTypeFlags)
5679 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5681 TRACE("(%p) index %d\n", This, index);
5683 if(This->TypeAttr.typekind == TKIND_DISPATCH && index == 0){
5684 *pImplTypeFlags = 0;
5685 return S_OK;
5688 if(index >= This->TypeAttr.cImplTypes)
5689 return TYPE_E_ELEMENTNOTFOUND;
5691 *pImplTypeFlags = This->impltypes[index].implflags;
5693 return S_OK;
5696 /* GetIDsOfNames
5697 * Maps between member names and member IDs, and parameter names and
5698 * parameter IDs.
5700 static HRESULT WINAPI ITypeInfo_fnGetIDsOfNames( ITypeInfo2 *iface,
5701 LPOLESTR *rgszNames, UINT cNames, MEMBERID *pMemId)
5703 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5704 const TLBVarDesc *pVDesc;
5705 HRESULT ret=S_OK;
5706 UINT i, fdc;
5708 TRACE("(%p) Name %s cNames %d\n", This, debugstr_w(*rgszNames),
5709 cNames);
5711 /* init out parameters in case of failure */
5712 for (i = 0; i < cNames; i++)
5713 pMemId[i] = MEMBERID_NIL;
5715 for (fdc = 0; fdc < This->TypeAttr.cFuncs; ++fdc) {
5716 int j;
5717 const TLBFuncDesc *pFDesc = &This->funcdescs[fdc];
5718 if(!lstrcmpiW(*rgszNames, pFDesc->Name)) {
5719 if(cNames) *pMemId=pFDesc->funcdesc.memid;
5720 for(i=1; i < cNames; i++){
5721 for(j=0; j<pFDesc->funcdesc.cParams; j++)
5722 if(!lstrcmpiW(rgszNames[i],pFDesc->pParamDesc[j].Name))
5723 break;
5724 if( j<pFDesc->funcdesc.cParams)
5725 pMemId[i]=j;
5726 else
5727 ret=DISP_E_UNKNOWNNAME;
5729 TRACE("-- 0x%08x\n", ret);
5730 return ret;
5733 pVDesc = TLB_get_vardesc_by_name(This->vardescs, This->TypeAttr.cVars, *rgszNames);
5734 if(pVDesc){
5735 if(cNames)
5736 *pMemId = pVDesc->vardesc.memid;
5737 return ret;
5739 /* not found, see if it can be found in an inherited interface */
5740 if(This->impltypes) {
5741 /* recursive search */
5742 ITypeInfo *pTInfo;
5743 ret=ITypeInfo_GetRefTypeInfo(iface,
5744 This->impltypes[0].hRef, &pTInfo);
5745 if(SUCCEEDED(ret)){
5746 ret=ITypeInfo_GetIDsOfNames(pTInfo, rgszNames, cNames, pMemId );
5747 ITypeInfo_Release(pTInfo);
5748 return ret;
5750 WARN("Could not search inherited interface!\n");
5751 } else
5752 WARN("no names found\n");
5753 return DISP_E_UNKNOWNNAME;
5757 #ifdef __i386__
5759 extern LONGLONG call_method( void *func, int nb_args, const DWORD *args, int *stack_offset );
5760 __ASM_GLOBAL_FUNC( call_method,
5761 "pushl %ebp\n\t"
5762 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
5763 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
5764 "movl %esp,%ebp\n\t"
5765 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
5766 "pushl %esi\n\t"
5767 __ASM_CFI(".cfi_rel_offset %esi,-4\n\t")
5768 "pushl %edi\n\t"
5769 __ASM_CFI(".cfi_rel_offset %edi,-8\n\t")
5770 "movl 12(%ebp),%edx\n\t"
5771 "movl %esp,%edi\n\t"
5772 "shll $2,%edx\n\t"
5773 "jz 1f\n\t"
5774 "subl %edx,%edi\n\t"
5775 "andl $~15,%edi\n\t"
5776 "movl %edi,%esp\n\t"
5777 "movl 12(%ebp),%ecx\n\t"
5778 "movl 16(%ebp),%esi\n\t"
5779 "cld\n\t"
5780 "rep; movsl\n"
5781 "1:\tcall *8(%ebp)\n\t"
5782 "subl %esp,%edi\n\t"
5783 "movl 20(%ebp),%ecx\n\t"
5784 "movl %edi,(%ecx)\n\t"
5785 "leal -8(%ebp),%esp\n\t"
5786 "popl %edi\n\t"
5787 __ASM_CFI(".cfi_same_value %edi\n\t")
5788 "popl %esi\n\t"
5789 __ASM_CFI(".cfi_same_value %esi\n\t")
5790 "popl %ebp\n\t"
5791 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
5792 __ASM_CFI(".cfi_same_value %ebp\n\t")
5793 "ret" )
5795 /* same function but returning floating point */
5796 static double (* const call_double_method)(void*,int,const DWORD*,int*) = (void *)call_method;
5798 /* ITypeInfo::Invoke
5800 * Invokes a method, or accesses a property of an object, that implements the
5801 * interface described by the type description.
5803 DWORD
5804 _invoke(FARPROC func,CALLCONV callconv, int nrargs, DWORD *args) {
5805 DWORD res;
5806 int stack_offset;
5808 if (TRACE_ON(ole)) {
5809 int i;
5810 TRACE("Calling %p(",func);
5811 for (i=0;i<min(nrargs,30);i++) TRACE("%08x,",args[i]);
5812 if (nrargs > 30) TRACE("...");
5813 TRACE(")\n");
5816 switch (callconv) {
5817 case CC_STDCALL:
5818 case CC_CDECL:
5819 res = call_method( func, nrargs, args, &stack_offset );
5820 break;
5821 default:
5822 FIXME("unsupported calling convention %d\n",callconv);
5823 res = -1;
5824 break;
5826 TRACE("returns %08x\n",res);
5827 return res;
5830 #elif defined(__x86_64__)
5832 extern DWORD_PTR CDECL call_method( void *func, int nb_args, const DWORD_PTR *args );
5833 __ASM_GLOBAL_FUNC( call_method,
5834 "pushq %rbp\n\t"
5835 __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t")
5836 __ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
5837 "movq %rsp,%rbp\n\t"
5838 __ASM_CFI(".cfi_def_cfa_register %rbp\n\t")
5839 "pushq %rsi\n\t"
5840 __ASM_CFI(".cfi_rel_offset %rsi,-8\n\t")
5841 "pushq %rdi\n\t"
5842 __ASM_CFI(".cfi_rel_offset %rdi,-16\n\t")
5843 "movq %rcx,%rax\n\t"
5844 "movq $4,%rcx\n\t"
5845 "cmp %rcx,%rdx\n\t"
5846 "cmovgq %rdx,%rcx\n\t"
5847 "leaq 0(,%rcx,8),%rdx\n\t"
5848 "subq %rdx,%rsp\n\t"
5849 "andq $~15,%rsp\n\t"
5850 "movq %rsp,%rdi\n\t"
5851 "movq %r8,%rsi\n\t"
5852 "rep; movsq\n\t"
5853 "movq 0(%rsp),%rcx\n\t"
5854 "movq 8(%rsp),%rdx\n\t"
5855 "movq 16(%rsp),%r8\n\t"
5856 "movq 24(%rsp),%r9\n\t"
5857 "movq %rcx,%xmm0\n\t"
5858 "movq %rdx,%xmm1\n\t"
5859 "movq %r8,%xmm2\n\t"
5860 "movq %r9,%xmm3\n\t"
5861 "callq *%rax\n\t"
5862 "leaq -16(%rbp),%rsp\n\t"
5863 "popq %rdi\n\t"
5864 __ASM_CFI(".cfi_same_value %rdi\n\t")
5865 "popq %rsi\n\t"
5866 __ASM_CFI(".cfi_same_value %rsi\n\t")
5867 __ASM_CFI(".cfi_def_cfa_register %rsp\n\t")
5868 "popq %rbp\n\t"
5869 __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t")
5870 __ASM_CFI(".cfi_same_value %rbp\n\t")
5871 "ret")
5873 /* same function but returning floating point */
5874 static double (CDECL * const call_double_method)(void*,int,const DWORD_PTR*) = (void *)call_method;
5876 #endif /* __x86_64__ */
5878 static HRESULT userdefined_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
5880 HRESULT hr = S_OK;
5881 ITypeInfo *tinfo2 = NULL;
5882 TYPEATTR *tattr = NULL;
5884 hr = ITypeInfo_GetRefTypeInfo(tinfo, tdesc->u.hreftype, &tinfo2);
5885 if (hr)
5887 ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED, "
5888 "hr = 0x%08x\n",
5889 tdesc->u.hreftype, hr);
5890 return hr;
5892 hr = ITypeInfo_GetTypeAttr(tinfo2, &tattr);
5893 if (hr)
5895 ERR("ITypeInfo_GetTypeAttr failed, hr = 0x%08x\n", hr);
5896 ITypeInfo_Release(tinfo2);
5897 return hr;
5900 switch (tattr->typekind)
5902 case TKIND_ENUM:
5903 *vt |= VT_I4;
5904 break;
5906 case TKIND_ALIAS:
5907 tdesc = &tattr->tdescAlias;
5908 hr = typedescvt_to_variantvt(tinfo2, &tattr->tdescAlias, vt);
5909 break;
5911 case TKIND_INTERFACE:
5912 if (tattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE)
5913 *vt |= VT_DISPATCH;
5914 else
5915 *vt |= VT_UNKNOWN;
5916 break;
5918 case TKIND_DISPATCH:
5919 *vt |= VT_DISPATCH;
5920 break;
5922 case TKIND_COCLASS:
5923 *vt |= VT_DISPATCH;
5924 break;
5926 case TKIND_RECORD:
5927 FIXME("TKIND_RECORD unhandled.\n");
5928 hr = E_NOTIMPL;
5929 break;
5931 case TKIND_UNION:
5932 FIXME("TKIND_UNION unhandled.\n");
5933 hr = E_NOTIMPL;
5934 break;
5936 default:
5937 FIXME("TKIND %d unhandled.\n",tattr->typekind);
5938 hr = E_NOTIMPL;
5939 break;
5941 ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
5942 ITypeInfo_Release(tinfo2);
5943 return hr;
5946 static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
5948 HRESULT hr = S_OK;
5950 /* enforce only one level of pointer indirection */
5951 if (!(*vt & VT_BYREF) && !(*vt & VT_ARRAY) && (tdesc->vt == VT_PTR))
5953 tdesc = tdesc->u.lptdesc;
5955 /* munch VT_PTR -> VT_USERDEFINED(interface) into VT_UNKNOWN or
5956 * VT_DISPATCH and VT_PTR -> VT_PTR -> VT_USERDEFINED(interface) into
5957 * VT_BYREF|VT_DISPATCH or VT_BYREF|VT_UNKNOWN */
5958 if ((tdesc->vt == VT_USERDEFINED) ||
5959 ((tdesc->vt == VT_PTR) && (tdesc->u.lptdesc->vt == VT_USERDEFINED)))
5961 VARTYPE vt_userdefined = 0;
5962 const TYPEDESC *tdesc_userdefined = tdesc;
5963 if (tdesc->vt == VT_PTR)
5965 vt_userdefined = VT_BYREF;
5966 tdesc_userdefined = tdesc->u.lptdesc;
5968 hr = userdefined_to_variantvt(tinfo, tdesc_userdefined, &vt_userdefined);
5969 if ((hr == S_OK) &&
5970 (((vt_userdefined & VT_TYPEMASK) == VT_UNKNOWN) ||
5971 ((vt_userdefined & VT_TYPEMASK) == VT_DISPATCH)))
5973 *vt |= vt_userdefined;
5974 return S_OK;
5977 *vt = VT_BYREF;
5980 switch (tdesc->vt)
5982 case VT_HRESULT:
5983 *vt |= VT_ERROR;
5984 break;
5985 case VT_USERDEFINED:
5986 hr = userdefined_to_variantvt(tinfo, tdesc, vt);
5987 break;
5988 case VT_VOID:
5989 case VT_CARRAY:
5990 case VT_PTR:
5991 case VT_LPSTR:
5992 case VT_LPWSTR:
5993 ERR("cannot convert type %d into variant VT\n", tdesc->vt);
5994 hr = DISP_E_BADVARTYPE;
5995 break;
5996 case VT_SAFEARRAY:
5997 *vt |= VT_ARRAY;
5998 hr = typedescvt_to_variantvt(tinfo, tdesc->u.lptdesc, vt);
5999 break;
6000 case VT_INT:
6001 *vt |= VT_I4;
6002 break;
6003 case VT_UINT:
6004 *vt |= VT_UI4;
6005 break;
6006 default:
6007 *vt |= tdesc->vt;
6008 break;
6010 return hr;
6013 /***********************************************************************
6014 * DispCallFunc (OLEAUT32.@)
6016 * Invokes a function of the specified calling convention, passing the
6017 * specified arguments and returns the result.
6019 * PARAMS
6020 * pvInstance [I] Optional pointer to the instance whose function to invoke.
6021 * oVft [I] The offset in the vtable. See notes.
6022 * cc [I] Calling convention of the function to call.
6023 * vtReturn [I] The return type of the function.
6024 * cActuals [I] Number of parameters.
6025 * prgvt [I] The types of the parameters to pass. This is used for sizing only.
6026 * prgpvarg [I] The arguments to pass.
6027 * pvargResult [O] The return value of the function. Can be NULL.
6029 * RETURNS
6030 * Success: S_OK.
6031 * Failure: HRESULT code.
6033 * NOTES
6034 * The HRESULT return value of this function is not affected by the return
6035 * value of the user supplied function, which is returned in pvargResult.
6037 * If pvInstance is NULL then a non-object function is to be called and oVft
6038 * is the address of the function to call.
6040 * The cc parameter can be one of the following values:
6041 *|CC_FASTCALL
6042 *|CC_CDECL
6043 *|CC_PASCAL
6044 *|CC_STDCALL
6045 *|CC_FPFASTCALL
6046 *|CC_SYSCALL
6047 *|CC_MPWCDECL
6048 *|CC_MPWPASCAL
6051 HRESULT WINAPI
6052 DispCallFunc(
6053 void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals,
6054 VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult)
6056 #ifdef __i386__
6057 int argspos, stack_offset;
6058 void *func;
6059 UINT i;
6060 DWORD *args;
6062 TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
6063 pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
6064 pvargResult, V_VT(pvargResult));
6066 if (cc != CC_STDCALL && cc != CC_CDECL)
6068 FIXME("unsupported calling convention %d\n",cc);
6069 return E_INVALIDARG;
6072 /* maximum size for an argument is sizeof(VARIANT) */
6073 args = heap_alloc(sizeof(VARIANT) * cActuals + sizeof(DWORD) * 2 );
6075 /* start at 1 in case we need to pass a pointer to the return value as arg 0 */
6076 argspos = 1;
6077 if (pvInstance)
6079 const FARPROC *vtable = *(FARPROC **)pvInstance;
6080 func = vtable[oVft/sizeof(void *)];
6081 args[argspos++] = (DWORD)pvInstance; /* the This pointer is always the first parameter */
6083 else func = (void *)oVft;
6085 for (i = 0; i < cActuals; i++)
6087 VARIANT *arg = prgpvarg[i];
6089 switch (prgvt[i])
6091 case VT_EMPTY:
6092 break;
6093 case VT_I8:
6094 case VT_UI8:
6095 case VT_R8:
6096 case VT_DATE:
6097 case VT_CY:
6098 memcpy( &args[argspos], &V_I8(arg), sizeof(V_I8(arg)) );
6099 argspos += sizeof(V_I8(arg)) / sizeof(DWORD);
6100 break;
6101 case VT_DECIMAL:
6102 case VT_VARIANT:
6103 memcpy( &args[argspos], arg, sizeof(*arg) );
6104 argspos += sizeof(*arg) / sizeof(DWORD);
6105 break;
6106 case VT_BOOL: /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
6107 args[argspos++] = V_BOOL(arg);
6108 break;
6109 default:
6110 args[argspos++] = V_UI4(arg);
6111 break;
6113 TRACE("arg %u: type %d\n",i,prgvt[i]);
6114 dump_Variant(arg);
6117 switch (vtReturn)
6119 case VT_EMPTY:
6120 call_method( func, argspos - 1, args + 1, &stack_offset );
6121 break;
6122 case VT_R4:
6123 V_R4(pvargResult) = call_double_method( func, argspos - 1, args + 1, &stack_offset );
6124 break;
6125 case VT_R8:
6126 case VT_DATE:
6127 V_R8(pvargResult) = call_double_method( func, argspos - 1, args + 1, &stack_offset );
6128 break;
6129 case VT_DECIMAL:
6130 case VT_VARIANT:
6131 args[0] = (DWORD)pvargResult; /* arg 0 is a pointer to the result */
6132 call_method( func, argspos, args, &stack_offset );
6133 break;
6134 case VT_I8:
6135 case VT_UI8:
6136 case VT_CY:
6137 V_UI8(pvargResult) = call_method( func, argspos - 1, args + 1, &stack_offset );
6138 break;
6139 default:
6140 V_UI4(pvargResult) = call_method( func, argspos - 1, args + 1, &stack_offset );
6141 break;
6143 heap_free( args );
6144 if (stack_offset && cc == CC_STDCALL)
6146 WARN( "stack pointer off by %d\n", stack_offset );
6147 return DISP_E_BADCALLEE;
6149 if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
6150 TRACE("retval: "); dump_Variant(pvargResult);
6151 return S_OK;
6153 #elif defined(__x86_64__)
6154 int argspos;
6155 UINT i;
6156 DWORD_PTR *args;
6157 void *func;
6159 TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
6160 pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
6161 pvargResult, V_VT(pvargResult));
6163 if (cc != CC_STDCALL && cc != CC_CDECL)
6165 FIXME("unsupported calling convention %d\n",cc);
6166 return E_INVALIDARG;
6169 /* maximum size for an argument is sizeof(DWORD_PTR) */
6170 args = heap_alloc( sizeof(DWORD_PTR) * (cActuals + 2) );
6172 /* start at 1 in case we need to pass a pointer to the return value as arg 0 */
6173 argspos = 1;
6174 if (pvInstance)
6176 const FARPROC *vtable = *(FARPROC **)pvInstance;
6177 func = vtable[oVft/sizeof(void *)];
6178 args[argspos++] = (DWORD_PTR)pvInstance; /* the This pointer is always the first parameter */
6180 else func = (void *)oVft;
6182 for (i = 0; i < cActuals; i++)
6184 VARIANT *arg = prgpvarg[i];
6186 switch (prgvt[i])
6188 case VT_DECIMAL:
6189 case VT_VARIANT:
6190 args[argspos++] = (ULONG_PTR)arg;
6191 break;
6192 case VT_BOOL: /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
6193 args[argspos++] = V_BOOL(arg);
6194 break;
6195 default:
6196 args[argspos++] = V_UI8(arg);
6197 break;
6199 TRACE("arg %u: type %d\n",i,prgvt[i]);
6200 dump_Variant(arg);
6203 switch (vtReturn)
6205 case VT_R4:
6206 V_R4(pvargResult) = call_double_method( func, argspos - 1, args + 1 );
6207 break;
6208 case VT_R8:
6209 case VT_DATE:
6210 V_R8(pvargResult) = call_double_method( func, argspos - 1, args + 1 );
6211 break;
6212 case VT_DECIMAL:
6213 case VT_VARIANT:
6214 args[0] = (DWORD_PTR)pvargResult; /* arg 0 is a pointer to the result */
6215 call_method( func, argspos, args );
6216 break;
6217 default:
6218 V_UI8(pvargResult) = call_method( func, argspos - 1, args + 1 );
6219 break;
6221 heap_free( args );
6222 if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
6223 TRACE("retval: "); dump_Variant(pvargResult);
6224 return S_OK;
6226 #else
6227 FIXME( "(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d)): not implemented for this CPU\n",
6228 pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg, pvargResult, V_VT(pvargResult));
6229 return E_NOTIMPL;
6230 #endif
6233 #define INVBUF_ELEMENT_SIZE \
6234 (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *) + sizeof(VARTYPE))
6235 #define INVBUF_GET_ARG_ARRAY(buffer, params) (buffer)
6236 #define INVBUF_GET_MISSING_ARG_ARRAY(buffer, params) \
6237 ((VARIANTARG *)((char *)(buffer) + sizeof(VARIANTARG) * (params)))
6238 #define INVBUF_GET_ARG_PTR_ARRAY(buffer, params) \
6239 ((VARIANTARG **)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG)) * (params)))
6240 #define INVBUF_GET_ARG_TYPE_ARRAY(buffer, params) \
6241 ((VARTYPE *)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *)) * (params)))
6243 static HRESULT WINAPI ITypeInfo_fnInvoke(
6244 ITypeInfo2 *iface,
6245 VOID *pIUnk,
6246 MEMBERID memid,
6247 UINT16 wFlags,
6248 DISPPARAMS *pDispParams,
6249 VARIANT *pVarResult,
6250 EXCEPINFO *pExcepInfo,
6251 UINT *pArgErr)
6253 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6254 int i;
6255 unsigned int var_index;
6256 TYPEKIND type_kind;
6257 HRESULT hres;
6258 const TLBFuncDesc *pFuncInfo;
6259 UINT fdc;
6261 TRACE("(%p)(%p,id=%d,flags=0x%08x,%p,%p,%p,%p)\n",
6262 This,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr
6265 if( This->TypeAttr.wTypeFlags & TYPEFLAG_FRESTRICTED )
6266 return DISP_E_MEMBERNOTFOUND;
6268 if (!pDispParams)
6270 ERR("NULL pDispParams not allowed\n");
6271 return E_INVALIDARG;
6274 dump_DispParms(pDispParams);
6276 if (pDispParams->cNamedArgs > pDispParams->cArgs)
6278 ERR("named argument array cannot be bigger than argument array (%d/%d)\n",
6279 pDispParams->cNamedArgs, pDispParams->cArgs);
6280 return E_INVALIDARG;
6283 /* we do this instead of using GetFuncDesc since it will return a fake
6284 * FUNCDESC for dispinterfaces and we want the real function description */
6285 for (fdc = 0; fdc < This->TypeAttr.cFuncs; ++fdc){
6286 pFuncInfo = &This->funcdescs[fdc];
6287 if ((memid == pFuncInfo->funcdesc.memid) &&
6288 (wFlags & pFuncInfo->funcdesc.invkind) &&
6289 (pFuncInfo->funcdesc.wFuncFlags & FUNCFLAG_FRESTRICTED) == 0)
6290 break;
6293 if (fdc < This->TypeAttr.cFuncs) {
6294 const FUNCDESC *func_desc = &pFuncInfo->funcdesc;
6296 if (TRACE_ON(ole))
6298 TRACE("invoking:\n");
6299 dump_TLBFuncDescOne(pFuncInfo);
6302 switch (func_desc->funckind) {
6303 case FUNC_PUREVIRTUAL:
6304 case FUNC_VIRTUAL: {
6305 void *buffer = heap_alloc_zero(INVBUF_ELEMENT_SIZE * func_desc->cParams);
6306 VARIANT varresult;
6307 VARIANT retval; /* pointer for storing byref retvals in */
6308 VARIANTARG **prgpvarg = INVBUF_GET_ARG_PTR_ARRAY(buffer, func_desc->cParams);
6309 VARIANTARG *rgvarg = INVBUF_GET_ARG_ARRAY(buffer, func_desc->cParams);
6310 VARTYPE *rgvt = INVBUF_GET_ARG_TYPE_ARRAY(buffer, func_desc->cParams);
6311 UINT cNamedArgs = pDispParams->cNamedArgs;
6312 DISPID *rgdispidNamedArgs = pDispParams->rgdispidNamedArgs;
6313 UINT vargs_converted=0;
6315 hres = S_OK;
6317 if (func_desc->invkind & (INVOKE_PROPERTYPUT|INVOKE_PROPERTYPUTREF))
6319 if (!cNamedArgs || (rgdispidNamedArgs[0] != DISPID_PROPERTYPUT))
6321 ERR("first named arg for property put invocation must be DISPID_PROPERTYPUT\n");
6322 hres = DISP_E_PARAMNOTFOUND;
6323 goto func_fail;
6327 if (func_desc->cParamsOpt < 0 && cNamedArgs)
6329 ERR("functions with the vararg attribute do not support named arguments\n");
6330 hres = DISP_E_NONAMEDARGS;
6331 goto func_fail;
6334 for (i = 0; i < func_desc->cParams; i++)
6336 TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc;
6337 hres = typedescvt_to_variantvt((ITypeInfo *)iface, tdesc, &rgvt[i]);
6338 if (FAILED(hres))
6339 goto func_fail;
6342 TRACE("changing args\n");
6343 for (i = 0; i < func_desc->cParams; i++)
6345 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
6346 VARIANTARG *src_arg;
6348 if (wParamFlags & PARAMFLAG_FLCID)
6350 VARIANTARG *arg;
6351 arg = prgpvarg[i] = &rgvarg[i];
6352 V_VT(arg) = VT_I4;
6353 V_I4(arg) = This->pTypeLib->lcid;
6354 continue;
6357 src_arg = NULL;
6359 if (cNamedArgs)
6361 USHORT j;
6362 for (j = 0; j < cNamedArgs; j++)
6363 if (rgdispidNamedArgs[j] == i || (i == func_desc->cParams-1 && rgdispidNamedArgs[j] == DISPID_PROPERTYPUT))
6365 src_arg = &pDispParams->rgvarg[j];
6366 break;
6370 if (!src_arg && vargs_converted + cNamedArgs < pDispParams->cArgs)
6372 src_arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted];
6373 vargs_converted++;
6376 if (wParamFlags & PARAMFLAG_FRETVAL)
6378 /* under most conditions the caller is not allowed to
6379 * pass in a dispparam arg in the index of what would be
6380 * the retval parameter. however, there is an exception
6381 * where the extra parameter is used in an extra
6382 * IDispatch::Invoke below */
6383 if ((i < pDispParams->cArgs) &&
6384 ((func_desc->cParams != 1) || !pVarResult ||
6385 !(func_desc->invkind & INVOKE_PROPERTYGET)))
6387 hres = DISP_E_BADPARAMCOUNT;
6388 break;
6391 /* note: this check is placed so that if the caller passes
6392 * in a VARIANTARG for the retval we just ignore it, like
6393 * native does */
6394 if (i == func_desc->cParams - 1)
6396 VARIANTARG *arg;
6397 arg = prgpvarg[i] = &rgvarg[i];
6398 memset(arg, 0, sizeof(*arg));
6399 V_VT(arg) = rgvt[i];
6400 memset(&retval, 0, sizeof(retval));
6401 V_BYREF(arg) = &retval;
6403 else
6405 ERR("[retval] parameter must be the last parameter of the method (%d/%d)\n", i, func_desc->cParams);
6406 hres = E_UNEXPECTED;
6407 break;
6410 else if (src_arg)
6412 dump_Variant(src_arg);
6414 if (rgvt[i] == VT_VARIANT)
6415 hres = VariantCopy(&rgvarg[i], src_arg);
6416 else if (rgvt[i] == (VT_VARIANT | VT_BYREF))
6418 if (rgvt[i] == V_VT(src_arg))
6419 V_VARIANTREF(&rgvarg[i]) = V_VARIANTREF(src_arg);
6420 else
6422 VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
6423 if (wParamFlags & PARAMFLAG_FIN)
6424 hres = VariantCopy(&missing_arg[i], src_arg);
6425 V_VARIANTREF(&rgvarg[i]) = &missing_arg[i];
6427 V_VT(&rgvarg[i]) = rgvt[i];
6429 else if (rgvt[i] == (VT_VARIANT | VT_ARRAY) && func_desc->cParamsOpt < 0 && i == func_desc->cParams-1)
6431 SAFEARRAY *a;
6432 SAFEARRAYBOUND bound;
6433 VARIANT *v;
6434 LONG j;
6435 bound.lLbound = 0;
6436 bound.cElements = pDispParams->cArgs-i;
6437 if (!(a = SafeArrayCreate(VT_VARIANT, 1, &bound)))
6439 ERR("SafeArrayCreate failed\n");
6440 break;
6442 hres = SafeArrayAccessData(a, (LPVOID)&v);
6443 if (hres != S_OK)
6445 ERR("SafeArrayAccessData failed with %x\n", hres);
6446 break;
6448 for (j = 0; j < bound.cElements; j++)
6449 VariantCopy(&v[j], &pDispParams->rgvarg[pDispParams->cArgs - 1 - i - j]);
6450 hres = SafeArrayUnaccessData(a);
6451 if (hres != S_OK)
6453 ERR("SafeArrayUnaccessData failed with %x\n", hres);
6454 break;
6456 V_ARRAY(&rgvarg[i]) = a;
6457 V_VT(&rgvarg[i]) = rgvt[i];
6459 else if ((rgvt[i] & VT_BYREF) && !V_ISBYREF(src_arg))
6461 VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
6462 if (wParamFlags & PARAMFLAG_FIN)
6463 hres = VariantChangeType(&missing_arg[i], src_arg, 0, rgvt[i] & ~VT_BYREF);
6464 else
6465 V_VT(&missing_arg[i]) = rgvt[i] & ~VT_BYREF;
6466 V_BYREF(&rgvarg[i]) = &V_NONE(&missing_arg[i]);
6467 V_VT(&rgvarg[i]) = rgvt[i];
6469 else if ((rgvt[i] & VT_BYREF) && (rgvt[i] == V_VT(src_arg)))
6471 V_BYREF(&rgvarg[i]) = V_BYREF(src_arg);
6472 V_VT(&rgvarg[i]) = rgvt[i];
6474 else
6476 /* FIXME: this doesn't work for VT_BYREF arguments if
6477 * they are not the same type as in the paramdesc */
6478 V_VT(&rgvarg[i]) = V_VT(src_arg);
6479 hres = VariantChangeType(&rgvarg[i], src_arg, 0, rgvt[i]);
6480 V_VT(&rgvarg[i]) = rgvt[i];
6483 if (FAILED(hres))
6485 ERR("failed to convert param %d to %s%s from %s%s\n", i,
6486 debugstr_vt(rgvt[i]), debugstr_vf(rgvt[i]),
6487 debugstr_VT(src_arg), debugstr_VF(src_arg));
6488 break;
6490 prgpvarg[i] = &rgvarg[i];
6492 else if (wParamFlags & PARAMFLAG_FOPT)
6494 VARIANTARG *arg;
6495 arg = prgpvarg[i] = &rgvarg[i];
6496 if (wParamFlags & PARAMFLAG_FHASDEFAULT)
6498 hres = VariantCopy(arg, &func_desc->lprgelemdescParam[i].u.paramdesc.pparamdescex->varDefaultValue);
6499 if (FAILED(hres))
6500 break;
6502 else
6504 VARIANTARG *missing_arg;
6505 /* if the function wants a pointer to a variant then
6506 * set that up, otherwise just pass the VT_ERROR in
6507 * the argument by value */
6508 if (rgvt[i] & VT_BYREF)
6510 missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams) + i;
6511 V_VT(arg) = VT_VARIANT | VT_BYREF;
6512 V_VARIANTREF(arg) = missing_arg;
6514 else
6515 missing_arg = arg;
6516 V_VT(missing_arg) = VT_ERROR;
6517 V_ERROR(missing_arg) = DISP_E_PARAMNOTFOUND;
6520 else
6522 hres = DISP_E_BADPARAMCOUNT;
6523 break;
6526 if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
6528 /* VT_VOID is a special case for return types, so it is not
6529 * handled in the general function */
6530 if (func_desc->elemdescFunc.tdesc.vt == VT_VOID)
6531 V_VT(&varresult) = VT_EMPTY;
6532 else
6534 V_VT(&varresult) = 0;
6535 hres = typedescvt_to_variantvt((ITypeInfo *)iface, &func_desc->elemdescFunc.tdesc, &V_VT(&varresult));
6536 if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
6539 hres = DispCallFunc(pIUnk, func_desc->oVft, func_desc->callconv,
6540 V_VT(&varresult), func_desc->cParams, rgvt,
6541 prgpvarg, &varresult);
6543 vargs_converted = 0;
6545 for (i = 0; i < func_desc->cParams; i++)
6547 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
6548 VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
6550 if (wParamFlags & PARAMFLAG_FLCID)
6551 continue;
6552 else if (wParamFlags & PARAMFLAG_FRETVAL)
6554 if (TRACE_ON(ole))
6556 TRACE("[retval] value: ");
6557 dump_Variant(prgpvarg[i]);
6560 if (pVarResult)
6562 VariantInit(pVarResult);
6563 /* deref return value */
6564 hres = VariantCopyInd(pVarResult, prgpvarg[i]);
6567 VARIANT_ClearInd(prgpvarg[i]);
6569 else if (vargs_converted < pDispParams->cArgs)
6571 VARIANTARG *arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted];
6572 if (wParamFlags & PARAMFLAG_FOUT)
6574 if ((rgvt[i] & VT_BYREF) && !(V_VT(arg) & VT_BYREF))
6576 hres = VariantChangeType(arg, &rgvarg[i], 0, V_VT(arg));
6578 if (FAILED(hres))
6580 ERR("failed to convert param %d to vt %d\n", i,
6581 V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted]));
6582 break;
6586 else if (V_VT(prgpvarg[i]) == (VT_VARIANT | VT_ARRAY) &&
6587 func_desc->cParamsOpt < 0 &&
6588 i == func_desc->cParams-1)
6590 SAFEARRAY *a = V_ARRAY(prgpvarg[i]);
6591 LONG j, ubound;
6592 VARIANT *v;
6593 hres = SafeArrayGetUBound(a, 1, &ubound);
6594 if (hres != S_OK)
6596 ERR("SafeArrayGetUBound failed with %x\n", hres);
6597 break;
6599 hres = SafeArrayAccessData(a, (LPVOID)&v);
6600 if (hres != S_OK)
6602 ERR("SafeArrayAccessData failed with %x\n", hres);
6603 break;
6605 for (j = 0; j <= ubound; j++)
6606 VariantClear(&v[j]);
6607 hres = SafeArrayUnaccessData(a);
6608 if (hres != S_OK)
6610 ERR("SafeArrayUnaccessData failed with %x\n", hres);
6611 break;
6614 VariantClear(&rgvarg[i]);
6615 vargs_converted++;
6617 else if (wParamFlags & PARAMFLAG_FOPT)
6619 if (wParamFlags & PARAMFLAG_FHASDEFAULT)
6620 VariantClear(&rgvarg[i]);
6623 VariantClear(&missing_arg[i]);
6626 if ((V_VT(&varresult) == VT_ERROR) && FAILED(V_ERROR(&varresult)))
6628 WARN("invoked function failed with error 0x%08x\n", V_ERROR(&varresult));
6629 hres = DISP_E_EXCEPTION;
6630 if (pExcepInfo)
6632 IErrorInfo *pErrorInfo;
6633 pExcepInfo->scode = V_ERROR(&varresult);
6634 if (GetErrorInfo(0, &pErrorInfo) == S_OK)
6636 IErrorInfo_GetDescription(pErrorInfo, &pExcepInfo->bstrDescription);
6637 IErrorInfo_GetHelpFile(pErrorInfo, &pExcepInfo->bstrHelpFile);
6638 IErrorInfo_GetSource(pErrorInfo, &pExcepInfo->bstrSource);
6639 IErrorInfo_GetHelpContext(pErrorInfo, &pExcepInfo->dwHelpContext);
6641 IErrorInfo_Release(pErrorInfo);
6645 if (V_VT(&varresult) != VT_ERROR)
6647 TRACE("varresult value: ");
6648 dump_Variant(&varresult);
6650 if (pVarResult)
6652 VariantClear(pVarResult);
6653 *pVarResult = varresult;
6655 else
6656 VariantClear(&varresult);
6659 if (SUCCEEDED(hres) && pVarResult && (func_desc->cParams == 1) &&
6660 (func_desc->invkind & INVOKE_PROPERTYGET) &&
6661 (func_desc->lprgelemdescParam[0].u.paramdesc.wParamFlags & PARAMFLAG_FRETVAL) &&
6662 (pDispParams->cArgs != 0))
6664 if (V_VT(pVarResult) == VT_DISPATCH)
6666 IDispatch *pDispatch = V_DISPATCH(pVarResult);
6667 /* Note: not VariantClear; we still need the dispatch
6668 * pointer to be valid */
6669 VariantInit(pVarResult);
6670 hres = IDispatch_Invoke(pDispatch, DISPID_VALUE, &IID_NULL,
6671 GetSystemDefaultLCID(), INVOKE_PROPERTYGET,
6672 pDispParams, pVarResult, pExcepInfo, pArgErr);
6673 IDispatch_Release(pDispatch);
6675 else
6677 VariantClear(pVarResult);
6678 hres = DISP_E_NOTACOLLECTION;
6682 func_fail:
6683 heap_free(buffer);
6684 break;
6686 case FUNC_DISPATCH: {
6687 IDispatch *disp;
6689 hres = IUnknown_QueryInterface((LPUNKNOWN)pIUnk,&IID_IDispatch,(LPVOID*)&disp);
6690 if (SUCCEEDED(hres)) {
6691 FIXME("Calling Invoke in IDispatch iface. untested!\n");
6692 hres = IDispatch_Invoke(
6693 disp,memid,&IID_NULL,LOCALE_USER_DEFAULT,wFlags,pDispParams,
6694 pVarResult,pExcepInfo,pArgErr
6696 if (FAILED(hres))
6697 FIXME("IDispatch::Invoke failed with %08x. (Could be not a real error?)\n", hres);
6698 IDispatch_Release(disp);
6699 } else
6700 FIXME("FUNC_DISPATCH used on object without IDispatch iface?\n");
6701 break;
6703 default:
6704 FIXME("Unknown function invocation type %d\n", func_desc->funckind);
6705 hres = E_FAIL;
6706 break;
6709 TRACE("-- 0x%08x\n", hres);
6710 return hres;
6712 } else if(SUCCEEDED(hres = ITypeInfo2_GetVarIndexOfMemId(iface, memid, &var_index))) {
6713 VARDESC *var_desc;
6715 hres = ITypeInfo2_GetVarDesc(iface, var_index, &var_desc);
6716 if(FAILED(hres)) return hres;
6718 FIXME("varseek: Found memid, but variable-based invoking not supported\n");
6719 dump_VARDESC(var_desc);
6720 ITypeInfo2_ReleaseVarDesc(iface, var_desc);
6721 return E_NOTIMPL;
6724 /* not found, look for it in inherited interfaces */
6725 ITypeInfo2_GetTypeKind(iface, &type_kind);
6726 if(type_kind == TKIND_INTERFACE || type_kind == TKIND_DISPATCH) {
6727 if(This->impltypes) {
6728 /* recursive search */
6729 ITypeInfo *pTInfo;
6730 hres = ITypeInfo_GetRefTypeInfo(iface, This->impltypes[0].hRef, &pTInfo);
6731 if(SUCCEEDED(hres)){
6732 hres = ITypeInfo_Invoke(pTInfo,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr);
6733 ITypeInfo_Release(pTInfo);
6734 return hres;
6736 WARN("Could not search inherited interface!\n");
6739 WARN("did not find member id %d, flags 0x%x!\n", memid, wFlags);
6740 return DISP_E_MEMBERNOTFOUND;
6743 /* ITypeInfo::GetDocumentation
6745 * Retrieves the documentation string, the complete Help file name and path,
6746 * and the context ID for the Help topic for a specified type description.
6748 * (Can be tested by the Visual Basic Editor in Word for instance.)
6750 static HRESULT WINAPI ITypeInfo_fnGetDocumentation( ITypeInfo2 *iface,
6751 MEMBERID memid, BSTR *pBstrName, BSTR *pBstrDocString,
6752 DWORD *pdwHelpContext, BSTR *pBstrHelpFile)
6754 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6755 const TLBFuncDesc *pFDesc;
6756 const TLBVarDesc *pVDesc;
6757 TRACE("(%p) memid %d Name(%p) DocString(%p)"
6758 " HelpContext(%p) HelpFile(%p)\n",
6759 This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
6760 if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
6761 if(pBstrName)
6762 *pBstrName=SysAllocString(This->Name);
6763 if(pBstrDocString)
6764 *pBstrDocString=SysAllocString(This->DocString);
6765 if(pdwHelpContext)
6766 *pdwHelpContext=This->dwHelpContext;
6767 if(pBstrHelpFile)
6768 *pBstrHelpFile=SysAllocString(This->DocString);/* FIXME */
6769 return S_OK;
6770 }else {/* for a member */
6771 pFDesc = TLB_get_funcdesc_by_memberid(This->funcdescs, This->TypeAttr.cFuncs, memid);
6772 if(pFDesc){
6773 if(pBstrName)
6774 *pBstrName = SysAllocString(pFDesc->Name);
6775 if(pBstrDocString)
6776 *pBstrDocString=SysAllocString(pFDesc->HelpString);
6777 if(pdwHelpContext)
6778 *pdwHelpContext=pFDesc->helpcontext;
6779 return S_OK;
6781 pVDesc = TLB_get_vardesc_by_memberid(This->vardescs, This->TypeAttr.cVars, memid);
6782 if(pVDesc){
6783 if(pBstrName)
6784 *pBstrName = SysAllocString(pVDesc->Name);
6785 if(pBstrDocString)
6786 *pBstrDocString=SysAllocString(pVDesc->HelpString);
6787 if(pdwHelpContext)
6788 *pdwHelpContext=pVDesc->HelpContext;
6789 return S_OK;
6793 if(This->impltypes &&
6794 (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
6795 /* recursive search */
6796 ITypeInfo *pTInfo;
6797 HRESULT result;
6798 result = ITypeInfo_GetRefTypeInfo(iface, This->impltypes[0].hRef,
6799 &pTInfo);
6800 if(SUCCEEDED(result)) {
6801 result = ITypeInfo_GetDocumentation(pTInfo, memid, pBstrName,
6802 pBstrDocString, pdwHelpContext, pBstrHelpFile);
6803 ITypeInfo_Release(pTInfo);
6804 return result;
6806 WARN("Could not search inherited interface!\n");
6809 WARN("member %d not found\n", memid);
6810 return TYPE_E_ELEMENTNOTFOUND;
6813 /* ITypeInfo::GetDllEntry
6815 * Retrieves a description or specification of an entry point for a function
6816 * in a DLL.
6818 static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid,
6819 INVOKEKIND invKind, BSTR *pBstrDllName, BSTR *pBstrName,
6820 WORD *pwOrdinal)
6822 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6823 const TLBFuncDesc *pFDesc;
6825 TRACE("(%p)->(memid %x, %d, %p, %p, %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
6827 if (pBstrDllName) *pBstrDllName = NULL;
6828 if (pBstrName) *pBstrName = NULL;
6829 if (pwOrdinal) *pwOrdinal = 0;
6831 if (This->TypeAttr.typekind != TKIND_MODULE)
6832 return TYPE_E_BADMODULEKIND;
6834 pFDesc = TLB_get_funcdesc_by_memberid(This->funcdescs, This->TypeAttr.cFuncs, memid);
6835 if(pFDesc){
6836 dump_TypeInfo(This);
6837 if (TRACE_ON(ole))
6838 dump_TLBFuncDescOne(pFDesc);
6840 if (pBstrDllName)
6841 *pBstrDllName = SysAllocString(This->DllName);
6843 if (!IS_INTRESOURCE(pFDesc->Entry) && (pFDesc->Entry != (void*)-1)) {
6844 if (pBstrName)
6845 *pBstrName = SysAllocString(pFDesc->Entry);
6846 if (pwOrdinal)
6847 *pwOrdinal = -1;
6848 return S_OK;
6850 if (pBstrName)
6851 *pBstrName = NULL;
6852 if (pwOrdinal)
6853 *pwOrdinal = LOWORD(pFDesc->Entry);
6854 return S_OK;
6856 return TYPE_E_ELEMENTNOTFOUND;
6859 /* internal function to make the inherited interfaces' methods appear
6860 * part of the interface */
6861 static HRESULT ITypeInfoImpl_GetDispatchRefTypeInfo( ITypeInfo *iface,
6862 HREFTYPE *hRefType, ITypeInfo **ppTInfo)
6864 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6865 HRESULT hr;
6867 TRACE("%p, 0x%x\n", iface, *hRefType);
6869 if (This->impltypes && (*hRefType & DISPATCH_HREF_MASK))
6871 ITypeInfo *pSubTypeInfo;
6873 hr = ITypeInfo_GetRefTypeInfo(iface, This->impltypes[0].hRef, &pSubTypeInfo);
6874 if (FAILED(hr))
6875 return hr;
6877 hr = ITypeInfoImpl_GetDispatchRefTypeInfo(pSubTypeInfo,
6878 hRefType, ppTInfo);
6879 ITypeInfo_Release(pSubTypeInfo);
6880 if (SUCCEEDED(hr))
6881 return hr;
6883 *hRefType -= DISPATCH_HREF_OFFSET;
6885 if (!(*hRefType & DISPATCH_HREF_MASK))
6886 return ITypeInfo_GetRefTypeInfo(iface, *hRefType, ppTInfo);
6887 else
6888 return E_FAIL;
6891 /* ITypeInfo::GetRefTypeInfo
6893 * If a type description references other type descriptions, it retrieves
6894 * the referenced type descriptions.
6896 static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo(
6897 ITypeInfo2 *iface,
6898 HREFTYPE hRefType,
6899 ITypeInfo **ppTInfo)
6901 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6902 HRESULT result = E_FAIL;
6904 if ((This->hreftype != -1) && (This->hreftype == hRefType))
6906 *ppTInfo = (ITypeInfo *)&This->lpVtbl;
6907 ITypeInfo_AddRef(*ppTInfo);
6908 result = S_OK;
6910 else if (hRefType == -1 &&
6911 (This->TypeAttr.typekind == TKIND_DISPATCH) &&
6912 (This->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL))
6914 /* when we meet a DUAL dispinterface, we must create the interface
6915 * version of it.
6917 ITypeInfoImpl *pTypeInfoImpl = ITypeInfoImpl_Constructor();
6920 /* the interface version contains the same information as the dispinterface
6921 * copy the contents of the structs.
6923 *pTypeInfoImpl = *This;
6924 pTypeInfoImpl->ref = 0;
6926 /* change the type to interface */
6927 pTypeInfoImpl->TypeAttr.typekind = TKIND_INTERFACE;
6929 *ppTInfo = (ITypeInfo*) pTypeInfoImpl;
6931 /* the AddRef implicitly adds a reference to the parent typelib, which
6932 * stops the copied data from being destroyed until the new typeinfo's
6933 * refcount goes to zero, but we need to signal to the new instance to
6934 * not free its data structures when it is destroyed */
6935 pTypeInfoImpl->not_attached_to_typelib = TRUE;
6937 ITypeInfo_AddRef(*ppTInfo);
6939 result = S_OK;
6941 } else if ((hRefType != -1) && (hRefType & DISPATCH_HREF_MASK) &&
6942 (This->TypeAttr.typekind == TKIND_DISPATCH))
6944 HREFTYPE href_dispatch = hRefType;
6945 result = ITypeInfoImpl_GetDispatchRefTypeInfo((ITypeInfo *)iface, &href_dispatch, ppTInfo);
6946 } else {
6947 TLBRefType *ref_type;
6948 LIST_FOR_EACH_ENTRY(ref_type, &This->pTypeLib->ref_list, TLBRefType, entry)
6950 if(ref_type->reference == hRefType)
6951 break;
6953 if(&ref_type->entry == &This->pTypeLib->ref_list)
6955 FIXME("Can't find pRefType for ref %x\n", hRefType);
6956 goto end;
6958 if(hRefType != -1) {
6959 ITypeLib *pTLib = NULL;
6961 if(ref_type->pImpTLInfo == TLB_REF_INTERNAL) {
6962 UINT Index;
6963 result = ITypeInfo_GetContainingTypeLib(iface, &pTLib, &Index);
6964 } else {
6965 if(ref_type->pImpTLInfo->pImpTypeLib) {
6966 TRACE("typeinfo in imported typelib that is already loaded\n");
6967 pTLib = (ITypeLib*)ref_type->pImpTLInfo->pImpTypeLib;
6968 ITypeLib2_AddRef(pTLib);
6969 result = S_OK;
6970 } else {
6971 TRACE("typeinfo in imported typelib that isn't already loaded\n");
6972 result = LoadRegTypeLib( &ref_type->pImpTLInfo->guid,
6973 ref_type->pImpTLInfo->wVersionMajor,
6974 ref_type->pImpTLInfo->wVersionMinor,
6975 ref_type->pImpTLInfo->lcid,
6976 &pTLib);
6978 if(FAILED(result)) {
6979 BSTR libnam=SysAllocString(ref_type->pImpTLInfo->name);
6980 result=LoadTypeLib(libnam, &pTLib);
6981 SysFreeString(libnam);
6983 if(SUCCEEDED(result)) {
6984 ref_type->pImpTLInfo->pImpTypeLib = (ITypeLibImpl*)pTLib;
6985 ITypeLib2_AddRef(pTLib);
6989 if(SUCCEEDED(result)) {
6990 if(ref_type->index == TLB_REF_USE_GUID)
6991 result = ITypeLib2_GetTypeInfoOfGuid(pTLib,
6992 &ref_type->guid,
6993 ppTInfo);
6994 else
6995 result = ITypeLib2_GetTypeInfo(pTLib, ref_type->index,
6996 ppTInfo);
6998 if (pTLib != NULL)
6999 ITypeLib2_Release(pTLib);
7003 end:
7004 TRACE("(%p) hreftype 0x%04x loaded %s (%p)\n", This, hRefType,
7005 SUCCEEDED(result)? "SUCCESS":"FAILURE", *ppTInfo);
7006 return result;
7009 /* ITypeInfo::AddressOfMember
7011 * Retrieves the addresses of static functions or variables, such as those
7012 * defined in a DLL.
7014 static HRESULT WINAPI ITypeInfo_fnAddressOfMember( ITypeInfo2 *iface,
7015 MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
7017 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7018 HRESULT hr;
7019 BSTR dll, entry;
7020 WORD ordinal;
7021 HMODULE module;
7023 TRACE("(%p)->(0x%x, 0x%x, %p)\n", This, memid, invKind, ppv);
7025 hr = ITypeInfo_GetDllEntry(iface, memid, invKind, &dll, &entry, &ordinal);
7026 if (FAILED(hr))
7027 return hr;
7029 module = LoadLibraryW(dll);
7030 if (!module)
7032 ERR("couldn't load %s\n", debugstr_w(dll));
7033 SysFreeString(dll);
7034 SysFreeString(entry);
7035 return STG_E_FILENOTFOUND;
7037 /* FIXME: store library somewhere where we can free it */
7039 if (entry)
7041 LPSTR entryA;
7042 INT len = WideCharToMultiByte(CP_ACP, 0, entry, -1, NULL, 0, NULL, NULL);
7043 entryA = heap_alloc(len);
7044 WideCharToMultiByte(CP_ACP, 0, entry, -1, entryA, len, NULL, NULL);
7046 *ppv = GetProcAddress(module, entryA);
7047 if (!*ppv)
7048 ERR("function not found %s\n", debugstr_a(entryA));
7050 heap_free(entryA);
7052 else
7054 *ppv = GetProcAddress(module, MAKEINTRESOURCEA(ordinal));
7055 if (!*ppv)
7056 ERR("function not found %d\n", ordinal);
7059 SysFreeString(dll);
7060 SysFreeString(entry);
7062 if (!*ppv)
7063 return TYPE_E_DLLFUNCTIONNOTFOUND;
7065 return S_OK;
7068 /* ITypeInfo::CreateInstance
7070 * Creates a new instance of a type that describes a component object class
7071 * (coclass).
7073 static HRESULT WINAPI ITypeInfo_fnCreateInstance( ITypeInfo2 *iface,
7074 IUnknown *pOuterUnk, REFIID riid, VOID **ppvObj)
7076 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7077 HRESULT hr;
7078 TYPEATTR *pTA;
7080 TRACE("(%p)->(%p, %s, %p)\n", This, pOuterUnk, debugstr_guid(riid), ppvObj);
7082 *ppvObj = NULL;
7084 if(pOuterUnk)
7086 WARN("Not able to aggregate\n");
7087 return CLASS_E_NOAGGREGATION;
7090 hr = ITypeInfo_GetTypeAttr(iface, &pTA);
7091 if(FAILED(hr)) return hr;
7093 if(pTA->typekind != TKIND_COCLASS)
7095 WARN("CreateInstance on typeinfo of type %x\n", pTA->typekind);
7096 hr = E_INVALIDARG;
7097 goto end;
7100 hr = S_FALSE;
7101 if(pTA->wTypeFlags & TYPEFLAG_FAPPOBJECT)
7103 IUnknown *pUnk;
7104 hr = GetActiveObject(&pTA->guid, NULL, &pUnk);
7105 TRACE("GetActiveObject rets %08x\n", hr);
7106 if(hr == S_OK)
7108 hr = IUnknown_QueryInterface(pUnk, riid, ppvObj);
7109 IUnknown_Release(pUnk);
7113 if(hr != S_OK)
7114 hr = CoCreateInstance(&pTA->guid, NULL,
7115 CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
7116 riid, ppvObj);
7118 end:
7119 ITypeInfo_ReleaseTypeAttr(iface, pTA);
7120 return hr;
7123 /* ITypeInfo::GetMops
7125 * Retrieves marshalling information.
7127 static HRESULT WINAPI ITypeInfo_fnGetMops( ITypeInfo2 *iface, MEMBERID memid,
7128 BSTR *pBstrMops)
7130 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7131 FIXME("(%p %d) stub!\n", This, memid);
7132 *pBstrMops = NULL;
7133 return S_OK;
7136 /* ITypeInfo::GetContainingTypeLib
7138 * Retrieves the containing type library and the index of the type description
7139 * within that type library.
7141 static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( ITypeInfo2 *iface,
7142 ITypeLib * *ppTLib, UINT *pIndex)
7144 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7146 /* If a pointer is null, we simply ignore it, the ATL in particular passes pIndex as 0 */
7147 if (pIndex) {
7148 *pIndex=This->index;
7149 TRACE("returning pIndex=%d\n", *pIndex);
7152 if (ppTLib) {
7153 *ppTLib=(LPTYPELIB )(This->pTypeLib);
7154 ITypeLib2_AddRef(*ppTLib);
7155 TRACE("returning ppTLib=%p\n", *ppTLib);
7158 return S_OK;
7161 /* ITypeInfo::ReleaseTypeAttr
7163 * Releases a TYPEATTR previously returned by GetTypeAttr.
7166 static void WINAPI ITypeInfo_fnReleaseTypeAttr( ITypeInfo2 *iface,
7167 TYPEATTR* pTypeAttr)
7169 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7170 TRACE("(%p)->(%p)\n", This, pTypeAttr);
7171 heap_free(pTypeAttr);
7174 /* ITypeInfo::ReleaseFuncDesc
7176 * Releases a FUNCDESC previously returned by GetFuncDesc. *
7178 static void WINAPI ITypeInfo_fnReleaseFuncDesc(
7179 ITypeInfo2 *iface,
7180 FUNCDESC *pFuncDesc)
7182 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7183 SHORT i;
7185 TRACE("(%p)->(%p)\n", This, pFuncDesc);
7187 for (i = 0; i < pFuncDesc->cParams; i++)
7188 TLB_FreeElemDesc(&pFuncDesc->lprgelemdescParam[i]);
7189 TLB_FreeElemDesc(&pFuncDesc->elemdescFunc);
7191 SysFreeString((BSTR)pFuncDesc);
7194 /* ITypeInfo::ReleaseVarDesc
7196 * Releases a VARDESC previously returned by GetVarDesc.
7198 static void WINAPI ITypeInfo_fnReleaseVarDesc( ITypeInfo2 *iface,
7199 VARDESC *pVarDesc)
7201 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7202 TRACE("(%p)->(%p)\n", This, pVarDesc);
7204 TLB_FreeElemDesc(&pVarDesc->elemdescVar);
7205 if (pVarDesc->varkind == VAR_CONST)
7206 VariantClear(pVarDesc->u.lpvarValue);
7207 SysFreeString((BSTR)pVarDesc);
7210 /* ITypeInfo2::GetTypeKind
7212 * Returns the TYPEKIND enumeration quickly, without doing any allocations.
7215 static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo2 * iface,
7216 TYPEKIND *pTypeKind)
7218 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7219 *pTypeKind=This->TypeAttr.typekind;
7220 TRACE("(%p) type 0x%0x\n", This,*pTypeKind);
7221 return S_OK;
7224 /* ITypeInfo2::GetTypeFlags
7226 * Returns the type flags without any allocations. This returns a DWORD type
7227 * flag, which expands the type flags without growing the TYPEATTR (type
7228 * attribute).
7231 static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo2 *iface, ULONG *pTypeFlags)
7233 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7234 *pTypeFlags=This->TypeAttr.wTypeFlags;
7235 TRACE("(%p) flags 0x%x\n", This,*pTypeFlags);
7236 return S_OK;
7239 /* ITypeInfo2::GetFuncIndexOfMemId
7240 * Binds to a specific member based on a known DISPID, where the member name
7241 * is not known (for example, when binding to a default member).
7244 static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo2 * iface,
7245 MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex)
7247 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7248 UINT fdc;
7249 HRESULT result;
7251 for (fdc = 0; fdc < This->TypeAttr.cFuncs; ++fdc){
7252 const TLBFuncDesc *pFuncInfo = &This->funcdescs[fdc];
7253 if(memid == pFuncInfo->funcdesc.memid && (invKind & pFuncInfo->funcdesc.invkind))
7254 break;
7256 if(fdc < This->TypeAttr.cFuncs) {
7257 *pFuncIndex = fdc;
7258 result = S_OK;
7259 } else
7260 result = TYPE_E_ELEMENTNOTFOUND;
7262 TRACE("(%p) memid 0x%08x invKind 0x%04x -> %s\n", This,
7263 memid, invKind, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
7264 return result;
7267 /* TypeInfo2::GetVarIndexOfMemId
7269 * Binds to a specific member based on a known DISPID, where the member name
7270 * is not known (for example, when binding to a default member).
7273 static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( ITypeInfo2 * iface,
7274 MEMBERID memid, UINT *pVarIndex)
7276 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7277 TLBVarDesc *pVarInfo;
7279 TRACE("%p %d %p\n", iface, memid, pVarIndex);
7281 pVarInfo = TLB_get_vardesc_by_memberid(This->vardescs, This->TypeAttr.cVars, memid);
7282 if(!pVarInfo)
7283 return TYPE_E_ELEMENTNOTFOUND;
7285 *pVarIndex = (pVarInfo - This->vardescs);
7287 return S_OK;
7290 /* ITypeInfo2::GetCustData
7292 * Gets the custom data
7294 static HRESULT WINAPI ITypeInfo2_fnGetCustData(
7295 ITypeInfo2 * iface,
7296 REFGUID guid,
7297 VARIANT *pVarVal)
7299 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7300 TLBCustData *pCData;
7302 TRACE("%p %s %p\n", This, debugstr_guid(guid), pVarVal);
7304 pCData = TLB_get_custdata_by_guid(&This->custdata_list, guid);
7306 VariantInit( pVarVal);
7307 if (pCData)
7308 VariantCopy( pVarVal, &pCData->data);
7309 else
7310 VariantClear( pVarVal );
7311 return S_OK;
7314 /* ITypeInfo2::GetFuncCustData
7316 * Gets the custom data
7318 static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData(
7319 ITypeInfo2 * iface,
7320 UINT index,
7321 REFGUID guid,
7322 VARIANT *pVarVal)
7324 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7325 TLBCustData *pCData;
7326 TLBFuncDesc *pFDesc = &This->funcdescs[index];
7328 TRACE("%p %u %s %p\n", This, index, debugstr_guid(guid), pVarVal);
7330 if(index >= This->TypeAttr.cFuncs)
7331 return TYPE_E_ELEMENTNOTFOUND;
7333 pCData = TLB_get_custdata_by_guid(&pFDesc->custdata_list, guid);
7334 if(!pCData)
7335 return TYPE_E_ELEMENTNOTFOUND;
7337 VariantInit(pVarVal);
7338 VariantCopy(pVarVal, &pCData->data);
7340 return S_OK;
7343 /* ITypeInfo2::GetParamCustData
7345 * Gets the custom data
7347 static HRESULT WINAPI ITypeInfo2_fnGetParamCustData(
7348 ITypeInfo2 * iface,
7349 UINT indexFunc,
7350 UINT indexParam,
7351 REFGUID guid,
7352 VARIANT *pVarVal)
7354 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7355 TLBCustData *pCData;
7356 TLBFuncDesc *pFDesc = &This->funcdescs[indexFunc];
7358 TRACE("%p %u %u %s %p\n", This, indexFunc, indexParam,
7359 debugstr_guid(guid), pVarVal);
7361 if(indexFunc >= This->TypeAttr.cFuncs)
7362 return TYPE_E_ELEMENTNOTFOUND;
7364 if(indexParam >= pFDesc->funcdesc.cParams)
7365 return TYPE_E_ELEMENTNOTFOUND;
7367 pCData = TLB_get_custdata_by_guid(&pFDesc->pParamDesc[indexParam].custdata_list, guid);
7368 if(!pCData)
7369 return TYPE_E_ELEMENTNOTFOUND;
7371 VariantInit(pVarVal);
7372 VariantCopy(pVarVal, &pCData->data);
7374 return S_OK;
7377 /* ITypeInfo2::GetVarCustData
7379 * Gets the custom data
7381 static HRESULT WINAPI ITypeInfo2_fnGetVarCustData(
7382 ITypeInfo2 * iface,
7383 UINT index,
7384 REFGUID guid,
7385 VARIANT *pVarVal)
7387 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7388 TLBCustData *pCData;
7389 TLBVarDesc *pVDesc = &This->vardescs[index];
7391 TRACE("%p %s %p\n", This, debugstr_guid(guid), pVarVal);
7393 if(index >= This->TypeAttr.cVars)
7394 return TYPE_E_ELEMENTNOTFOUND;
7396 pCData = TLB_get_custdata_by_guid(&pVDesc->custdata_list, guid);
7397 if(!pCData)
7398 return TYPE_E_ELEMENTNOTFOUND;
7400 VariantInit(pVarVal);
7401 VariantCopy(pVarVal, &pCData->data);
7403 return S_OK;
7406 /* ITypeInfo2::GetImplCustData
7408 * Gets the custom data
7410 static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData(
7411 ITypeInfo2 * iface,
7412 UINT index,
7413 REFGUID guid,
7414 VARIANT *pVarVal)
7416 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7417 TLBCustData *pCData;
7418 TLBImplType *pRDesc = &This->impltypes[index];
7420 TRACE("%p %u %s %p\n", This, index, debugstr_guid(guid), pVarVal);
7422 if(index >= This->TypeAttr.cImplTypes)
7423 return TYPE_E_ELEMENTNOTFOUND;
7425 pCData = TLB_get_custdata_by_guid(&pRDesc->custdata_list, guid);
7426 if(!pCData)
7427 return TYPE_E_ELEMENTNOTFOUND;
7429 VariantInit(pVarVal);
7430 VariantCopy(pVarVal, &pCData->data);
7432 return S_OK;
7435 /* ITypeInfo2::GetDocumentation2
7437 * Retrieves the documentation string, the complete Help file name and path,
7438 * the localization context to use, and the context ID for the library Help
7439 * topic in the Help file.
7442 static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2(
7443 ITypeInfo2 * iface,
7444 MEMBERID memid,
7445 LCID lcid,
7446 BSTR *pbstrHelpString,
7447 DWORD *pdwHelpStringContext,
7448 BSTR *pbstrHelpStringDll)
7450 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7451 const TLBFuncDesc *pFDesc;
7452 const TLBVarDesc *pVDesc;
7453 TRACE("(%p) memid %d lcid(0x%x) HelpString(%p) "
7454 "HelpStringContext(%p) HelpStringDll(%p)\n",
7455 This, memid, lcid, pbstrHelpString, pdwHelpStringContext,
7456 pbstrHelpStringDll );
7457 /* the help string should be obtained from the helpstringdll,
7458 * using the _DLLGetDocumentation function, based on the supplied
7459 * lcid. Nice to do sometime...
7461 if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
7462 if(pbstrHelpString)
7463 *pbstrHelpString=SysAllocString(This->Name);
7464 if(pdwHelpStringContext)
7465 *pdwHelpStringContext=This->dwHelpStringContext;
7466 if(pbstrHelpStringDll)
7467 *pbstrHelpStringDll=
7468 SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
7469 return S_OK;
7470 }else {/* for a member */
7471 pFDesc = TLB_get_funcdesc_by_memberid(This->funcdescs, This->TypeAttr.cFuncs, memid);
7472 if(pFDesc){
7473 if(pbstrHelpString)
7474 *pbstrHelpString=SysAllocString(pFDesc->HelpString);
7475 if(pdwHelpStringContext)
7476 *pdwHelpStringContext=pFDesc->HelpStringContext;
7477 if(pbstrHelpStringDll)
7478 *pbstrHelpStringDll=
7479 SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
7480 return S_OK;
7482 pVDesc = TLB_get_vardesc_by_memberid(This->vardescs, This->TypeAttr.cVars, memid);
7483 if(pVDesc){
7484 if(pbstrHelpString)
7485 *pbstrHelpString=SysAllocString(pVDesc->HelpString);
7486 if(pdwHelpStringContext)
7487 *pdwHelpStringContext=pVDesc->HelpStringContext;
7488 if(pbstrHelpStringDll)
7489 *pbstrHelpStringDll=
7490 SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
7491 return S_OK;
7494 return TYPE_E_ELEMENTNOTFOUND;
7497 /* ITypeInfo2::GetAllCustData
7499 * Gets all custom data items for the Type info.
7502 static HRESULT WINAPI ITypeInfo2_fnGetAllCustData(
7503 ITypeInfo2 * iface,
7504 CUSTDATA *pCustData)
7506 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7508 TRACE("%p %p\n", This, pCustData);
7510 return TLB_copy_all_custdata(&This->custdata_list, pCustData);
7513 /* ITypeInfo2::GetAllFuncCustData
7515 * Gets all custom data items for the specified Function
7518 static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData(
7519 ITypeInfo2 * iface,
7520 UINT index,
7521 CUSTDATA *pCustData)
7523 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7524 TLBFuncDesc *pFDesc = &This->funcdescs[index];
7526 TRACE("%p %u %p\n", This, index, pCustData);
7528 if(index >= This->TypeAttr.cFuncs)
7529 return TYPE_E_ELEMENTNOTFOUND;
7531 return TLB_copy_all_custdata(&pFDesc->custdata_list, pCustData);
7534 /* ITypeInfo2::GetAllParamCustData
7536 * Gets all custom data items for the Functions
7539 static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo2 * iface,
7540 UINT indexFunc, UINT indexParam, CUSTDATA *pCustData)
7542 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7543 TLBFuncDesc *pFDesc = &This->funcdescs[indexFunc];
7545 TRACE("%p %u %u %p\n", This, indexFunc, indexParam, pCustData);
7547 if(indexFunc >= This->TypeAttr.cFuncs)
7548 return TYPE_E_ELEMENTNOTFOUND;
7550 if(indexParam >= pFDesc->funcdesc.cParams)
7551 return TYPE_E_ELEMENTNOTFOUND;
7553 return TLB_copy_all_custdata(&pFDesc->pParamDesc[indexParam].custdata_list, pCustData);
7556 /* ITypeInfo2::GetAllVarCustData
7558 * Gets all custom data items for the specified Variable
7561 static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo2 * iface,
7562 UINT index, CUSTDATA *pCustData)
7564 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7565 TLBVarDesc * pVDesc = &This->vardescs[index];
7567 TRACE("%p %u %p\n", This, index, pCustData);
7569 if(index >= This->TypeAttr.cVars)
7570 return TYPE_E_ELEMENTNOTFOUND;
7572 return TLB_copy_all_custdata(&pVDesc->custdata_list, pCustData);
7575 /* ITypeInfo2::GetAllImplCustData
7577 * Gets all custom data items for the specified implementation type
7580 static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData(
7581 ITypeInfo2 * iface,
7582 UINT index,
7583 CUSTDATA *pCustData)
7585 ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7586 TLBImplType *pRDesc = &This->impltypes[index];
7588 TRACE("%p %u %p\n", This, index, pCustData);
7590 if(index >= This->TypeAttr.cImplTypes)
7591 return TYPE_E_ELEMENTNOTFOUND;
7593 return TLB_copy_all_custdata(&pRDesc->custdata_list, pCustData);
7596 static const ITypeInfo2Vtbl tinfvt =
7599 ITypeInfo_fnQueryInterface,
7600 ITypeInfo_fnAddRef,
7601 ITypeInfo_fnRelease,
7603 ITypeInfo_fnGetTypeAttr,
7604 ITypeInfo_fnGetTypeComp,
7605 ITypeInfo_fnGetFuncDesc,
7606 ITypeInfo_fnGetVarDesc,
7607 ITypeInfo_fnGetNames,
7608 ITypeInfo_fnGetRefTypeOfImplType,
7609 ITypeInfo_fnGetImplTypeFlags,
7610 ITypeInfo_fnGetIDsOfNames,
7611 ITypeInfo_fnInvoke,
7612 ITypeInfo_fnGetDocumentation,
7613 ITypeInfo_fnGetDllEntry,
7614 ITypeInfo_fnGetRefTypeInfo,
7615 ITypeInfo_fnAddressOfMember,
7616 ITypeInfo_fnCreateInstance,
7617 ITypeInfo_fnGetMops,
7618 ITypeInfo_fnGetContainingTypeLib,
7619 ITypeInfo_fnReleaseTypeAttr,
7620 ITypeInfo_fnReleaseFuncDesc,
7621 ITypeInfo_fnReleaseVarDesc,
7623 ITypeInfo2_fnGetTypeKind,
7624 ITypeInfo2_fnGetTypeFlags,
7625 ITypeInfo2_fnGetFuncIndexOfMemId,
7626 ITypeInfo2_fnGetVarIndexOfMemId,
7627 ITypeInfo2_fnGetCustData,
7628 ITypeInfo2_fnGetFuncCustData,
7629 ITypeInfo2_fnGetParamCustData,
7630 ITypeInfo2_fnGetVarCustData,
7631 ITypeInfo2_fnGetImplTypeCustData,
7632 ITypeInfo2_fnGetDocumentation2,
7633 ITypeInfo2_fnGetAllCustData,
7634 ITypeInfo2_fnGetAllFuncCustData,
7635 ITypeInfo2_fnGetAllParamCustData,
7636 ITypeInfo2_fnGetAllVarCustData,
7637 ITypeInfo2_fnGetAllImplTypeCustData,
7640 /******************************************************************************
7641 * CreateDispTypeInfo [OLEAUT32.31]
7643 * Build type information for an object so it can be called through an
7644 * IDispatch interface.
7646 * RETURNS
7647 * Success: S_OK. pptinfo contains the created ITypeInfo object.
7648 * Failure: E_INVALIDARG, if one or more arguments is invalid.
7650 * NOTES
7651 * This call allows an objects methods to be accessed through IDispatch, by
7652 * building an ITypeInfo object that IDispatch can use to call through.
7654 HRESULT WINAPI CreateDispTypeInfo(
7655 INTERFACEDATA *pidata, /* [I] Description of the interface to build type info for */
7656 LCID lcid, /* [I] Locale Id */
7657 ITypeInfo **pptinfo) /* [O] Destination for created ITypeInfo object */
7659 ITypeInfoImpl *pTIClass, *pTIIface;
7660 ITypeLibImpl *pTypeLibImpl;
7661 unsigned int param, func;
7662 TLBFuncDesc *pFuncDesc;
7663 TLBRefType *ref;
7665 TRACE("\n");
7666 pTypeLibImpl = TypeLibImpl_Constructor();
7667 if (!pTypeLibImpl) return E_FAIL;
7669 pTypeLibImpl->TypeInfoCount = 2;
7670 pTypeLibImpl->typeinfos = heap_alloc_zero(pTypeLibImpl->TypeInfoCount * sizeof(ITypeInfoImpl*));
7672 pTIIface = pTypeLibImpl->typeinfos[0] = ITypeInfoImpl_Constructor();
7673 pTIIface->pTypeLib = pTypeLibImpl;
7674 pTIIface->index = 0;
7675 pTIIface->Name = NULL;
7676 pTIIface->dwHelpContext = -1;
7677 memset(&pTIIface->TypeAttr.guid, 0, sizeof(GUID));
7678 pTIIface->TypeAttr.lcid = lcid;
7679 pTIIface->TypeAttr.typekind = TKIND_INTERFACE;
7680 pTIIface->TypeAttr.wMajorVerNum = 0;
7681 pTIIface->TypeAttr.wMinorVerNum = 0;
7682 pTIIface->TypeAttr.cbAlignment = 2;
7683 pTIIface->TypeAttr.cbSizeInstance = -1;
7684 pTIIface->TypeAttr.cbSizeVft = -1;
7685 pTIIface->TypeAttr.cFuncs = 0;
7686 pTIIface->TypeAttr.cImplTypes = 0;
7687 pTIIface->TypeAttr.cVars = 0;
7688 pTIIface->TypeAttr.wTypeFlags = 0;
7690 pTIIface->funcdescs = TLBFuncDesc_Constructor(pidata->cMembers);
7691 pFuncDesc = pTIIface->funcdescs;
7692 for(func = 0; func < pidata->cMembers; func++) {
7693 METHODDATA *md = pidata->pmethdata + func;
7694 pFuncDesc->Name = SysAllocString(md->szName);
7695 pFuncDesc->funcdesc.memid = md->dispid;
7696 pFuncDesc->funcdesc.lprgscode = NULL;
7697 pFuncDesc->funcdesc.funckind = FUNC_VIRTUAL;
7698 pFuncDesc->funcdesc.invkind = md->wFlags;
7699 pFuncDesc->funcdesc.callconv = md->cc;
7700 pFuncDesc->funcdesc.cParams = md->cArgs;
7701 pFuncDesc->funcdesc.cParamsOpt = 0;
7702 pFuncDesc->funcdesc.oVft = md->iMeth * sizeof(void *);
7703 pFuncDesc->funcdesc.cScodes = 0;
7704 pFuncDesc->funcdesc.wFuncFlags = 0;
7705 pFuncDesc->funcdesc.elemdescFunc.tdesc.vt = md->vtReturn;
7706 pFuncDesc->funcdesc.elemdescFunc.u.paramdesc.wParamFlags = PARAMFLAG_NONE;
7707 pFuncDesc->funcdesc.elemdescFunc.u.paramdesc.pparamdescex = NULL;
7708 pFuncDesc->funcdesc.lprgelemdescParam = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7709 md->cArgs * sizeof(ELEMDESC));
7710 pFuncDesc->pParamDesc = TLBParDesc_Constructor(md->cArgs);
7711 for(param = 0; param < md->cArgs; param++) {
7712 pFuncDesc->funcdesc.lprgelemdescParam[param].tdesc.vt = md->ppdata[param].vt;
7713 pFuncDesc->pParamDesc[param].Name = SysAllocString(md->ppdata[param].szName);
7715 pFuncDesc->helpcontext = 0;
7716 pFuncDesc->HelpStringContext = 0;
7717 pFuncDesc->HelpString = NULL;
7718 pFuncDesc->Entry = NULL;
7719 list_init(&pFuncDesc->custdata_list);
7720 pTIIface->TypeAttr.cFuncs++;
7721 ++pFuncDesc;
7724 dump_TypeInfo(pTIIface);
7726 pTIClass = pTypeLibImpl->typeinfos[1] = ITypeInfoImpl_Constructor();
7727 pTIClass->pTypeLib = pTypeLibImpl;
7728 pTIClass->index = 1;
7729 pTIClass->Name = NULL;
7730 pTIClass->dwHelpContext = -1;
7731 memset(&pTIClass->TypeAttr.guid, 0, sizeof(GUID));
7732 pTIClass->TypeAttr.lcid = lcid;
7733 pTIClass->TypeAttr.typekind = TKIND_COCLASS;
7734 pTIClass->TypeAttr.wMajorVerNum = 0;
7735 pTIClass->TypeAttr.wMinorVerNum = 0;
7736 pTIClass->TypeAttr.cbAlignment = 2;
7737 pTIClass->TypeAttr.cbSizeInstance = -1;
7738 pTIClass->TypeAttr.cbSizeVft = -1;
7739 pTIClass->TypeAttr.cFuncs = 0;
7740 pTIClass->TypeAttr.cImplTypes = 1;
7741 pTIClass->TypeAttr.cVars = 0;
7742 pTIClass->TypeAttr.wTypeFlags = 0;
7744 pTIClass->impltypes = TLBImplType_Constructor(1);
7746 ref = heap_alloc_zero(sizeof(*ref));
7747 ref->pImpTLInfo = TLB_REF_INTERNAL;
7748 list_add_head(&pTypeLibImpl->ref_list, &ref->entry);
7750 dump_TypeInfo(pTIClass);
7752 *pptinfo = (ITypeInfo*)pTIClass;
7754 ITypeInfo_AddRef(*pptinfo);
7755 ITypeLib_Release((ITypeLib *)&pTypeLibImpl->lpVtbl);
7757 return S_OK;
7761 static HRESULT WINAPI ITypeComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
7763 ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7765 return ITypeInfo_QueryInterface((ITypeInfo *)This, riid, ppv);
7768 static ULONG WINAPI ITypeComp_fnAddRef(ITypeComp * iface)
7770 ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7772 return ITypeInfo_AddRef((ITypeInfo *)This);
7775 static ULONG WINAPI ITypeComp_fnRelease(ITypeComp * iface)
7777 ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7779 return ITypeInfo_Release((ITypeInfo *)This);
7782 static HRESULT WINAPI ITypeComp_fnBind(
7783 ITypeComp * iface,
7784 OLECHAR * szName,
7785 ULONG lHash,
7786 WORD wFlags,
7787 ITypeInfo ** ppTInfo,
7788 DESCKIND * pDescKind,
7789 BINDPTR * pBindPtr)
7791 ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7792 const TLBFuncDesc *pFDesc;
7793 const TLBVarDesc *pVDesc;
7794 HRESULT hr = DISP_E_MEMBERNOTFOUND;
7795 UINT fdc;
7797 TRACE("(%p)->(%s, %x, 0x%x, %p, %p, %p)\n", This, debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
7799 *pDescKind = DESCKIND_NONE;
7800 pBindPtr->lpfuncdesc = NULL;
7801 *ppTInfo = NULL;
7803 for(fdc = 0; fdc < This->TypeAttr.cFuncs; ++fdc){
7804 pFDesc = &This->funcdescs[fdc];
7805 if (!strcmpiW(pFDesc->Name, szName)) {
7806 if (!wFlags || (pFDesc->funcdesc.invkind & wFlags))
7807 break;
7808 else
7809 /* name found, but wrong flags */
7810 hr = TYPE_E_TYPEMISMATCH;
7814 if (fdc < This->TypeAttr.cFuncs)
7816 HRESULT hr = TLB_AllocAndInitFuncDesc(
7817 &pFDesc->funcdesc,
7818 &pBindPtr->lpfuncdesc,
7819 This->TypeAttr.typekind == TKIND_DISPATCH);
7820 if (FAILED(hr))
7821 return hr;
7822 *pDescKind = DESCKIND_FUNCDESC;
7823 *ppTInfo = (ITypeInfo *)&This->lpVtbl;
7824 ITypeInfo_AddRef(*ppTInfo);
7825 return S_OK;
7826 } else {
7827 pVDesc = TLB_get_vardesc_by_name(This->vardescs, This->TypeAttr.cVars, szName);
7828 if(pVDesc){
7829 HRESULT hr = TLB_AllocAndInitVarDesc(&pVDesc->vardesc, &pBindPtr->lpvardesc);
7830 if (FAILED(hr))
7831 return hr;
7832 *pDescKind = DESCKIND_VARDESC;
7833 *ppTInfo = (ITypeInfo *)&This->lpVtbl;
7834 ITypeInfo_AddRef(*ppTInfo);
7835 return S_OK;
7838 /* FIXME: search each inherited interface, not just the first */
7839 if (hr == DISP_E_MEMBERNOTFOUND && This->impltypes) {
7840 /* recursive search */
7841 ITypeInfo *pTInfo;
7842 ITypeComp *pTComp;
7843 HRESULT hr;
7844 hr=ITypeInfo_GetRefTypeInfo((ITypeInfo *)&This->lpVtbl, This->impltypes[0].hRef, &pTInfo);
7845 if (SUCCEEDED(hr))
7847 hr = ITypeInfo_GetTypeComp(pTInfo,&pTComp);
7848 ITypeInfo_Release(pTInfo);
7850 if (SUCCEEDED(hr))
7852 hr = ITypeComp_Bind(pTComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
7853 ITypeComp_Release(pTComp);
7854 return hr;
7856 WARN("Could not search inherited interface!\n");
7858 if (hr == DISP_E_MEMBERNOTFOUND)
7859 hr = S_OK;
7860 TRACE("did not find member with name %s, flags 0x%x\n", debugstr_w(szName), wFlags);
7861 return hr;
7864 static HRESULT WINAPI ITypeComp_fnBindType(
7865 ITypeComp * iface,
7866 OLECHAR * szName,
7867 ULONG lHash,
7868 ITypeInfo ** ppTInfo,
7869 ITypeComp ** ppTComp)
7871 TRACE("(%s, %x, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
7873 /* strange behaviour (does nothing) but like the
7874 * original */
7876 if (!ppTInfo || !ppTComp)
7877 return E_POINTER;
7879 *ppTInfo = NULL;
7880 *ppTComp = NULL;
7882 return S_OK;
7885 static const ITypeCompVtbl tcompvt =
7888 ITypeComp_fnQueryInterface,
7889 ITypeComp_fnAddRef,
7890 ITypeComp_fnRelease,
7892 ITypeComp_fnBind,
7893 ITypeComp_fnBindType