Skip to content

Commit

Permalink
Sync with OS (#296)
Browse files Browse the repository at this point in the history
* Sync with OS commit b58d62a22e8b065355e83f17d32f446bac7d5e75

* Fix build issues

* Fix test
  • Loading branch information
dunhor authored Feb 2, 2023
1 parent ecbb399 commit d0849dc
Show file tree
Hide file tree
Showing 10 changed files with 259 additions and 44 deletions.
6 changes: 3 additions & 3 deletions include/wil/Tracelogging.h
Original file line number Diff line number Diff line change
Expand Up @@ -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++;
Expand Down
11 changes: 7 additions & 4 deletions include/wil/com.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
#if __has_include(<tuple>)
#include <tuple>
#endif
#if __has_include(<type_traits>)
#include <type_traits>
#endif

// Forward declaration within WIL (see https://msdn.microsoft.com/en-us/library/br244983.aspx)
/// @cond
Expand Down Expand Up @@ -1988,7 +1991,7 @@ namespace wil
return CoGetClassObjectNoThrow<Interface>(__uuidof(Class), dwClsContext);
}

#if __has_include(<tuple>) && (__WI_LIBCPP_STD_VER >= 17)
#if __cpp_lib_apply && __has_include(<type_traits>)
namespace details
{
template <typename error_policy, typename... Results>
Expand All @@ -2011,7 +2014,7 @@ namespace wil

std::apply([i = 0, &multiQis](auto&... a) mutable
{
(a.attach(reinterpret_cast<typename std::remove_reference_t<decltype(a)>::pointer>(multiQis[i++].pItf)), ...);
(a.attach(reinterpret_cast<typename std::remove_reference<decltype(a)>::type::pointer>(multiQis[i++].pItf)), ...);
}, resultTuple);
return std::tuple<HRESULT, decltype(resultTuple)>(hr, std::move(resultTuple));
}
Expand All @@ -2038,7 +2041,7 @@ namespace wil
hr = multiQi->QueryMultipleInterfaces(ARRAYSIZE(multiQis), multiQis);
std::apply([i = 0, &multiQis](auto&... a) mutable
{
(a.attach(reinterpret_cast<typename std::remove_reference_t<decltype(a)>::pointer>(multiQis[i++].pItf)), ...);
(a.attach(reinterpret_cast<typename std::remove_reference<decltype(a)>::type::pointer>(multiQis[i++].pItf)), ...);
}, resultTuple);
}
return std::tuple<HRESULT, decltype(resultTuple)>{hr, std::move(resultTuple)};
Expand Down Expand Up @@ -2119,7 +2122,7 @@ namespace wil
}
#endif

#endif // __has_include(<tuple>)
#endif // __cpp_lib_apply && __has_include(<type_traits>)

#pragma endregion

Expand Down
97 changes: 73 additions & 24 deletions include/wil/com_apartment_variable.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,17 @@
#ifndef __WIL_COM_APARTMENT_VARIABLE_INCLUDED
#define __WIL_COM_APARTMENT_VARIABLE_INCLUDED

#include <unordered_map>
#include <any>
#include <objidl.h>
#include <roapi.h>
#include <type_traits>
#include <unordered_map>
#include <winrt/Windows.Foundation.h>

#include "com.h"
#include "cppwinrt.h"
#include <roapi.h>
#include <objidl.h>
#include "result_macros.h"
#include <winrt/Windows.Foundation.h>
#include "win32_helpers.h"

#ifndef WIL_ENABLE_EXCEPTIONS
#error This header requires exceptions
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -117,7 +133,8 @@ namespace wil
}
};

template<typename test_hook = apartment_variable_platform>
template<apartment_variable_leak_action leak_action = apartment_variable_leak_action::fail_fast,
typename test_hook = apartment_variable_platform>
struct apartment_variable_base
{
inline static winrt::slim_mutex s_lock;
Expand All @@ -133,25 +150,54 @@ namespace wil

winrt::apartment_context context;
typename test_hook::shutdown_type cookie;
std::unordered_map<apartment_variable_base<test_hook>*, std::any> variables;
// Variables are stored using the address of the apartment_variable_base<> as the key.
std::unordered_map<apartment_variable_base<leak_action, test_hook>*, 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<unsigned long long, apartment_variable_storage> s_apartmentStorage;
// Apartment id -> variables storage.
inline static wil::object_without_destructor_on_shutdown<
std::unordered_map<unsigned long long, apartment_variable_storage>>
s_apartmentStorage;

apartment_variable_base() = default;
constexpr apartment_variable_base() = default;
~apartment_variable_base()
{
// Global variables (object with static storage duration)
// are run down when the process is shutting down or when the
// 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<T, wil::apartment_variable_leak_action::ignore>
//
// For DLLs, if this is expected, disable this fail fast using
// wil::apartment_variable<T, wil::apartment_variable_leak_action::ignore>
//
// 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
Expand All @@ -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;
}
Expand All @@ -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
Expand All @@ -205,12 +251,12 @@ namespace wil
}
};
auto shutdownRegistration = test_hook::RegisterForApartmentShutdown(winrt::make<ApartmentObserver>().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<typename T>
std::any& get_or_create(any_maker<T>&& creator)
std::any& get_or_create(any_maker<T> && creator)
{
apartment_variable_storage* variable_storage = nullptr;

Expand Down Expand Up @@ -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());
Expand All @@ -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());
}
}
}
Expand All @@ -289,7 +335,7 @@ namespace wil
std::vector<winrt::apartment_context> 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())
Expand Down Expand Up @@ -344,7 +390,7 @@ namespace wil

static const auto& storage()
{
return s_apartmentStorage;
return s_apartmentStorage.get();
}

static size_t current_apartment_variable_count()
Expand Down Expand Up @@ -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<typename T, typename test_hook = wil::apartment_variable_platform>
struct apartment_variable : details::apartment_variable_base<test_hook>
template<typename T, apartment_variable_leak_action leak_action = apartment_variable_leak_action::fail_fast,
typename test_hook = wil::apartment_variable_platform>
struct apartment_variable : details::apartment_variable_base<leak_action, test_hook>
{
using base = details::apartment_variable_base<test_hook>;
using base = details::apartment_variable_base<leak_action, test_hook>;

constexpr apartment_variable() = default;

// Get current value or throw if no value has been set.
T& get_existing() { return std::any_cast<T&>(base::get_existing()); }
Expand Down
16 changes: 16 additions & 0 deletions include/wil/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,22 @@ namespace wil
static_assert(wistd::is_same<T, long>::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 <typename T>
_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<T, long>::value || wistd::is_same<T, unsigned long>::value, "Wrong Type: Win32 error code (long / unsigned long) expected");
return error;
}
/// @} // end type validation routines

/// @cond
Expand Down
37 changes: 37 additions & 0 deletions include/wil/cppwinrt_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <winrt/Windows.UI.h>
//! <Windows.UI.Interop.h> 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
4 changes: 2 additions & 2 deletions include/wil/nt_result_macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions include/wil/resource.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<close_fn_t, close_fn, pointer_storage_t>
{
Expand Down Expand Up @@ -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<details::unique_storage<details::resource_policy<pointer, close_fn_t, close_fn, pointer_access, pointer_storage, invalid_t, invalid, pointer_invalid>>>;

Expand Down
6 changes: 6 additions & 0 deletions include/wil/result_macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
Loading

0 comments on commit d0849dc

Please sign in to comment.