Skip to content

Commit d0849dc

Browse files
authored
Sync with OS (#296)
* Sync with OS commit b58d62a22e8b065355e83f17d32f446bac7d5e75 * Fix build issues * Fix test
1 parent ecbb399 commit d0849dc

File tree

10 files changed

+259
-44
lines changed

10 files changed

+259
-44
lines changed

include/wil/Tracelogging.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3656,17 +3656,17 @@ namespace wil
36563656
FAIL_FAST_IF_FAILED(StringCchCatW(apiList.get(), totalApiListLength, node->apiName));
36573657
if (node->specialization)
36583658
{
3659-
FAIL_FAST_IF_WIN32_ERROR(strncat_s(specializationList.get(), totalSpecializationsLength, node->specialization, strlen(node->specialization)) != 0);
3659+
FAIL_FAST_IF(strncat_s(specializationList.get(), totalSpecializationsLength, node->specialization, strlen(node->specialization)) != 0);
36603660
}
36613661
else
36623662
{
3663-
FAIL_FAST_IF_WIN32_ERROR(strncat_s(specializationList.get(), totalSpecializationsLength, "-", 1) != 0);
3663+
FAIL_FAST_IF(strncat_s(specializationList.get(), totalSpecializationsLength, "-", 1) != 0);
36643664
}
36653665

36663666
if (countArrayIndex != (numCounts - 1))
36673667
{
36683668
FAIL_FAST_IF_FAILED(StringCchCatW(apiList.get(), totalApiListLength, L","));
3669-
FAIL_FAST_IF_WIN32_ERROR(strncat_s(specializationList.get(), totalSpecializationsLength, ",", 1) != 0);
3669+
FAIL_FAST_IF(strncat_s(specializationList.get(), totalSpecializationsLength, ",", 1) != 0);
36703670
}
36713671

36723672
countArrayIndex++;

include/wil/com.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
#if __has_include(<tuple>)
2020
#include <tuple>
2121
#endif
22+
#if __has_include(<type_traits>)
23+
#include <type_traits>
24+
#endif
2225

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

1991-
#if __has_include(<tuple>) && (__WI_LIBCPP_STD_VER >= 17)
1994+
#if __cpp_lib_apply && __has_include(<type_traits>)
19921995
namespace details
19931996
{
19941997
template <typename error_policy, typename... Results>
@@ -2011,7 +2014,7 @@ namespace wil
20112014

20122015
std::apply([i = 0, &multiQis](auto&... a) mutable
20132016
{
2014-
(a.attach(reinterpret_cast<typename std::remove_reference_t<decltype(a)>::pointer>(multiQis[i++].pItf)), ...);
2017+
(a.attach(reinterpret_cast<typename std::remove_reference<decltype(a)>::type::pointer>(multiQis[i++].pItf)), ...);
20152018
}, resultTuple);
20162019
return std::tuple<HRESULT, decltype(resultTuple)>(hr, std::move(resultTuple));
20172020
}
@@ -2038,7 +2041,7 @@ namespace wil
20382041
hr = multiQi->QueryMultipleInterfaces(ARRAYSIZE(multiQis), multiQis);
20392042
std::apply([i = 0, &multiQis](auto&... a) mutable
20402043
{
2041-
(a.attach(reinterpret_cast<typename std::remove_reference_t<decltype(a)>::pointer>(multiQis[i++].pItf)), ...);
2044+
(a.attach(reinterpret_cast<typename std::remove_reference<decltype(a)>::type::pointer>(multiQis[i++].pItf)), ...);
20422045
}, resultTuple);
20432046
}
20442047
return std::tuple<HRESULT, decltype(resultTuple)>{hr, std::move(resultTuple)};
@@ -2119,7 +2122,7 @@ namespace wil
21192122
}
21202123
#endif
21212124

2122-
#endif // __has_include(<tuple>)
2125+
#endif // __cpp_lib_apply && __has_include(<type_traits>)
21232126

21242127
#pragma endregion
21252128

include/wil/com_apartment_variable.h

Lines changed: 73 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,17 @@
1111
#ifndef __WIL_COM_APARTMENT_VARIABLE_INCLUDED
1212
#define __WIL_COM_APARTMENT_VARIABLE_INCLUDED
1313

14-
#include <unordered_map>
1514
#include <any>
15+
#include <objidl.h>
16+
#include <roapi.h>
1617
#include <type_traits>
18+
#include <unordered_map>
19+
#include <winrt/Windows.Foundation.h>
20+
1721
#include "com.h"
1822
#include "cppwinrt.h"
19-
#include <roapi.h>
20-
#include <objidl.h>
2123
#include "result_macros.h"
22-
#include <winrt/Windows.Foundation.h>
24+
#include "win32_helpers.h"
2325

