[PATCH v23 0/5] MR10659: combase: Implement restricted WinRT error handling APIs.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58900 Bug 58900 This series implements restricted WinRT error handling in combase and\ adds conformance tests for the new behavior. Implemented APIs include restricted error creation / retrieval,\ error context capture, transform, matching, and unhandled error reporting\ paths. Tests were added under dlls/combase/tests and pass locally.\ The existing combase tests also continue to pass. -- v23: combase/tests: Add basic tests for Get/SetRestrictedErrorInfo. https://gitlab.winehq.org/wine/wine/-/merge_requests/10659
From: Anna R Békefi <annareginabekefi@gmail.com> --- dlls/combase/errorinfo.c | 223 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) diff --git a/dlls/combase/errorinfo.c b/dlls/combase/errorinfo.c index 9383e8d5a72..c383854e2d3 100644 --- a/dlls/combase/errorinfo.c +++ b/dlls/combase/errorinfo.c @@ -27,6 +27,8 @@ #include "wine/debug.h" +#include "roerrorapi.h" + WINE_DEFAULT_DEBUG_CHANNEL(ole); struct error_info @@ -393,3 +395,224 @@ HRESULT WINAPI SetErrorInfo(ULONG reserved, IErrorInfo *error_info) return S_OK; } + +/*********************************************************************** + * IRestrictedErrorInfo implementation / helper (combase internal) + */ +struct restricted_error_info +{ + IRestrictedErrorInfo IRestrictedErrorInfo_iface; + IErrorInfo IErrorInfo_iface; + LONG refcount; + + GUID guid; + WCHAR *source; + WCHAR *help_file; + DWORD help_context; + + HRESULT hr; + WCHAR *description; + WCHAR *restricted_description; + WCHAR *capability_sid; + WCHAR *reference; + + BOOL context_captured; + USHORT stack_frame_count; + void *stack_frames[32]; + ULONG stack_hash; +}; + +static struct restricted_error_info *impl_from_IRestrictedErrorInfo(IRestrictedErrorInfo *iface) +{ + return CONTAINING_RECORD(iface, struct restricted_error_info, IRestrictedErrorInfo_iface); +} + +static struct restricted_error_info *impl_from_restricted_IErrorInfo(IErrorInfo *iface) +{ + return CONTAINING_RECORD(iface, struct restricted_error_info, IErrorInfo_iface); +} + +static ULONG restricted_errorinfo_addref(struct restricted_error_info *info) +{ + ULONG refcount = InterlockedIncrement(&info->refcount); + + TRACE("%p, refcount %lu.\n", info, refcount); + return refcount; +} + +static ULONG restricted_errorinfo_release(struct restricted_error_info *info) +{ + ULONG refcount = InterlockedDecrement(&info->refcount); + + TRACE("%p, refcount %lu.\n", info, refcount); + + if (!refcount) + { + free(info->source); + free(info->help_file); + free(info->description); + free(info->restricted_description); + free(info->capability_sid); + free(info->reference); + free(info); + } + + return refcount; +} + +static HRESULT WINAPI restricted_errorinfo_QueryInterface(IRestrictedErrorInfo *iface, REFIID riid, void **obj) +{ + struct restricted_error_info *info = impl_from_IRestrictedErrorInfo(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + if (!obj) return E_POINTER; + *obj = NULL; + + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IRestrictedErrorInfo)) + *obj = &info->IRestrictedErrorInfo_iface; + else if (IsEqualIID(riid, &IID_IErrorInfo)) + *obj = &info->IErrorInfo_iface; + + if (*obj) + { + restricted_errorinfo_addref(info); + return S_OK; + } + + WARN("Unsupported interface %s.\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI restricted_errorinfo_AddRef(IRestrictedErrorInfo *iface) +{ + struct restricted_error_info *info = impl_from_IRestrictedErrorInfo(iface); + return restricted_errorinfo_addref(info); +} + +static ULONG WINAPI restricted_errorinfo_Release(IRestrictedErrorInfo *iface) +{ + struct restricted_error_info *info = impl_from_IRestrictedErrorInfo(iface); + return restricted_errorinfo_release(info); +} + +static HRESULT WINAPI restricted_errorinfo_GetErrorDetails(IRestrictedErrorInfo *iface, + BSTR *description, HRESULT *error, BSTR *restricted_description, BSTR *capability_sid) +{ + FIXME("%p, %p, %p, %p, %p: stub\n", iface, description, error, restricted_description, capability_sid); + return E_NOTIMPL; +} + +static HRESULT WINAPI restricted_errorinfo_GetReference(IRestrictedErrorInfo *iface, BSTR *reference) +{ + FIXME("%p, %p: stub\n", iface, reference); + return E_NOTIMPL; +} + +static HRESULT WINAPI restricted_errorinfo_ierror_QueryInterface(IErrorInfo *iface, REFIID riid, void **obj) +{ + struct restricted_error_info *info = impl_from_restricted_IErrorInfo(iface); + return IRestrictedErrorInfo_QueryInterface(&info->IRestrictedErrorInfo_iface, riid, obj); +} + +static ULONG WINAPI restricted_errorinfo_ierror_AddRef(IErrorInfo *iface) +{ + struct restricted_error_info *info = impl_from_restricted_IErrorInfo(iface); + return restricted_errorinfo_addref(info); +} + +static ULONG WINAPI restricted_errorinfo_ierror_Release(IErrorInfo *iface) +{ + struct restricted_error_info *info = impl_from_restricted_IErrorInfo(iface); + return restricted_errorinfo_release(info); +} + +static HRESULT WINAPI restricted_errorinfo_ierror_GetGUID(IErrorInfo *iface, GUID *guid) +{ + FIXME("%p, %p: stub\n", iface, guid); + return E_NOTIMPL; +} + +static HRESULT WINAPI restricted_errorinfo_ierror_GetSource(IErrorInfo *iface, BSTR *source) +{ + FIXME("%p, %p: stub\n", iface, source); + return E_NOTIMPL; +} + +static HRESULT WINAPI restricted_errorinfo_ierror_GetDescription(IErrorInfo *iface, BSTR *description) +{ + FIXME("%p, %p: stub\n", iface, description); + return E_NOTIMPL; +} + +static HRESULT WINAPI restricted_errorinfo_ierror_GetHelpFile(IErrorInfo *iface, BSTR *helpfile) +{ + FIXME("%p, %p: stub\n", iface, helpfile); + return E_NOTIMPL; +} + +static HRESULT WINAPI restricted_errorinfo_ierror_GetHelpContext(IErrorInfo *iface, DWORD *help_context) +{ + FIXME("%p, %p: stub\n", iface, help_context); + return E_NOTIMPL; +} + +static const IErrorInfoVtbl restricted_errorinfo_ierror_vtbl = +{ + restricted_errorinfo_ierror_QueryInterface, + restricted_errorinfo_ierror_AddRef, + restricted_errorinfo_ierror_Release, + restricted_errorinfo_ierror_GetGUID, + restricted_errorinfo_ierror_GetSource, + restricted_errorinfo_ierror_GetDescription, + restricted_errorinfo_ierror_GetHelpFile, + restricted_errorinfo_ierror_GetHelpContext +}; + +static const IRestrictedErrorInfoVtbl restricted_errorinfo_vtbl = +{ + restricted_errorinfo_QueryInterface, + restricted_errorinfo_AddRef, + restricted_errorinfo_Release, + restricted_errorinfo_GetErrorDetails, + restricted_errorinfo_GetReference +}; + +HRESULT create_restricted_error_info(HRESULT hr, const WCHAR *description, + const WCHAR *restricted_description, const WCHAR *capability_sid, + const WCHAR *reference, IRestrictedErrorInfo **ret) +{ + struct restricted_error_info *info; + + TRACE("%#lx, %s, %s, %s, %s, %p.\n", hr, debugstr_w(description), + debugstr_w(restricted_description), debugstr_w(capability_sid), + debugstr_w(reference), ret); + + if (!ret) return E_INVALIDARG; + *ret = NULL; + + info = calloc(1, sizeof(*info)); + if (!info) return E_OUTOFMEMORY; + + info->IRestrictedErrorInfo_iface.lpVtbl = &restricted_errorinfo_vtbl; + info->IErrorInfo_iface.lpVtbl = &restricted_errorinfo_ierror_vtbl; + info->refcount = 1; + + info->guid = GUID_NULL; + info->source = NULL; + info->help_file = NULL; + info->help_context = 0; + + info->hr = hr; + info->description = description ? wcsdup(description) : NULL; + info->restricted_description = restricted_description ? wcsdup(restricted_description) : NULL; + info->capability_sid = capability_sid ? wcsdup(capability_sid) : NULL; + info->reference = reference ? wcsdup(reference) : NULL; + + info->context_captured = FALSE; + info->stack_frame_count = 0; + info->stack_hash = 0; + + *ret = &info->IRestrictedErrorInfo_iface; + return S_OK; +} -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10659
From: Anna R Békefi <annareginabekefi@gmail.com> --- dlls/combase/errorinfo.c | 70 ++++++++++++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 14 deletions(-) diff --git a/dlls/combase/errorinfo.c b/dlls/combase/errorinfo.c index c383854e2d3..47934c199cb 100644 --- a/dlls/combase/errorinfo.c +++ b/dlls/combase/errorinfo.c @@ -499,14 +499,31 @@ static ULONG WINAPI restricted_errorinfo_Release(IRestrictedErrorInfo *iface) static HRESULT WINAPI restricted_errorinfo_GetErrorDetails(IRestrictedErrorInfo *iface, BSTR *description, HRESULT *error, BSTR *restricted_description, BSTR *capability_sid) { - FIXME("%p, %p, %p, %p, %p: stub\n", iface, description, error, restricted_description, capability_sid); - return E_NOTIMPL; + struct restricted_error_info *info = impl_from_IRestrictedErrorInfo(iface); + + TRACE("%p, %p, %p, %p, %p.\n", iface, description, error, restricted_description, capability_sid); + + if (description) + *description = info->description ? SysAllocString(info->description) : NULL; + if (error) + *error = info->hr; + if (restricted_description) + *restricted_description = info->restricted_description ? SysAllocString(info->restricted_description) : NULL; + if (capability_sid) + *capability_sid = info->capability_sid ? SysAllocString(info->capability_sid) : NULL; + + return S_OK; } static HRESULT WINAPI restricted_errorinfo_GetReference(IRestrictedErrorInfo *iface, BSTR *reference) { - FIXME("%p, %p: stub\n", iface, reference); - return E_NOTIMPL; + struct restricted_error_info *info = impl_from_IRestrictedErrorInfo(iface); + + TRACE("%p, %p.\n", iface, reference); + + if (!reference) return E_POINTER; + *reference = info->reference ? SysAllocString(info->reference) : NULL; + return S_OK; } static HRESULT WINAPI restricted_errorinfo_ierror_QueryInterface(IErrorInfo *iface, REFIID riid, void **obj) @@ -529,32 +546,57 @@ static ULONG WINAPI restricted_errorinfo_ierror_Release(IErrorInfo *iface) static HRESULT WINAPI restricted_errorinfo_ierror_GetGUID(IErrorInfo *iface, GUID *guid) { - FIXME("%p, %p: stub\n", iface, guid); - return E_NOTIMPL; + struct restricted_error_info *info = impl_from_restricted_IErrorInfo(iface); + + TRACE("%p, %p.\n", iface, guid); + + if (!guid) return E_INVALIDARG; + *guid = info->guid; + return S_OK; } static HRESULT WINAPI restricted_errorinfo_ierror_GetSource(IErrorInfo *iface, BSTR *source) { - FIXME("%p, %p: stub\n", iface, source); - return E_NOTIMPL; + struct restricted_error_info *info = impl_from_restricted_IErrorInfo(iface); + + TRACE("%p, %p.\n", iface, source); + + if (!source) return E_INVALIDARG; + *source = info->source ? SysAllocString(info->source) : NULL; + return S_OK; } static HRESULT WINAPI restricted_errorinfo_ierror_GetDescription(IErrorInfo *iface, BSTR *description) { - FIXME("%p, %p: stub\n", iface, description); - return E_NOTIMPL; + struct restricted_error_info *info = impl_from_restricted_IErrorInfo(iface); + + TRACE("%p, %p.\n", iface, description); + + if (!description) return E_INVALIDARG; + *description = info->description ? SysAllocString(info->description) : NULL; + return S_OK; } static HRESULT WINAPI restricted_errorinfo_ierror_GetHelpFile(IErrorInfo *iface, BSTR *helpfile) { - FIXME("%p, %p: stub\n", iface, helpfile); - return E_NOTIMPL; + struct restricted_error_info *info = impl_from_restricted_IErrorInfo(iface); + + TRACE("%p, %p.\n", iface, helpfile); + + if (!helpfile) return E_INVALIDARG; + *helpfile = info->help_file ? SysAllocString(info->help_file) : NULL; + return S_OK; } static HRESULT WINAPI restricted_errorinfo_ierror_GetHelpContext(IErrorInfo *iface, DWORD *help_context) { - FIXME("%p, %p: stub\n", iface, help_context); - return E_NOTIMPL; + struct restricted_error_info *info = impl_from_restricted_IErrorInfo(iface); + + TRACE("%p, %p.\n", iface, help_context); + + if (!help_context) return E_INVALIDARG; + *help_context = info->help_context; + return S_OK; } static const IErrorInfoVtbl restricted_errorinfo_ierror_vtbl = -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10659
From: Anna R Békefi <annareginabekefi@gmail.com> --- dlls/combase/roapi.c | 54 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/dlls/combase/roapi.c b/dlls/combase/roapi.c index f4f7c0aac26..19351961932 100644 --- a/dlls/combase/roapi.c +++ b/dlls/combase/roapi.c @@ -17,6 +17,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #define COBJMACROS +#define WINOLEAUTAPI #include "objbase.h" #include "initguid.h" #include "roapi.h" @@ -498,8 +499,36 @@ HRESULT WINAPI RoRegisterActivationFactories(HSTRING *classes, PFNGETACTIVATIONF */ HRESULT WINAPI GetRestrictedErrorInfo(IRestrictedErrorInfo **info) { - FIXME( "(%p)\n", info ); - return E_NOTIMPL; + IErrorInfo *error_info = NULL; + HRESULT hr; + + TRACE("(%p)\n", info); + + if (!info) return E_POINTER; + *info = NULL; + + hr = GetErrorInfo(0, &error_info); + if (hr == S_FALSE) + return S_FALSE; + if (FAILED(hr)) + { + WARN("GetErrorInfo failed, hr %#lx.\n", hr); + return hr; + } + + if (!error_info) + return S_FALSE; + + hr = IErrorInfo_QueryInterface(error_info, &IID_IRestrictedErrorInfo, (void **)info); + IErrorInfo_Release(error_info); + + if (FAILED(hr)) + { + TRACE("Current error object does not support IRestrictedErrorInfo.\n"); + return S_FALSE; + } + + return S_OK; } /*********************************************************************** @@ -507,8 +536,25 @@ HRESULT WINAPI GetRestrictedErrorInfo(IRestrictedErrorInfo **info) */ HRESULT WINAPI SetRestrictedErrorInfo(IRestrictedErrorInfo *info) { - FIXME( "(%p)\n", info ); - return E_NOTIMPL; + IErrorInfo *error_info = NULL; + HRESULT hr; + + TRACE("(%p)\n", info); + + if (!info) + return SetErrorInfo(0, NULL); + + hr = IRestrictedErrorInfo_QueryInterface(info, &IID_IErrorInfo, (void **)&error_info); + if (FAILED(hr)) + { + WARN("Restricted error object does not expose IErrorInfo, hr %#lx.\n", hr); + return hr; + } + + hr = SetErrorInfo(0, error_info); + IErrorInfo_Release(error_info); + + return hr; } /*********************************************************************** -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10659
From: Anna R Békefi <annareginabekefi@gmail.com> --- dlls/combase/errorinfo.c | 42 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/dlls/combase/errorinfo.c b/dlls/combase/errorinfo.c index 47934c199cb..a617dd4b47c 100644 --- a/dlls/combase/errorinfo.c +++ b/dlls/combase/errorinfo.c @@ -658,3 +658,45 @@ HRESULT create_restricted_error_info(HRESULT hr, const WCHAR *description, *ret = &info->IRestrictedErrorInfo_iface; return S_OK; } + +HRESULT capture_restricted_error_context(IRestrictedErrorInfo *iface, HRESULT hr) +{ + struct restricted_error_info *info; + ULONG hash = 0; + + TRACE("%p, %#lx.\n", iface, hr); + + if (!iface) + return E_INVALIDARG; + + info = impl_from_IRestrictedErrorInfo(iface); + + info->hr = hr; + memset(info->stack_frames, 0, sizeof(info->stack_frames)); + info->stack_frame_count = RtlCaptureStackBackTrace(1, ARRAY_SIZE(info->stack_frames), + info->stack_frames, &hash); + info->stack_hash = hash; + info->context_captured = TRUE; + + return S_OK; +} + +HRESULT copy_restricted_error_context(IRestrictedErrorInfo *dst_iface, IRestrictedErrorInfo *src_iface) +{ + struct restricted_error_info *dst, *src; + + TRACE("%p, %p.\n", dst_iface, src_iface); + + if (!dst_iface || !src_iface) + return E_INVALIDARG; + + dst = impl_from_IRestrictedErrorInfo(dst_iface); + src = impl_from_IRestrictedErrorInfo(src_iface); + + dst->context_captured = src->context_captured; + dst->stack_frame_count = src->stack_frame_count; + memcpy(dst->stack_frames, src->stack_frames, sizeof(dst->stack_frames)); + dst->stack_hash = src->stack_hash; + + return S_OK; +} -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10659
From: Anna R Békefi <annareginabekefi@gmail.com> --- dlls/combase/tests/roapi.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/dlls/combase/tests/roapi.c b/dlls/combase/tests/roapi.c index e4100cb11bc..e8febc608d2 100644 --- a/dlls/combase/tests/roapi.c +++ b/dlls/combase/tests/roapi.c @@ -639,6 +639,38 @@ static void test_RoGetErrorReportingFlags(void) ok(flags == RO_ERROR_REPORTING_USESETERRORINFO, "Got unexpected flag %#x.\n", flags); } +static void test_GetSetRestrictedErrorInfo(void) +{ + IRestrictedErrorInfo *info = NULL; + HRESULT hr; + BOOL uninit = FALSE; + + hr = RoInitialize(RO_INIT_MULTITHREADED); + ok(hr == S_OK || hr == S_FALSE, "RoInitialize returned %#lx.\n", hr); + if (SUCCEEDED(hr)) + uninit = TRUE; + + hr = SetRestrictedErrorInfo(NULL); + ok(hr == S_OK, "SetRestrictedErrorInfo(NULL) returned %#lx.\n", hr); + + hr = GetRestrictedErrorInfo(NULL); + ok(hr == E_POINTER, "GetRestrictedErrorInfo(NULL) returned %#lx.\n", hr); + + hr = GetRestrictedErrorInfo(&info); + ok(hr == S_FALSE, "GetRestrictedErrorInfo returned %#lx.\n", hr); + ok(!info, "got info %p.\n", info); + + hr = SetRestrictedErrorInfo(NULL); + ok(hr == S_OK, "SetRestrictedErrorInfo(NULL) returned %#lx.\n", hr); + + hr = GetRestrictedErrorInfo(&info); + ok(hr == S_FALSE, "GetRestrictedErrorInfo returned %#lx.\n", hr); + ok(!info, "got info %p.\n", info); + + if (uninit) + RoUninitialize(); +} + START_TEST(roapi) { BOOL ret; @@ -649,6 +681,7 @@ START_TEST(roapi) test_ActivationFactories(); test_RoGetAgileReference(); test_RoGetErrorReportingFlags(); + test_GetSetRestrictedErrorInfo(); SetLastError(0xdeadbeef); ret = DeleteFileW(L"wine.combase.test.dll"); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10659
Apologies, I only saw this MR today. There is already a pending MR that implements `IRestrictedErrorInfo` and `GetRestrictedErrorInfo`: https://gitlab.winehq.org/wine/wine/-/merge_requests/9332. Adding `SetRestrictedErrorInfo` to that one should be fairly trivial, could please you try doing that and see if it resolves the bug and the additional tests here? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10659#note_141716
participants (3)
-
Anna R Békefi -
Anna R Békefi (@annareginabekefi) -
Vibhav Pant (@vibhavp)