From d0849dca2c466bdce38a32a7e4265b193b8fb0f9 Mon Sep 17 00:00:00 2001 From: Duncan Horn <40036384+dunhor@users.noreply.github.com> Date: Thu, 2 Feb 2023 10:13:01 -0800 Subject: [PATCH] Sync with OS (#296) * Sync with OS commit b58d62a22e8b065355e83f17d32f446bac7d5e75 * Fix build issues * Fix test --- include/wil/Tracelogging.h | 6 +- include/wil/com.h | 11 +-- include/wil/com_apartment_variable.h | 97 ++++++++++++++++++------- include/wil/common.h | 16 +++++ include/wil/cppwinrt_helpers.h | 37 ++++++++++ include/wil/nt_result_macros.h | 4 +- include/wil/resource.h | 4 +- include/wil/result_macros.h | 6 ++ include/wil/win32_result_macros.h | 104 +++++++++++++++++++++++++++ tests/ComApartmentVariableTests.cpp | 18 ++--- 10 files changed, 259 insertions(+), 44 deletions(-) create mode 100644 include/wil/win32_result_macros.h diff --git a/include/wil/Tracelogging.h b/include/wil/Tracelogging.h index 6ff5fb8aa..bcedd5132 100644 --- a/include/wil/Tracelogging.h +++ b/include/wil/Tracelogging.h @@ -3656,17 +3656,17 @@ namespace wil FAIL_FAST_IF_FAILED(StringCchCatW(apiList.get(), totalApiListLength, node->apiName)); if (node->specialization) { - FAIL_FAST_IF_WIN32_ERROR(strncat_s(specializationList.get(), totalSpecializationsLength, node->specialization, strlen(node->specialization)) != 0); + FAIL_FAST_IF(strncat_s(specializationList.get(), totalSpecializationsLength, node->specialization, strlen(node->specialization)) != 0); } else { - FAIL_FAST_IF_WIN32_ERROR(strncat_s(specializationList.get(), totalSpecializationsLength, "-", 1) != 0); + FAIL_FAST_IF(strncat_s(specializationList.get(), totalSpecializationsLength, "-", 1) != 0); } if (countArrayIndex != (numCounts - 1)) { FAIL_FAST_IF_FAILED(StringCchCatW(apiList.get(), totalApiListLength, L",")); - FAIL_FAST_IF_WIN32_ERROR(strncat_s(specializationList.get(), totalSpecializationsLength, ",", 1) != 0); + FAIL_FAST_IF(strncat_s(specializationList.get(), totalSpecializationsLength, ",", 1) != 0); } countArrayIndex++; diff --git a/include/wil/com.h b/include/wil/com.h index 0e2a14095..79dff91a6 100644 --- a/include/wil/com.h +++ b/include/wil/com.h @@ -19,6 +19,9 @@ #if __has_include() #include #endif +#if __has_include() +#include +#endif // Forward declaration within WIL (see https://msdn.microsoft.com/en-us/library/br244983.aspx) /// @cond @@ -1988,7 +1991,7 @@ namespace wil return CoGetClassObjectNoThrow(__uuidof(Class), dwClsContext); } -#if __has_include() && (__WI_LIBCPP_STD_VER >= 17) +#if __cpp_lib_apply && __has_include() namespace details { template @@ -2011,7 +2014,7 @@ namespace wil std::apply([i = 0, &multiQis](auto&... a) mutable { - (a.attach(reinterpret_cast::pointer>(multiQis[i++].pItf)), ...); + (a.attach(reinterpret_cast::type::pointer>(multiQis[i++].pItf)), ...); }, resultTuple); return std::tuple(hr, std::move(resultTuple)); } @@ -2038,7 +2041,7 @@ namespace wil hr = multiQi->QueryMultipleInterfaces(ARRAYSIZE(multiQis), multiQis); std::apply([i = 0, &multiQis](auto&... a) mutable { - (a.attach(reinterpret_cast::pointer>(multiQis[i++].pItf)), ...); + (a.attach(reinterpret_cast::type::pointer>(multiQis[i++].pItf)), ...); }, resultTuple); } return std::tuple{hr, std::move(resultTuple)}; @@ -2119,7 +2122,7 @@ namespace wil } #endif -#endif // __has_include() +#endif // __cpp_lib_apply && __has_include() #pragma endregion diff --git a/include/wil/com_apartment_variable.h b/include/wil/com_apartment_variable.h index 6dc95f3ba..3ae0b9238 100644 --- a/include/wil/com_apartment_variable.h +++ b/include/wil/com_apartment_variable.h @@ -11,15 +11,17 @@ #ifndef __WIL_COM_APARTMENT_VARIABLE_INCLUDED #define __WIL_COM_APARTMENT_VARIABLE_INCLUDED -#include #include +#include +#include #include +#include +#include + #include "com.h" #include "cppwinrt.h" -#include -#include #include "result_macros.h" -#include +#include "win32_helpers.h" #ifndef WIL_ENABLE_EXCEPTIONS #error This header requires exceptions @@ -75,6 +77,20 @@ namespace wil using shutdown_type = wil::unique_apartment_shutdown_registration; }; + enum class apartment_variable_leak_action { fail_fast, ignore }; + + // "pins" the current module in memory by incrementing the module reference count and leaking that. + inline void ensure_module_stays_loaded() + { + static INIT_ONCE s_initLeakModule{}; // avoiding magic statics + wil::init_once_failfast(s_initLeakModule, []() + { + HMODULE result{}; + FAIL_FAST_IF(!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN, L"", &result)); + return S_OK; + }); + } + namespace details { // For the address of data, you can detect global variables by the ability to resolve the module from the address. @@ -117,7 +133,8 @@ namespace wil } }; - template + template struct apartment_variable_base { inline static winrt::slim_mutex s_lock; @@ -133,14 +150,16 @@ namespace wil winrt::apartment_context context; typename test_hook::shutdown_type cookie; - std::unordered_map*, std::any> variables; + // Variables are stored using the address of the apartment_variable_base<> as the key. + std::unordered_map*, std::any> variables; }; - // Apartment id -> variable storage. - // Variables are stored using the address of the global variable as the key. - inline static std::unordered_map s_apartmentStorage; + // Apartment id -> variables storage. + inline static wil::object_without_destructor_on_shutdown< + std::unordered_map> + s_apartmentStorage; - apartment_variable_base() = default; + constexpr apartment_variable_base() = default; ~apartment_variable_base() { // Global variables (object with static storage duration) @@ -148,10 +167,37 @@ namespace wil // dll is unloaded. At these points it is not possible to start // an async operation and the work performed is not needed, // the apartments with variable have been run down already. - if (!details::IsGlobalVariable(this)) + const auto isGlobal = details::IsGlobalVariable(this); + if (!isGlobal) { clear_all_apartments_async(); } + + if constexpr (leak_action == apartment_variable_leak_action::fail_fast) + { + if (isGlobal && !ProcessShutdownInProgress()) + { + // If you hit this fail fast it means the storage in s_apartmentStorage will be leaked. + // For apartment variables used in .exes, this is expected and + // this fail fast should be disabled using + // wil::apartment_variable + // + // For DLLs, if this is expected, disable this fail fast using + // wil::apartment_variable + // + // Use of apartment variables in DLLs only loaded by COM will never hit this case + // as COM will unload DLLs before apartments are rundown, + // providing the opportunity to empty s_apartmentStorage. + // + // But DLLs loaded and unloaded to call DLL entry points (outside of COM) may + // create variable storage that can't be cleaned up as the DLL lifetime is + // shorter that the COM lifetime. In these cases either + // 1) accept the leaks and disable the fail fast as describe above + // 2) disable module unloading by calling wil::ensure_module_stays_loaded + // 3) CoCreate an object from this DLL to make COM aware of the DLL + FAIL_FAST_IF(!s_apartmentStorage.get().empty()); + } + } } // non-copyable, non-assignable @@ -170,8 +216,8 @@ namespace wil static apartment_variable_storage* get_current_apartment_variable_storage() { - auto storage = s_apartmentStorage.find(test_hook::GetApartmentId()); - if (storage != s_apartmentStorage.end()) + auto storage = s_apartmentStorage.get().find(test_hook::GetApartmentId()); + if (storage != s_apartmentStorage.get().end()) { return &storage->second; } @@ -195,7 +241,7 @@ namespace wil auto variables = [apartmentId]() { auto lock = winrt::slim_lock_guard(s_lock); - return s_apartmentStorage.extract(apartmentId); + return s_apartmentStorage.get().extract(apartmentId); }(); WI_ASSERT(variables.key() == apartmentId); // The system implicitly releases the shutdown observer @@ -205,12 +251,12 @@ namespace wil } }; auto shutdownRegistration = test_hook::RegisterForApartmentShutdown(winrt::make().get()); - return &s_apartmentStorage.insert({ test_hook::GetApartmentId(), apartment_variable_storage(std::move(shutdownRegistration)) }).first->second; + return &s_apartmentStorage.get().insert({ test_hook::GetApartmentId(), apartment_variable_storage(std::move(shutdownRegistration)) }).first->second; } // get current value or custom-construct one on demand template - std::any& get_or_create(any_maker&& creator) + std::any& get_or_create(any_maker && creator) { apartment_variable_storage* variable_storage = nullptr; @@ -256,8 +302,8 @@ namespace wil // release value, with the swapped value, outside of the lock { auto lock = winrt::slim_lock_guard(s_lock); - auto storage = s_apartmentStorage.find(test_hook::GetApartmentId()); - FAIL_FAST_IF(storage == s_apartmentStorage.end()); + auto storage = s_apartmentStorage.get().find(test_hook::GetApartmentId()); + FAIL_FAST_IF(storage == s_apartmentStorage.get().end()); auto& variable_storage = storage->second; auto variable = variable_storage.variables.find(this); FAIL_FAST_IF(variable == variable_storage.variables.end()); @@ -274,7 +320,7 @@ namespace wil variable_storage->variables.erase(this); if (variable_storage->variables.size() == 0) { - s_apartmentStorage.erase(test_hook::GetApartmentId()); + s_apartmentStorage.get().erase(test_hook::GetApartmentId()); } } } @@ -289,7 +335,7 @@ namespace wil std::vector contexts; { // scope for lock auto lock = winrt::slim_lock_guard(s_lock); - for (auto& [id, storage] : s_apartmentStorage) + for (auto& [id, storage] : s_apartmentStorage.get()) { auto variable = storage.variables.find(this); if (variable != storage.variables.end()) @@ -344,7 +390,7 @@ namespace wil static const auto& storage() { - return s_apartmentStorage; + return s_apartmentStorage.get(); } static size_t current_apartment_variable_count() @@ -372,10 +418,13 @@ namespace wil // C++ WinRT objects. This is automatic for DLLs that host C++ WinRT objects // but WRL projects will need to be updated to call winrt::get_module_lock(). - template - struct apartment_variable : details::apartment_variable_base + template + struct apartment_variable : details::apartment_variable_base { - using base = details::apartment_variable_base; + using base = details::apartment_variable_base; + + constexpr apartment_variable() = default; // Get current value or throw if no value has been set. T& get_existing() { return std::any_cast(base::get_existing()); } diff --git a/include/wil/common.h b/include/wil/common.h index 2d5b581c9..5b336884a 100644 --- a/include/wil/common.h +++ b/include/wil/common.h @@ -692,6 +692,22 @@ namespace wil static_assert(wistd::is_same::value, "Wrong Type: NTSTATUS expected"); return status; } + + /** Verify that `error` is a Win32 error code. + Other types will generate an intentional compilation error. Note that this will accept any `long` value as that is + the underlying type used for WIN32 error codes, as well as any `DWORD` (`unsigned long`) value since this is the type + commonly used when manipulating Win32 error codes. + @param error The Win32 error code returning expression + @return An Win32 error code representing the evaluation of `error`. */ + template + _Post_satisfies_(return == error) + inline T verify_win32(T error) + { + // Note: Win32 error code are defined as 'long' (#define ERROR_SUCCESS 0L), but are more frequently used as DWORD (unsigned long). + // This accept both types. + static_assert(wistd::is_same::value || wistd::is_same::value, "Wrong Type: Win32 error code (long / unsigned long) expected"); + return error; + } /// @} // end type validation routines /// @cond diff --git a/include/wil/cppwinrt_helpers.h b/include/wil/cppwinrt_helpers.h index 7692d8d25..6678b8f3b 100644 --- a/include/wil/cppwinrt_helpers.h +++ b/include/wil/cppwinrt_helpers.h @@ -313,3 +313,40 @@ namespace wil } } #endif + +#if defined(WINRT_Windows_UI_H) && defined(_WINDOWS_UI_INTEROP_H_) && !defined(__WIL_CPPWINRT_WINDOWS_UI_INTEROP_HELPERS) +#define __WIL_CPPWINRT_WINDOWS_UI_INTEROP_HELPERS +#if !defined(____x_ABI_CWindows_CFoundation_CIClosable_FWD_DEFINED__) && !defined(MIDL_NS_PREFIX) +#pragma push_macro("ABI") +#undef ABI +#define ABI +#endif + +namespace wil +{ +#if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_WIN10_CU) + //! The following methods require that you include both + //! before including wil/cppwinrt_helpers.h, and that NTDDI_VERSION + //! is at least NTDDI_WIN10_CU. It is okay to include wil\cppwinrt_helpers.h multiple times: + //! support will be enabled for any headers that were included since the previous inclusion + //! of wil\cppwinrt_headers.h. + inline winrt::Windows::UI::WindowId GetWindowIdFromWindow(HWND hwnd) + { + ABI::Windows::UI::WindowId abiWindowId; + winrt::check_hresult(::GetWindowIdFromWindow(hwnd, &abiWindowId)); + return winrt::Windows::UI::WindowId{ abiWindowId.Value }; + } + + inline HWND GetWindowFromWindowId(winrt::Windows::UI::WindowId windowId) + { + HWND hwnd; + winrt::check_hresult(::GetWindowFromWindowId({ windowId.Value }, &hwnd)); + return hwnd; + } +#endif /*defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_WIN10_CU)*/ +} + +#if !defined(____x_ABI_CWindows_CFoundation_CIClosable_FWD_DEFINED__) && !defined(MIDL_NS_PREFIX) +#pragma pop_macro("ABI") +#endif +#endif // __WIL_CPPWINRT_WINDOWS_UI_INTEROP_HELPERS diff --git a/include/wil/nt_result_macros.h b/include/wil/nt_result_macros.h index 14e3c950e..ddb9740b7 100644 --- a/include/wil/nt_result_macros.h +++ b/include/wil/nt_result_macros.h @@ -14,8 +14,8 @@ #include "result_macros.h" // Helpers for return macros -#define __NT_RETURN_NTSTATUS(status, str) __WI_SUPPRESS_4127_S do { NTSTATUS __status = (status); if (FAILED_NTSTATUS(__status)) { __R_FN(Return_NtStatus)(__R_INFO(str) __status); } return __status; } while ((void)0, 0) -#define __NT_RETURN_NTSTATUS_MSG(status, str, fmt, ...) __WI_SUPPRESS_4127_S do { NTSTATUS __status = (status); if (FAILED_NTSTATUS(__status)) { __R_FN(Return_NtStatusMsg)(__R_INFO(str) __status, fmt, ##__VA_ARGS__); } return __status; } while ((void)0, 0) +#define __NT_RETURN_NTSTATUS(status, str) __WI_SUPPRESS_4127_S do { NTSTATUS __status = (status); if (FAILED_NTSTATUS(__status)) { __R_FN(Return_NtStatus)(__R_INFO(str) __status); } return __status; } __WI_SUPPRESS_4127_E while ((void)0, 0) +#define __NT_RETURN_NTSTATUS_MSG(status, str, fmt, ...) __WI_SUPPRESS_4127_S do { NTSTATUS __status = (status); if (FAILED_NTSTATUS(__status)) { __R_FN(Return_NtStatusMsg)(__R_INFO(str) __status, fmt, ##__VA_ARGS__); } return __status; } __WI_SUPPRESS_4127_E while ((void)0, 0) //***************************************************************************** // Macros for returning failures as NTSTATUS diff --git a/include/wil/resource.h b/include/wil/resource.h index fbe83888c..e46265a93 100644 --- a/include/wil/resource.h +++ b/include/wil/resource.h @@ -150,7 +150,7 @@ namespace wil typename pointer_access_t = pointer_access_all, // all, noaddress or none to control pointer method access typename pointer_storage_t = pointer_t, // The type used to store the handle (usually the same as the handle itself) typename invalid_t = pointer_t, // The invalid handle value type - invalid_t invalid = invalid_t(), // * and its value (default ZERO value) + invalid_t invalid = invalid_t{}, // * and its value (default ZERO value) typename pointer_invalid_t = wistd::nullptr_t> // nullptr_t if the invalid handle value is compatible with nullptr, otherwise pointer struct resource_policy : close_invoker { @@ -436,7 +436,7 @@ namespace wil typename pointer_access = details::pointer_access_all, // all, noaddress or none to control pointer method access typename pointer_storage = pointer, // The type used to store the handle (usually the same as the handle itself) typename invalid_t = pointer, // The invalid handle value type - invalid_t invalid = invalid_t(), // * and its value (default ZERO value) + invalid_t invalid = invalid_t{}, // * and its value (default ZERO value) typename pointer_invalid = wistd::nullptr_t> // nullptr_t if the invalid handle value is compatible with nullptr, otherwise pointer using unique_any = unique_any_t>>; diff --git a/include/wil/result_macros.h b/include/wil/result_macros.h index b8892937f..8c99893f2 100644 --- a/include/wil/result_macros.h +++ b/include/wil/result_macros.h @@ -2044,6 +2044,12 @@ __WI_POP_WARNINGS return err; } + inline __declspec(noinline) DWORD GetLastErrorFail() WI_NOEXCEPT + { + __R_FN_LOCALS_FULL_RA; + return GetLastErrorFail(__R_FN_CALL_FULL); + } + _Translates_last_error_to_HRESULT_ inline HRESULT GetLastErrorFailHr(__R_FN_PARAMS_FULL) WI_NOEXCEPT { diff --git a/include/wil/win32_result_macros.h b/include/wil/win32_result_macros.h new file mode 100644 index 000000000..947db3326 --- /dev/null +++ b/include/wil/win32_result_macros.h @@ -0,0 +1,104 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. +// +//********************************************************* +#ifndef __WIL_WIN32_RESULTMACROS_INCLUDED +#define __WIL_WIN32_RESULTMACROS_INCLUDED + +#include "result_macros.h" + +// Helpers for return macros +#define __WIN32_RETURN_WIN32(error, str) __WI_SUPPRESS_4127_S do { const auto __error = (error); if (FAILED_WIN32(__error)) { __R_FN(Return_Win32)(__R_INFO(str) __error); } return __error; } __WI_SUPPRESS_4127_E while ((void)0, 0) +#define __WIN32_RETURN_GLE_FAIL(str) return __R_FN(Win32_Return_GetLastError)(__R_INFO_ONLY(str)) + +FORCEINLINE long __WIN32_FROM_HRESULT(HRESULT hr) +{ + if (SUCCEEDED(hr)) + { + return ERROR_SUCCESS; + } + return HRESULT_FACILITY(hr) == FACILITY_WIN32 ? HRESULT_CODE(hr) : hr; +} + +//***************************************************************************** +// Macros for returning failures as WIN32 error codes +//***************************************************************************** + +// Always returns a known result (WIN32 error code) - always logs failures +#define WIN32_RETURN_WIN32(error) __WIN32_RETURN_WIN32(wil::verify_win32(error), #error) +#define WIN32_RETURN_LAST_ERROR() __WIN32_RETURN_GLE_FAIL(nullptr) + +// Conditionally returns failures (WIN32 error code) - always logs failures +#define WIN32_RETURN_IF_WIN32_ERROR(error) __WI_SUPPRESS_4127_S do { const auto __errorRet = wil::verify_win32(error); if (FAILED_WIN32(__errorRet)) { __WIN32_RETURN_WIN32(__errorRet, #error); }} __WI_SUPPRESS_4127_E while ((void)0, 0) +#define WIN32_RETURN_WIN32_IF(error, condition) __WI_SUPPRESS_4127_S do { if (wil::verify_bool(condition)) { __WIN32_RETURN_WIN32(wil::verify_win32(error), #condition); }} __WI_SUPPRESS_4127_E while ((void)0, 0) +#define WIN32_RETURN_WIN32_IF_NULL(error, ptr) __WI_SUPPRESS_4127_S do { if ((ptr) == nullptr) { __WIN32_RETURN_WIN32(wil::verify_win32(error), #ptr); }} __WI_SUPPRESS_4127_E while ((void)0, 0) +#define WIN32_RETURN_LAST_ERROR_IF(condition) __WI_SUPPRESS_4127_S do { if (wil::verify_bool(condition)) { __WIN32_RETURN_GLE_FAIL(#condition); }} __WI_SUPPRESS_4127_E while ((void)0, 0) +#define WIN32_RETURN_LAST_ERROR_IF_NULL(ptr) __WI_SUPPRESS_4127_S do { if ((ptr) == nullptr) { __WIN32_RETURN_GLE_FAIL(#ptr); }} __WI_SUPPRESS_4127_E while ((void)0, 0) + +// Conditionally returns failures (WIN32 error code) - use for failures that are expected in common use - failures are not logged - macros are only for control flow pattern +#define WIN32_RETURN_IF_WIN32_ERROR_EXPECTED(error) __WI_SUPPRESS_4127_S do { const auto __errorRet = wil::verify_win32(error); if (FAILED_WIN32(__errorRet)) { return __errorRet; }} __WI_SUPPRESS_4127_E while ((void)0, 0) +#define WIN32_RETURN_WIN32_IF_EXPECTED(error, condition) __WI_SUPPRESS_4127_S do { if (wil::verify_bool(condition)) { return wil::verify_win32(error); }} __WI_SUPPRESS_4127_E while ((void)0, 0) +#define WIN32_RETURN_WIN32_IF_NULL_EXPECTED(error, ptr) __WI_SUPPRESS_4127_S do { if ((ptr) == nullptr) { return wil::verify_win32(error); }} __WI_SUPPRESS_4127_E while ((void)0, 0) +#define WIN32_RETURN_LAST_ERROR_IF_EXPECTED(condition) __WI_SUPPRESS_4127_S do { if (wil::verify_bool(condition)) { return wil::verify_win32(wil::details::GetLastErrorFail()); }} __WI_SUPPRESS_4127_E while ((void)0, 0) +#define WIN32_RETURN_LAST_ERROR_IF_NULL_EXPECTED(ptr) __WI_SUPPRESS_4127_S do { if ((ptr) == nullptr) { return wil::verify_win32(wil::details::GetLastErrorFail()); }} __WI_SUPPRESS_4127_E while ((void)0, 0) + + +//***************************************************************************** +// Macros to catch and convert exceptions on failure +//***************************************************************************** + +// Use these macros *within* a catch (...) block to handle exceptions +#define WIN32_RETURN_CAUGHT_EXCEPTION() return __R_FN(Win32_Return_CaughtException)(__R_INFO_ONLY(nullptr)) + +// Use these macros in place of a catch block to handle exceptions +#define WIN32_CATCH_RETURN() catch (...) { WIN32_RETURN_CAUGHT_EXCEPTION(); } + +namespace wil +{ + //***************************************************************************** + // Public Helpers that catch -- mostly only enabled when exceptions are enabled + //***************************************************************************** + + // Win32ErrorFromCaughtException is a function that is meant to be called from within a catch(...) block. Internally + // it re-throws and catches the exception to convert it to a WIN32 error code. If an exception is of an unrecognized type + // the function will fail fast. + // + // try + // { + // // Code + // } + // catch (...) + // { + // status = wil::Win32ErrorFromCaughtException(); + // } + _Always_(_Post_satisfies_(return > 0)) + __declspec(noinline) inline long Win32ErrorFromCaughtException() WI_NOEXCEPT + { + return __WIN32_FROM_HRESULT(ResultFromCaughtException()); + } + + namespace details::__R_NS_NAME + { +#ifdef WIL_ENABLE_EXCEPTIONS + __R_DIRECT_METHOD(long, Win32_Return_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __R_FN_LOCALS; + return __WIN32_FROM_HRESULT(wil::details::ReportFailure_CaughtException(__R_DIRECT_FN_CALL_ONLY)); + } +#endif + + __R_DIRECT_METHOD(long, Win32_Return_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __R_FN_LOCALS; + return __WIN32_FROM_HRESULT(wil::details::ReportFailure_GetLastErrorHr(__R_DIRECT_FN_CALL_ONLY)); + } + } +} + +#endif // __WIL_WIN32_RESULTMACROS_INCLUDED diff --git a/tests/ComApartmentVariableTests.cpp b/tests/ComApartmentVariableTests.cpp index 62ac2d2f8..ddc6148c0 100644 --- a/tests/ComApartmentVariableTests.cpp +++ b/tests/ComApartmentVariableTests.cpp @@ -111,8 +111,8 @@ struct mock_platform auto fn() { return 42; }; auto fn2() { return 43; }; -wil::apartment_variable g_v1; -wil::apartment_variable g_v2; +wil::apartment_variable g_v1; +wil::apartment_variable g_v2; template void TestApartmentVariableAllMethods() @@ -121,7 +121,7 @@ void TestApartmentVariableAllMethods() std::ignore = g_v1.get_or_create(fn); - wil::apartment_variable v1; + wil::apartment_variable v1; REQUIRE(v1.get_if() == nullptr); REQUIRE(v1.get_or_create(fn) == 42); @@ -138,7 +138,7 @@ void TestApartmentVariableGetOrCreateForms() { auto coUninit = platform::CoInitializeEx(COINIT_MULTITHREADED); - wil::apartment_variable v1; + wil::apartment_variable v1; REQUIRE(v1.get_or_create(fn) == 42); v1.clear(); REQUIRE(v1.get_or_create([&] @@ -152,7 +152,7 @@ void TestApartmentVariableGetOrCreateForms() template void TestApartmentVariableLifetimes() { - wil::apartment_variable av1, av2; + wil::apartment_variable av1, av2; { auto coUninit = platform::CoInitializeEx(COINIT_MULTITHREADED); @@ -217,7 +217,7 @@ void TestApartmentVariableLifetimes() template void TestMultipleApartments() { - wil::apartment_variable av1, av2; + wil::apartment_variable av1, av2; wil::unique_event t1Created{ wil::EventOptions::None }, t2Created{ wil::EventOptions::None }; wil::unique_event t1Shutdown{ wil::EventOptions::None }, t2Shutdown{ wil::EventOptions::None }; @@ -253,7 +253,7 @@ void TestMultipleApartments() apt1_thread.join(); apt2_thread.join(); - REQUIRE((wil::apartment_variable::storage().size() == 0)); + REQUIRE((wil::apartment_variable::storage().size() == 0)); } template @@ -261,7 +261,7 @@ void TestWinningApartmentAlreadyRundownRace() { auto coUninit = platform::CoInitializeEx(COINIT_MULTITHREADED); - wil::apartment_variable av; + wil::apartment_variable av; std::ignore = av.get_or_create(fn); const auto& storage = av.storage(); // for viewing the storage in the debugger @@ -295,7 +295,7 @@ void TestLosingApartmentAlreadyRundownRace() { auto coUninit = platform::CoInitializeEx(COINIT_MULTITHREADED); - wil::apartment_variable av; + wil::apartment_variable av; std::ignore = av.get_or_create(fn); const auto& storage = av.storage(); // for viewing the storage in the debugger