2426
#ifndef WIL_ENABLE_EXCEPTIONS
2527
#error This header requires exceptions
@@ -75,6 +77,20 @@ namespace wil
7577
using shutdown_type = wil::unique_apartment_shutdown_registration;
7678
};
7779

80+
enum class apartment_variable_leak_action { fail_fast, ignore };
81+
82+
// "pins" the current module in memory by incrementing the module reference count and leaking that.
83+
inline void ensure_module_stays_loaded()
84+
{
85+
static INIT_ONCE s_initLeakModule{}; // avoiding magic statics
86+
wil::init_once_failfast(s_initLeakModule, []()
87+
{
88+
HMODULE result{};
89+
FAIL_FAST_IF(!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN, L"", &result));
90+
return S_OK;
91+
});
92+
}
93+
7894
namespace details
7995
{
8096
// 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
117133
}
118134
};
119135

120-
template<typename test_hook = apartment_variable_platform>
136+
template<apartment_variable_leak_action leak_action = apartment_variable_leak_action::fail_fast,
137+
typename test_hook = apartment_variable_platform>
121138
struct apartment_variable_base
122139
{
123140
inline static winrt::slim_mutex s_lock;
@@ -133,25 +150,54 @@ namespace wil
133150

134151
winrt::apartment_context context;
135152
typename test_hook::shutdown_type cookie;
136-
std::unordered_map<apartment_variable_base<test_hook>*, std::any> variables;
153+
// Variables are stored using the address of the apartment_variable_base<> as the key.
154+
std::unordered_map<apartment_variable_base<leak_action, test_hook>*, std::any> variables;
137155
};
138156

139-
// Apartment id -> variable storage.
140-
// Variables are stored using the address of the global variable as the key.
141-
inline static std::unordered_map<unsigned long long, apartment_variable_storage> s_apartmentStorage;
157+
// Apartment id -> variables storage.
158+
inline static wil::object_without_destructor_on_shutdown<
159+
std::unordered_map<unsigned long long, apartment_variable_storage>>
160+
s_apartmentStorage;
142161

143-
apartment_variable_base() = default;
162+
constexpr apartment_variable_base() = default;
144163
~apartment_variable_base()
145164
{
146165
// Global variables (object with static storage duration)
147166
// are run down when the process is shutting down or when the
148167
// dll is unloaded. At these points it is not possible to start
149168
// an async operation and the work performed is not needed,
150169
// the apartments with variable have been run down already.
151-
if (!details::IsGlobalVariable(this))
170+
const auto isGlobal = details::IsGlobalVariable(this);
171+
if (!isGlobal)
152172
{
153173
clear_all_apartments_async();
154174
}
175+
176+
if constexpr (leak_action == apartment_variable_leak_action::fail_fast)
177+
{
178+
if (isGlobal && !ProcessShutdownInProgress())
179+
{
180+
// If you hit this fail fast it means the storage in s_apartmentStorage will be leaked.
181+
// For apartment variables used in .exes, this is expected and
182+
// this fail fast should be disabled using
183+
// wil::apartment_variable<T, wil::apartment_variable_leak_action::ignore>
184+
//
185+
// For DLLs, if this is expected, disable this fail fast using
186+
// wil::apartment_variable<T, wil::apartment_variable_leak_action::ignore>
187+
//
188+
// Use of apartment variables in DLLs only loaded by COM will never hit this case
189+
// as COM will unload DLLs before apartments are rundown,
190+
// providing the opportunity to empty s_apartmentStorage.
191+
//
192+
// But DLLs loaded and unloaded to call DLL entry points (outside of COM) may
193+
// create variable storage that can't be cleaned up as the DLL lifetime is
194+
// shorter that the COM lifetime. In these cases either
195+
// 1) accept the leaks and disable the fail fast as describe above
196+
// 2) disable module unloading by calling wil::ensure_module_stays_loaded
197+
// 3) CoCreate an object from this DLL to make COM aware of the DLL
198+
FAIL_FAST_IF(!s_apartmentStorage.get().empty());
199+
}
200+
}
155201
}
156202

157203
// non-copyable, non-assignable
@@ -170,8 +216,8 @@ namespace wil
170216

