-- v9: vccorlib140: Implement __abi_translateCurrentException. vccorlib140: Implement Platform::Exception.
From: Vibhav Pant vibhavp@gmail.com
--- dlls/vccorlib140/Makefile.in | 2 +- dlls/vccorlib140/cxx.h | 23 +- dlls/vccorlib140/tests/vccorlib.c | 13 +- dlls/vccorlib140/vccorlib.c | 487 ++++++++++++++++++++++++++---- 4 files changed, 451 insertions(+), 74 deletions(-)
diff --git a/dlls/vccorlib140/Makefile.in b/dlls/vccorlib140/Makefile.in index 13d54aa369e..08fb0d7c679 100644 --- a/dlls/vccorlib140/Makefile.in +++ b/dlls/vccorlib140/Makefile.in @@ -1,5 +1,5 @@ MODULE = vccorlib140.dll -IMPORTS = combase +IMPORTS = combase oleaut32 vcruntime140
SOURCES = \ vccorlib.c diff --git a/dlls/vccorlib140/cxx.h b/dlls/vccorlib140/cxx.h index b803d35a283..0ce3275886c 100644 --- a/dlls/vccorlib140/cxx.h +++ b/dlls/vccorlib140/cxx.h @@ -139,21 +139,21 @@ static void init_ ## name ## _rtti(char *base) \
#ifndef CXX_USE_RVA
-#define DEFINE_CXX_TYPE(type, dtor, ...) \ +#define DEFINE_CXX_TYPE(type, ...) \ static const cxx_type_info type ## _cxx_type_info[1] = \ - { { 0, &type ##_type_info, { 0, -1, 0 }, sizeof(type), THISCALL(type ##_copy_ctor) } }; \ + { { 0, &type ##_type_info, { 0, -1, 0 }, sizeof(type), NULL } }; \ \ 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 }; + { 16, NULL, 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, ...) \ +#define DEFINE_CXX_TYPE2(type, ...) \ 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) \ @@ -163,25 +163,25 @@ void __asm_dummy_ ## type ## _exception_type(void) \ ".long 0\n\t" \ ".rva " #type "_type_info\n\t" \ ".long 0, -1, 0, %c0\n\t" \ - ".rva " #type "_copy_ctor\n" \ + ".long 0\n\t" \ #type "_type_table:\n\t" \ ".long %c1\n\t" \ ".rva " #__VA_ARGS__ "\n\t" \ __ASM_GLOBL(#type "_exception_type") "\n\t" \ + ".long 16\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 DEFINE_CXX_TYPE(type, ...) \ + DEFINE_CXX_TYPE2(type, 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, ...) \ +#define DEFINE_CXX_TYPE(type, ...) \ static cxx_type_info type ## _cxx_type_info[1] = \ { { 0, 0xdeadbeef, { 0, -1, 0 }, sizeof(type), 0xdeadbeef } }; \ \ @@ -192,10 +192,11 @@ 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; \ + type ## _cxx_type_info[0].copy_ctor = NULL; \ 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.flags = 16; \ + type ## _exception_type.destructor = NULL; \ type ## _exception_type.type_info_table = (char *)&type ## _cxx_type_table - base; \ }
diff --git a/dlls/vccorlib140/tests/vccorlib.c b/dlls/vccorlib140/tests/vccorlib.c index 95ce908d49d..77c18079df0 100644 --- a/dlls/vccorlib140/tests/vccorlib.c +++ b/dlls/vccorlib140/tests/vccorlib.c @@ -1370,17 +1370,12 @@ static void test_exceptions(void)
cur_test = &test_cases[i]; obj = pCreateException(cur_test->hr); - todo_wine ok(obj != NULL, "got obj %p\n", obj); - if (!obj) - { - winetest_pop_context(); - continue; - } + ok(obj != NULL, "got obj %p\n", obj);
inspectable = (IInspectable *)obj; /* Verify that the IMarshal field is lazily-initialized. */ ok((ULONG_PTR)obj->marshal == UINTPTR_MAX, "got marshal %p\n", obj->marshal); - todo_wine check_interface(inspectable, &IID_IMarshal); + check_interface(inspectable, &IID_IMarshal); ok(obj->marshal != NULL && (ULONG_PTR)obj->marshal != UINTPTR_MAX, "got marshal %p\n", obj->marshal);
test_interface_layout(obj, &IID_IUnknown, &obj->IInspectable_iface); @@ -1484,9 +1479,9 @@ static void test_exceptions(void)
cxx_info = (cxx_type_info *)(base + type_info_table->info[j]); if (j == type_info_table->count - 1) - ok(cxx_info->flags == CLASS_IS_SIMPLE_TYPE, "got flags %u\n", cxx_info->flags); + todo_wine ok(cxx_info->flags == CLASS_IS_SIMPLE_TYPE, "got flags %u\n", cxx_info->flags); else - ok(cxx_info->flags == (CLASS_IS_SIMPLE_TYPE | CLASS_IS_IUNKNOWN), "got flags %u\n", cxx_info->flags); + todo_wine ok(cxx_info->flags == (CLASS_IS_SIMPLE_TYPE | CLASS_IS_IUNKNOWN), "got flags %u\n", cxx_info->flags); ok(cxx_info->size == sizeof(void *), "got size %u\n", cxx_info->size); ok(cxx_info->copy_ctor == 0, "got copy_ctor %#x\n", cxx_info->copy_ctor); ok(cxx_info->type_info != 0, "got type_info"); diff --git a/dlls/vccorlib140/vccorlib.c b/dlls/vccorlib140/vccorlib.c index 68100ac7291..550e85c9776 100644 --- a/dlls/vccorlib140/vccorlib.c +++ b/dlls/vccorlib140/vccorlib.c @@ -20,11 +20,13 @@ #define COBJMACROS
#include <stdbool.h> +#include <stdint.h>
#include "initguid.h" #include "roapi.h" #include "weakreference.h" #include "winstring.h" +#include "roerrorapi.h" #define WIDL_using_Windows_Foundation #include "windows.foundation.h" #include "wine/asm.h" @@ -88,6 +90,10 @@ HRESULT WINAPI GetIidsFn(unsigned int count, unsigned int *copied, const GUID *s return S_OK; }
+void WINAPI DECLSPEC_NORETURN __abi_WinRTraiseCOMException(HRESULT); +void WINAPI DECLSPEC_NORETURN __abi_WinRTraiseOutOfMemoryException(void); +void WINAPI DECLSPEC_NORETURN __abi_WinRTraiseInvalidArgumentException(void); + void *__cdecl Allocate(size_t size) { void *addr; @@ -95,9 +101,8 @@ void *__cdecl Allocate(size_t size) TRACE("(%Iu)\n", size);
addr = malloc(size); - /* TODO: Throw a COMException on allocation failure. */ if (!addr) - FIXME("allocation failure\n"); + __abi_WinRTraiseOutOfMemoryException(); return addr; }
@@ -421,8 +426,7 @@ 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: - * Implement IEquatable and IPrintable. - * Throw a COMException if CoCreateFreeThreadedMarshaler fails. */ + * Implement IEquatable and IPrintable. */ struct platform_type *obj; HRESULT hr;
@@ -436,9 +440,8 @@ void *WINAPI __abi_make_type_id(const struct __abi_type_descriptor *desc) hr = CoCreateFreeThreadedMarshaler((IUnknown *)&obj->IInspectable_iface, &obj->marshal); if (FAILED(hr)) { - FIXME("CoCreateFreeThreadedMarshaler failed: %#lx\n", hr); Free(obj); - return NULL; + __abi_WinRTraiseCOMException(hr); } return &obj->IInspectable_iface; } @@ -604,30 +607,10 @@ void *WINAPI CreateValue(int typecode, const void *val)
IPropertyValueStatics_Release(statics); if (FAILED(hr)) - { - FIXME("Failed to create IPropertyValue object: %#lx\n", hr); - return NULL; - } + __abi_WinRTraiseCOMException(hr); return obj; }
-void *__cdecl CreateExceptionWithMessage(HRESULT hr, HSTRING msg) -{ - FIXME("(%#lx, %s): stub!\n", hr, debugstr_hstring(msg)); - return NULL; -} - -void *__cdecl CreateException(HRESULT hr) -{ - FIXME("(%#lx): stub!\n", hr); - return NULL; -} - -void WINAPI __abi_WinRTraiseCOMException(HRESULT hr) -{ - FIXME("(%#lx): stub!\n", hr); -} - #define WINRT_EXCEPTIONS \ WINRT_EXCEPTION(AccessDenied, E_ACCESSDENIED) \ WINRT_EXCEPTION(ChangedState, E_CHANGED_STATE) \ @@ -644,58 +627,456 @@ void WINAPI __abi_WinRTraiseCOMException(HRESULT hr) WINRT_EXCEPTION(OutOfMemory, E_OUTOFMEMORY) \ WINRT_EXCEPTION(WrongThread, RPC_E_WRONG_THREAD)
-#define WINRT_EXCEPTION(name, hr) \ - void WINAPI __abi_WinRTraise##name##Exception(void) \ - { \ - FIXME("(): stub!\n"); \ - } \ - void *__cdecl platform_##name##Exception_ctor(void *this) \ - { \ - FIXME("(%p): stub!\n", this); \ - return this; \ - } \ - void *__cdecl platform_##name##Exception_hstring_ctor(void *this, HSTRING msg) \ - { \ - FIXME("(%p, %s): stub!\n", this, debugstr_hstring(msg)); \ - return this; \ +/* Data members of the "Exception" C++/CX class. + * A back-pointer to this struct is stored just before the IInspectable vtable of an Exception object. + * TODO: The message fields are likely obtained from IRestrictedErrorInfo::GetErrorDetails, so we + * should use that once it has been implemented. */ +struct exception_inner +{ + /* This only gets set when the exception is thrown. */ + BSTR message1; + /* Likewise, but can also be set by CreateExceptionWithMessage. */ + BSTR message2; + void *unknown1; + void *unknown2; + HRESULT hr; + /* Only gets set when the exception is thrown. */ + IRestrictedErrorInfo *error_info; + const cxx_exception_type *exception_type; + /* Set to 32 and 64 on 32 and 64-bit platforms respectively, not sure what the purpose is. */ + UINT32 unknown3; + void *unknown4; +}; +struct platform_exception +{ + IInspectable IInspectable_iface; + const void *IPrintable_iface; + const void *IEquatable_iface; + IClosable IClosable_iface; + struct exception_inner inner; + /* Exceptions use the weakref control block for reference counting, even though they don't implement + * IWeakReferenceSource. */ + struct control_block *control_block; + /* This is lazily initialized, i.e, only when QueryInterface(IID_IMarshal) gets called. The default value is + * UINTPTR_MAX/-1 */ + IUnknown *marshal; +}; + +static inline struct platform_exception *impl_platform_exception_from_IInspectable(IInspectable *iface) +{ + return CONTAINING_RECORD(iface, struct platform_exception, IInspectable_iface); +} + +static HRESULT WINAPI platform_exception_QueryInterface(IInspectable *iface, const GUID *iid, void **out) +{ + struct platform_exception *impl = impl_platform_exception_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_IAgileObject)) + { + IInspectable_AddRef((*out = &impl->IInspectable_iface)); + return S_OK; + } + if (IsEqualGUID(iid, &IID_IClosable)) + { + IClosable_AddRef((*out = &impl->IClosable_iface)); + return S_OK; + } + if (IsEqualGUID(iid, &IID_IMarshal)) + { + IUnknown *marshal, *old; + HRESULT hr; + + if ((ULONG_PTR)impl->marshal != UINTPTR_MAX) + return IUnknown_QueryInterface(impl->marshal, iid, out); + /* Try initializing impl->marshal. */ + if (FAILED(hr = CoCreateFreeThreadedMarshaler((IUnknown *)&impl->IInspectable_iface, &marshal))) + return hr; + old = InterlockedCompareExchangePointer((void *)&impl->marshal, marshal, (void *)UINTPTR_MAX); + if ((ULONG_PTR)old != UINTPTR_MAX) /* Someone else has already set impl->marshal, use it. */ + IUnknown_Release(marshal); + return IUnknown_QueryInterface(impl->marshal, iid, out); }
-WINRT_EXCEPTIONS + ERR("%s not implemented, returning E_NOTINTERFACE.\n", debugstr_guid(iid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI platform_exception_AddRef(IInspectable *iface) +{ + struct platform_exception *impl = impl_platform_exception_from_IInspectable(iface); + TRACE("(%p)\n", iface); + return InterlockedIncrement(&impl->control_block->ref_strong); +} + +static ULONG WINAPI platform_exception_Release(IInspectable *iface) +{ + struct platform_exception *impl = impl_platform_exception_from_IInspectable(iface); + ULONG ref = InterlockedDecrement(&impl->control_block->ref_strong); + + TRACE("(%p)\n", iface); + + if (!ref) + { + SysFreeString(impl->inner.message1); + SysFreeString(impl->inner.message2); + if ((ULONG_PTR)impl->marshal != UINTPTR_MAX) + IUnknown_Release((IUnknown *)impl->marshal); + /* Because Exception objects are never allocated inline, we don't need to use ReleaseTarget. */ + IWeakReference_Release(&impl->control_block->IWeakReference_iface); + FreeException(impl); + } + return ref; +} + +static HRESULT WINAPI platform_exception_GetRuntimeClassName(IInspectable *iface, HSTRING *class_name) +{ + struct platform_exception *impl = impl_platform_exception_from_IInspectable(iface); + const WCHAR *buf; + + TRACE("(%p, %p)\n", iface, class_name); + +#define WINRT_EXCEPTION(name, hr) case (hr): buf = L"Platform." #name "Exception"; break; + switch (impl->inner.hr) + { + WINRT_EXCEPTIONS #undef WINRT_EXCEPTION + default: + buf = L"Platform.COMException"; + break; + } + return WindowsCreateString(buf, wcslen(buf), class_name); +} + +static HRESULT WINAPI platform_exception_GetIids(IInspectable *iface, ULONG *count, IID **iids) +{ + TRACE("(%p, %p, %p)\n", iface, count, iids); + + *count = 0; + *iids = NULL; + return S_OK; +} + +static HRESULT WINAPI platform_exception_GetTrustLevel(IInspectable *iface, TrustLevel *level) +{ + FIXME("(%p, %p)\n", iface, level); + return S_OK; +}
-void *__cdecl platform_Exception_ctor(void *this, HRESULT hr) +DEFINE_IINSPECTABLE_(platform_exception_closable, IClosable, struct platform_exception, impl_exception_from_IClosable, + IClosable_iface, &impl->IInspectable_iface); + +static HRESULT WINAPI platform_exception_closable_Close(IClosable *iface) { - FIXME("(%p, %#lx): stub!\n", this, hr); + FIXME("(%p)\n", iface); + return E_NOTIMPL; +} + +#ifdef _WIN64 +#define EXCEPTION_RTTI_NAME(name) ".PE$AAV" #name "Exception@Platform@@" +#else +#define EXCEPTION_RTTI_NAME(name) ".P$AAV" #name "Exception@Platform@@" +#endif + +#ifdef _WIN64 +DEFINE_RTTI_DATA(Exception, 0, ".PE$AAVException@Platform@@"); +#else +DEFINE_RTTI_DATA(Exception, 0, ".P$AAVException@Platform@@"); +#endif +typedef IInspectable Exception; +DEFINE_CXX_TYPE(Exception); + +DEFINE_RTTI_DATA(platform_Exception, 0, "?.AVException@Platform@@"); +COM_VTABLE_RTTI_START(IInspectable, platform_Exception) +COM_VTABLE_ENTRY(platform_exception_QueryInterface) +COM_VTABLE_ENTRY(platform_exception_AddRef) +COM_VTABLE_ENTRY(platform_exception_Release) +COM_VTABLE_ENTRY(platform_exception_GetIids) +COM_VTABLE_ENTRY(platform_exception_GetRuntimeClassName) +COM_VTABLE_ENTRY(platform_exception_GetTrustLevel) +COM_VTABLE_RTTI_END; + +DEFINE_RTTI_DATA(platform_Exception_closable, offsetof(struct platform_exception, IClosable_iface), + "?.AVException@Platform@@") +COM_VTABLE_RTTI_START(IClosable, platform_Exception_closable) +COM_VTABLE_ENTRY(platform_exception_closable_QueryInterface) +COM_VTABLE_ENTRY(platform_exception_closable_AddRef) +COM_VTABLE_ENTRY(platform_exception_closable_Release) +COM_VTABLE_ENTRY(platform_exception_closable_GetIids) +COM_VTABLE_ENTRY(platform_exception_closable_GetRuntimeClassName) +COM_VTABLE_ENTRY(platform_exception_closable_GetTrustLevel) +COM_VTABLE_ENTRY(platform_exception_closable_Close) +COM_VTABLE_RTTI_END; + +DEFINE_RTTI_DATA(COMException, 0, EXCEPTION_RTTI_NAME(COM), Exception_rtti_base_descriptor); +typedef IInspectable COMException; +DEFINE_CXX_TYPE(COMException, Exception_cxx_type_info); + +DEFINE_RTTI_DATA(platform_COMException, 0, ".?AVCOMException@Platform@@"); +COM_VTABLE_RTTI_START(IInspectable, platform_COMException) +COM_VTABLE_ENTRY(platform_exception_QueryInterface) +COM_VTABLE_ENTRY(platform_exception_AddRef) +COM_VTABLE_ENTRY(platform_exception_Release) +COM_VTABLE_ENTRY(platform_exception_GetIids) +COM_VTABLE_ENTRY(platform_exception_GetRuntimeClassName) +COM_VTABLE_ENTRY(platform_exception_GetTrustLevel) +COM_VTABLE_RTTI_END; + +DEFINE_RTTI_DATA(platform_COMException_closable, offsetof(struct platform_exception, IClosable_iface), + ".?AVCOMException@Platform@@") +COM_VTABLE_RTTI_START(IClosable, platform_COMException_closable) +COM_VTABLE_ENTRY(platform_exception_closable_QueryInterface) +COM_VTABLE_ENTRY(platform_exception_closable_AddRef) +COM_VTABLE_ENTRY(platform_exception_closable_Release) +COM_VTABLE_ENTRY(platform_exception_closable_GetIids) +COM_VTABLE_ENTRY(platform_exception_closable_GetRuntimeClassName) +COM_VTABLE_ENTRY(platform_exception_closable_GetTrustLevel) +COM_VTABLE_ENTRY(platform_exception_closable_Close) +COM_VTABLE_RTTI_END; + +struct platform_exception *__cdecl platform_Exception_ctor(struct platform_exception *this, HRESULT hr) +{ + struct exception_alloc *base = CONTAINING_RECORD(this, struct exception_alloc, data); + + TRACE("(%p, %#lx)\n", this, hr); + + this->IInspectable_iface.lpVtbl = &platform_Exception_vtable.vtable; + this->IClosable_iface.lpVtbl = &platform_Exception_closable_vtable.vtable; + this->IEquatable_iface = this->IPrintable_iface = NULL; + + memset(&this->inner, 0, sizeof(this->inner)); + base->exception_inner = &this->inner; + this->inner.exception_type = &Exception_exception_type; + this->inner.hr = hr; + this->inner.unknown3 = sizeof(void *) == 8 ? 64 : 32; + + this->marshal = (IUnknown *)UINTPTR_MAX; + + /* Native throws InvalidArgumentException if hr is S_OK or S_FALSE. */ + if (SUCCEEDED(hr)) + __abi_WinRTraiseInvalidArgumentException(); return this; }
-void *__cdecl platform_Exception_hstring_ctor(void *this, HRESULT hr, HSTRING msg) +struct platform_exception *__cdecl platform_Exception_hstring_ctor(struct platform_exception *this, HRESULT hr, + HSTRING msg) { - FIXME("(%p, %#lx, %s): stub!\n", this, hr, debugstr_hstring(msg)); + const WCHAR *buf; + BOOL has_null; + UINT32 len; + + TRACE("(%p, %#lx, %s)\n", this, hr, debugstr_hstring(msg)); + + platform_Exception_ctor(this, hr); + if (WindowsIsStringEmpty(msg)) return this; + + /* Native throws InvalidArgumentException if msg has an embedded NUL byte. */ + if (FAILED(hr = WindowsStringHasEmbeddedNull(msg, &has_null))) + __abi_WinRTraiseCOMException(hr); + else if (has_null) + __abi_WinRTraiseInvalidArgumentException(); + + buf = WindowsGetStringRawBuffer(msg, &len); + if (len && !(this->inner.message2 = SysAllocStringLen(buf, len))) + __abi_WinRTraiseOutOfMemoryException(); return this; }
-void *__cdecl platform_COMException_ctor(void *this, HRESULT hr) +struct platform_exception *__cdecl platform_COMException_ctor(struct platform_exception *this, HRESULT hr) { - FIXME("(%p, %#lx): stub!\n", this, hr); + TRACE("(%p, %#lx)\n", this, hr); + + platform_Exception_ctor(this, hr); + + this->IInspectable_iface.lpVtbl = &platform_COMException_vtable.vtable; + this->IClosable_iface.lpVtbl = &platform_COMException_closable_vtable.vtable; + this->inner.exception_type = &COMException_exception_type; return this; }
-void *__cdecl platform_COMException_hstring_ctor(void *this, HRESULT hr, HSTRING msg) +struct platform_exception *__cdecl platform_COMException_hstring_ctor(struct platform_exception *this, HRESULT hr, + HSTRING msg) { - FIXME("(%p, %#lx, %s): stub!\n", this, hr, debugstr_hstring(msg)); + TRACE("(%p, %#lx, %s)\n", this, hr, debugstr_hstring(msg)); + + platform_Exception_hstring_ctor(this, hr, msg); + + this->IInspectable_iface.lpVtbl = &platform_COMException_vtable.vtable; + this->IClosable_iface.lpVtbl = &platform_COMException_closable_vtable.vtable; + this->inner.exception_type = &COMException_exception_type; return this; }
-HSTRING __cdecl platform_exception_get_Message(void *excp) +#define WINRT_EXCEPTION(name, hr) \ + DEFINE_RTTI_DATA(name##Exception, 0, EXCEPTION_RTTI_NAME(name), COMException_rtti_base_descriptor, \ + Exception_rtti_base_descriptor); \ + typedef COMException name##Exception; \ + DEFINE_CXX_TYPE(name##Exception, COMException_cxx_type_info, Exception_cxx_type_info); \ + \ + DEFINE_RTTI_DATA(platform_##name##Exception, 0, ".?AV" #name "Exception@Platform@@"); \ + COM_VTABLE_RTTI_START(IInspectable, platform_##name##Exception) \ + COM_VTABLE_ENTRY(platform_exception_QueryInterface) \ + COM_VTABLE_ENTRY(platform_exception_AddRef) \ + COM_VTABLE_ENTRY(platform_exception_Release) \ + COM_VTABLE_ENTRY(platform_exception_GetIids) \ + COM_VTABLE_ENTRY(platform_exception_GetRuntimeClassName) \ + COM_VTABLE_ENTRY(platform_exception_GetTrustLevel) \ + COM_VTABLE_RTTI_END; \ + \ + DEFINE_RTTI_DATA(platform_##name##Exception_closable, offsetof(struct platform_exception, IClosable_iface), \ + ".?AV" #name "Exception@Platform@@"); \ + COM_VTABLE_RTTI_START(IClosable, platform_##name##Exception_closable) \ + COM_VTABLE_ENTRY(platform_exception_closable_QueryInterface) \ + COM_VTABLE_ENTRY(platform_exception_closable_AddRef) \ + COM_VTABLE_ENTRY(platform_exception_closable_Release) \ + COM_VTABLE_ENTRY(platform_exception_closable_GetIids) \ + COM_VTABLE_ENTRY(platform_exception_closable_GetRuntimeClassName) \ + COM_VTABLE_ENTRY(platform_exception_closable_GetTrustLevel) \ + COM_VTABLE_ENTRY(platform_exception_closable_Close) \ + COM_VTABLE_RTTI_END; \ + \ + struct platform_exception *__cdecl platform_##name##Exception_ctor(struct platform_exception *this) \ + { \ + TRACE("(%p)\n", this); \ + platform_COMException_ctor(this, (hr)); \ + this->IInspectable_iface.lpVtbl = &platform_##name##Exception_vtable.vtable; \ + this->IClosable_iface.lpVtbl = &platform_##name##Exception_closable_vtable.vtable; \ + this->inner.exception_type = &name##Exception_exception_type; \ + return this; \ + } \ + \ + struct platform_exception *__cdecl platform_##name##Exception_hstring_ctor(struct platform_exception *this, \ + HSTRING msg) \ + { \ + TRACE("(%p, %s)\n", this, debugstr_hstring(msg)); \ + platform_COMException_hstring_ctor(this, (hr), msg); \ + this->IInspectable_iface.lpVtbl = &platform_##name##Exception_vtable.vtable; \ + this->IClosable_iface.lpVtbl = &platform_##name##Exception_closable_vtable.vtable; \ + this->inner.exception_type = &name##Exception_exception_type; \ + return this; \ + } +WINRT_EXCEPTIONS +#undef EXCEPTION_RTTI_NAME +#undef WINRT_EXCEPTION + +static void init_exception(void *base) +{ + INIT_RTTI(Exception, base); + INIT_RTTI(platform_Exception, base); + +#define WINRT_EXCEPTION(name, ...) \ + do \ + { \ + INIT_RTTI(name##Exception, base); \ + INIT_RTTI(platform_exception_##name, base); \ + } while(0); + WINRT_EXCEPTION(COM); + WINRT_EXCEPTIONS +#undef WINRT_EXCEPTION +} + +void *__cdecl CreateExceptionWithMessage(HRESULT code, HSTRING msg) +{ + struct platform_exception *impl; + + TRACE("(%#lx, %s)\n", code, debugstr_hstring(msg)); + + impl = AllocateExceptionWithWeakRef(offsetof(struct platform_exception, control_block), sizeof(*impl)); + + #define WINRT_EXCEPTION(name, h) \ + case (h): \ + platform_##name##Exception_hstring_ctor(impl, msg); \ + break; + + switch (code) + { + WINRT_EXCEPTIONS; +#undef WINRT_EXCEPTION + default: + platform_COMException_hstring_ctor(impl, code, msg); + break; + } + + return &impl->IInspectable_iface; +} + +void *__cdecl CreateException(HRESULT hr) { - FIXME("(%p): stub!\n", excp); - return NULL; + TRACE("(%#lx)\n", hr); + return CreateExceptionWithMessage(hr, NULL); +} + +HSTRING __cdecl platform_exception_get_Message(struct platform_exception *this) +{ + HSTRING msg = NULL; + HRESULT hr = S_OK; + + TRACE("(%p)\n", this); + + if (this->inner.message2) + hr = WindowsCreateString(this->inner.message2, wcslen(this->inner.message2), &msg); + else + { + WCHAR buf[256]; + + if (FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, this->inner.hr, 0, buf, ARRAY_SIZE(buf), NULL)) + hr = WindowsCreateString(buf, wcslen(buf), &msg); + else + ERR("FormatMessageW failed: %lu\n", GetLastError()); + } + + if (FAILED(hr)) + __abi_WinRTraiseCOMException(hr); + return msg; +} + +extern void WINAPI DECLSPEC_NORETURN _CxxThrowException(void *, const cxx_exception_type *); + +static void DECLSPEC_NORETURN throw_exception(struct platform_exception *excp, const cxx_exception_type *type) +{ + if (excp->inner.message2) + { + excp->inner.message1 = SysAllocStringLen(excp->inner.message1, SysStringLen(excp->inner.message1)); + if (!excp->inner.message1) + __abi_WinRTraiseOutOfMemoryException(); + } + /* Thrown exceptions have a refcount of 2. */ + IInspectable_AddRef(&excp->IInspectable_iface); + _CxxThrowException(&excp, type); +} + +#define WINRT_EXCEPTION(name, hr) \ + void WINAPI DECLSPEC_NORETURN __abi_WinRTraise##name##Exception(void) \ + { \ + FIXME("(): semi-stub!\n"); \ + throw_exception(CreateException((hr)), &name##Exception_exception_type); \ + } +WINRT_EXCEPTIONS +#undef WINRT_EXCEPTION + +void WINAPI DECLSPEC_NORETURN __abi_WinRTraiseCOMException(HRESULT hr) +{ + FIXME("(%#lx): semi-stub!\n", hr); + + switch (hr) + { +#define WINRT_EXCEPTION(name, code) case (code): __abi_WinRTraise##name##Exception(); + WINRT_EXCEPTIONS; +#undef WINRT_EXCEPTION + default: + throw_exception(CreateException(hr), &COMException_exception_type); + } }
BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, void *reserved) { if (reason == DLL_PROCESS_ATTACH) + { init_platform_type(inst); + init_exception(inst); + } return TRUE; }
From: Vibhav Pant vibhavp@gmail.com
--- dlls/vccorlib140/cxx.h | 1 + dlls/vccorlib140/vccorlib.c | 23 +++++++++++++++++++++++ dlls/vccorlib140/vccorlib140.spec | 6 +++--- 3 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/dlls/vccorlib140/cxx.h b/dlls/vccorlib140/cxx.h index 0ce3275886c..f8f8fe08984 100644 --- a/dlls/vccorlib140/cxx.h +++ b/dlls/vccorlib140/cxx.h @@ -168,6 +168,7 @@ void __asm_dummy_ ## type ## _exception_type(void) \ ".long %c1\n\t" \ ".rva " #__VA_ARGS__ "\n\t" \ __ASM_GLOBL(#type "_exception_type") "\n\t" \ + /* All C++/CX exceptions set this field to 16, presumably for __abi__translateCurrentException? */ \ ".long 16\n\t" \ ".long 0\n\t" \ ".long 0\n\t" \ diff --git a/dlls/vccorlib140/vccorlib.c b/dlls/vccorlib140/vccorlib.c index 550e85c9776..31c7913ee46 100644 --- a/dlls/vccorlib140/vccorlib.c +++ b/dlls/vccorlib140/vccorlib.c @@ -1071,6 +1071,29 @@ void WINAPI DECLSPEC_NORETURN __abi_WinRTraiseCOMException(HRESULT hr) } }
+#define TYPE_FLAG_CPPCX 16 +extern const void **__cdecl __current_exception(void); + +HRESULT WINAPI __abi_translateCurrentException(bool unknown) +{ + const struct platform_exception *excp; + const EXCEPTION_RECORD *record; + const cxx_exception_type *type; + + FIXME("(%d): semi-stub!\n", unknown); + + record = *__current_exception(); + /* Native aborts if: + * There is no exception being currently handled. + * There is no associated exception object (_CxxThrowException(NULL, ...) was called). + * There is no associated cxx_exception_type param (_CxxThrowException(..., NULL) was called). + * A non C++/CX exception has been thrown. */ + if (!record || !(excp = (struct platform_exception *)record->ExceptionInformation[1]) || + !(type = (cxx_exception_type *)record->ExceptionInformation[2]) || !(type->flags & TYPE_FLAG_CPPCX)) + abort(); + return excp->inner.hr; +} + BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, void *reserved) { if (reason == DLL_PROCESS_ATTACH) diff --git a/dlls/vccorlib140/vccorlib140.spec b/dlls/vccorlib140/vccorlib140.spec index b6c1f985c0c..ca0e7795db7 100644 --- a/dlls/vccorlib140/vccorlib140.spec +++ b/dlls/vccorlib140/vccorlib140.spec @@ -338,9 +338,9 @@ @ stdcall -arch=win64 ?__abi_make_type_id@@YAPE$AAVType@Platform@@AEBU__abi_type_descriptor@@@Z(ptr) __abi_make_type_id @ stub -arch=win32 ??0IntPtr@Platform@@QAA@PAX@Z @ stub -arch=win64 ??0IntPtr@Platform@@QEAA@PEAX@Z -@ stub -arch=i386 ?__abi_translateCurrentException@@YGJ_N@Z -@ stub -arch=arm ?__abi_translateCurrentException@@YAJ_N@Z -@ stub -arch=win64 ?__abi_translateCurrentException@@YAJ_N@Z +@ stdcall -arch=i386 ?__abi_translateCurrentException@@YGJ_N@Z(long) __abi_translateCurrentException +@ stdcall -arch=arm ?__abi_translateCurrentException@@YAJ_N@Z(long) __abi_translateCurrentException +@ stdcall -arch=win64 ?__abi_translateCurrentException@@YAJ_N@Z(long) __abi_translateCurrentException @ stub -arch=i386 ?__getActivationFactoryByHSTRING@@YGJPAUHSTRING__@@AAVGuid@Platform@@PAPAX@Z @ stub -arch=arm ?__getActivationFactoryByHSTRING@@YAJPAUHSTRING__@@AAVGuid@Platform@@PAPAX@Z @ stub -arch=win64 ?__getActivationFactoryByHSTRING@@YAJPEAUHSTRING__@@AEAVGuid@Platform@@PEAPEAX@Z
On Wed Oct 29 11:12:51 2025 +0000, Piotr Caban wrote:
Some of the recent fixes where added to wrong patches (first patch has base set incorrectly, it's fixed in second patch). Another problem is that there's something wrong with how the WinRT exceptions are handled/implemented. With code from this MR it's not possible to mix native and builtin ucrtbase and vccorlib140 (we're getting ACCESS_VIOLATION while using exception throwing functions). While it might be not critical I would like to understand what's going on. I'm planning to look into it more. I guess it might be some kind of side-effect of trying to make these exceptions working with older exception handlers.
Thanks! Are you still getting a crash while throwing exceptions? I'm using [this code ](https://gitlab.winehq.org/wine/wine/-/snippets/30)to test exceptions, and it seems to work just fine for me on the current branch.
On Wed Oct 29 11:12:51 2025 +0000, Vibhav Pant wrote:
Thanks! Are you still getting a crash while throwing exceptions? I'm using [this code ](https://gitlab.winehq.org/wine/wine/-/snippets/30)to test exceptions, and it seems to work just fine for me on the current branch.
I've been using something very similar for testing. I'm still getting crashes when native vcruntime140 and builtin vccorlib140 is used.