From: Vibhav Pant vibhavp@gmail.com
--- dlls/vccorlib140/Makefile.in | 2 +- dlls/vccorlib140/cxx.h | 23 +- dlls/vccorlib140/tests/vccorlib.c | 9 +- dlls/vccorlib140/vccorlib.c | 487 ++++++++++++++++++++++++++---- 4 files changed, 449 insertions(+), 72 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 c2522abd434..740b1c9565c 100644 --- a/dlls/vccorlib140/tests/vccorlib.c +++ b/dlls/vccorlib140/tests/vccorlib.c @@ -1354,17 +1354,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); diff --git a/dlls/vccorlib140/vccorlib.c b/dlls/vccorlib140/vccorlib.c index 67a12cad72b..9c71a36393e 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_default_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_default_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_default_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_default_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_default_ctor(void *this, HRESULT hr) +struct platform_exception *__cdecl platform_COMException_default_ctor(struct platform_exception *this, HRESULT hr) { - FIXME("(%p, %#lx): stub!\n", this, hr); + TRACE("(%p, %#lx)\n", this, hr); + + platform_Exception_default_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_default_ctor(struct platform_exception *this) \ + { \ + TRACE("(%p)\n", this); \ + platform_COMException_default_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; }