171217
static apartment_variable_storage* get_current_apartment_variable_storage()
172218
{
173-
auto storage = s_apartmentStorage.find(test_hook::GetApartmentId());
174-
if (storage != s_apartmentStorage.end())
219+
auto storage = s_apartmentStorage.get().find(test_hook::GetApartmentId());
220+
if (storage != s_apartmentStorage.get().end())
175221
{
176222
return &storage->second;
177223
}
@@ -195,7 +241,7 @@ namespace wil
195241
auto variables = [apartmentId]()
196242
{
197243
auto lock = winrt::slim_lock_guard(s_lock);
198-
return s_apartmentStorage.extract(apartmentId);
244+
return s_apartmentStorage.get().extract(apartmentId);
199245
}();
200246
WI_ASSERT(variables.key() == apartmentId);
201247
// The system implicitly releases the shutdown observer
@@ -205,12 +251,12 @@ namespace wil
205251
}
206252
};
207253
auto shutdownRegistration = test_hook::RegisterForApartmentShutdown(winrt::make<ApartmentObserver>().get());
208-
return &s_apartmentStorage.insert({ test_hook::GetApartmentId(), apartment_variable_storage(std::move(shutdownRegistration)) }).first->second;
254+
return &s_apartmentStorage.get().insert({ test_hook::GetApartmentId(), apartment_variable_storage(std::move(shutdownRegistration)) }).first->second;
209255
}
210256

211257
// get current value or custom-construct one on demand
212258
template<typename T>
213-
std::any& get_or_create(any_maker<T>&& creator)
259+
std::any& get_or_create(any_maker<T> && creator)
214260
{
215261
apartment_variable_storage* variable_storage = nullptr;
216262

@@ -256,8 +302,8 @@ namespace wil
256302
// release value, with the swapped value, outside of the lock
257303
{
258304
auto lock = winrt::slim_lock_guard(s_lock);
259-
auto storage = s_apartmentStorage.find(test_hook::GetApartmentId());
260-
FAIL_FAST_IF(storage == s_apartmentStorage.end());
305+
auto storage = s_apartmentStorage.get().find(test_hook::GetApartmentId());
306+
FAIL_FAST_IF(storage == s_apartmentStorage.get().end());
261307
auto& variable_storage = storage->second;
262308
auto variable = variable_storage.variables.find(this);
263309
FAIL_FAST_IF(variable == variable_storage.variables.end());
@@ -274,7 +320,7 @@ namespace wil
274320
variable_storage->variables.erase(this);
275321
if (variable_storage->variables.size() == 0)
276322
{
277-
s_apartmentStorage.erase(test_hook::GetApartmentId());
323+
s_apartmentStorage.get().erase(test_hook::GetApartmentId());
278324
}
279325
}
280326
}
@@ -289,7 +335,7 @@ namespace wil
289335
std::vector<winrt::apartment_context> contexts;
290336
{ // scope for lock
291337
auto lock = winrt::slim_lock_guard(s_lock);
292-
for (auto& [id, storage] : s_apartmentStorage)
338+
for (auto& [id, storage] : s_apartmentStorage.get())
293339
{
294340
auto variable = storage.variables.find(this);
295341
if (variable != storage.variables.end())
@@ -344,7 +390,7 @@ namespace wil
344390

345391
static const auto& storage()
346392
{
347-
return s_apartmentStorage;
393+
return s_apartmentStorage.get();
348394
}
349395

350396
static size_t current_apartment_variable_count()
@@ -372,10 +418,13 @@ namespace wil
372418
// C++ WinRT objects. This is automatic for DLLs that host C++ WinRT objects
373419
// but WRL projects will need to be updated to call winrt::get_module_lock().
374420

375-
template<typename T, typename test_hook = wil::apartment_variable_platform>
376-
struct apartment_variable : details::apartment_variable_base<test_hook>
421+
template<typename T, apartment_variable_leak_action leak_action = apartment_variable_leak_action::fail_fast,
422+
typename test_hook = wil::apartment_variable_platform>
423+
struct apartment_variable : details::apartment_variable_base<leak_action, test_hook>
377424
{
378-
using base = details::apartment_variable_base<test_hook>;
425+
using base = details::apartment_variable_base<leak_action, test_hook>;
426+
427+
constexpr apartment_variable() = default;
379428

380429
// Get current value or throw if no value has been set.
381430
T& get_existing() { return std::any_cast<T&>(base::get_existing()); }

include/wil/common.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,22 @@ namespace wil
692692
static_assert(wistd::is_same<T, long>::value, "Wrong Type: NTSTATUS expected");
693693
return status;
694694
}
695+
696+
/** Verify that `error` is a Win32 error code.
697+
Other types will generate an intentional compilation error. Note that this will accept any `long` value as that is
698+
the underlying type used for WIN32 error codes, as well as any `DWORD` (`unsigned long`) value since this is the type
699+
commonly used when manipulating Win32 error codes.
700+
@param error The Win32 error code returning expression
701+
@return An Win32 error code representing the evaluation of `error`. */
702+
template <typename T>
703+
_Post_satisfies_(return == error)
704+
inline T verify_win32(T error)
705+
{
706+
// Note: Win32 error code are defined as 'long' (#define ERROR_SUCCESS 0L), but are more frequently used as DWORD (unsigned long).
707+
// This accept both types.
708+
static_assert(wistd::is_same<T, long>::value || wistd::is_same<T, unsigned long>::value, "Wrong Type: Win32 error code (long / unsigned long) expected");
709+
return error;
710+
}
695711
/// @} // end type validation routines
696712

697713
/// @cond

include/wil/cppwinrt_helpers.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,3 +313,40 @@ namespace wil
313313
}
314314
}
315315
#endif
316+
317+
#if defined(WINRT_Windows_UI_H) && defined(_WINDOWS_UI_INTEROP_H_) && !defined(__WIL_CPPWINRT_WINDOWS_UI_INTEROP_HELPERS)
318+
#define __WIL_CPPWINRT_WINDOWS_UI_INTEROP_HELPERS
319+
#if !defined(____x_ABI_CWindows_CFoundation_CIClosable_FWD_DEFINED__) && !defined(MIDL_NS_PREFIX)
320+
#pragma push_macro("ABI")
321+
#undef ABI
322+
#define ABI
323+
#endif
324+
325+
namespace wil
326+
{
327+
#if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_WIN10_CU)
328+
//! The following methods require that you include both <winrt/Windows.UI.h>
329+
//! <Windows.UI.Interop.h> before including wil/cppwinrt_helpers.h, and that NTDDI_VERSION
330+
//! is at least NTDDI_WIN10_CU. It is okay to include wil\cppwinrt_helpers.h multiple times:
331+
//! support will be enabled for any headers that were included since the previous inclusion
332+
//! of wil\cppwinrt_headers.h.
333+
inline winrt::Windows::UI::WindowId GetWindowIdFromWindow(HWND hwnd)
334+
{
335+
ABI::Windows::UI::WindowId abiWindowId;
336+
winrt::check_hresult(::GetWindowIdFromWindow(hwnd, &abiWindowId));
337+
return winrt::Windows::UI::WindowId{ abiWindowId.Value };
338+
}
339+
340+
inline HWND GetWindowFromWindowId(winrt::Windows::UI::WindowId windowId)
341+
{
342+
HWND hwnd;
343+
winrt::check_hresult(::GetWindowFromWindowId({ windowId.Value }, &hwnd));
344+
return hwnd;
345+
}
346+
#endif /*defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_WIN10_CU)*/
347+
}
348+
349+
#if !defined(____x_ABI_CWindows_CFoundation_CIClosable_FWD_DEFINED__) && !defined(MIDL_NS_PREFIX)
350+
#pragma pop_macro("ABI")
351+
#endif
352+
#endif // __WIL_CPPWINRT_WINDOWS_UI_INTEROP_HELPERS

