diff --git a/strings/base_error.h b/strings/base_error.h index 45ed39cd3..44b955b95 100644 --- a/strings/base_error.h +++ b/strings/base_error.h @@ -207,17 +207,17 @@ WINRT_EXPORT namespace winrt return *this; } - explicit hresult_error(hresult const code) noexcept : m_code(verify_error(code)) + explicit hresult_error(hresult const code WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : m_code(verify_error(code)) { - originate(code, nullptr); + originate(code, nullptr WINRT_IMPL_SOURCE_LOCATION_FORWARD); } - hresult_error(hresult const code, param::hstring const& message) noexcept : m_code(verify_error(code)) + hresult_error(hresult const code, param::hstring const& message WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : m_code(verify_error(code)) { - originate(code, get_abi(message)); + originate(code, get_abi(message) WINRT_IMPL_SOURCE_LOCATION_FORWARD); } - hresult_error(hresult const code, take_ownership_from_abi_t) noexcept : m_code(verify_error(code)) + hresult_error(hresult const code, take_ownership_from_abi_t WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : m_code(verify_error(code)) { com_ptr info; WINRT_IMPL_GetErrorInfo(0, info.put_void()); @@ -247,7 +247,7 @@ WINRT_EXPORT namespace winrt message = impl::trim_hresult_message(legacy.get(), WINRT_IMPL_SysStringLen(legacy.get())); } - originate(code, get_abi(message)); + originate(code, get_abi(message) WINRT_IMPL_SOURCE_LOCATION_FORWARD); } } @@ -309,12 +309,24 @@ WINRT_EXPORT namespace winrt return 1; } - void originate(hresult const code, void* message) noexcept + void originate(hresult const code, void* message WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept { static int32_t(__stdcall* handler)(int32_t error, void* message, void* exception) noexcept; impl::load_runtime_function(L"combase.dll", "RoOriginateLanguageException", handler, fallback_RoOriginateLanguageException); WINRT_VERIFY(handler(code, message, nullptr)); + // This is an extension point that can be filled in by other libraries (such as WIL) to get call outs when errors are + // originated. This is intended for logging purposes. When possible include the std::source_information so that accurate + // information is available on the caller who generated the error. + if (winrt_throw_hresult_handler) + { +#ifdef __cpp_lib_source_location + winrt_throw_hresult_handler(sourceInformation.line(), sourceInformation.file_name(), sourceInformation.function_name(), WINRT_IMPL_RETURNADDRESS(), code); +#else + winrt_throw_hresult_handler(0, nullptr, nullptr, WINRT_IMPL_RETURNADDRESS(), code); +#endif + } + com_ptr info; WINRT_VERIFY_(0, WINRT_IMPL_GetErrorInfo(0, info.put_void())); WINRT_VERIFY(info.try_as(m_info)); @@ -344,100 +356,104 @@ WINRT_EXPORT namespace winrt struct hresult_access_denied : hresult_error { - hresult_access_denied() noexcept : hresult_error(impl::error_access_denied) {} - hresult_access_denied(param::hstring const& message) noexcept : hresult_error(impl::error_access_denied, message) {} - hresult_access_denied(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_access_denied, take_ownership_from_abi) {} + hresult_access_denied(WINRT_IMPL_SOURCE_LOCATION_ARGS_SINGLE_PARAM) noexcept : hresult_error(impl::error_access_denied WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} + hresult_access_denied(param::hstring const& message WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : hresult_error(impl::error_access_denied, message WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} + hresult_access_denied(take_ownership_from_abi_t WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : hresult_error(impl::error_access_denied, take_ownership_from_abi WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} }; struct hresult_wrong_thread : hresult_error { - hresult_wrong_thread() noexcept : hresult_error(impl::error_wrong_thread) {} - hresult_wrong_thread(param::hstring const& message) noexcept : hresult_error(impl::error_wrong_thread, message) {} - hresult_wrong_thread(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_wrong_thread, take_ownership_from_abi) {} + hresult_wrong_thread(WINRT_IMPL_SOURCE_LOCATION_ARGS_SINGLE_PARAM) noexcept : hresult_error(impl::error_wrong_thread WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} + hresult_wrong_thread(param::hstring const& message WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : hresult_error(impl::error_wrong_thread, message WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} + hresult_wrong_thread(take_ownership_from_abi_t WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : hresult_error(impl::error_wrong_thread, take_ownership_from_abi WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} }; struct hresult_not_implemented : hresult_error { - hresult_not_implemented() noexcept : hresult_error(impl::error_not_implemented) {} - hresult_not_implemented(param::hstring const& message) noexcept : hresult_error(impl::error_not_implemented, message) {} - hresult_not_implemented(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_not_implemented, take_ownership_from_abi) {} + hresult_not_implemented(WINRT_IMPL_SOURCE_LOCATION_ARGS_SINGLE_PARAM) noexcept : hresult_error(impl::error_not_implemented WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} + hresult_not_implemented(param::hstring const& message WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : hresult_error(impl::error_not_implemented, message WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} + hresult_not_implemented(take_ownership_from_abi_t WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : hresult_error(impl::error_not_implemented, take_ownership_from_abi WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} }; struct hresult_invalid_argument : hresult_error { - hresult_invalid_argument() noexcept : hresult_error(impl::error_invalid_argument) {} - hresult_invalid_argument(param::hstring const& message) noexcept : hresult_error(impl::error_invalid_argument, message) {} - hresult_invalid_argument(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_invalid_argument, take_ownership_from_abi) {} + hresult_invalid_argument(WINRT_IMPL_SOURCE_LOCATION_ARGS_SINGLE_PARAM) noexcept : hresult_error(impl::error_invalid_argument WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} + hresult_invalid_argument(param::hstring const& message WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : hresult_error(impl::error_invalid_argument, message WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} + hresult_invalid_argument(take_ownership_from_abi_t WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : hresult_error(impl::error_invalid_argument, take_ownership_from_abi WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} }; struct hresult_out_of_bounds : hresult_error { - hresult_out_of_bounds() noexcept : hresult_error(impl::error_out_of_bounds) {} - hresult_out_of_bounds(param::hstring const& message) noexcept : hresult_error(impl::error_out_of_bounds, message) {} - hresult_out_of_bounds(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_out_of_bounds, take_ownership_from_abi) {} + hresult_out_of_bounds(WINRT_IMPL_SOURCE_LOCATION_ARGS_SINGLE_PARAM) noexcept : hresult_error(impl::error_out_of_bounds WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} + hresult_out_of_bounds(param::hstring const& message WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : hresult_error(impl::error_out_of_bounds, message WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} + hresult_out_of_bounds(take_ownership_from_abi_t WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : hresult_error(impl::error_out_of_bounds, take_ownership_from_abi WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} }; struct hresult_no_interface : hresult_error { - hresult_no_interface() noexcept : hresult_error(impl::error_no_interface) {} - hresult_no_interface(param::hstring const& message) noexcept : hresult_error(impl::error_no_interface, message) {} - hresult_no_interface(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_no_interface, take_ownership_from_abi) {} + hresult_no_interface(WINRT_IMPL_SOURCE_LOCATION_ARGS_SINGLE_PARAM) noexcept : hresult_error(impl::error_no_interface WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} + hresult_no_interface(param::hstring const& message WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : hresult_error(impl::error_no_interface, message WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} + hresult_no_interface(take_ownership_from_abi_t WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : hresult_error(impl::error_no_interface, take_ownership_from_abi WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} }; struct hresult_class_not_available : hresult_error { - hresult_class_not_available() noexcept : hresult_error(impl::error_class_not_available) {} - hresult_class_not_available(param::hstring const& message) noexcept : hresult_error(impl::error_class_not_available, message) {} - hresult_class_not_available(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_class_not_available, take_ownership_from_abi) {} + hresult_class_not_available(WINRT_IMPL_SOURCE_LOCATION_ARGS_SINGLE_PARAM) noexcept : hresult_error(impl::error_class_not_available WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} + hresult_class_not_available(param::hstring const& message WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : hresult_error(impl::error_class_not_available, message WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} + hresult_class_not_available(take_ownership_from_abi_t WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : hresult_error(impl::error_class_not_available, take_ownership_from_abi WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} }; struct hresult_class_not_registered : hresult_error { - hresult_class_not_registered() noexcept : hresult_error(impl::error_class_not_registered) {} - hresult_class_not_registered(param::hstring const& message) noexcept : hresult_error(impl::error_class_not_registered, message) {} - hresult_class_not_registered(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_class_not_registered, take_ownership_from_abi) {} + hresult_class_not_registered(WINRT_IMPL_SOURCE_LOCATION_ARGS_SINGLE_PARAM) noexcept : hresult_error(impl::error_class_not_registered WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} + hresult_class_not_registered(param::hstring const& message WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : hresult_error(impl::error_class_not_registered, message WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} + hresult_class_not_registered(take_ownership_from_abi_t WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : hresult_error(impl::error_class_not_registered, take_ownership_from_abi WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} }; struct hresult_changed_state : hresult_error { - hresult_changed_state() noexcept : hresult_error(impl::error_changed_state) {} - hresult_changed_state(param::hstring const& message) noexcept : hresult_error(impl::error_changed_state, message) {} - hresult_changed_state(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_changed_state, take_ownership_from_abi) {} + hresult_changed_state(WINRT_IMPL_SOURCE_LOCATION_ARGS_SINGLE_PARAM) noexcept : hresult_error(impl::error_changed_state WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} + hresult_changed_state(param::hstring const& message WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : hresult_error(impl::error_changed_state, message WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} + hresult_changed_state(take_ownership_from_abi_t WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : hresult_error(impl::error_changed_state, take_ownership_from_abi WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} }; struct hresult_illegal_method_call : hresult_error { - hresult_illegal_method_call() noexcept : hresult_error(impl::error_illegal_method_call) {} - hresult_illegal_method_call(param::hstring const& message) noexcept : hresult_error(impl::error_illegal_method_call, message) {} - hresult_illegal_method_call(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_illegal_method_call, take_ownership_from_abi) {} + hresult_illegal_method_call(WINRT_IMPL_SOURCE_LOCATION_ARGS_SINGLE_PARAM) noexcept : hresult_error(impl::error_illegal_method_call WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} + hresult_illegal_method_call(param::hstring const& message WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : hresult_error(impl::error_illegal_method_call, message WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} + hresult_illegal_method_call(take_ownership_from_abi_t WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : hresult_error(impl::error_illegal_method_call, take_ownership_from_abi WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} }; struct hresult_illegal_state_change : hresult_error { - hresult_illegal_state_change() noexcept : hresult_error(impl::error_illegal_state_change) {} - hresult_illegal_state_change(param::hstring const& message) noexcept : hresult_error(impl::error_illegal_state_change, message) {} - hresult_illegal_state_change(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_illegal_state_change, take_ownership_from_abi) {} + hresult_illegal_state_change(WINRT_IMPL_SOURCE_LOCATION_ARGS_SINGLE_PARAM) noexcept : hresult_error(impl::error_illegal_state_change WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} + hresult_illegal_state_change(param::hstring const& message WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : hresult_error(impl::error_illegal_state_change, message WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} + hresult_illegal_state_change(take_ownership_from_abi_t WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : hresult_error(impl::error_illegal_state_change, take_ownership_from_abi WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} }; struct hresult_illegal_delegate_assignment : hresult_error { - hresult_illegal_delegate_assignment() noexcept : hresult_error(impl::error_illegal_delegate_assignment) {} - hresult_illegal_delegate_assignment(param::hstring const& message) noexcept : hresult_error(impl::error_illegal_delegate_assignment, message) {} - hresult_illegal_delegate_assignment(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_illegal_delegate_assignment, take_ownership_from_abi) {} + hresult_illegal_delegate_assignment(WINRT_IMPL_SOURCE_LOCATION_ARGS_SINGLE_PARAM) noexcept : hresult_error(impl::error_illegal_delegate_assignment WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} + hresult_illegal_delegate_assignment(param::hstring const& message WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : hresult_error(impl::error_illegal_delegate_assignment, message WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} + hresult_illegal_delegate_assignment(take_ownership_from_abi_t WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : hresult_error(impl::error_illegal_delegate_assignment, take_ownership_from_abi WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} }; struct hresult_canceled : hresult_error { - hresult_canceled() noexcept : hresult_error(impl::error_canceled) {} - hresult_canceled(param::hstring const& message) noexcept : hresult_error(impl::error_canceled, message) {} - hresult_canceled(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_canceled, take_ownership_from_abi) {} + hresult_canceled(WINRT_IMPL_SOURCE_LOCATION_ARGS_SINGLE_PARAM) noexcept : hresult_error(impl::error_canceled WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} + hresult_canceled(param::hstring const& message WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : hresult_error(impl::error_canceled, message WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} + hresult_canceled(take_ownership_from_abi_t WINRT_IMPL_SOURCE_LOCATION_ARGS) noexcept : hresult_error(impl::error_canceled, take_ownership_from_abi WINRT_IMPL_SOURCE_LOCATION_FORWARD) {} }; - [[noreturn]] inline WINRT_IMPL_NOINLINE void throw_hresult(hresult const result) + [[noreturn]] inline WINRT_IMPL_NOINLINE void throw_hresult(hresult const result WINRT_IMPL_SOURCE_LOCATION_ARGS) { if (winrt_throw_hresult_handler) { +#ifdef __cpp_lib_source_location + winrt_throw_hresult_handler(sourceInformation.line(), sourceInformation.file_name(), sourceInformation.function_name(), WINRT_IMPL_RETURNADDRESS(), result); +#else winrt_throw_hresult_handler(0, nullptr, nullptr, WINRT_IMPL_RETURNADDRESS(), result); +#endif } if (result == impl::error_bad_alloc) @@ -447,70 +463,70 @@ WINRT_EXPORT namespace winrt if (result == impl::error_access_denied) { - throw hresult_access_denied(take_ownership_from_abi); + throw hresult_access_denied(take_ownership_from_abi WINRT_IMPL_SOURCE_LOCATION_FORWARD); } if (result == impl::error_wrong_thread) { - throw hresult_wrong_thread(take_ownership_from_abi); + throw hresult_wrong_thread(take_ownership_from_abi WINRT_IMPL_SOURCE_LOCATION_FORWARD); } if (result == impl::error_not_implemented) { - throw hresult_not_implemented(take_ownership_from_abi); + throw hresult_not_implemented(take_ownership_from_abi WINRT_IMPL_SOURCE_LOCATION_FORWARD); } if (result == impl::error_invalid_argument) { - throw hresult_invalid_argument(take_ownership_from_abi); + throw hresult_invalid_argument(take_ownership_from_abi WINRT_IMPL_SOURCE_LOCATION_FORWARD); } if (result == impl::error_out_of_bounds) { - throw hresult_out_of_bounds(take_ownership_from_abi); + throw hresult_out_of_bounds(take_ownership_from_abi WINRT_IMPL_SOURCE_LOCATION_FORWARD); } if (result == impl::error_no_interface) { - throw hresult_no_interface(take_ownership_from_abi); + throw hresult_no_interface(take_ownership_from_abi WINRT_IMPL_SOURCE_LOCATION_FORWARD); } if (result == impl::error_class_not_available) { - throw hresult_class_not_available(take_ownership_from_abi); + throw hresult_class_not_available(take_ownership_from_abi WINRT_IMPL_SOURCE_LOCATION_FORWARD); } if (result == impl::error_class_not_registered) { - throw hresult_class_not_registered(take_ownership_from_abi); + throw hresult_class_not_registered(take_ownership_from_abi WINRT_IMPL_SOURCE_LOCATION_FORWARD); } if (result == impl::error_changed_state) { - throw hresult_changed_state(take_ownership_from_abi); + throw hresult_changed_state(take_ownership_from_abi WINRT_IMPL_SOURCE_LOCATION_FORWARD); } if (result == impl::error_illegal_method_call) { - throw hresult_illegal_method_call(take_ownership_from_abi); + throw hresult_illegal_method_call(take_ownership_from_abi WINRT_IMPL_SOURCE_LOCATION_FORWARD); } if (result == impl::error_illegal_state_change) { - throw hresult_illegal_state_change(take_ownership_from_abi); + throw hresult_illegal_state_change(take_ownership_from_abi WINRT_IMPL_SOURCE_LOCATION_FORWARD); } if (result == impl::error_illegal_delegate_assignment) { - throw hresult_illegal_delegate_assignment(take_ownership_from_abi); + throw hresult_illegal_delegate_assignment(take_ownership_from_abi WINRT_IMPL_SOURCE_LOCATION_FORWARD); } if (result == impl::error_canceled) { - throw hresult_canceled(take_ownership_from_abi); + throw hresult_canceled(take_ownership_from_abi WINRT_IMPL_SOURCE_LOCATION_FORWARD); } - throw hresult_error(result, take_ownership_from_abi); + throw hresult_error(result, take_ownership_from_abi WINRT_IMPL_SOURCE_LOCATION_FORWARD); } inline WINRT_IMPL_NOINLINE hresult to_hresult() noexcept @@ -571,53 +587,53 @@ WINRT_EXPORT namespace winrt } } - [[noreturn]] inline void throw_last_error() + [[noreturn]] inline void throw_last_error(WINRT_IMPL_SOURCE_LOCATION_ARGS_SINGLE_PARAM) { - throw_hresult(impl::hresult_from_win32(WINRT_IMPL_GetLastError())); + throw_hresult(impl::hresult_from_win32(WINRT_IMPL_GetLastError()) WINRT_IMPL_SOURCE_LOCATION_FORWARD); } - inline hresult check_hresult(hresult const result) + inline hresult check_hresult(hresult const result WINRT_IMPL_SOURCE_LOCATION_ARGS_NO_DEFAULT) { if (result < 0) { - throw_hresult(result); + throw_hresult(result WINRT_IMPL_SOURCE_LOCATION_FORWARD); } return result; } template - void check_nt(T result) + void check_nt(T result WINRT_IMPL_SOURCE_LOCATION_ARGS) { if (result != 0) { - throw_hresult(impl::hresult_from_nt(result)); + throw_hresult(impl::hresult_from_nt(result) WINRT_IMPL_SOURCE_LOCATION_FORWARD); } } template - void check_win32(T result) + void check_win32(T result WINRT_IMPL_SOURCE_LOCATION_ARGS) { if (result != 0) { - throw_hresult(impl::hresult_from_win32(result)); + throw_hresult(impl::hresult_from_win32(result) WINRT_IMPL_SOURCE_LOCATION_FORWARD); } } template - void check_bool(T result) + void check_bool(T result WINRT_IMPL_SOURCE_LOCATION_ARGS) { if (!result) { - winrt::throw_last_error(); + winrt::throw_last_error(WINRT_IMPL_SOURCE_LOCATION_FORWARD_SINGLE_PARAM); } } template - T* check_pointer(T* pointer) + T* check_pointer(T* pointer WINRT_IMPL_SOURCE_LOCATION_ARGS) { if (!pointer) { - throw_last_error(); + throw_last_error(WINRT_IMPL_SOURCE_LOCATION_FORWARD_SINGLE_PARAM); } return pointer; @@ -634,11 +650,11 @@ WINRT_EXPORT namespace winrt namespace winrt::impl { - inline hresult check_hresult_allow_bounds(hresult const result) + inline hresult check_hresult_allow_bounds(hresult const result WINRT_IMPL_SOURCE_LOCATION_ARGS) { if (result != impl::error_out_of_bounds && result != impl::error_fail && result != impl::error_file_not_found) { - check_hresult(result); + check_hresult(result WINRT_IMPL_SOURCE_LOCATION_FORWARD); } return result; } diff --git a/strings/base_includes.h b/strings/base_includes.h index 14d992fc9..8fe598212 100644 --- a/strings/base_includes.h +++ b/strings/base_includes.h @@ -28,6 +28,10 @@ #include #endif +#ifdef __cpp_lib_source_location +#include +#endif + #ifdef __cpp_lib_coroutine #include diff --git a/strings/base_macros.h b/strings/base_macros.h index 40473bb5d..c1d0617c8 100644 --- a/strings/base_macros.h +++ b/strings/base_macros.h @@ -54,3 +54,27 @@ struct IUnknown; typedef struct _GUID GUID; #endif + +// std::source_location is a C++20 feature, which is above the C++17 feature floor for cppwinrt. The source location needs +// to be the calling code, not cppwinrt itself, so that it is useful to developers building on top of this library. As a +// result any public-facing method that can result in an error needs a default-constructed source_location argument. Because +// this type does not exist in C++17 we need to use a macro to optionally add parameters and forwarding wherever appropriate. +#ifdef __cpp_lib_source_location +#define WINRT_IMPL_SOURCE_LOCATION_ARGS_NO_DEFAULT , std::source_location const& sourceInformation +#define WINRT_IMPL_SOURCE_LOCATION_ARGS , std::source_location const& sourceInformation = std::source_location::current() +#define WINRT_IMPL_SOURCE_LOCATION_ARGS_SINGLE_PARAM std::source_location const& sourceInformation = std::source_location::current() + +#define WINRT_IMPL_SOURCE_LOCATION_FORWARD , sourceInformation +#define WINRT_IMPL_SOURCE_LOCATION_FORWARD_SINGLE_PARAM sourceInformation + +#pragma detect_mismatch("WINRT_SOURCE_LOCATION", "true") +#else +#define WINRT_IMPL_SOURCE_LOCATION_ARGS_NO_DEFAULT +#define WINRT_IMPL_SOURCE_LOCATION_ARGS +#define WINRT_IMPL_SOURCE_LOCATION_ARGS_SINGLE_PARAM + +#define WINRT_IMPL_SOURCE_LOCATION_FORWARD +#define WINRT_IMPL_SOURCE_LOCATION_FORWARD_SINGLE_PARAM + +#pragma detect_mismatch("WINRT_SOURCE_LOCATION", "false") +#endif diff --git a/strings/base_meta.h b/strings/base_meta.h index e80afb9bf..4bfa82d18 100644 --- a/strings/base_meta.h +++ b/strings/base_meta.h @@ -1,7 +1,7 @@ WINRT_EXPORT namespace winrt { - hresult check_hresult(hresult const result); + hresult check_hresult(hresult const result WINRT_IMPL_SOURCE_LOCATION_ARGS); hresult to_hresult() noexcept; template diff --git a/test/test/custom_error.cpp b/test/test/custom_error.cpp index a39024c03..28a21aca3 100644 --- a/test/test/custom_error.cpp +++ b/test/test/custom_error.cpp @@ -59,7 +59,11 @@ namespace void __stdcall logger(uint32_t lineNumber, char const* fileName, char const* functionName, void* returnAddress, winrt::hresult const result) noexcept { - lineNumber; fileName; functionName; + // In C++17 these fields cannot be filled in so they are expected to be empty. + REQUIRE(lineNumber == 0); + REQUIRE(fileName == nullptr); + REQUIRE(functionName == nullptr); + REQUIRE(returnAddress); REQUIRE(result == 0x80000018); // E_ILLEGAL_DELEGATE_ASSIGNMENT) s_loggerCalled = true; diff --git a/test/test_cpp20/custom_error.cpp b/test/test_cpp20/custom_error.cpp new file mode 100644 index 000000000..dc38bbdf9 --- /dev/null +++ b/test/test_cpp20/custom_error.cpp @@ -0,0 +1,48 @@ +#include "pch.h" + +using namespace winrt; +using namespace Windows::Foundation; + +namespace +{ + static bool s_loggerCalled = false; + + // Note that we are checking that the source line number matches expectations. If lines above this are changed + // then this value needs to change as well. + void FailOnLine15() + { + // Validate that handler translated exception + REQUIRE_THROWS_AS(check_hresult(0x80000018), hresult_illegal_delegate_assignment); + } + + void __stdcall logger(uint32_t lineNumber, char const* fileName, char const* functionName, void* returnAddress, winrt::hresult const result) noexcept + { + // In C++20 these fields should be filled in by std::source_location + REQUIRE(lineNumber == 15); + const auto fileNameSv = std::string_view(fileName); + REQUIRE(!fileNameSv.empty()); + REQUIRE(fileNameSv.find("custom_error.cpp") != std::string::npos); + const auto functionNameSv = std::string_view(functionName); + REQUIRE(!functionNameSv.empty()); + REQUIRE(functionNameSv == "FailOnLine15"); + + REQUIRE(returnAddress); + REQUIRE(result == 0x80000018); // E_ILLEGAL_DELEGATE_ASSIGNMENT) + s_loggerCalled = true; + } +} + +TEST_CASE("custom_error_logger") +{ + // Set up global handler + REQUIRE(!s_loggerCalled); + REQUIRE(!winrt_throw_hresult_handler); + winrt_throw_hresult_handler = logger; + + FailOnLine15(); + REQUIRE(s_loggerCalled); + + // Remove global handler + winrt_throw_hresult_handler = nullptr; + s_loggerCalled = false; +} diff --git a/test/test_cpp20/pch.h b/test/test_cpp20/pch.h index bd678407c..6565bea1b 100644 --- a/test/test_cpp20/pch.h +++ b/test/test_cpp20/pch.h @@ -11,4 +11,6 @@ #include #include "catch.hpp" +#include + using namespace std::literals; diff --git a/test/test_cpp20/test_cpp20.vcxproj b/test/test_cpp20/test_cpp20.vcxproj index 9fff3774a..1717d6bf8 100644 --- a/test/test_cpp20/test_cpp20.vcxproj +++ b/test/test_cpp20/test_cpp20.vcxproj @@ -281,6 +281,7 @@ +