-- v4: vccorlib140: Emit RTTI for Platform::Type. vccorlib140/tests: Add RTTI tests for Platform::Type.
From: Vibhav Pant vibhavp@gmail.com
--- dlls/vccorlib140/tests/vccorlib.c | 65 ++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 2 deletions(-)
diff --git a/dlls/vccorlib140/tests/vccorlib.c b/dlls/vccorlib140/tests/vccorlib.c index 7750794d93e..cbcaf4abcea 100644 --- a/dlls/vccorlib140/tests/vccorlib.c +++ b/dlls/vccorlib140/tests/vccorlib.c @@ -72,6 +72,7 @@ struct thiscall_thunk #pragma pack( pop )
static ULONG_PTR (WINAPI *call_thiscall_func1)(void *func, void *this); +static ULONG_PTR (WINAPI *call_thiscall_func2)(void *func, void *this, void *arg1);
static void init_thiscall_thunk(void) { @@ -82,16 +83,19 @@ static void init_thiscall_thunk(void) thunk->push_eax = 0x50; /* pushl %eax */ thunk->jmp_edx = 0xe2ff; /* jmp *%edx */ call_thiscall_func1 = (void *)thunk; + call_thiscall_func2 = (void *)thunk; }
#define __thiscall __stdcall #define call_func1(func,_this) call_thiscall_func1(func,_this) +#define call_func2(func,_this,arg1) call_thiscall_func2(func, _this, arg1)
#else
#define init_thiscall_thunk() #define __thiscall __cdecl #define call_func1(func,_this) func(_this) +#define call_func2(func,_this,arg1) func(_this,arg1)
#endif /* __i386__ */
@@ -127,9 +131,16 @@ static HSTRING (__cdecl *p_platform_type_ToString)(void *); static HSTRING (__cdecl *p_platform_type_get_FullName)(void *); static void *(WINAPI *pCreateValue)(int type, const void *);
+static void *(__cdecl *p__RTtypeid)(const void *); +static const char *(__thiscall *p_type_info_name)(void *); +static const char *(__thiscall *p_type_info_raw_name)(void *); +static int (__thiscall *p_type_info_opequals_equals)(void *, void *); +static int (__thiscall *p_type_info_opnot_equals)(void *, void *); + static BOOL init(void) { HMODULE hmod = LoadLibraryA("vccorlib140.dll"); + HMODULE msvcrt = LoadLibraryA("msvcrt.dll");
if (!hmod) { @@ -143,6 +154,8 @@ static BOOL init(void) pUninitializeData = (void *)GetProcAddress(hmod, "?UninitializeData@Details@Platform@@YAXH@Z"); ok(pUninitializeData != NULL, "UninitializeData not available\n"); + p__RTtypeid = (void *)GetProcAddress(msvcrt, "__RTtypeid"); + ok(p__RTtypeid != NULL, "__RTtypeid not available\n");
#ifdef __arm__ pGetActivationFactoryByPCWSTR = (void *)GetProcAddress(hmod, @@ -160,6 +173,10 @@ static BOOL init(void) p_platform_type_ToString = (void *)GetProcAddress(hmod, "?ToString@Type@Platform@@U$AAAP$AAVString@2@XZ"); p_platform_type_get_FullName = (void *)GetProcAddress(hmod, "?get@FullName@Type@Platform@@Q$AAAP$AAVString@3@XZ"); pCreateValue = (void *)GetProcAddress(hmod, "?CreateValue@Details@Platform@@YAP$AAVObject@2@W4TypeCode@2@PBX@Z"); + p_type_info_name = (void *)GetProcAddress(msvcrt, "?name@type_info@@QBAPBDXZ"); + p_type_info_raw_name = (void *)GetProcAddress(msvcrt, "?raw_name@type_info@@QBAPBDXZ"); + p_type_info_opequals_equals = (void *)GetProcAddress(msvcrt, "??8type_info@@QBAHABV0@@Z"); + p_type_info_opnot_equals = (void *)GetProcAddress(msvcrt, "??9type_info@@QBAHABV0@@Z"); #else if (sizeof(void *) == 8) { @@ -181,6 +198,10 @@ static BOOL init(void) "?get@FullName@Type@Platform@@QE$AAAPE$AAVString@3@XZ"); pCreateValue = (void *)GetProcAddress(hmod, "?CreateValue@Details@Platform@@YAPE$AAVObject@2@W4TypeCode@2@PEBX@Z"); + p_type_info_name = (void *)GetProcAddress(msvcrt, "?name@type_info@@QEBAPEBDXZ"); + p_type_info_raw_name = (void *)GetProcAddress(msvcrt, "?raw_name@type_info@@QEBAPEBDXZ"); + p_type_info_opequals_equals = (void *)GetProcAddress(msvcrt, "??8type_info@@QEBAHAEBV0@@Z"); + p_type_info_opnot_equals = (void *)GetProcAddress(msvcrt, "??9type_info@@QEBAHAEBV0@@Z"); } else { @@ -201,6 +222,10 @@ static BOOL init(void) "?get@FullName@Type@Platform@@Q$AAAP$AAVString@3@XZ"); pCreateValue = (void *)GetProcAddress(hmod, "?CreateValue@Details@Platform@@YGP$AAVObject@2@W4TypeCode@2@PBX@Z"); + p_type_info_name = (void *)GetProcAddress(msvcrt, "?name@type_info@@QBEPBDXZ"); + p_type_info_raw_name = (void *)GetProcAddress(msvcrt, "?raw_name@type_info@@QBEPBDXZ"); + p_type_info_opequals_equals = (void *)GetProcAddress(msvcrt, "??8type_info@@QBEHABV0@@Z"); + p_type_info_opnot_equals = (void *)GetProcAddress(msvcrt, "??9type_info@@QBEHABV0@@Z"); } #endif ok(pGetActivationFactoryByPCWSTR != NULL, "GetActivationFactoryByPCWSTR not available\n"); @@ -216,6 +241,11 @@ static BOOL init(void) ok(p_platform_type_get_FullName != NULL, "Platform::Type::FullName not available\n"); ok(pCreateValue != NULL, "CreateValue not available\n");
+ ok(p_type_info_name != NULL, "type_info::name not available\n"); + ok(p_type_info_raw_name != NULL, "type_info::raw_name not available\n"); + ok(p_type_info_opequals_equals != NULL, "type_info::operator== not available\n"); + ok(p_type_info_opnot_equals != NULL, "type_info::operator!= not available\n"); + init_thiscall_thunk();
return TRUE; @@ -678,9 +708,11 @@ DEFINE_GUID(IID_IPrintable,0xde0cbaeb,0x8065,0x4a45,0x96,0xb1,0xc9,0xd4,0x43,0xf static void test___abi_make_type_id(void) { const struct __abi_type_descriptor desc = {L"foo", 0xdeadbeef}, desc2 = {L"foo", 0xdeadbeef}, desc3 = {NULL, 1}; - void *type_obj, *type_obj2; + void *type_obj, *type_obj2, *type_info, *type_info2; + const char *name, *raw_name; + IClosable *closable; + int typecode, ret; const WCHAR *buf; - int typecode; HSTRING str; ULONG count; bool equals; @@ -730,6 +762,35 @@ static void test___abi_make_type_id(void) ok(type_obj2 != NULL, "got type_obj %p\n", type_obj); ok(type_obj2 != type_obj, "got type_obj2 %p\n", type_obj2);
+ type_info = p__RTtypeid(type_obj); + todo_wine ok(type_info != NULL, "got type_info %p\n", type_info); + if (type_info) + { + name = (char *)call_func1(p_type_info_name, type_info); + ok(!strcmp(name, "class Platform::Type"), "got name %s\n", debugstr_a(name)); + raw_name = (char *)call_func1(p_type_info_raw_name, type_info); + ok(!strcmp(raw_name, ".?AVType@Platform@@"), "got raw_name %s\n", debugstr_a(raw_name)); + } + + hr = IInspectable_QueryInterface(type_obj, &IID_IClosable, (void **)&closable); + ok(hr == S_OK, "got hr %#lx\n", hr); + type_info2 = p__RTtypeid(closable); + todo_wine ok(type_info2 != NULL, "got type_info %p\n", type_info2); + if (type_info2) + { + name = (char *)call_func1(p_type_info_name, type_info2); + ok(!strcmp(name, "class Platform::Type"), "got name %s\n", debugstr_a(name)); + + raw_name = (char *)call_func1(p_type_info_raw_name, type_info2); + ok(!strcmp(raw_name, ".?AVType@Platform@@"), "got raw_name %s\n", debugstr_a(raw_name)); + + ret = call_func2(p_type_info_opequals_equals, type_info, type_info2); + ok(ret, "got ret %d\n", ret); + ret = call_func2(p_type_info_opnot_equals, type_info, type_info2); + ok(!ret, "got ret %d\n", ret); + } + IClosable_Release(closable); + check_interface(type_obj2, &IID_IInspectable); check_interface(type_obj2, &IID_IClosable); check_interface(type_obj2, &IID_IMarshal);
From: Vibhav Pant vibhavp@gmail.com
--- dlls/msvcp90/cxx.h | 1 + dlls/msvcrt/cxx.h | 1 + dlls/vccorlib140/cxx.h | 430 ++++++++++++++++++++++++++++++ dlls/vccorlib140/private.h | 63 +++++ dlls/vccorlib140/tests/vccorlib.c | 35 ++- dlls/vccorlib140/vccorlib.c | 93 ++++--- 6 files changed, 573 insertions(+), 50 deletions(-) create mode 100644 dlls/vccorlib140/cxx.h create mode 100644 dlls/vccorlib140/private.h
diff --git a/dlls/msvcp90/cxx.h b/dlls/msvcp90/cxx.h index 642162ca0b4..b803d35a283 100644 --- a/dlls/msvcp90/cxx.h +++ b/dlls/msvcp90/cxx.h @@ -79,6 +79,7 @@ const rtti_object_locator name ## _rtti = \ #elif defined __WINE_PE_BUILD
#define DEFINE_RTTI_DATA2(name, off, mangled_name, ...) \ +extern const rtti_object_locator name##_rtti; \ type_info name ## _type_info = { &type_info_vtable, NULL, mangled_name }; \ extern const rtti_base_descriptor name ## _rtti_base_descriptor[1]; \ void __asm_dummy_ ## name ## _rtti(void) \ diff --git a/dlls/msvcrt/cxx.h b/dlls/msvcrt/cxx.h index 642162ca0b4..b803d35a283 100644 --- a/dlls/msvcrt/cxx.h +++ b/dlls/msvcrt/cxx.h @@ -79,6 +79,7 @@ const rtti_object_locator name ## _rtti = \ #elif defined __WINE_PE_BUILD
#define DEFINE_RTTI_DATA2(name, off, mangled_name, ...) \ +extern const rtti_object_locator name##_rtti; \ type_info name ## _type_info = { &type_info_vtable, NULL, mangled_name }; \ extern const rtti_base_descriptor name ## _rtti_base_descriptor[1]; \ void __asm_dummy_ ## name ## _rtti(void) \ diff --git a/dlls/vccorlib140/cxx.h b/dlls/vccorlib140/cxx.h new file mode 100644 index 00000000000..b803d35a283 --- /dev/null +++ b/dlls/vccorlib140/cxx.h @@ -0,0 +1,430 @@ +/* + * Copyright 2012 Piotr Caban for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "windef.h" +#include "winternl.h" +#include "rtlsupportapi.h" +#include "wine/asm.h" + +#ifdef __i386__ +#undef CXX_USE_RVA +#else +#define CXX_USE_RVA 1 +#endif + +#ifndef _WIN64 +#undef RTTI_USE_RVA +#else +#define RTTI_USE_RVA 1 +#endif + +#ifdef _WIN64 + +#define VTABLE_ADD_FUNC(name) "\t.quad " THISCALL_NAME(name) "\n" + +#define __ASM_VTABLE(name,funcs) \ + __asm__(".data\n" \ + "\t.balign 8\n" \ + "\t.quad " __ASM_NAME(#name "_rtti") "\n" \ + __ASM_GLOBL(__ASM_NAME(#name "_vtable")) "\n" \ + funcs "\n\t.text") + +#else + +#define VTABLE_ADD_FUNC(name) "\t.long " THISCALL_NAME(name) "\n" + +#define __ASM_VTABLE(name,funcs) \ + __asm__(".data\n" \ + "\t.balign 4\n" \ + "\t.long " __ASM_NAME(#name "_rtti") "\n" \ + __ASM_GLOBL(__ASM_NAME(#name "_vtable")) "\n" \ + funcs "\n\t.text") + +#endif /* _WIN64 */ + +#ifndef RTTI_USE_RVA + +#define DEFINE_RTTI_DATA(name, off, mangled_name, ...) \ +static type_info name ## _type_info = { &type_info_vtable, NULL, mangled_name }; \ +\ +static const rtti_base_descriptor name ## _rtti_base_descriptor[1] = \ + { { &name ##_type_info, ARRAY_SIZE(((const void *[]){ __VA_ARGS__ })), { 0, -1, 0}, 64 } }; \ +\ +static const rtti_base_array name ## _rtti_base_array = \ + { { name ## _rtti_base_descriptor, __VA_ARGS__ } }; \ +\ +static const rtti_object_hierarchy name ## _hierarchy = \ + { 0, 0, ARRAY_SIZE(((const void *[]){ NULL, __VA_ARGS__ })), &name ## _rtti_base_array }; \ +\ +const rtti_object_locator name ## _rtti = \ + { 0, off, 0, &name ## _type_info, &name ## _hierarchy }; + +#define INIT_RTTI(name,base) /* nothing to do */ + +#elif defined __WINE_PE_BUILD + +#define DEFINE_RTTI_DATA2(name, off, mangled_name, ...) \ +extern const rtti_object_locator name##_rtti; \ +type_info name ## _type_info = { &type_info_vtable, NULL, mangled_name }; \ +extern const rtti_base_descriptor name ## _rtti_base_descriptor[1]; \ +void __asm_dummy_ ## name ## _rtti(void) \ +{ \ + asm( ".balign 4\n\t" \ + __ASM_GLOBL(#name "_rtti_base_descriptor") "\n\t" \ + ".rva " #name "_type_info\n\t" \ + ".long %c0-1, 0, -1, 0, 64\n" \ + #name "_rtti_base_array:\n\t" \ + ".rva " #__VA_ARGS__ "\n" \ + #name "_rtti_hierarchy:\n\t" \ + ".long 0, 0, %c0\n\t" \ + ".rva " #name "_rtti_base_array\n\t" \ + __ASM_GLOBL(#name "_rtti") "\n\t" \ + ".long 1, %c1, 0\n\t" \ + ".rva " #name "_type_info\n\t" \ + ".rva " #name "_rtti_hierarchy\n\t" \ + ".rva " #name "_rtti\n\t" \ + :: "i"(ARRAY_SIZE(((const void *[]){ __VA_ARGS__ }))), "i"(off) ); \ +} +#define DEFINE_RTTI_DATA(name, off, mangled_name, ...) \ + DEFINE_RTTI_DATA2(name, off, mangled_name, name ## _rtti_base_descriptor, ##__VA_ARGS__) + +#define INIT_RTTI(name,base) /* nothing to do */ + +#else /* RTTI_USE_RVA */ + +#define DEFINE_RTTI_DATA(name, off, mangled_name, ...) \ +static type_info name ## _type_info = { &type_info_vtable, NULL, mangled_name }; \ +\ +static rtti_base_descriptor name ## _rtti_base_descriptor[1] = \ + { { 0xdeadbeef, ARRAY_SIZE(((const void *[]){ __VA_ARGS__ })), { 0, -1, 0}, 64 } }; \ +\ +static rtti_base_array name ## _rtti_base_array; \ +\ +static rtti_object_hierarchy name ## _hierarchy = \ + { 0, 0, ARRAY_SIZE(((const void *[]){ NULL, __VA_ARGS__ })) }; \ +\ +rtti_object_locator name ## _rtti = \ + { 1, off, 0, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef }; \ +\ +static void init_ ## name ## _rtti(char *base) \ +{ \ + const void * const name ## _rtti_bases[] = { name ## _rtti_base_descriptor, __VA_ARGS__ }; \ + name ## _rtti_base_descriptor[0].type_descriptor = (char*)&name ## _type_info - base; \ + for (unsigned int i = 0; i < ARRAY_SIZE(name ## _rtti_bases); i++) \ + name ## _rtti_base_array.bases[i] = (char*)name ## _rtti_bases[i] - base; \ + name ## _hierarchy.base_classes = (char*)&name ## _rtti_base_array - base; \ + name ## _rtti.type_descriptor = (char*)&name ## _type_info - base; \ + name ## _rtti.type_hierarchy = (char*)&name ## _hierarchy - base; \ + name ## _rtti.object_locator = (char*)&name ## _rtti - base; \ +} + +#define INIT_RTTI(name,base) init_ ## name ## _rtti((void *)(base)) + +#endif /* RTTI_USE_RVA */ + +#ifndef CXX_USE_RVA + +#define DEFINE_CXX_TYPE(type, dtor, ...) \ +static const cxx_type_info type ## _cxx_type_info[1] = \ + { { 0, &type ##_type_info, { 0, -1, 0 }, sizeof(type), THISCALL(type ##_copy_ctor) } }; \ +\ +static const cxx_type_info_table type ## _cxx_type_table = \ + { ARRAY_SIZE(((const void *[]){ NULL, __VA_ARGS__ })), { type ## _cxx_type_info, __VA_ARGS__ } }; \ +\ +static const cxx_exception_type type ## _exception_type = \ + { 0, THISCALL(dtor), NULL, & type ## _cxx_type_table }; + +#define INIT_CXX_TYPE(name,base) (void)name ## _exception_type + +#elif defined __WINE_PE_BUILD + +#define DEFINE_CXX_TYPE2(type, dtor, ...) \ +extern const cxx_type_info type ## _cxx_type_info[1]; \ +extern const cxx_exception_type type ## _exception_type; \ +void __asm_dummy_ ## type ## _exception_type(void) \ +{ \ + asm( ".balign 4\n\t" \ + __ASM_GLOBL(#type "_cxx_type_info") "\n\t" \ + ".long 0\n\t" \ + ".rva " #type "_type_info\n\t" \ + ".long 0, -1, 0, %c0\n\t" \ + ".rva " #type "_copy_ctor\n" \ + #type "_type_table:\n\t" \ + ".long %c1\n\t" \ + ".rva " #__VA_ARGS__ "\n\t" \ + __ASM_GLOBL(#type "_exception_type") "\n\t" \ + ".long 0\n\t" \ + ".rva " #dtor "\n\t" \ + ".long 0\n\t" \ + ".rva " #type "_type_table\n\t" \ + :: "i"(sizeof(type)), "i"(ARRAY_SIZE(((const void *[]){ &__VA_ARGS__ }))) ); \ +} +#define DEFINE_CXX_TYPE(type, dtor, ...) \ + DEFINE_CXX_TYPE2(type, dtor, type ## _cxx_type_info, ##__VA_ARGS__) + +#define INIT_CXX_TYPE(name,base) /* nothing to do */ + +#else /* CXX_USE_RVA */ + +#define DEFINE_CXX_TYPE(type, dtor, ...) \ +static cxx_type_info type ## _cxx_type_info[1] = \ + { { 0, 0xdeadbeef, { 0, -1, 0 }, sizeof(type), 0xdeadbeef } }; \ +\ +static const void * const type ## _cxx_type_classes[] = { type ## _cxx_type_info, __VA_ARGS__ }; \ +static cxx_type_info_table type ## _cxx_type_table = { ARRAY_SIZE(type ## _cxx_type_classes) }; \ +static cxx_exception_type type ##_exception_type; \ +\ +static void init_ ## type ## _cxx(char *base) \ +{ \ + type ## _cxx_type_info[0].type_info = (char *)&type ## _type_info - base; \ + type ## _cxx_type_info[0].copy_ctor = (char *)type ## _copy_ctor - base; \ + for (unsigned int i = 0; i < ARRAY_SIZE(type ## _cxx_type_classes); i++) \ + type ## _cxx_type_table.info[i] = (char *)type ## _cxx_type_classes[i] - base; \ + type ## _exception_type.destructor = (char *)dtor - base; \ + type ## _exception_type.type_info_table = (char *)&type ## _cxx_type_table - base; \ +} + +#define INIT_CXX_TYPE(name,base) init_ ## name ## _cxx((void *)(base)) + +#endif /* CXX_USE_RVA */ + +#ifdef __ASM_USE_THISCALL_WRAPPER + +#define CALL_VTBL_FUNC(this, off, ret, type, args) ((ret (WINAPI*)type)&vtbl_wrapper_##off)args + +extern void *vtbl_wrapper_0; +extern void *vtbl_wrapper_4; +extern void *vtbl_wrapper_8; +extern void *vtbl_wrapper_12; +extern void *vtbl_wrapper_16; +extern void *vtbl_wrapper_20; +extern void *vtbl_wrapper_24; +extern void *vtbl_wrapper_28; +extern void *vtbl_wrapper_32; +extern void *vtbl_wrapper_36; +extern void *vtbl_wrapper_40; +extern void *vtbl_wrapper_44; +extern void *vtbl_wrapper_48; +extern void *vtbl_wrapper_52; +extern void *vtbl_wrapper_56; + +#else + +#define CALL_VTBL_FUNC(this, off, ret, type, args) ((ret (__thiscall***)type)this)[0][off/4]args + +#endif + +/* exception object */ +typedef void (*vtable_ptr)(void); +typedef struct __exception +{ + const vtable_ptr *vtable; + char *name; /* Name of this exception, always a new copy for each object */ + int do_free; /* Whether to free 'name' in our dtor */ +} exception; + +/* rtti */ +typedef struct __type_info +{ + const vtable_ptr *vtable; + char *name; /* Unmangled name, allocated lazily */ + char mangled[128]; /* Variable length, but we declare it large enough for static RTTI */ +} type_info; + +/* offsets for computing the this pointer */ +typedef struct +{ + int this_offset; /* offset of base class this pointer from start of object */ + int vbase_descr; /* offset of virtual base class descriptor */ + int vbase_offset; /* offset of this pointer offset in virtual base class descriptor */ +} this_ptr_offsets; + +#ifndef RTTI_USE_RVA + +typedef struct _rtti_base_descriptor +{ + const type_info *type_descriptor; + int num_base_classes; + this_ptr_offsets offsets; /* offsets for computing the this pointer */ + unsigned int attributes; +} rtti_base_descriptor; + +typedef struct _rtti_base_array +{ + const rtti_base_descriptor *bases[10]; /* First element is the class itself */ +} rtti_base_array; + +typedef struct _rtti_object_hierarchy +{ + unsigned int signature; + unsigned int attributes; + int array_len; /* Size of the array pointed to by 'base_classes' */ + const rtti_base_array *base_classes; +} rtti_object_hierarchy; + +typedef struct _rtti_object_locator +{ + unsigned int signature; + int base_class_offset; + unsigned int flags; + const type_info *type_descriptor; + const rtti_object_hierarchy *type_hierarchy; +} rtti_object_locator; + +#else + +typedef struct +{ + unsigned int type_descriptor; + int num_base_classes; + this_ptr_offsets offsets; /* offsets for computing the this pointer */ + unsigned int attributes; +} rtti_base_descriptor; + +typedef struct +{ + unsigned int bases[10]; /* First element is the class itself */ +} rtti_base_array; + +typedef struct +{ + unsigned int signature; + unsigned int attributes; + int array_len; /* Size of the array pointed to by 'base_classes' */ + unsigned int base_classes; +} rtti_object_hierarchy; + +typedef struct +{ + unsigned int signature; + int base_class_offset; + unsigned int flags; + unsigned int type_descriptor; + unsigned int type_hierarchy; + unsigned int object_locator; +} rtti_object_locator; + +#endif /* RTTI_USE_RVA */ + +#ifndef CXX_USE_RVA + +typedef struct +{ + UINT flags; + const type_info *type_info; + this_ptr_offsets offsets; + unsigned int size; + void *copy_ctor; +} cxx_type_info; + +typedef struct +{ + UINT count; + const cxx_type_info *info[5]; +} cxx_type_info_table; + +typedef struct +{ + UINT flags; + void *destructor; + void *custom_handler; + const cxx_type_info_table *type_info_table; +} cxx_exception_type; + +#else + +typedef struct +{ + UINT flags; + unsigned int type_info; + this_ptr_offsets offsets; + unsigned int size; + unsigned int copy_ctor; +} cxx_type_info; + +typedef struct +{ + UINT count; + unsigned int info[5]; +} cxx_type_info_table; + +typedef struct +{ + UINT flags; + unsigned int destructor; + unsigned int custom_handler; + unsigned int type_info_table; +} cxx_exception_type; + +#endif /* CXX_USE_RVA */ + +extern const vtable_ptr type_info_vtable; + +#ifdef CXX_USE_RVA + +static inline uintptr_t cxx_rva_base( const void *ptr ) +{ + void *base; + return (uintptr_t)RtlPcToFileHeader( (void *)ptr, &base ); +} + +static inline void *cxx_rva( unsigned int rva, uintptr_t base ) +{ + return (void *)(base + rva); +} + +#else + +static inline uintptr_t cxx_rva_base( const void *ptr ) +{ + return 0; +} + +static inline void *cxx_rva( const void *ptr, uintptr_t base ) +{ + return (void *)ptr; +} + +#endif + +#define CREATE_TYPE_INFO_VTABLE \ +DEFINE_THISCALL_WRAPPER(type_info_vector_dtor,8) \ +void * __thiscall type_info_vector_dtor(type_info * _this, unsigned int flags) \ +{ \ + if (flags & 2) \ + { \ + /* we have an array, with the number of elements stored before the first object */ \ + INT_PTR i, *ptr = (INT_PTR *)_this - 1; \ +\ + for (i = *ptr - 1; i >= 0; i--) free(_this[i].name); \ + free(ptr); \ + } \ + else \ + { \ + free(_this->name); \ + if (flags & 1) free(_this); \ + } \ + return _this; \ +} \ +\ +DEFINE_RTTI_DATA( type_info, 0, ".?AVtype_info@@" ) \ +\ +__ASM_BLOCK_BEGIN(type_info_vtables) \ + __ASM_VTABLE(type_info, \ + VTABLE_ADD_FUNC(type_info_vector_dtor)); \ +__ASM_BLOCK_END diff --git a/dlls/vccorlib140/private.h b/dlls/vccorlib140/private.h new file mode 100644 index 00000000000..1b30dbcb867 --- /dev/null +++ b/dlls/vccorlib140/private.h @@ -0,0 +1,63 @@ +/* + * Copyright 2025 Vibhav Pant + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COM_VTABLE_RTTI_START(iface, type) \ + static const struct \ + { \ + const rtti_object_locator *locator; \ + iface##Vtbl vtable; \ + } type##_vtable = {&(type##_rtti), { +#define COM_VTABLE_ENTRY(func) (func), +#define COM_VTABLE_RTTI_END }} + +#define DEFINE_IINSPECTABLE_(pfx, iface_type, impl_type, impl_from, iface_mem, expr) \ + static inline impl_type *impl_from(iface_type *iface) { return CONTAINING_RECORD(iface, impl_type, iface_mem); } \ + static HRESULT WINAPI pfx##_QueryInterface(iface_type *iface, const GUID *iid, void **out) \ + { \ + impl_type *impl = impl_from(iface); \ + return IInspectable_QueryInterface((IInspectable *)(expr), iid, out); \ + } \ + static ULONG WINAPI pfx##_AddRef(iface_type *iface) \ + { \ + impl_type *impl = impl_from(iface); \ + return IInspectable_AddRef((IInspectable *)(expr)); \ + } \ + static ULONG WINAPI pfx##_Release(iface_type *iface) \ + { \ + impl_type *impl = impl_from(iface); \ + return IInspectable_Release((IInspectable *)(expr)); \ + } \ + static HRESULT WINAPI pfx##_GetIids(iface_type *iface, ULONG *iid_count, IID **iids) \ + { \ + impl_type *impl = impl_from(iface); \ + return IInspectable_GetIids((IInspectable *)(expr), iid_count, iids); \ + } \ + static HRESULT WINAPI pfx##_GetRuntimeClassName(iface_type *iface, HSTRING *class_name) \ + { \ + impl_type *impl = impl_from(iface); \ + return IInspectable_GetRuntimeClassName((IInspectable *)(expr), class_name); \ + } \ + static HRESULT WINAPI pfx##_GetTrustLevel(iface_type *iface, TrustLevel *trust_level) \ + { \ + impl_type *impl = impl_from(iface); \ + return IInspectable_GetTrustLevel((IInspectable *)(expr), trust_level); \ + } +#define DEFINE_IINSPECTABLE(pfx, iface_type, impl_type, base_iface) \ + DEFINE_IINSPECTABLE_(pfx, iface_type, impl_type, impl_from_##iface_type, iface_type##_iface, &impl->base_iface) +#define DEFINE_IINSPECTABLE_OUTER(pfx, iface_type, impl_type, outer_iface) \ + DEFINE_IINSPECTABLE_(pfx, iface_type, impl_type, impl_from_##iface_type, iface_type##_iface, impl->outer_iface) diff --git a/dlls/vccorlib140/tests/vccorlib.c b/dlls/vccorlib140/tests/vccorlib.c index cbcaf4abcea..1b597a9325a 100644 --- a/dlls/vccorlib140/tests/vccorlib.c +++ b/dlls/vccorlib140/tests/vccorlib.c @@ -763,32 +763,27 @@ static void test___abi_make_type_id(void) ok(type_obj2 != type_obj, "got type_obj2 %p\n", type_obj2);
type_info = p__RTtypeid(type_obj); - todo_wine ok(type_info != NULL, "got type_info %p\n", type_info); - if (type_info) - { - name = (char *)call_func1(p_type_info_name, type_info); - ok(!strcmp(name, "class Platform::Type"), "got name %s\n", debugstr_a(name)); - raw_name = (char *)call_func1(p_type_info_raw_name, type_info); - ok(!strcmp(raw_name, ".?AVType@Platform@@"), "got raw_name %s\n", debugstr_a(raw_name)); - } + ok(type_info != NULL, "got type_info %p\n", type_info); + name = (char *)call_func1(p_type_info_name, type_info); + ok(!strcmp(name, "class Platform::Type"), "got name %s\n", debugstr_a(name)); + raw_name = (char *)call_func1(p_type_info_raw_name, type_info); + ok(!strcmp(raw_name, ".?AVType@Platform@@"), "got raw_name %s\n", debugstr_a(raw_name));
hr = IInspectable_QueryInterface(type_obj, &IID_IClosable, (void **)&closable); ok(hr == S_OK, "got hr %#lx\n", hr); type_info2 = p__RTtypeid(closable); - todo_wine ok(type_info2 != NULL, "got type_info %p\n", type_info2); - if (type_info2) - { - name = (char *)call_func1(p_type_info_name, type_info2); - ok(!strcmp(name, "class Platform::Type"), "got name %s\n", debugstr_a(name)); + ok(type_info2 != NULL, "got type_info %p\n", type_info2); + name = (char *)call_func1(p_type_info_name, type_info2); + ok(!strcmp(name, "class Platform::Type"), "got name %s\n", debugstr_a(name));
- raw_name = (char *)call_func1(p_type_info_raw_name, type_info2); - ok(!strcmp(raw_name, ".?AVType@Platform@@"), "got raw_name %s\n", debugstr_a(raw_name)); + raw_name = (char *)call_func1(p_type_info_raw_name, type_info2); + ok(!strcmp(raw_name, ".?AVType@Platform@@"), "got raw_name %s\n", debugstr_a(raw_name)); + + ret = call_func2(p_type_info_opequals_equals, type_info, type_info2); + ok(ret, "got ret %d\n", ret); + ret = call_func2(p_type_info_opnot_equals, type_info, type_info2); + ok(!ret, "got ret %d\n", ret);
- ret = call_func2(p_type_info_opequals_equals, type_info, type_info2); - ok(ret, "got ret %d\n", ret); - ret = call_func2(p_type_info_opnot_equals, type_info, type_info2); - ok(!ret, "got ret %d\n", ret); - } IClosable_Release(closable);
check_interface(type_obj2, &IID_IInspectable); diff --git a/dlls/vccorlib140/vccorlib.c b/dlls/vccorlib140/vccorlib.c index 39877f407bb..3294aab6dd0 100644 --- a/dlls/vccorlib140/vccorlib.c +++ b/dlls/vccorlib140/vccorlib.c @@ -30,8 +30,13 @@ #include "wine/asm.h" #include "wine/debug.h"
+#include "cxx.h" +#include "private.h" + WINE_DEFAULT_DEBUG_CHANNEL(vccorlib);
+CREATE_TYPE_INFO_VTABLE + HRESULT __cdecl InitializeData(int type) { HRESULT hres; @@ -236,27 +241,32 @@ struct __abi_type_descriptor
struct platform_type { + IInspectable IInspectable_iface; IClosable IClosable_iface; IUnknown *marshal; const struct __abi_type_descriptor *desc; LONG ref; };
-static inline struct platform_type *impl_from_IClosable(IClosable *iface) +static inline struct platform_type *impl_from_IInspectable(IInspectable *iface) { - return CONTAINING_RECORD(iface, struct platform_type, IClosable_iface); + return CONTAINING_RECORD(iface, struct platform_type, IInspectable_iface); }
-static HRESULT WINAPI platform_type_QueryInterface(IClosable *iface, const GUID *iid, void **out) +HRESULT WINAPI platform_type_QueryInterface(IInspectable *iface, const GUID *iid, void **out) { - struct platform_type *impl = impl_from_IClosable(iface); + struct platform_type *impl = impl_from_IInspectable(iface);
TRACE("(%p, %s, %p)\n", iface, debugstr_guid(iid), out);
if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IInspectable) || - IsEqualGUID(iid, &IID_IClosable) || IsEqualGUID(iid, &IID_IAgileObject)) + { + IInspectable_AddRef((*out = &impl->IInspectable_iface)); + return S_OK; + } + if (IsEqualGUID(iid, &IID_IClosable)) { IClosable_AddRef((*out = &impl->IClosable_iface)); return S_OK; @@ -269,16 +279,16 @@ static HRESULT WINAPI platform_type_QueryInterface(IClosable *iface, const GUID return E_NOINTERFACE; }
-static ULONG WINAPI platform_type_AddRef(IClosable *iface) +static ULONG WINAPI platform_type_AddRef(IInspectable *iface) { - struct platform_type *impl = impl_from_IClosable(iface); + struct platform_type *impl = impl_from_IInspectable(iface); TRACE("(%p)\n", iface); return InterlockedIncrement(&impl->ref); }
-static ULONG WINAPI platform_type_Release(IClosable *iface) +static ULONG WINAPI platform_type_Release(IInspectable *iface) { - struct platform_type *impl = impl_from_IClosable(iface); + struct platform_type *impl = impl_from_IInspectable(iface); ULONG ref = InterlockedDecrement(&impl->ref);
TRACE("(%p)\n", iface); @@ -291,13 +301,13 @@ static ULONG WINAPI platform_type_Release(IClosable *iface) return ref; }
-static HRESULT WINAPI platform_type_GetIids(IClosable *iface, ULONG *count, GUID **iids) +static HRESULT WINAPI platform_type_GetIids(IInspectable *iface, ULONG *count, GUID **iids) { FIXME("(%p, %p, %p) stub\n", iface, count, iids); return E_NOTIMPL; }
-static HRESULT WINAPI platform_type_GetRuntimeClassName(IClosable *iface, HSTRING *name) +static HRESULT WINAPI platform_type_GetRuntimeClassName(IInspectable *iface, HSTRING *name) { static const WCHAR *str = L"Platform.Type";
@@ -305,31 +315,47 @@ static HRESULT WINAPI platform_type_GetRuntimeClassName(IClosable *iface, HSTRIN return WindowsCreateString(str, wcslen(str), name); }
-static HRESULT WINAPI platform_type_GetTrustLevel(IClosable *iface, TrustLevel *level) +static HRESULT WINAPI platform_type_GetTrustLevel(IInspectable *iface, TrustLevel *level) { FIXME("(%p, %p) stub\n", iface, level); return E_NOTIMPL; }
-static HRESULT WINAPI platform_type_Close(IClosable *iface) +DEFINE_RTTI_DATA(platform_type, 0, ".?AVType@Platform@@"); +COM_VTABLE_RTTI_START(IInspectable, platform_type) +COM_VTABLE_ENTRY(platform_type_QueryInterface) +COM_VTABLE_ENTRY(platform_type_AddRef) +COM_VTABLE_ENTRY(platform_type_Release) +COM_VTABLE_ENTRY(platform_type_GetIids) +COM_VTABLE_ENTRY(platform_type_GetRuntimeClassName) +COM_VTABLE_ENTRY(platform_type_GetTrustLevel) +COM_VTABLE_RTTI_END; + +DEFINE_IINSPECTABLE(platform_type_closable, IClosable, struct platform_type, IInspectable_iface); + +static HRESULT WINAPI platform_type_closable_Close(IClosable *iface) { FIXME("(%p) stub\n", iface); return E_NOTIMPL; }
-static const IClosableVtbl platform_type_closable_vtbl = -{ - /* IUnknown */ - platform_type_QueryInterface, - platform_type_AddRef, - platform_type_Release, - /* IInspectable */ - platform_type_GetIids, - platform_type_GetRuntimeClassName, - platform_type_GetTrustLevel, - /* ICloseable */ - platform_type_Close -}; +DEFINE_RTTI_DATA(platform_type_closable, offsetof(struct platform_type, IClosable_iface), ".?AVType@Platform@@"); +COM_VTABLE_RTTI_START(IClosable, platform_type_closable) +COM_VTABLE_ENTRY(platform_type_closable_QueryInterface) +COM_VTABLE_ENTRY(platform_type_closable_AddRef) +COM_VTABLE_ENTRY(platform_type_closable_Release) +COM_VTABLE_ENTRY(platform_type_closable_GetIids) +COM_VTABLE_ENTRY(platform_type_closable_GetRuntimeClassName) +COM_VTABLE_ENTRY(platform_type_closable_GetTrustLevel) +COM_VTABLE_ENTRY(platform_type_closable_Close) +COM_VTABLE_RTTI_END; + +static void init_platform_type(void *base) +{ + INIT_RTTI(type_info, base); + INIT_RTTI(platform_type, base); + INIT_RTTI(platform_type_closable, base); +}
static const char *debugstr_abi_type_descriptor(const struct __abi_type_descriptor *desc) { @@ -341,7 +367,6 @@ static const char *debugstr_abi_type_descriptor(const struct __abi_type_descript void *WINAPI __abi_make_type_id(const struct __abi_type_descriptor *desc) { /* TODO: - * Emit RTTI for Platform::Type. * Implement IEquatable and IPrintable. * Throw a COMException if CoCreateFreeThreadedMarshaler fails. */ struct platform_type *obj; @@ -350,17 +375,18 @@ void *WINAPI __abi_make_type_id(const struct __abi_type_descriptor *desc) TRACE("(%s)\n", debugstr_abi_type_descriptor(desc));
obj = Allocate(sizeof(*obj)); - obj->IClosable_iface.lpVtbl = &platform_type_closable_vtbl; + obj->IInspectable_iface.lpVtbl = &platform_type_vtable.vtable; + obj->IClosable_iface.lpVtbl = &platform_type_closable_vtable.vtable; obj->desc = desc; obj->ref = 1; - hr = CoCreateFreeThreadedMarshaler((IUnknown *)&obj->IClosable_iface, &obj->marshal); + hr = CoCreateFreeThreadedMarshaler((IUnknown *)&obj->IInspectable_iface, &obj->marshal); if (FAILED(hr)) { FIXME("CoCreateFreeThreadedMarshaler failed: %#lx\n", hr); Free(obj); return NULL; } - return &obj->IClosable_iface; + return &obj->IInspectable_iface; }
bool __cdecl platform_type_Equals_Object(struct platform_type *this, struct platform_type *object) @@ -530,3 +556,10 @@ void *WINAPI CreateValue(int typecode, const void *val) } return obj; } + +BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, void *reserved) +{ + if (reason == DLL_PROCESS_ATTACH) + init_platform_type(inst); + return TRUE; +}