include/wil/nt_result_macros.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
#include "result_macros.h"
1515

1616
// Helpers for return macros
17-
#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)
18-
#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)
17+
#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)
18+
#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)
1919

2020
//*****************************************************************************
2121
// Macros for returning failures as NTSTATUS

include/wil/resource.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ namespace wil
150150
typename pointer_access_t = pointer_access_all, // all, noaddress or none to control pointer method access
151151
typename pointer_storage_t = pointer_t, // The type used to store the handle (usually the same as the handle itself)
152152
typename invalid_t = pointer_t, // The invalid handle value type
153-
invalid_t invalid = invalid_t(), // * and its value (default ZERO value)
153+
invalid_t invalid = invalid_t{}, // * and its value (default ZERO value)
154154
typename pointer_invalid_t = wistd::nullptr_t> // nullptr_t if the invalid handle value is compatible with nullptr, otherwise pointer
155155
struct resource_policy : close_invoker<close_fn_t, close_fn, pointer_storage_t>
156156
{
@@ -436,7 +436,7 @@ namespace wil
436436
typename pointer_access = details::pointer_access_all, // all, noaddress or none to control pointer method access
437437
typename pointer_storage = pointer, // The type used to store the handle (usually the same as the handle itself)
438438
typename invalid_t = pointer, // The invalid handle value type
439-
invalid_t invalid = invalid_t(), // * and its value (default ZERO value)
439+
invalid_t invalid = invalid_t{}, // * and its value (default ZERO value)
440440
typename pointer_invalid = wistd::nullptr_t> // nullptr_t if the invalid handle value is compatible with nullptr, otherwise pointer
441441
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>>>;
442442

include/wil/result_macros.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2044,6 +2044,12 @@ __WI_POP_WARNINGS
20442044
return err;
20452045
}
20462046

2047+
inline __declspec(noinline) DWORD GetLastErrorFail() WI_NOEXCEPT
2048+
{
2049+
__R_FN_LOCALS_FULL_RA;
2050+
return GetLastErrorFail(__R_FN_CALL_FULL);
2051+
}
2052+
20472053
_Translates_last_error_to_HRESULT_
20482054
inline HRESULT GetLastErrorFailHr(__R_FN_PARAMS_FULL) WI_NOEXCEPT
20492055
{

0 commit comments

Comments
 (0)