From: Vibhav Pant vibhavp@gmail.com
--- dlls/vccorlib140/Makefile.in | 2 +- dlls/vccorlib140/cxx.h | 64 +++++++--- dlls/vccorlib140/except.c | 238 ++++++++++++++++++++++++++++++++++- dlls/vccorlib140/private.h | 29 +++++ dlls/vccorlib140/vccorlib.c | 27 +--- 5 files changed, 313 insertions(+), 47 deletions(-)
diff --git a/dlls/vccorlib140/Makefile.in b/dlls/vccorlib140/Makefile.in index 988d761efda..bad509dbdf5 100644 --- a/dlls/vccorlib140/Makefile.in +++ b/dlls/vccorlib140/Makefile.in @@ -1,5 +1,5 @@ MODULE = vccorlib140.dll -IMPORTS = combase +IMPORTS = combase oleaut32
SOURCES = \ except.c \ diff --git a/dlls/vccorlib140/cxx.h b/dlls/vccorlib140/cxx.h index b803d35a283..64776822d9e 100644 --- a/dlls/vccorlib140/cxx.h +++ b/dlls/vccorlib140/cxx.h @@ -21,6 +21,15 @@ #include "rtlsupportapi.h" #include "wine/asm.h"
+#define CLASS_IS_SIMPLE_TYPE 1 +#define CLASS_HAS_VIRTUAL_BASE_CLASS 4 +#define CLASS_IS_WINRT 8 + +#define TYPE_FLAG_CONST 1 +#define TYPE_FLAG_VOLATILE 2 +#define TYPE_FLAG_REFERENCE 8 +#define TYPE_FLAG_WINRT 16 + #ifdef __i386__ #undef CXX_USE_RVA #else @@ -139,63 +148,70 @@ static void init_ ## name ## _rtti(char *base) \
#ifndef CXX_USE_RVA
-#define DEFINE_CXX_TYPE(type, dtor, ...) \ +#define CXX_FUNC(func) THISCALL(func) +#define CXX_NULL NULL + +#define DEFINE_CXX_TYPE2(type, flags, ti_flags, dtor, copyctor, ...) \ static const cxx_type_info type ## _cxx_type_info[1] = \ - { { 0, &type ##_type_info, { 0, -1, 0 }, sizeof(type), THISCALL(type ##_copy_ctor) } }; \ + { { ti_flags, &type ##_type_info, { 0, -1, 0 }, sizeof(type), copyctor } }; \ \ static const cxx_type_info_table type ## _cxx_type_table = \ - { ARRAY_SIZE(((const void *[]){ NULL, __VA_ARGS__ })), { type ## _cxx_type_info, __VA_ARGS__ } }; \ + { ARRAY_SIZE(((const void *[]){ __VA_ARGS__ })), { __VA_ARGS__ } }; \ \ static const cxx_exception_type type ## _exception_type = \ - { 0, THISCALL(dtor), NULL, & type ## _cxx_type_table }; + { flags, 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, ...) \ +#define CXX_FUNC(func) ".rva " #func +#define CXX_NULL ".long 0" + +#define DEFINE_CXX_TYPE2(type, flags, ti_flags, dtor, copyctor, ...) \ 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" \ + ".long %c0\n\t" \ ".rva " #type "_type_info\n\t" \ - ".long 0, -1, 0, %c0\n\t" \ - ".rva " #type "_copy_ctor\n" \ + ".long 0, -1, 0, %c1\n\t" \ + copyctor "\n\t" \ #type "_type_table:\n\t" \ - ".long %c1\n\t" \ + ".long %c2\n\t" \ ".rva " #__VA_ARGS__ "\n\t" \ __ASM_GLOBL(#type "_exception_type") "\n\t" \ - ".long 0\n\t" \ - ".rva " #dtor "\n\t" \ + ".long %c3\n\t" \ + dtor "\n\t" \ ".long 0\n\t" \ ".rva " #type "_type_table\n\t" \ - :: "i"(sizeof(type)), "i"(ARRAY_SIZE(((const void *[]){ &__VA_ARGS__ }))) ); \ + :: "i"(ti_flags), "i"(sizeof(type)), "i"(ARRAY_SIZE(((const void *[]){ &__VA_ARGS__ }))), "i"(flags) ); \ } -#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, ...) \ +#define CXX_FUNC(func) func +#define CXX_NULL NULL + +#define DEFINE_CXX_TYPE2(type, flags, ti_flags, dtor, copyctor, ...) \ static cxx_type_info type ## _cxx_type_info[1] = \ - { { 0, 0xdeadbeef, { 0, -1, 0 }, sizeof(type), 0xdeadbeef } }; \ + { { ti_flags, 0xdeadbeef, { 0, -1, 0 }, sizeof(type), 0xdeadbeef } }; \ \ -static const void * const type ## _cxx_type_classes[] = { type ## _cxx_type_info, __VA_ARGS__ }; \ +static const void * const type ## _cxx_type_classes[] = { __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 cxx_exception_type type ##_exception_type = {flags}; \ \ 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 = (copyctor) ? (char *)(copyctor) - base : 0; \ 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.destructor = (dtor) ? (char *)(dtor) - base : 0; \ type ## _exception_type.type_info_table = (char *)&type ## _cxx_type_table - base; \ }
@@ -203,6 +219,14 @@ static void init_ ## type ## _cxx(char *base) \
#endif /* CXX_USE_RVA */
+#define DEFINE_CXX_TYPE(type, dtor, ...) \ + DEFINE_CXX_TYPE2(type, 0, 0, CXX_FUNC(dtor), CXX_FUNC(type ##_copy_ctor), \ + type ## _cxx_type_info, ##__VA_ARGS__) + +#define DEFINE_WINRT_CXX_TYPE(type, ...) \ + DEFINE_CXX_TYPE2(type, TYPE_FLAG_WINRT, CLASS_IS_SIMPLE_TYPE | CLASS_IS_WINRT, \ + CXX_NULL, CXX_NULL, type ## _cxx_type_info, ##__VA_ARGS__) + #ifdef __ASM_USE_THISCALL_WRAPPER
#define CALL_VTBL_FUNC(this, off, ret, type, args) ((ret (WINAPI*)type)&vtbl_wrapper_##off)args diff --git a/dlls/vccorlib140/except.c b/dlls/vccorlib140/except.c index 0165fe8878f..b5c4254b6fc 100644 --- a/dlls/vccorlib140/except.c +++ b/dlls/vccorlib140/except.c @@ -16,12 +16,67 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#define COBJMACROS + +#include <stdint.h> + #include "roapi.h" #include "winstring.h" +#include "roerrorapi.h" +#define WIDL_using_Windows_Foundation +#include "windows.foundation.h" #include "wine/debug.h"
+#include "cxx.h" +#include "private.h" + WINE_DEFAULT_DEBUG_CHANNEL(vccorlib);
+#ifdef _WIN64 +#define EXCEPTION_REF_NAME(name) ".PE$AAV" #name "Exception@Platform@@" +#else +#define EXCEPTION_REF_NAME(name) ".P$AAV" #name "Exception@Platform@@" +#endif + +/* 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 description; + /* Likewise, but can also be set by CreateExceptionWithMessage. */ + BSTR restricted_desc; + 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; + /* Called before the exception is thrown by _CxxThrowException. + * This sets the description and error_info fields, and probably originates a WinRT error + * with RoOriginateError/RoOriginateLanguageException. */ + void (*WINAPI set_exception_info)(struct exception_inner **); +}; + +struct 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; +}; + void *__cdecl CreateExceptionWithMessage(HRESULT hr, HSTRING msg) { FIXME("(%#lx, %s): stub!\n", hr, debugstr_hstring(msg)); @@ -74,9 +129,180 @@ void WINAPI __abi_WinRTraiseCOMException(HRESULT hr) WINRT_EXCEPTIONS #undef WINRT_EXCEPTION
-void *__cdecl Exception_ctor(void *this, HRESULT hr) +static inline struct Exception *impl_Exception_from_IInspectable(IInspectable *iface) { - FIXME("(%p, %#lx): stub!\n", this, hr); + return CONTAINING_RECORD(iface, struct Exception, IInspectable_iface); +} + +static HRESULT WINAPI Exception_QueryInterface(IInspectable *iface, const GUID *iid, void **out) +{ + struct Exception *impl = impl_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); + } + + ERR("%s not implemented, returning E_NOTINTERFACE.\n", debugstr_guid(iid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI Exception_AddRef(IInspectable *iface) +{ + struct Exception *impl = impl_Exception_from_IInspectable(iface); + TRACE("(%p)\n", iface); + return InterlockedIncrement(&impl->control_block->ref_strong); +} + +static ULONG WINAPI Exception_Release(IInspectable *iface) +{ + struct Exception *impl = impl_Exception_from_IInspectable(iface); + ULONG ref = InterlockedDecrement(&impl->control_block->ref_strong); + + TRACE("(%p)\n", iface); + + if (!ref) + { + SysFreeString(impl->inner.description); + SysFreeString(impl->inner.restricted_desc); + 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 Exception_GetRuntimeClassName(IInspectable *iface, HSTRING *class_name) +{ + struct Exception *impl = impl_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 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 Exception_GetTrustLevel(IInspectable *iface, TrustLevel *level) +{ + FIXME("(%p, %p)\n", iface, level); + return E_NOTIMPL; +} + +DEFINE_RTTI_DATA(Exception_ref, 0, EXCEPTION_REF_NAME()); +typedef struct Exception *Exception_ref; +DEFINE_WINRT_CXX_TYPE(Exception_ref); + +DEFINE_RTTI_DATA(Exception, 0, "?.AVException@Platform@@"); +COM_VTABLE_RTTI_START(IInspectable, Exception) +COM_VTABLE_ENTRY(Exception_QueryInterface) +COM_VTABLE_ENTRY(Exception_AddRef) +COM_VTABLE_ENTRY(Exception_Release) +COM_VTABLE_ENTRY(Exception_GetIids) +COM_VTABLE_ENTRY(Exception_GetRuntimeClassName) +COM_VTABLE_ENTRY(Exception_GetTrustLevel) +COM_VTABLE_RTTI_END; + +DEFINE_IINSPECTABLE_(Exception_Closable, IClosable, struct Exception, + impl_Exception_from_IClosable, IClosable_iface, &impl->IInspectable_iface); + +static HRESULT WINAPI Exception_Closable_Close(IClosable *iface) +{ + FIXME("(%p)\n", iface); + return E_NOTIMPL; +} + +DEFINE_RTTI_DATA(Exception_Closable, offsetof(struct Exception, IClosable_iface), + "?.AVException@Platform@@") +COM_VTABLE_RTTI_START(IClosable, Exception_Closable) +COM_VTABLE_ENTRY(Exception_Closable_QueryInterface) +COM_VTABLE_ENTRY(Exception_Closable_AddRef) +COM_VTABLE_ENTRY(Exception_Closable_Release) +COM_VTABLE_ENTRY(Exception_Closable_GetIids) +COM_VTABLE_ENTRY(Exception_Closable_GetRuntimeClassName) +COM_VTABLE_ENTRY(Exception_Closable_GetTrustLevel) +COM_VTABLE_ENTRY(Exception_Closable_Close) +COM_VTABLE_RTTI_END; + +static void WINAPI set_exception_info(struct exception_inner **inner) +{ + struct exception_inner *info = *inner; + WCHAR buf[256]; + + FIXME("(%p): semi-stub!\n", inner); + + if (FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, info->hr, 0, buf, ARRAY_SIZE(buf), NULL)) + info->description = SysAllocString(buf); + if (!info->restricted_desc) + info->restricted_desc = SysAllocString(info->description); + info->error_info = NULL; +} + +struct Exception *__cdecl Exception_ctor(struct 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 = &Exception_vtable.vtable; + this->IClosable_iface.lpVtbl = &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_ref_exception_type; + this->inner.hr = hr; + this->inner.unknown3 = sizeof(void *) == 8 ? 64 : 32; + this->inner.set_exception_info = set_exception_info; + + this->marshal = (IUnknown *)UINTPTR_MAX; + + if (SUCCEEDED(hr)) + __abi_WinRTraiseInvalidArgumentException(); return this; }
@@ -103,3 +329,11 @@ HSTRING __cdecl Exception_get_Message(void *excp) FIXME("(%p): stub!\n", excp); return NULL; } + +void init_exception(void *base) +{ + INIT_RTTI(Exception_ref, base); + INIT_CXX_TYPE(Exception_ref, base); + INIT_RTTI(Exception, base); + INIT_RTTI(Exception_Closable, base); +} diff --git a/dlls/vccorlib140/private.h b/dlls/vccorlib140/private.h index 1b30dbcb867..384cb6bfd40 100644 --- a/dlls/vccorlib140/private.h +++ b/dlls/vccorlib140/private.h @@ -16,6 +16,35 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#include <stdbool.h> + +#include "weakreference.h" + +struct exception_alloc +{ + void *unknown; + void *exception_inner; + char data[0]; +}; + +struct control_block +{ + IWeakReference IWeakReference_iface; + LONG ref_weak; + LONG ref_strong; + IUnknown *object; + bool is_inline; + bool unknown; + bool is_exception; +#ifdef _WIN32 + char _padding[5]; +#endif +}; + +void __cdecl FreeException(void *); + +void init_exception(void *); + #define COM_VTABLE_RTTI_START(iface, type) \ static const struct \ { \ diff --git a/dlls/vccorlib140/vccorlib.c b/dlls/vccorlib140/vccorlib.c index 869d40aea10..49b730a2914 100644 --- a/dlls/vccorlib140/vccorlib.c +++ b/dlls/vccorlib140/vccorlib.c @@ -19,11 +19,8 @@
#define COBJMACROS
-#include <stdbool.h> - #include "initguid.h" #include "roapi.h" -#include "weakreference.h" #include "winstring.h" #define WIDL_using_Windows_Foundation #include "windows.foundation.h" @@ -101,13 +98,6 @@ void *__cdecl Allocate(size_t size) return addr; }
-struct exception_alloc -{ - void *unknown; - void *exception_inner; - char data[0]; -}; - void *__cdecl AllocateException(size_t size) { struct exception_alloc *base; @@ -134,20 +124,6 @@ void __cdecl FreeException(void *addr) Free(base); }
-struct control_block -{ - IWeakReference IWeakReference_iface; - LONG ref_weak; - LONG ref_strong; - IUnknown *object; - bool is_inline; - bool unknown; - bool is_exception; -#ifdef _WIN32 - char _padding[5]; -#endif -}; - static inline struct control_block *impl_from_IWeakReference(IWeakReference *iface) { return CONTAINING_RECORD(iface, struct control_block, IWeakReference_iface); @@ -614,6 +590,9 @@ void *WINAPI CreateValue(int typecode, const void *val) BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, void *reserved) { if (reason == DLL_PROCESS_ATTACH) + { + init_exception(inst); init_platform_type(inst); + } return TRUE; }