mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 14:19:46 -06:00
update wil to 0b2d6c2d822bb301e7558a14ee66d567c14f5dc7
This commit is contained in:
3359
Externals/WIL/include/wil/Tracelogging.h
vendored
Normal file
3359
Externals/WIL/include/wil/Tracelogging.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
241
Externals/WIL/include/wil/com.h
vendored
241
Externals/WIL/include/wil/com.h
vendored
@ -16,6 +16,13 @@
|
||||
#include "result.h"
|
||||
#include "resource.h" // last to ensure _COMBASEAPI_H_ protected definitions are available
|
||||
|
||||
#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
|
||||
namespace Microsoft
|
||||
@ -46,10 +53,10 @@ namespace wil
|
||||
{
|
||||
};
|
||||
|
||||
typedef wistd::integral_constant<char, 0> tag_com_query;
|
||||
typedef wistd::integral_constant<char, 1> tag_try_com_query;
|
||||
typedef wistd::integral_constant<char, 2> tag_com_copy;
|
||||
typedef wistd::integral_constant<char, 3> tag_try_com_copy;
|
||||
using tag_com_query = wistd::integral_constant<char, 0>;
|
||||
using tag_try_com_query = wistd::integral_constant<char, 1>;
|
||||
using tag_com_copy = wistd::integral_constant<char, 2>;
|
||||
using tag_try_com_copy = wistd::integral_constant<char, 3>;
|
||||
|
||||
class default_query_policy
|
||||
{
|
||||
@ -87,7 +94,7 @@ namespace wil
|
||||
template <typename T>
|
||||
struct query_policy_helper
|
||||
{
|
||||
typedef default_query_policy type;
|
||||
using type = default_query_policy;
|
||||
};
|
||||
|
||||
class weak_query_policy
|
||||
@ -99,7 +106,7 @@ namespace wil
|
||||
*result = nullptr;
|
||||
|
||||
IInspectable* temp;
|
||||
HRESULT hr = ptr->Resolve(__uuidof(IInspectable), reinterpret_cast<IInspectable**>(&temp));
|
||||
HRESULT hr = ptr->Resolve(__uuidof(IInspectable), &temp);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
if (temp == nullptr)
|
||||
@ -144,7 +151,7 @@ namespace wil
|
||||
template <>
|
||||
struct query_policy_helper<IWeakReference>
|
||||
{
|
||||
typedef weak_query_policy type;
|
||||
using type = weak_query_policy;
|
||||
};
|
||||
|
||||
#if (NTDDI_VERSION >= NTDDI_WINBLUE)
|
||||
@ -170,7 +177,7 @@ namespace wil
|
||||
template <>
|
||||
struct query_policy_helper<IAgileReference>
|
||||
{
|
||||
typedef agile_query_policy type;
|
||||
using type = agile_query_policy;
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -190,15 +197,15 @@ namespace wil
|
||||
class com_ptr_t
|
||||
{
|
||||
private:
|
||||
typedef typename wistd::add_lvalue_reference<T>::type element_type_reference;
|
||||
typedef details::query_policy_t<T> query_policy;
|
||||
using element_type_reference = typename wistd::add_lvalue_reference<T>::type;
|
||||
using query_policy = details::query_policy_t<T>;
|
||||
public:
|
||||
//! The function return result (HRESULT or void) for the given err_policy (see @ref page_errors).
|
||||
typedef typename err_policy::result result;
|
||||
using result = typename err_policy::result;
|
||||
//! The template type `T` being held by the com_ptr_t.
|
||||
typedef T element_type;
|
||||
using element_type = T;
|
||||
//! A pointer to the template type `T` being held by the com_ptr_t (what `get()` returns).
|
||||
typedef T* pointer;
|
||||
using pointer = T*;
|
||||
|
||||
//! @name Constructors
|
||||
//! @{
|
||||
@ -359,8 +366,7 @@ namespace wil
|
||||
m_ptr = other;
|
||||
if (ptr)
|
||||
{
|
||||
ULONG ref;
|
||||
ref = ptr->Release();
|
||||
ULONG ref = ptr->Release();
|
||||
WI_ASSERT_MSG(((other != ptr) || (ref > 0)), "Bug: Attaching the same already assigned, destructed pointer");
|
||||
}
|
||||
}
|
||||
@ -397,9 +403,9 @@ namespace wil
|
||||
|
||||
//! Returns the address of the internal pointer casted to IUnknown** (releases ownership of the pointer BEFORE returning the address).
|
||||
//! @see put
|
||||
IUnknown** put_unknown() WI_NOEXCEPT
|
||||
::IUnknown** put_unknown() WI_NOEXCEPT
|
||||
{
|
||||
return reinterpret_cast<IUnknown**>(put());
|
||||
return reinterpret_cast<::IUnknown**>(put());
|
||||
}
|
||||
|
||||
//! Returns the address of the internal pointer (releases ownership of the pointer BEFORE returning the address).
|
||||
@ -863,7 +869,7 @@ namespace wil
|
||||
// Internal Helpers
|
||||
/// @cond
|
||||
template <class U>
|
||||
inline com_ptr_t(_In_ U* ptr, details::tag_com_query)
|
||||
inline com_ptr_t(_In_ U* ptr, details::tag_com_query) : m_ptr(nullptr)
|
||||
{
|
||||
err_policy::HResult(details::query_policy_t<U>::query(ptr, &m_ptr));
|
||||
}
|
||||
@ -875,14 +881,12 @@ namespace wil
|
||||
}
|
||||
|
||||
template <class U>
|
||||
inline com_ptr_t(_In_opt_ U* ptr, details::tag_com_copy)
|
||||
inline com_ptr_t(_In_opt_ U* ptr, details::tag_com_copy) : m_ptr(nullptr)
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
err_policy::HResult(details::query_policy_t<U>::query(ptr, &m_ptr));
|
||||
return;
|
||||
}
|
||||
m_ptr = nullptr;
|
||||
}
|
||||
|
||||
template <class U>
|
||||
@ -1182,6 +1186,43 @@ namespace wil
|
||||
#endif
|
||||
/// @endcond
|
||||
|
||||
#ifdef WIL_ENABLE_EXCEPTIONS
|
||||
//! Constructs a `com_ptr` from a raw pointer.
|
||||
//! This avoids having to restate the interface in pre-C++20.
|
||||
//! Starting in C++20, you can write `wil::com_ptr(p)` directly.
|
||||
//! ~~~
|
||||
//! void example(ILongNamedThing* thing)
|
||||
//! {
|
||||
//! callback([thing = wil::make_com_ptr(thing)] { /* do something */ });
|
||||
//! }
|
||||
//! ~~~
|
||||
template <typename T>
|
||||
com_ptr<T> make_com_ptr(T* p) { return p; }
|
||||
#endif
|
||||
|
||||
//! Constructs a `com_ptr_nothrow` from a raw pointer.
|
||||
//! This avoids having to restate the interface in pre-C++20.
|
||||
//! Starting in C++20, you can write `wil::com_ptr_nothrow(p)` directly.
|
||||
//! ~~~
|
||||
//! void example(ILongNamedThing* thing)
|
||||
//! {
|
||||
//! callback([thing = wil::make_com_ptr_nothrow(thing)] { /* do something */ });
|
||||
//! }
|
||||
//! ~~~
|
||||
template <typename T>
|
||||
com_ptr_nothrow<T> make_com_ptr_nothrow(T* p) { return p; }
|
||||
|
||||
//! Constructs a `com_ptr_failfast` from a raw pointer.
|
||||
//! This avoids having to restate the interface in pre-C++20.
|
||||
//! Starting in C++20, you can write `wil::com_ptr_failfast(p)` directly.
|
||||
//! ~~~
|
||||
//! void example(ILongNamedThing* thing)
|
||||
//! {
|
||||
//! callback([thing = wil::make_com_ptr_failfast(thing)] { /* do something */ });
|
||||
//! }
|
||||
//! ~~~
|
||||
template <typename T>
|
||||
com_ptr_failfast<T> make_com_ptr_failfast(T* p) { return p; }
|
||||
|
||||
//! @name Stand-alone query helpers
|
||||
//! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr
|
||||
@ -1255,7 +1296,7 @@ namespace wil
|
||||
auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
|
||||
auto hr = details::query_policy_t<decltype(raw)>::query(raw, ptrResult);
|
||||
__analysis_assume(SUCCEEDED(hr) || (*ptrResult == nullptr));
|
||||
RETURN_HR(hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
#ifdef WIL_ENABLE_EXCEPTIONS
|
||||
@ -1297,7 +1338,7 @@ namespace wil
|
||||
auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
|
||||
auto hr = details::query_policy_t<decltype(raw)>::query(raw, riid, ptrResult);
|
||||
__analysis_assume(SUCCEEDED(hr) || (*ptrResult == nullptr));
|
||||
RETURN_HR(hr);
|
||||
return hr;
|
||||
}
|
||||
//! @}
|
||||
|
||||
@ -1687,7 +1728,7 @@ namespace wil
|
||||
auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
|
||||
auto hr = ::RoGetAgileReference(options, __uuidof(raw), raw, ptrResult);
|
||||
__analysis_assume(SUCCEEDED(hr) || (*ptrResult == nullptr));
|
||||
RETURN_HR(hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
#ifdef WIL_ENABLE_EXCEPTIONS
|
||||
@ -1802,7 +1843,7 @@ namespace wil
|
||||
auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
|
||||
auto hr = details::GetWeakReference(raw, ptrResult);
|
||||
__analysis_assume(SUCCEEDED(hr) || (*ptrResult == nullptr));
|
||||
RETURN_HR(hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
#ifdef WIL_ENABLE_EXCEPTIONS
|
||||
@ -1873,14 +1914,14 @@ namespace wil
|
||||
|
||||
/** constructs a COM object using an CLSID on a specific interface or IUnknown. */
|
||||
template<typename Interface = IUnknown>
|
||||
wil::com_ptr_failfast<Interface> CoCreateInstanceFailFast(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER)
|
||||
wil::com_ptr_failfast<Interface> CoCreateInstanceFailFast(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER) WI_NOEXCEPT
|
||||
{
|
||||
return CoCreateInstance<Interface, err_failfast_policy>(rclsid, dwClsContext);
|
||||
}
|
||||
|
||||
/** constructs a COM object using the class as the identifier (that has an associated CLSID) on a specific interface or IUnknown. */
|
||||
template<typename Class, typename Interface = IUnknown>
|
||||
wil::com_ptr_failfast<Interface> CoCreateInstanceFailFast(DWORD dwClsContext = CLSCTX_INPROC_SERVER)
|
||||
wil::com_ptr_failfast<Interface> CoCreateInstanceFailFast(DWORD dwClsContext = CLSCTX_INPROC_SERVER) WI_NOEXCEPT
|
||||
{
|
||||
return CoCreateInstanceFailFast<Interface>(__uuidof(Class), dwClsContext);
|
||||
}
|
||||
@ -1888,7 +1929,7 @@ namespace wil
|
||||
/** constructs a COM object using an CLSID on a specific interface or IUnknown.
|
||||
Note, failures are reported as a null result, the HRESULT is lost. */
|
||||
template<typename Interface = IUnknown>
|
||||
wil::com_ptr_nothrow<Interface> CoCreateInstanceNoThrow(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER)
|
||||
wil::com_ptr_nothrow<Interface> CoCreateInstanceNoThrow(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER) WI_NOEXCEPT
|
||||
{
|
||||
return CoCreateInstance<Interface, err_returncode_policy>(rclsid, dwClsContext);
|
||||
}
|
||||
@ -1896,7 +1937,7 @@ namespace wil
|
||||
/** constructs a COM object using the class as the identifier (that has an associated CLSID) on a specific interface or IUnknown.
|
||||
Note, failures are reported as a null result, the HRESULT is lost. */
|
||||
template<typename Class, typename Interface = IUnknown>
|
||||
wil::com_ptr_nothrow<Interface> CoCreateInstanceNoThrow(DWORD dwClsContext = CLSCTX_INPROC_SERVER)
|
||||
wil::com_ptr_nothrow<Interface> CoCreateInstanceNoThrow(DWORD dwClsContext = CLSCTX_INPROC_SERVER) WI_NOEXCEPT
|
||||
{
|
||||
return CoCreateInstanceNoThrow<Interface>(__uuidof(Class), dwClsContext);
|
||||
}
|
||||
@ -1949,6 +1990,140 @@ namespace wil
|
||||
{
|
||||
return CoGetClassObjectNoThrow<Interface>(__uuidof(Class), dwClsContext);
|
||||
}
|
||||
|
||||
#if __cpp_lib_apply && __has_include(<type_traits>)
|
||||
namespace details
|
||||
{
|
||||
template <typename error_policy, typename... Results>
|
||||
auto CoCreateInstanceEx(REFCLSID clsid, CLSCTX clsCtx) noexcept
|
||||
{
|
||||
MULTI_QI multiQis[sizeof...(Results)]{};
|
||||
const IID* iids[sizeof...(Results)]{ &__uuidof(Results)... };
|
||||
|
||||
static_assert(sizeof...(Results) > 0);
|
||||
|
||||
for (auto i = 0U; i < sizeof...(Results); ++i)
|
||||
{
|
||||
multiQis[i].pIID = iids[i];
|
||||
}
|
||||
|
||||
const auto hr = CoCreateInstanceEx(clsid, nullptr, clsCtx, nullptr,
|
||||
ARRAYSIZE(multiQis), multiQis);
|
||||
|
||||
std::tuple<wil::com_ptr_t<Results, error_policy>...> resultTuple;
|
||||
|
||||
std::apply([i = 0, &multiQis](auto&... a) mutable
|
||||
{
|
||||
(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));
|
||||
}
|
||||
|
||||
template<typename error_policy, typename... Results>
|
||||
auto com_multi_query(IUnknown* obj)
|
||||
{
|
||||
MULTI_QI multiQis[sizeof...(Results)]{};
|
||||
const IID* iids[sizeof...(Results)]{ &__uuidof(Results)... };
|
||||
|
||||
static_assert(sizeof...(Results) > 0);
|
||||
|
||||
for (auto i = 0U; i < sizeof...(Results); ++i)
|
||||
{
|
||||
multiQis[i].pIID = iids[i];
|
||||
}
|
||||
|
||||
std::tuple<wil::com_ptr_t<Results, error_policy>...> resultTuple{};
|
||||
|
||||
wil::com_ptr_nothrow<IMultiQI> multiQi;
|
||||
auto hr = obj->QueryInterface(IID_PPV_ARGS(&multiQi));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = multiQi->QueryMultipleInterfaces(ARRAYSIZE(multiQis), multiQis);
|
||||
std::apply([i = 0, &multiQis](auto&... a) mutable
|
||||
{
|
||||
(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)};
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WIL_ENABLE_EXCEPTIONS
|
||||
// CoCreateInstanceEx can be used to improve performance by requesting multiple interfaces
|
||||
// from an object at create time. This is most useful for out of process (OOP) servers, saving
|
||||
// and RPC per extra interface requested.
|
||||
template <typename... Results>
|
||||
auto CoCreateInstanceEx(REFCLSID clsid, CLSCTX clsCtx = CLSCTX_LOCAL_SERVER)
|
||||
{
|
||||
auto [error, result] = details::CoCreateInstanceEx<err_exception_policy, Results...>(clsid, clsCtx);
|
||||
THROW_IF_FAILED(error);
|
||||
THROW_HR_IF(E_NOINTERFACE, error == CO_S_NOTALLINTERFACES);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename... Results>
|
||||
auto TryCoCreateInstanceEx(REFCLSID clsid, CLSCTX clsCtx = CLSCTX_LOCAL_SERVER)
|
||||
{
|
||||
auto [error, result] = details::CoCreateInstanceEx<err_exception_policy, Results...>(clsid, clsCtx);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Returns [error, result] where result is a tuple with each of the requested interfaces.
|
||||
template <typename... Results>
|
||||
auto CoCreateInstanceExNoThrow(REFCLSID clsid, CLSCTX clsCtx = CLSCTX_LOCAL_SERVER) noexcept
|
||||
{
|
||||
auto [error, result] = details::CoCreateInstanceEx<err_returncode_policy, Results...>(clsid, clsCtx);
|
||||
if (SUCCEEDED(error) && (error == CO_S_NOTALLINTERFACES))
|
||||
{
|
||||
return std::tuple<HRESULT, decltype(result)>{E_NOINTERFACE, {}};
|
||||
}
|
||||
return std::tuple<HRESULT, decltype(result)>{error, result};
|
||||
}
|
||||
|
||||
template <typename... Results>
|
||||
auto TryCoCreateInstanceExNoThrow(REFCLSID clsid, CLSCTX clsCtx = CLSCTX_LOCAL_SERVER) noexcept
|
||||
{
|
||||
auto [error, result] = details::CoCreateInstanceEx<err_returncode_policy, Results...>(clsid, clsCtx);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename... Results>
|
||||
auto CoCreateInstanceExFailFast(REFCLSID clsid, CLSCTX clsCtx = CLSCTX_LOCAL_SERVER) noexcept
|
||||
{
|
||||
auto [error, result] = details::CoCreateInstanceEx<err_failfast_policy, Results...>(clsid, clsCtx);
|
||||
FAIL_FAST_IF_FAILED(error);
|
||||
FAIL_FAST_HR_IF(E_NOINTERFACE, error == CO_S_NOTALLINTERFACES);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename... Results>
|
||||
auto TryCoCreateInstanceExFailFast(REFCLSID clsid, CLSCTX clsCtx = CLSCTX_LOCAL_SERVER) noexcept
|
||||
{
|
||||
auto [error, result] = details::CoCreateInstanceEx<err_failfast_policy, Results...>(clsid, clsCtx);
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef WIL_ENABLE_EXCEPTIONS
|
||||
template<typename... Results>
|
||||
auto com_multi_query(IUnknown* obj)
|
||||
{
|
||||
auto [error, result] = details::com_multi_query<err_exception_policy, Results...>(obj);
|
||||
THROW_IF_FAILED(error);
|
||||
THROW_HR_IF(E_NOINTERFACE, error == S_FALSE);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename... Results>
|
||||
auto try_com_multi_query(IUnknown* obj)
|
||||
{
|
||||
auto [error, result] = details::com_multi_query<err_exception_policy, Results...>(obj);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __cpp_lib_apply && __has_include(<type_traits>)
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Stream helpers
|
||||
@ -2262,8 +2437,8 @@ namespace wil
|
||||
@param value Set to point to the allocated result of reading a string from `source`
|
||||
*/
|
||||
inline HRESULT stream_read_string_nothrow(
|
||||
_In_ ISequentialStream* source,
|
||||
_When_(options == empty_string_options::returns_empty, _Outptr_result_z_) _When_(options == empty_string_options::returns_null, _Outptr_result_maybenull_z_) wchar_t** value,
|
||||
_In_ ISequentialStream* source,
|
||||
_When_(options == empty_string_options::returns_empty, _Outptr_result_z_) _When_(options == empty_string_options::returns_null, _Outptr_result_maybenull_z_) wchar_t** value,
|
||||
empty_string_options options = empty_string_options::returns_empty)
|
||||
{
|
||||
unsigned short cch;
|
||||
@ -2601,8 +2776,8 @@ namespace wil
|
||||
wil::stream_write_string(target, L"Waffles", 3);
|
||||
~~~~
|
||||
@param target The stream to which to write a string
|
||||
@param source The string to write. Can be null if `writeLength` is zero
|
||||
@param writeLength The number of characters to write from source into `target`
|
||||
@param source The string to write. Can be null if `toWriteCch` is zero
|
||||
@param toWriteCch The number of characters to write from source into `target`
|
||||
*/
|
||||
inline void stream_write_string(_In_ ISequentialStream* target, _In_reads_opt_(toWriteCch) const wchar_t* source, _In_ size_t toWriteCch)
|
||||
{
|
||||
|
467
Externals/WIL/include/wil/com_apartment_variable.h
vendored
Normal file
467
Externals/WIL/include/wil/com_apartment_variable.h
vendored
Normal file
@ -0,0 +1,467 @@
|
||||
//*********************************************************
|
||||
//
|
||||
// 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_COM_APARTMENT_VARIABLE_INCLUDED
|
||||
#define __WIL_COM_APARTMENT_VARIABLE_INCLUDED
|
||||
|
||||
#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 "result_macros.h"
|
||||
#include "win32_helpers.h"
|
||||
|
||||
#ifndef WIL_ENABLE_EXCEPTIONS
|
||||
#error This header requires exceptions
|
||||
#endif
|
||||
|
||||
namespace wil
|
||||
{
|
||||
// Determine if apartment variables are supported in the current process context.
|
||||
// Prior to build 22365, the APIs needed to create apartment variables (e.g. RoGetApartmentIdentifier)
|
||||
// failed for unpackaged processes. For MS people, see http://task.ms/31861017 for details.
|
||||
// APIs needed to implement apartment variables did not work in non-packaged processes.
|
||||
inline bool are_apartment_variables_supported()
|
||||
{
|
||||
unsigned long long apartmentId{};
|
||||
return RoGetApartmentIdentifier(&apartmentId) != HRESULT_FROM_WIN32(ERROR_API_UNAVAILABLE);
|
||||
}
|
||||
|
||||
// COM will implicitly rundown the apartment registration when it invokes a handler
|
||||
// and blocks calling unregister when executing the callback. So be careful to release()
|
||||
// this when callback is invoked to avoid a double free of the cookie.
|
||||
using unique_apartment_shutdown_registration = unique_any<APARTMENT_SHUTDOWN_REGISTRATION_COOKIE, decltype(&::RoUnregisterForApartmentShutdown), ::RoUnregisterForApartmentShutdown>;
|
||||
|
||||
struct apartment_variable_platform
|
||||
{
|
||||
static unsigned long long GetApartmentId()
|
||||
{
|
||||
unsigned long long apartmentId{};
|
||||
FAIL_FAST_IF_FAILED(RoGetApartmentIdentifier(&apartmentId));
|
||||
return apartmentId;
|
||||
}
|
||||
|
||||
static auto RegisterForApartmentShutdown(IApartmentShutdown* observer)
|
||||
{
|
||||
unsigned long long id{};
|
||||
shutdown_type cookie;
|
||||
THROW_IF_FAILED(RoRegisterForApartmentShutdown(observer, &id, cookie.put()));
|
||||
return cookie;
|
||||
}
|
||||
|
||||
static void UnRegisterForApartmentShutdown(APARTMENT_SHUTDOWN_REGISTRATION_COOKIE cookie)
|
||||
{
|
||||
FAIL_FAST_IF_FAILED(RoUnregisterForApartmentShutdown(cookie));
|
||||
}
|
||||
|
||||
static auto CoInitializeEx(DWORD coinitFlags = 0 /*COINIT_MULTITHREADED*/)
|
||||
{
|
||||
return wil::CoInitializeEx(coinitFlags);
|
||||
}
|
||||
|
||||
// disable the test hook
|
||||
inline static constexpr unsigned long AsyncRundownDelayForTestingRaces = INFINITE;
|
||||
|
||||
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.
|
||||
inline bool IsGlobalVariable(const void* moduleAddress) noexcept
|
||||
{
|
||||
wil::unique_hmodule moduleHandle;
|
||||
return GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, static_cast<PCWSTR>(moduleAddress), &moduleHandle) != FALSE;
|
||||
}
|
||||
|
||||
struct any_maker_base
|
||||
{
|
||||
std::any(*adapter)(void*);
|
||||
void* inner;
|
||||
|
||||
std::any operator()() const
|
||||
{
|
||||
return adapter(inner);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct any_maker : any_maker_base
|
||||
{
|
||||
any_maker()
|
||||
{
|
||||
adapter = [](auto) -> std::any { return T{}; };
|
||||
}
|
||||
|
||||
any_maker(T(*maker)())
|
||||
{
|
||||
adapter = [](auto maker) -> std::any { return reinterpret_cast<T(*)()>(maker)(); };
|
||||
inner = reinterpret_cast<void*>(maker);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
any_maker(F&& f)
|
||||
{
|
||||
adapter = [](auto maker) -> std::any { return reinterpret_cast<F*>(maker)[0](); };
|
||||
inner = std::addressof(f);
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
struct apartment_variable_storage
|
||||
{
|
||||
apartment_variable_storage(apartment_variable_storage&& other) noexcept = default;
|
||||
apartment_variable_storage(const apartment_variable_storage& other) = delete;
|
||||
|
||||
apartment_variable_storage(typename test_hook::shutdown_type&& cookie_) : cookie(std::move(cookie_))
|
||||
{
|
||||
}
|
||||
|
||||
winrt::apartment_context context;
|
||||
typename test_hook::shutdown_type cookie;
|
||||
// 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 -> variables storage.
|
||||
inline static wil::object_without_destructor_on_shutdown<
|
||||
std::unordered_map<unsigned long long, apartment_variable_storage>>
|
||||
s_apartmentStorage;
|
||||
|
||||
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.
|
||||
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
|
||||
apartment_variable_base(apartment_variable_base const&) = delete;
|
||||
void operator=(apartment_variable_base const&) = delete;
|
||||
|
||||
// get current value or throw if no value has been set
|
||||
std::any& get_existing()
|
||||
{
|
||||
if (auto any = get_if())
|
||||
{
|
||||
return *any;
|
||||
}
|
||||
THROW_HR(E_NOT_SET);
|
||||
}
|
||||
|
||||
static apartment_variable_storage* get_current_apartment_variable_storage()
|
||||
{
|
||||
auto storage = s_apartmentStorage.get().find(test_hook::GetApartmentId());
|
||||
if (storage != s_apartmentStorage.get().end())
|
||||
{
|
||||
return &storage->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
apartment_variable_storage* ensure_current_apartment_variables()
|
||||
{
|
||||
auto variables = get_current_apartment_variable_storage();
|
||||
if (variables)
|
||||
{
|
||||
return variables;
|
||||
}
|
||||
|
||||
struct ApartmentObserver : public winrt::implements<ApartmentObserver, IApartmentShutdown>
|
||||
{
|
||||
void STDMETHODCALLTYPE OnUninitialize(unsigned long long apartmentId) noexcept override
|
||||
{
|
||||
// This code runs at apartment rundown so be careful to avoid deadlocks by
|
||||
// extracting the variables under the lock then release them outside.
|
||||
auto variables = [apartmentId]()
|
||||
{
|
||||
auto lock = winrt::slim_lock_guard(s_lock);
|
||||
return s_apartmentStorage.get().extract(apartmentId);
|
||||
}();
|
||||
WI_ASSERT(variables.key() == apartmentId);
|
||||
// The system implicitly releases the shutdown observer
|
||||
// after invoking the callback and does not allow calling unregister
|
||||
// in the callback. So release the reference to the registration.
|
||||
variables.mapped().cookie.release();
|
||||
}
|
||||
};
|
||||
auto shutdownRegistration = test_hook::RegisterForApartmentShutdown(winrt::make<ApartmentObserver>().get());
|
||||
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)
|
||||
{
|
||||
apartment_variable_storage* variable_storage = nullptr;
|
||||
|
||||
{ // scope for lock
|
||||
auto lock = winrt::slim_lock_guard(s_lock);
|
||||
variable_storage = ensure_current_apartment_variables();
|
||||
|
||||
auto variable = variable_storage->variables.find(this);
|
||||
if (variable != variable_storage->variables.end())
|
||||
{
|
||||
return variable->second;
|
||||
}
|
||||
} // drop the lock
|
||||
|
||||
// create the object outside the lock to avoid reentrant deadlock
|
||||
auto value = creator();
|
||||
|
||||
auto insert_lock = winrt::slim_lock_guard(s_lock);
|
||||
// The insertion may fail if creator() recursively caused itself to be created,
|
||||
// in which case we return the existing object and the falsely-created one is discarded.
|
||||
return variable_storage->variables.insert({ this, std::move(value) }).first->second;
|
||||
}
|
||||
|
||||
// get pointer to current value or nullptr if no value has been set
|
||||
std::any* get_if()
|
||||
{
|
||||
auto lock = winrt::slim_lock_guard(s_lock);
|
||||
|
||||
if (auto variable_storage = get_current_apartment_variable_storage())
|
||||
{
|
||||
auto variable = variable_storage->variables.find(this);
|
||||
if (variable != variable_storage->variables.end())
|
||||
{
|
||||
return &(variable->second);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// replace or create the current value, fail fasts if the value is not already stored
|
||||
void set(std::any value)
|
||||
{
|
||||
// release value, with the swapped value, outside of the lock
|
||||
{
|
||||
auto lock = winrt::slim_lock_guard(s_lock);
|
||||
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());
|
||||
variable->second.swap(value);
|
||||
}
|
||||
}
|
||||
|
||||
// remove any current value
|
||||
void clear()
|
||||
{
|
||||
auto lock = winrt::slim_lock_guard(s_lock);
|
||||
if (auto variable_storage = get_current_apartment_variable_storage())
|
||||
{
|
||||
variable_storage->variables.erase(this);
|
||||
if (variable_storage->variables.size() == 0)
|
||||
{
|
||||
s_apartmentStorage.get().erase(test_hook::GetApartmentId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
winrt::Windows::Foundation::IAsyncAction clear_all_apartments_async()
|
||||
{
|
||||
// gather all the apartments that hold objects we need to destruct
|
||||
// (do not gather the objects themselves, because the apartment might
|
||||
// destruct before we get around to it, and we should let the apartment
|
||||
// destruct the object while it still can).
|
||||
|
||||
std::vector<winrt::apartment_context> contexts;
|
||||
{ // scope for lock
|
||||
auto lock = winrt::slim_lock_guard(s_lock);
|
||||
for (auto& [id, storage] : s_apartmentStorage.get())
|
||||
{
|
||||
auto variable = storage.variables.find(this);
|
||||
if (variable != storage.variables.end())
|
||||
{
|
||||
contexts.push_back(storage.context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (contexts.empty())
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
wil::unique_mta_usage_cookie mta_reference; // need to extend the MTA due to async cleanup
|
||||
FAIL_FAST_IF_FAILED(CoIncrementMTAUsage(mta_reference.put()));
|
||||
|
||||
// From a background thread hop into each apartment to run down the object
|
||||
// if it's still there.
|
||||
co_await winrt::resume_background();
|
||||
|
||||
// This hook enables testing the case where execution of this method loses the race with
|
||||
// apartment rundown by other means.
|
||||
if constexpr (test_hook::AsyncRundownDelayForTestingRaces != INFINITE)
|
||||
{
|
||||
Sleep(test_hook::AsyncRundownDelayForTestingRaces);
|
||||
}
|
||||
|
||||
for (auto&& context : contexts)
|
||||
{
|
||||
try
|
||||
{
|
||||
co_await context;
|
||||
clear();
|
||||
}
|
||||
catch (winrt::hresult_error const& e)
|
||||
{
|
||||
// Ignore failure if apartment ran down before we could clean it up.
|
||||
// The object already ran down as part of apartment cleanup.
|
||||
if ((e.code() != RPC_E_SERVER_DIED_DNE) &&
|
||||
(e.code() != RPC_E_DISCONNECTED))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
FAIL_FAST();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const auto& storage()
|
||||
{
|
||||
return s_apartmentStorage.get();
|
||||
}
|
||||
|
||||
static size_t current_apartment_variable_count()
|
||||
{
|
||||
auto lock = winrt::slim_lock_guard(s_lock);
|
||||
if (auto variable_storage = get_current_apartment_variable_storage())
|
||||
{
|
||||
return variable_storage->variables.size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Apartment variables enable storing COM objects safely in globals
|
||||
// (objects with static storage duration) by creating a unique copy
|
||||
// in each apartment and managing their lifetime based on apartment rundown
|
||||
// notifications.
|
||||
// They can also be used for automatic or dynamic storage duration but those
|
||||
// cases are less common.
|
||||
// This type is also useful for storing references to apartment affine objects.
|
||||
//
|
||||
// Note, that apartment variables hosted in a COM DLL need to integrate with
|
||||
// the DllCanUnloadNow() function to include the ref counts contributed by
|
||||
// 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, 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<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()); }
|
||||
|
||||
// Get current value or default-construct one on demand.
|
||||
T& get_or_create()
|
||||
{
|
||||
return std::any_cast<T&>(base::get_or_create(details::any_maker<T>()));
|
||||
}
|
||||
|
||||
// Get current value or custom-construct one on demand.
|
||||
template<typename F>
|
||||
T& get_or_create(F&& f)
|
||||
{
|
||||
return std::any_cast<T&>(base::get_or_create(details::any_maker<T>(std::forward<F>(f))));
|
||||
}
|
||||
|
||||
// get pointer to current value or nullptr if no value has been set
|
||||
T* get_if() { return std::any_cast<T>(base::get_if()); }
|
||||
|
||||
// replace or create the current value, fail fasts if the value is not already stored
|
||||
template<typename V> void set(V&& value) { return base::set(std::forward<V>(value)); }
|
||||
|
||||
// Clear the value in the current apartment.
|
||||
using base::clear;
|
||||
|
||||
// Asynchronously clear the value in all apartments it is present in.
|
||||
using base::clear_all_apartments_async;
|
||||
|
||||
// For testing only.
|
||||
// 1) To observe the state of the storage in the debugger assign this to
|
||||
// a temporary variable (const&) and watch its contents.
|
||||
// 2) Use this to test the implementation.
|
||||
using base::storage;
|
||||
// For testing only. The number of variables in the current apartment.
|
||||
using base::current_apartment_variable_count;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // __WIL_COM_APARTMENT_VARIABLE_INCLUDED
|
247
Externals/WIL/include/wil/common.h
vendored
247
Externals/WIL/include/wil/common.h
vendored
@ -75,27 +75,7 @@
|
||||
#define __WI_SUPPRESS_NOEXCEPT_ANALYSIS
|
||||
#endif
|
||||
|
||||
#if !defined(__cplusplus) || defined(__WIL_MIN_KERNEL)
|
||||
|
||||
#define WI_ODR_PRAGMA(NAME, TOKEN)
|
||||
#define WI_NOEXCEPT
|
||||
|
||||
#else
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4714) // __forceinline not honored
|
||||
|
||||
// DO NOT add *any* further includes to this file -- there should be no dependencies from its usage
|
||||
#include <sal.h>
|
||||
#include "wistd_type_traits.h"
|
||||
|
||||
//! This macro inserts ODR violation protection; the macro allows it to be compatible with straight "C" code
|
||||
#define WI_ODR_PRAGMA(NAME, TOKEN) __pragma(detect_mismatch("ODR_violation_" NAME "_mismatch", TOKEN))
|
||||
|
||||
#ifdef WIL_KERNEL_MODE
|
||||
WI_ODR_PRAGMA("WIL_KERNEL_MODE", "1")
|
||||
#else
|
||||
WI_ODR_PRAGMA("WIL_KERNEL_MODE", "0")
|
||||
#endif
|
||||
|
||||
// Some SAL remapping / decoration to better support Doxygen. Macros that look like function calls can
|
||||
// confuse Doxygen when they are used to decorate a function or variable. We simplify some of these to
|
||||
@ -107,73 +87,6 @@ WI_ODR_PRAGMA("WIL_KERNEL_MODE", "0")
|
||||
#define __declspec_selectany_ __declspec(selectany)
|
||||
/// @endcond
|
||||
|
||||
#if defined(_CPPUNWIND) && !defined(WIL_SUPPRESS_EXCEPTIONS)
|
||||
/** This define is automatically set when exceptions are enabled within wil.
|
||||
It is automatically defined when your code is compiled with exceptions enabled (via checking for the built-in
|
||||
_CPPUNWIND flag) unless you explicitly define WIL_SUPPRESS_EXCEPTIONS ahead of including your first wil
|
||||
header. All exception-based WIL methods and classes are included behind:
|
||||
~~~~
|
||||
#ifdef WIL_ENABLE_EXCEPTIONS
|
||||
// code
|
||||
#endif
|
||||
~~~~
|
||||
This enables exception-free code to directly include WIL headers without worrying about exception-based
|
||||
routines suddenly becoming available. */
|
||||
#define WIL_ENABLE_EXCEPTIONS
|
||||
#endif
|
||||
/// @endcond
|
||||
|
||||
/// @cond
|
||||
#if defined(WIL_EXCEPTION_MODE)
|
||||
static_assert(WIL_EXCEPTION_MODE <= 2, "Invalid exception mode");
|
||||
#elif !defined(WIL_LOCK_EXCEPTION_MODE)
|
||||
#define WIL_EXCEPTION_MODE 0 // default, can link exception-based and non-exception based libraries together
|
||||
#pragma detect_mismatch("ODR_violation_WIL_EXCEPTION_MODE_mismatch", "0")
|
||||
#elif defined(WIL_ENABLE_EXCEPTIONS)
|
||||
#define WIL_EXCEPTION_MODE 1 // new code optimization: ONLY support linking libraries together that have exceptions enabled
|
||||
#pragma detect_mismatch("ODR_violation_WIL_EXCEPTION_MODE_mismatch", "1")
|
||||
#else
|
||||
#define WIL_EXCEPTION_MODE 2 // old code optimization: ONLY support linking libraries that are NOT using exceptions
|
||||
#pragma detect_mismatch("ODR_violation_WIL_EXCEPTION_MODE_mismatch", "2")
|
||||
#endif
|
||||
|
||||
#if WIL_EXCEPTION_MODE == 1 && !defined(WIL_ENABLE_EXCEPTIONS)
|
||||
#error Must enable exceptions when WIL_EXCEPTION_MODE == 1
|
||||
#endif
|
||||
|
||||
// block for documentation only
|
||||
#if defined(WIL_DOXYGEN)
|
||||
/** This define can be explicitly set to disable exception usage within wil.
|
||||
Normally this define is never needed as the WIL_ENABLE_EXCEPTIONS macro is enabled automatically by looking
|
||||
at _CPPUNWIND. If your code compiles with exceptions enabled, but does not want to enable the exception-based
|
||||
classes and methods from WIL, define this macro ahead of including the first WIL header. */
|
||||
#define WIL_SUPPRESS_EXCEPTIONS
|
||||
|
||||
/** This define can be explicitly set to lock the process exception mode to WIL_ENABLE_EXCEPTIONS.
|
||||
Locking the exception mode provides optimizations to exception barriers, staging hooks and DLL load costs as it eliminates the need to
|
||||
do copy-on-write initialization of various function pointers and the necessary indirection that's done within WIL to avoid ODR violations
|
||||
when linking libraries together with different exception handling semantics. */
|
||||
#define WIL_LOCK_EXCEPTION_MODE
|
||||
|
||||
/** This define explicit sets the exception mode for the process to control optimizations.
|
||||
Three exception modes are available:
|
||||
0) This is the default. This enables a binary to link both exception-based and non-exception based libraries together that
|
||||
use WIL. This adds overhead to exception barriers, DLL copy on write pages and indirection through function pointers to avoid ODR
|
||||
violations when linking libraries together with different exception handling semantics.
|
||||
1) Prefer this setting when it can be used. This locks the binary to only supporting libraries which were built with exceptions enabled.
|
||||
2) This locks the binary to libraries built without exceptions. */
|
||||
#define WIL_EXCEPTION_MODE
|
||||
#endif
|
||||
|
||||
#if (__cplusplus >= 201703) || (_MSVC_LANG >= 201703)
|
||||
#define WIL_HAS_CXX_17 1
|
||||
#else
|
||||
#define WIL_HAS_CXX_17 0
|
||||
#endif
|
||||
|
||||
// Until we'll have C++17 enabled in our code base, we're falling back to SAL
|
||||
#define WI_NODISCARD __WI_LIBCPP_NODISCARD_ATTRIBUTE
|
||||
|
||||
//! @defgroup macrobuilding Macro Composition
|
||||
//! The following macros are building blocks primarily intended for authoring other macros.
|
||||
//! @{
|
||||
@ -327,8 +240,96 @@ Three exception modes are available:
|
||||
|
||||
//! @} // Macro composition helpers
|
||||
|
||||
#define __R_ENABLE_IF_IS_CLASS(ptrType) wistd::enable_if_t<wistd::is_class<ptrType>::value, void*> = (void*)0
|
||||
#define __R_ENABLE_IF_IS_NOT_CLASS(ptrType) wistd::enable_if_t<!wistd::is_class<ptrType>::value, void*> = (void*)0
|
||||
#if !defined(__cplusplus) || defined(__WIL_MIN_KERNEL)
|
||||
|
||||
#define WI_ODR_PRAGMA(NAME, TOKEN)
|
||||
#define WI_NOEXCEPT
|
||||
|
||||
#else
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4714) // __forceinline not honored
|
||||
|
||||
// DO NOT add *any* further includes to this file -- there should be no dependencies from its usage
|
||||
#include "wistd_type_traits.h"
|
||||
|
||||
//! This macro inserts ODR violation protection; the macro allows it to be compatible with straight "C" code
|
||||
#define WI_ODR_PRAGMA(NAME, TOKEN) __pragma(detect_mismatch("ODR_violation_" NAME "_mismatch", TOKEN))
|
||||
|
||||
#ifdef WIL_KERNEL_MODE
|
||||
WI_ODR_PRAGMA("WIL_KERNEL_MODE", "1")
|
||||
#else
|
||||
WI_ODR_PRAGMA("WIL_KERNEL_MODE", "0")
|
||||
#endif
|
||||
|
||||
#if (defined(_CPPUNWIND) || defined(__EXCEPTIONS)) && !defined(WIL_SUPPRESS_EXCEPTIONS)
|
||||
/** This define is automatically set when exceptions are enabled within wil.
|
||||
It is automatically defined when your code is compiled with exceptions enabled (via checking for the built-in
|
||||
_CPPUNWIND or __EXCEPTIONS flag) unless you explicitly define WIL_SUPPRESS_EXCEPTIONS ahead of including your first wil
|
||||
header. All exception-based WIL methods and classes are included behind:
|
||||
~~~~
|
||||
#ifdef WIL_ENABLE_EXCEPTIONS
|
||||
// code
|
||||
#endif
|
||||
~~~~
|
||||
This enables exception-free code to directly include WIL headers without worrying about exception-based
|
||||
routines suddenly becoming available. */
|
||||
#define WIL_ENABLE_EXCEPTIONS
|
||||
#endif
|
||||
/// @endcond
|
||||
|
||||
/// @cond
|
||||
#if defined(WIL_EXCEPTION_MODE)
|
||||
static_assert(WIL_EXCEPTION_MODE <= 2, "Invalid exception mode");
|
||||
#elif !defined(WIL_LOCK_EXCEPTION_MODE)
|
||||
#define WIL_EXCEPTION_MODE 0 // default, can link exception-based and non-exception based libraries together
|
||||
#pragma detect_mismatch("ODR_violation_WIL_EXCEPTION_MODE_mismatch", "0")
|
||||
#elif defined(WIL_ENABLE_EXCEPTIONS)
|
||||
#define WIL_EXCEPTION_MODE 1 // new code optimization: ONLY support linking libraries together that have exceptions enabled
|
||||
#pragma detect_mismatch("ODR_violation_WIL_EXCEPTION_MODE_mismatch", "1")
|
||||
#else
|
||||
#define WIL_EXCEPTION_MODE 2 // old code optimization: ONLY support linking libraries that are NOT using exceptions
|
||||
#pragma detect_mismatch("ODR_violation_WIL_EXCEPTION_MODE_mismatch", "2")
|
||||
#endif
|
||||
|
||||
#if WIL_EXCEPTION_MODE == 1 && !defined(WIL_ENABLE_EXCEPTIONS)
|
||||
#error Must enable exceptions when WIL_EXCEPTION_MODE == 1
|
||||
#endif
|
||||
|
||||
// block for documentation only
|
||||
#if defined(WIL_DOXYGEN)
|
||||
/** This define can be explicitly set to disable exception usage within wil.
|
||||
Normally this define is never needed as the WIL_ENABLE_EXCEPTIONS macro is enabled automatically by looking
|
||||
at _CPPUNWIND. If your code compiles with exceptions enabled, but does not want to enable the exception-based
|
||||
classes and methods from WIL, define this macro ahead of including the first WIL header. */
|
||||
#define WIL_SUPPRESS_EXCEPTIONS
|
||||
|
||||
/** This define can be explicitly set to lock the process exception mode to WIL_ENABLE_EXCEPTIONS.
|
||||
Locking the exception mode provides optimizations to exception barriers, staging hooks and DLL load costs as it eliminates the need to
|
||||
do copy-on-write initialization of various function pointers and the necessary indirection that's done within WIL to avoid ODR violations
|
||||
when linking libraries together with different exception handling semantics. */
|
||||
#define WIL_LOCK_EXCEPTION_MODE
|
||||
|
||||
/** This define explicit sets the exception mode for the process to control optimizations.
|
||||
Three exception modes are available:
|
||||
0) This is the default. This enables a binary to link both exception-based and non-exception based libraries together that
|
||||
use WIL. This adds overhead to exception barriers, DLL copy on write pages and indirection through function pointers to avoid ODR
|
||||
violations when linking libraries together with different exception handling semantics.
|
||||
1) Prefer this setting when it can be used. This locks the binary to only supporting libraries which were built with exceptions enabled.
|
||||
2) This locks the binary to libraries built without exceptions. */
|
||||
#define WIL_EXCEPTION_MODE
|
||||
#endif
|
||||
|
||||
#if (__cplusplus >= 201703) || (_MSVC_LANG >= 201703)
|
||||
#define WIL_HAS_CXX_17 1
|
||||
#else
|
||||
#define WIL_HAS_CXX_17 0
|
||||
#endif
|
||||
|
||||
// Until we'll have C++17 enabled in our code base, we're falling back to SAL
|
||||
#define WI_NODISCARD __WI_LIBCPP_NODISCARD_ATTRIBUTE
|
||||
|
||||
#define __R_ENABLE_IF_IS_CLASS(ptrType) wistd::enable_if_t<wistd::is_class<ptrType>::value, void*> = nullptr
|
||||
#define __R_ENABLE_IF_IS_NOT_CLASS(ptrType) wistd::enable_if_t<!wistd::is_class<ptrType>::value, void*> = nullptr
|
||||
|
||||
//! @defgroup bitwise Bitwise Inspection and Manipulation
|
||||
//! Bitwise helpers to improve readability and reduce the error rate of bitwise operations.
|
||||
@ -612,10 +613,10 @@ namespace wil
|
||||
}
|
||||
|
||||
template <>
|
||||
_Post_satisfies_(return == !!val)
|
||||
_Post_satisfies_(return == (val != 0))
|
||||
__forceinline constexpr bool verify_bool<unsigned char>(unsigned char val)
|
||||
{
|
||||
return !!val;
|
||||
return (val != 0);
|
||||
}
|
||||
|
||||
/** Verify that `val` is a Win32 BOOL value.
|
||||
@ -651,16 +652,62 @@ namespace wil
|
||||
~~~~
|
||||
RETURN_HR_IF(static_cast<HRESULT>(UIA_E_NOTSUPPORTED), (patternId != UIA_DragPatternId));
|
||||
~~~~
|
||||
@param val The HRESULT returning expression
|
||||
@param hr The HRESULT returning expression
|
||||
@return An HRESULT representing the evaluation of `val`. */
|
||||
template <typename T>
|
||||
_Post_satisfies_(return == hr)
|
||||
inline constexpr long verify_hresult(T hr)
|
||||
{
|
||||
// Note: Written in terms of 'int' as HRESULT is actually: typedef _Return_type_success_(return >= 0) long HRESULT
|
||||
// Note: Written in terms of 'long' as HRESULT is actually: typedef _Return_type_success_(return >= 0) long HRESULT
|
||||
static_assert(wistd::is_same<T, long>::value, "Wrong Type: HRESULT expected");
|
||||
return hr;
|
||||
}
|
||||
|
||||
/** Verify that `status` is an NTSTATUS value.
|
||||
Other types will generate an intentional compilation error. Note that this will accept any `long` value as that is the
|
||||
underlying typedef behind NTSTATUS.
|
||||
//!
|
||||
Note that occasionally you might run into an NTSTATUS which is directly defined with a #define, such as:
|
||||
~~~~
|
||||
#define STATUS_NOT_SUPPORTED 0x1
|
||||
~~~~
|
||||
Though this looks like an `NTSTATUS`, this is actually an `unsigned long` (the hex specification forces this). When
|
||||
these are encountered and they are NOT in the public SDK (have not yet shipped to the public), then you should change
|
||||
their definition to match the manner in which `NTSTATUS` constants are defined in ntstatus.h:
|
||||
~~~~
|
||||
#define STATUS_NOT_SUPPORTED ((NTSTATUS)0xC00000BBL)
|
||||
~~~~
|
||||
When these are encountered in the public SDK, their type should not be changed and you should use a static_cast
|
||||
to use this value in a macro that utilizes `verify_ntstatus`, for example:
|
||||
~~~~
|
||||
NT_RETURN_IF_FALSE(static_cast<NTSTATUS>(STATUS_NOT_SUPPORTED), (dispatch->Version == HKE_V1_0));
|
||||
~~~~
|
||||
@param status The NTSTATUS returning expression
|
||||
@return An NTSTATUS representing the evaluation of `val`. */
|
||||
template <typename T>
|
||||
_Post_satisfies_(return == status)
|
||||
inline long verify_ntstatus(T status)
|
||||
{
|
||||
// Note: Written in terms of 'long' as NTSTATUS is actually: typedef _Return_type_success_(return >= 0) long NTSTATUS
|
||||
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
|
||||
@ -706,31 +753,31 @@ namespace wil
|
||||
template <>
|
||||
struct variable_size<1>
|
||||
{
|
||||
typedef unsigned char type;
|
||||
using type = unsigned char;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct variable_size<2>
|
||||
{
|
||||
typedef unsigned short type;
|
||||
using type = unsigned short;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct variable_size<4>
|
||||
{
|
||||
typedef unsigned long type;
|
||||
using type = unsigned long;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct variable_size<8>
|
||||
{
|
||||
typedef unsigned long long type;
|
||||
using type = unsigned long long;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct variable_size_mapping
|
||||
{
|
||||
typedef typename variable_size<sizeof(T)>::type type;
|
||||
using type = typename variable_size<sizeof(T)>::type;
|
||||
};
|
||||
} // details
|
||||
/// @endcond
|
||||
@ -739,6 +786,10 @@ namespace wil
|
||||
This allows code to generically convert any enum class to it's corresponding underlying type. */
|
||||
template <typename T>
|
||||
using integral_from_enum = typename details::variable_size_mapping<T>::type;
|
||||
|
||||
//! Declares a name that intentionally hides a name from an outer scope.
|
||||
//! Use this to prevent accidental use of a parameter or lambda captured variable.
|
||||
using hide_name = void(struct hidden_name);
|
||||
} // wil
|
||||
|
||||
#pragma warning(pop)
|
||||
|
173
Externals/WIL/include/wil/cppwinrt.h
vendored
173
Externals/WIL/include/wil/cppwinrt.h
vendored
@ -14,6 +14,7 @@
|
||||
#include "common.h"
|
||||
#include <windows.h>
|
||||
#include <unknwn.h>
|
||||
#include <inspectable.h>
|
||||
#include <hstring.h>
|
||||
|
||||
// WIL and C++/WinRT use two different exception types for communicating HRESULT failures. Thus, both libraries need to
|
||||
@ -27,18 +28,43 @@
|
||||
namespace wil::details
|
||||
{
|
||||
// Since the C++/WinRT version macro is a string...
|
||||
inline constexpr int major_version_from_string(const char* versionString)
|
||||
// For example: "2.0.221104.6"
|
||||
inline constexpr int version_from_string(const char* versionString)
|
||||
{
|
||||
int result = 0;
|
||||
auto str = versionString;
|
||||
while ((*str >= '0') && (*str <= '9'))
|
||||
while ((*versionString >= '0') && (*versionString <= '9'))
|
||||
{
|
||||
result = result * 10 + (*str - '0');
|
||||
++str;
|
||||
result = result * 10 + (*versionString - '0');
|
||||
++versionString;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline constexpr int major_version_from_string(const char* versionString)
|
||||
{
|
||||
return version_from_string(versionString);
|
||||
}
|
||||
|
||||
inline constexpr int minor_version_from_string(const char* versionString)
|
||||
{
|
||||
int dotCount = 0;
|
||||
while ((*versionString != '\0'))
|
||||
{
|
||||
if (*versionString == '.')
|
||||
{
|
||||
++dotCount;
|
||||
}
|
||||
|
||||
++versionString;
|
||||
if (dotCount == 2)
|
||||
{
|
||||
return version_from_string(versionString);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
@ -74,6 +100,9 @@ static_assert(::wil::details::major_version_from_string(CPPWINRT_VERSION) >= 2,
|
||||
// use it unless the version of C++/WinRT is high enough
|
||||
extern std::int32_t(__stdcall* winrt_to_hresult_handler)(void*) noexcept;
|
||||
|
||||
// The same is true with this function pointer as well, except that the version must be 2.X or higher.
|
||||
extern void(__stdcall* winrt_throw_hresult_handler)(uint32_t, char const*, char const*, void*, winrt::hresult const) noexcept;
|
||||
|
||||
/// @cond
|
||||
namespace wil::details
|
||||
{
|
||||
@ -108,7 +137,7 @@ namespace wil::details
|
||||
catch (const winrt::hresult_error& exception)
|
||||
{
|
||||
MaybeGetExceptionString(exception, debugString, debugStringChars);
|
||||
return exception.code().value;
|
||||
return exception.to_abi();
|
||||
}
|
||||
catch (const std::bad_alloc& exception)
|
||||
{
|
||||
@ -149,7 +178,7 @@ namespace wil::details
|
||||
catch (const winrt::hresult_error& exception)
|
||||
{
|
||||
MaybeGetExceptionString(exception, debugString, debugStringChars);
|
||||
return exception.code().value;
|
||||
return exception.to_abi();
|
||||
}
|
||||
catch (const std::bad_alloc& exception)
|
||||
{
|
||||
@ -192,6 +221,12 @@ namespace wil
|
||||
return static_cast<std::int32_t>(details::ReportFailure_CaughtException<FailureType::Return>(__R_DIAGNOSTICS_RA(DiagnosticsInfo{}, returnAddress)));
|
||||
}
|
||||
|
||||
inline void __stdcall winrt_throw_hresult(uint32_t lineNumber, char const* fileName, char const* functionName, void* returnAddress, winrt::hresult const result) noexcept
|
||||
{
|
||||
void* callerReturnAddress{nullptr}; PCSTR code{nullptr};
|
||||
wil::details::ReportFailure_Hr<FailureType::Log>(__R_FN_CALL_FULL __R_COMMA result);
|
||||
}
|
||||
|
||||
inline void WilInitialize_CppWinRT()
|
||||
{
|
||||
details::g_pfnResultFromCaughtException_CppWinRt = details::ResultFromCaughtException_CppWinRt;
|
||||
@ -199,9 +234,15 @@ namespace wil
|
||||
{
|
||||
WI_ASSERT(winrt_to_hresult_handler == nullptr);
|
||||
winrt_to_hresult_handler = winrt_to_hresult;
|
||||
|
||||
if constexpr (details::minor_version_from_string(CPPWINRT_VERSION) >= 210122)
|
||||
{
|
||||
WI_ASSERT(winrt_throw_hresult_handler == nullptr);
|
||||
winrt_throw_hresult_handler = winrt_throw_hresult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @cond
|
||||
namespace details
|
||||
{
|
||||
@ -236,6 +277,11 @@ namespace wil
|
||||
return static_cast<HSTRING>(winrt::get_abi(object));
|
||||
}
|
||||
|
||||
inline auto str_raw_ptr(const winrt::hstring& str) noexcept
|
||||
{
|
||||
return str.c_str();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto put_abi(T& object) noexcept
|
||||
{
|
||||
@ -246,6 +292,117 @@ namespace wil
|
||||
{
|
||||
return reinterpret_cast<HSTRING*>(winrt::put_abi(object));
|
||||
}
|
||||
|
||||
inline ::IUnknown* com_raw_ptr(const winrt::Windows::Foundation::IUnknown& ptr) noexcept
|
||||
{
|
||||
return static_cast<::IUnknown*>(winrt::get_abi(ptr));
|
||||
}
|
||||
|
||||
// Needed to power wil::cx_object_from_abi that requires IInspectable
|
||||
inline ::IInspectable* com_raw_ptr(const winrt::Windows::Foundation::IInspectable& ptr) noexcept
|
||||
{
|
||||
return static_cast<::IInspectable*>(winrt::get_abi(ptr));
|
||||
}
|
||||
|
||||
// Taken from the docs.microsoft.com article
|
||||
template <typename T>
|
||||
T convert_from_abi(::IUnknown* from)
|
||||
{
|
||||
T to{ nullptr }; // `T` is a projected type.
|
||||
winrt::check_hresult(from->QueryInterface(winrt::guid_of<T>(), winrt::put_abi(to)));
|
||||
return to;
|
||||
}
|
||||
|
||||
// For obtaining an object from an interop method on the factory. Example:
|
||||
// winrt::InputPane inputPane = wil::capture_interop<winrt::InputPane>(&IInputPaneInterop::GetForWindow, hwnd);
|
||||
// If the method produces something different from the factory type:
|
||||
// winrt::IAsyncAction action = wil::capture_interop<winrt::IAsyncAction, winrt::AccountsSettingsPane>(&IAccountsSettingsPaneInterop::ShowAddAccountForWindow, hwnd);
|
||||
template<typename WinRTResult, typename WinRTFactory = WinRTResult, typename Interface, typename... InterfaceArgs, typename... Args>
|
||||
auto capture_interop(HRESULT(__stdcall Interface::* method)(InterfaceArgs...), Args&&... args)
|
||||
{
|
||||
auto interop = winrt::get_activation_factory<WinRTFactory, Interface>();
|
||||
return winrt::capture<WinRTResult>(interop, method, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// For obtaining an object from an interop method on an instance. Example:
|
||||
// winrt::UserActivitySession session = wil::capture_interop<winrt::UserActivitySession>(activity, &IUserActivityInterop::CreateSessionForWindow, hwnd);
|
||||
template<typename WinRTResult, typename Interface, typename... InterfaceArgs, typename... Args>
|
||||
auto capture_interop(winrt::Windows::Foundation::IUnknown const& o, HRESULT(__stdcall Interface::* method)(InterfaceArgs...), Args&&... args)
|
||||
{
|
||||
return winrt::capture<WinRTResult>(o.as<Interface>(), method, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/** Holds a reference to the host C++/WinRT module to prevent it from being unloaded.
|
||||
Normally, this is done by being in an IAsyncOperation coroutine or by holding a strong
|
||||
reference to a C++/WinRT object hosted in the same module, but if you have neither,
|
||||
you will need to hold a reference explicitly. For the WRL equivalent, see wrl_module_reference.
|
||||
|
||||
This can be used as a base, which permits EBO:
|
||||
~~~~
|
||||
struct NonWinrtObject : wil::winrt_module_reference
|
||||
{
|
||||
int value;
|
||||
};
|
||||
|
||||
// DLL will not be unloaded as long as NonWinrtObject is still alive.
|
||||
auto p = std::make_unique<NonWinrtObject>();
|
||||
~~~~
|
||||
|
||||
Or it can be used as a member (with [[no_unique_address]] to avoid
|
||||
occupying any memory):
|
||||
~~~~
|
||||
struct NonWinrtObject
|
||||
{
|
||||
int value;
|
||||
|
||||
[[no_unique_address]] wil::winrt_module_reference module_ref;
|
||||
};
|
||||
|
||||
// DLL will not be unloaded as long as NonWinrtObject is still alive.
|
||||
auto p = std::make_unique<NonWinrtObject>();
|
||||
~~~~
|
||||
|
||||
If using it to prevent the host DLL from unloading while a thread
|
||||
or threadpool work item is still running, create the object before
|
||||
starting the thread, and pass it to the thread. This avoids a race
|
||||
condition where the host DLL could get unloaded before the thread starts.
|
||||
~~~~
|
||||
std::thread([module_ref = wil::winrt_module_reference()]() { do_background_work(); });
|
||||
|
||||
// Don't do this (race condition)
|
||||
std::thread([]() { wil::winrt_module_reference module_ref; do_background_work(); }); // WRONG
|
||||
~~~~
|
||||
|
||||
Also useful in coroutines that neither capture DLL-hosted COM objects, nor are themselves
|
||||
DLL-hosted COM objects. (If the coroutine returns IAsyncAction or captures a get_strong()
|
||||
of its containing WinRT class, then the IAsyncAction or strong reference will itself keep
|
||||
a strong reference to the host module.)
|
||||
~~~~
|
||||
winrt::fire_and_forget ContinueBackgroundWork()
|
||||
{
|
||||
// prevent DLL from unloading while we are running on a background thread.
|
||||
// Do this before switching to the background thread.
|
||||
wil::winrt_module_reference module_ref;
|
||||
|
||||
co_await winrt::resume_background();
|
||||
do_background_work();
|
||||
};
|
||||
~~~~
|
||||
*/
|
||||
struct [[nodiscard]] winrt_module_reference
|
||||
{
|
||||
winrt_module_reference()
|
||||
{
|
||||
++winrt::get_module_lock();
|
||||
}
|
||||
|
||||
winrt_module_reference(winrt_module_reference const&) : winrt_module_reference() {}
|
||||
|
||||
~winrt_module_reference()
|
||||
{
|
||||
--winrt::get_module_lock();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // __WIL_CPPWINRT_INCLUDED
|
||||
|
352
Externals/WIL/include/wil/cppwinrt_helpers.h
vendored
Normal file
352
Externals/WIL/include/wil/cppwinrt_helpers.h
vendored
Normal file
@ -0,0 +1,352 @@
|
||||
//*********************************************************
|
||||
//
|
||||
// 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_CPPWINRT_HELPERS_DEFINED
|
||||
#define __WIL_CPPWINRT_HELPERS_DEFINED
|
||||
|
||||
/// @cond
|
||||
namespace wil::details
|
||||
{
|
||||
struct dispatcher_RunAsync
|
||||
{
|
||||
template<typename Dispatcher, typename... Args>
|
||||
static void Schedule(Dispatcher const& dispatcher, Args&&... args)
|
||||
{
|
||||
dispatcher.RunAsync(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
struct dispatcher_TryEnqueue
|
||||
{
|
||||
template<typename Dispatcher, typename... Args>
|
||||
static void Schedule(Dispatcher const& dispatcher, Args&&... args)
|
||||
{
|
||||
dispatcher.TryEnqueue(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Dispatcher> struct dispatcher_traits;
|
||||
}
|
||||
|
||||
#if defined(_RESUMABLE_FUNCTIONS_SUPPORTED)
|
||||
#include <experimental/coroutine>
|
||||
namespace wil::details
|
||||
{
|
||||
template<typename T = void> using coroutine_handle = std::experimental::coroutine_handle<T>;
|
||||
}
|
||||
#elif defined(__cpp_lib_coroutine) && (__cpp_lib_coroutine >= 201902L)
|
||||
#include <coroutine>
|
||||
namespace wil::details
|
||||
{
|
||||
template<typename T = void> using coroutine_handle = std::coroutine_handle<T>;
|
||||
}
|
||||
#endif
|
||||
/// @endcond
|
||||
|
||||
#if defined(_RESUMABLE_FUNCTIONS_SUPPORTED) || (defined(__cpp_lib_coroutine) && (__cpp_lib_coroutine >= 201902L))
|
||||
/// @cond
|
||||
namespace wil::details
|
||||
{
|
||||
struct dispatched_handler_state
|
||||
{
|
||||
details::coroutine_handle<> handle{};
|
||||
bool orphaned = false;
|
||||
};
|
||||
|
||||
struct dispatcher_handler
|
||||
{
|
||||
dispatcher_handler(dispatched_handler_state* state) : m_state(state) { }
|
||||
dispatcher_handler(dispatcher_handler&& other) noexcept : m_state(std::exchange(other.m_state, {})) {}
|
||||
|
||||
~dispatcher_handler()
|
||||
{
|
||||
if (m_state && m_state->handle)
|
||||
{
|
||||
m_state->orphaned = true;
|
||||
Complete();
|
||||
}
|
||||
}
|
||||
void operator()()
|
||||
{
|
||||
Complete();
|
||||
}
|
||||
|
||||
void Complete()
|
||||
{
|
||||
auto state = std::exchange(m_state, nullptr);
|
||||
std::exchange(state->handle, {}).resume();
|
||||
}
|
||||
|
||||
dispatched_handler_state* m_state;
|
||||
};
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
namespace wil
|
||||
{
|
||||
//! Resumes coroutine execution on the thread associated with the dispatcher, or throws
|
||||
//! an exception (from an arbitrary thread) if unable. Supported dispatchers are
|
||||
//! Windows.System.DispatcherQueue, Microsoft.System.DispatcherQueue,
|
||||
//! Microsoft.UI.Dispatching.DispatcherQueue, and Windows.UI.Core.CoreDispatcher,
|
||||
//! but you must include the corresponding <winrt/Namespace.h> header before including
|
||||
//! wil\cppwinrt_helpers.h. It is okay to include wil\cppwinrt_helpers.h multiple times:
|
||||
//! support will be enabled for any winrt/Namespace.h headers that were included since
|
||||
//! the previous inclusion of wil\cppwinrt_headers.h.
|
||||
template<typename Dispatcher>
|
||||
[[nodiscard]] auto resume_foreground(Dispatcher const& dispatcher,
|
||||
typename details::dispatcher_traits<Dispatcher>::Priority priority = details::dispatcher_traits<Dispatcher>::Priority::Normal)
|
||||
{
|
||||
using Traits = details::dispatcher_traits<Dispatcher>;
|
||||
using Priority = typename Traits::Priority;
|
||||
using Handler = typename Traits::Handler;
|
||||
|
||||
struct awaitable
|
||||
{
|
||||
awaitable(Dispatcher const& dispatcher, Priority priority) noexcept :
|
||||
m_dispatcher(dispatcher),
|
||||
m_priority(priority)
|
||||
{
|
||||
}
|
||||
bool await_ready() const noexcept { return false; }
|
||||
|
||||
void await_suspend(details::coroutine_handle<> handle)
|
||||
{
|
||||
m_state.handle = handle;
|
||||
Handler handler{ details::dispatcher_handler(&m_state) };
|
||||
try
|
||||
{
|
||||
// The return value of Schedule is not reliable. Use the dispatcher_handler destructor
|
||||
// to detect whether the work item failed to run.
|
||||
Traits::Scheduler::Schedule(m_dispatcher, m_priority, handler);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
m_state.handle = nullptr; // the exception will resume the coroutine, so the handler shouldn't do it
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void await_resume() const
|
||||
{
|
||||
if (m_state.orphaned)
|
||||
{
|
||||
throw winrt::hresult_error(static_cast<winrt::hresult>(0x800701ab)); // HRESULT_FROM_WIN32(ERROR_NO_TASK_QUEUE)
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Dispatcher const& m_dispatcher;
|
||||
Priority const m_priority;
|
||||
details::dispatched_handler_state m_state;
|
||||
};
|
||||
return awaitable{ dispatcher, priority };
|
||||
}
|
||||
}
|
||||
#endif // Coroutines are supported
|
||||
|
||||
#endif // __WIL_CPPWINRT_HELPERS_DEFINED
|
||||
|
||||
/// @cond
|
||||
#if defined(WINRT_Windows_UI_Core_H) && !defined(__WIL_CPPWINRT_WINDOWS_UI_CORE_HELPERS)
|
||||
#define __WIL_CPPWINRT_WINDOWS_UI_CORE_HELPERS
|
||||
namespace wil::details
|
||||
{
|
||||
template<>
|
||||
struct dispatcher_traits<winrt::Windows::UI::Core::CoreDispatcher>
|
||||
{
|
||||
using Priority = winrt::Windows::UI::Core::CoreDispatcherPriority;
|
||||
using Handler = winrt::Windows::UI::Core::DispatchedHandler;
|
||||
using Scheduler = dispatcher_RunAsync;
|
||||
};
|
||||
}
|
||||
#endif // __WIL_CPPWINRT_WINDOWS_UI_CORE_HELPERS
|
||||
|
||||
#if defined(WINRT_Windows_System_H) && !defined(__WIL_CPPWINRT_WINDOWS_SYSTEM_HELPERS)
|
||||
#define __WIL_CPPWINRT_WINDOWS_SYSTEM_HELPERS
|
||||
namespace wil::details
|
||||
{
|
||||
template<>
|
||||
struct dispatcher_traits<winrt::Windows::System::DispatcherQueue>
|
||||
{
|
||||
using Priority = winrt::Windows::System::DispatcherQueuePriority;
|
||||
using Handler = winrt::Windows::System::DispatcherQueueHandler;
|
||||
using Scheduler = dispatcher_TryEnqueue;
|
||||
};
|
||||
}
|
||||
#endif // __WIL_CPPWINRT_WINDOWS_SYSTEM_HELPERS
|
||||
|
||||
#if defined(WINRT_Microsoft_System_H) && !defined(__WIL_CPPWINRT_MICROSOFT_SYSTEM_HELPERS)
|
||||
#define __WIL_CPPWINRT_MICROSOFT_SYSTEM_HELPERS
|
||||
namespace wil::details
|
||||
{
|
||||
template<>
|
||||
struct dispatcher_traits<winrt::Microsoft::System::DispatcherQueue>
|
||||
{
|
||||
using Priority = winrt::Microsoft::System::DispatcherQueuePriority;
|
||||
using Handler = winrt::Microsoft::System::DispatcherQueueHandler;
|
||||
using Scheduler = dispatcher_TryEnqueue;
|
||||
};
|
||||
}
|
||||
#endif // __WIL_CPPWINRT_MICROSOFT_SYSTEM_HELPERS
|
||||
|
||||
#if defined(WINRT_Microsoft_UI_Dispatching_H) && !defined(__WIL_CPPWINRT_MICROSOFT_UI_DISPATCHING_HELPERS)
|
||||
#define __WIL_CPPWINRT_MICROSOFT_UI_DISPATCHING_HELPERS
|
||||
namespace wil::details
|
||||
{
|
||||
template<>
|
||||
struct dispatcher_traits<winrt::Microsoft::UI::Dispatching::DispatcherQueue>
|
||||
{
|
||||
using Priority = winrt::Microsoft::UI::Dispatching::DispatcherQueuePriority;
|
||||
using Handler = winrt::Microsoft::UI::Dispatching::DispatcherQueueHandler;
|
||||
using Scheduler = dispatcher_TryEnqueue;
|
||||
};
|
||||
}
|
||||
#endif // __WIL_CPPWINRT_MICROSOFT_UI_DISPATCHING_HELPERS
|
||||
/// @endcond
|
||||
|
||||
#if defined(WINRT_Windows_Foundation_Collections_H) && !defined(__WIL_CPPWINRT_WINDOWS_FOUNDATION_COLLECTION_HELPERS)
|
||||
#define __WIL_CPPWINRT_WINDOWS_FOUNDATION_COLLECTION_HELPERS
|
||||
namespace wil
|
||||
{
|
||||
/// @cond
|
||||
namespace details
|
||||
{
|
||||
template<typename T> struct is_winrt_vector_like {
|
||||
private:
|
||||
template <typename U,
|
||||
typename = decltype(std::declval<U>().GetMany(std::declval<U>().Size(),
|
||||
winrt::array_view<decltype(std::declval<U>().GetAt(0))>{}))>
|
||||
static constexpr bool get_value(int) { return true; }
|
||||
template <typename> static constexpr bool get_value(...) { return false; }
|
||||
public:
|
||||
static constexpr bool value = get_value<T>(0);
|
||||
};
|
||||
|
||||
template<typename T> struct is_winrt_iterator_like {
|
||||
private:
|
||||
template <typename U,
|
||||
typename = decltype(std::declval<U>().GetMany(winrt::array_view<decltype(std::declval<U>().Current())>{}))>
|
||||
static constexpr bool get_value(int) { return true; }
|
||||
template <typename> static constexpr bool get_value(...) { return false; }
|
||||
public:
|
||||
static constexpr bool value = get_value<T>(0);
|
||||
};
|
||||
|
||||
template<typename T> constexpr T empty() noexcept
|
||||
{
|
||||
if constexpr (std::is_base_of_v<winrt::Windows::Foundation::IUnknown, T>)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
/** Converts C++ / WinRT vectors, iterators, and iterables to std::vector by requesting the
|
||||
collection's data in bulk. This can be more efficient in terms of IPC cost than iteratively
|
||||
processing the collection.
|
||||
~~~
|
||||
winrt::IVector<winrt::hstring> collection = GetCollection();
|
||||
std::vector<winrt::hstring> allData = wil::to_vector(collection); // read all data from collection
|
||||
for (winrt::hstring const& item : allData)
|
||||
{
|
||||
// use item
|
||||
}
|
||||
~~~
|
||||
Can be used for IVector<T>, IVectorView<T>, IIterable<T>, IIterator<T>, and any type or
|
||||
interface that C++/WinRT projects those interfaces for (PropertySet, IMap<T,K>, etc.)
|
||||
Iterable-only types fetch content in units of 64. When used with an iterator, the returned
|
||||
vector contains the iterator's current position and any others after it.
|
||||
*/
|
||||
template<typename TSrc> auto to_vector(TSrc const& src)
|
||||
{
|
||||
if constexpr (details::is_winrt_vector_like<TSrc>::value)
|
||||
{
|
||||
using T = decltype(src.GetAt(0));
|
||||
std::vector<T> result;
|
||||
if (auto expected = src.Size())
|
||||
{
|
||||
result.resize(expected + 1, details::empty<T>());
|
||||
auto actual = src.GetMany(0, result);
|
||||
if (actual > expected)
|
||||
{
|
||||
throw winrt::hresult_changed_state();
|
||||
}
|
||||
result.resize(actual);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else if constexpr (details::is_winrt_iterator_like<TSrc>::value)
|
||||
{
|
||||
using T = decltype(src.Current());
|
||||
std::vector<T> result;
|
||||
constexpr uint32_t chunkSize = 64;
|
||||
while (true)
|
||||
{
|
||||
auto const lastSize = result.size();
|
||||
result.resize(lastSize + chunkSize, details::empty<T>());
|
||||
auto fetched = src.GetMany({result.data() + lastSize, result.data() + lastSize + chunkSize });
|
||||
if (fetched < chunkSize)
|
||||
{
|
||||
result.resize(lastSize + fetched);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return to_vector(src.First());
|
||||
}
|
||||
}
|
||||
}
|
||||
#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
|
74
Externals/WIL/include/wil/cppwinrt_wrl.h
vendored
Normal file
74
Externals/WIL/include/wil/cppwinrt_wrl.h
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
//*********************************************************
|
||||
//
|
||||
// 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_CPPWINRT_WRL_INCLUDED
|
||||
#define __WIL_CPPWINRT_WRL_INCLUDED
|
||||
|
||||
#include "cppwinrt.h"
|
||||
#include <winrt\base.h>
|
||||
|
||||
#include "result_macros.h"
|
||||
#include <wrl\module.h>
|
||||
|
||||
// wil::wrl_factory_for_winrt_com_class provides interopability between a
|
||||
// C++/WinRT class and the WRL Module system, allowing the winrt class to be
|
||||
// CoCreatable.
|
||||
//
|
||||
// Usage:
|
||||
// - In your cpp, add:
|
||||
// CoCreatableCppWinRtClass(className)
|
||||
//
|
||||
// - In the dll.cpp (or equivalent) for the module containing your class, add:
|
||||
// CoCreatableClassWrlCreatorMapInclude(className)
|
||||
//
|
||||
namespace wil
|
||||
{
|
||||
namespace details
|
||||
{
|
||||
template <typename TCppWinRTClass>
|
||||
class module_count_wrapper : public TCppWinRTClass
|
||||
{
|
||||
public:
|
||||
module_count_wrapper()
|
||||
{
|
||||
if (auto modulePtr = ::Microsoft::WRL::GetModuleBase())
|
||||
{
|
||||
modulePtr->IncrementObjectCount();
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~module_count_wrapper()
|
||||
{
|
||||
if (auto modulePtr = ::Microsoft::WRL::GetModuleBase())
|
||||
{
|
||||
modulePtr->DecrementObjectCount();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <typename TCppWinRTClass>
|
||||
class wrl_factory_for_winrt_com_class : public ::Microsoft::WRL::ClassFactory<>
|
||||
{
|
||||
public:
|
||||
IFACEMETHODIMP CreateInstance(_In_opt_ ::IUnknown* unknownOuter, REFIID riid, _COM_Outptr_ void **object) noexcept try
|
||||
{
|
||||
*object = nullptr;
|
||||
RETURN_HR_IF(CLASS_E_NOAGGREGATION, unknownOuter != nullptr);
|
||||
|
||||
return winrt::make<details::module_count_wrapper<TCppWinRTClass>>().as(riid, object);
|
||||
}
|
||||
CATCH_RETURN()
|
||||
};
|
||||
}
|
||||
|
||||
#define CoCreatableCppWinRtClass(className) CoCreatableClassWithFactory(className, ::wil::wrl_factory_for_winrt_com_class<className>)
|
||||
|
||||
#endif // __WIL_CPPWINRT_WRL_INCLUDED
|
192
Externals/WIL/include/wil/filesystem.h
vendored
192
Externals/WIL/include/wil/filesystem.h
vendored
@ -31,6 +31,7 @@ namespace wil
|
||||
return wcsncmp(path, L"\\\\?\\", 4) == 0;
|
||||
}
|
||||
|
||||
#if (_WIN32_WINNT >= _WIN32_WINNT_WIN7)
|
||||
//! Find the last segment of a path. Matches the behavior of shlwapi!PathFindFileNameW()
|
||||
//! note, does not support streams being specified like PathFindFileNameW(), is that a bug or a feature?
|
||||
inline PCWSTR find_last_path_segment(_In_ PCWSTR path)
|
||||
@ -51,6 +52,7 @@ namespace wil
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
//! Determine if the file name is one of the special "." or ".." names.
|
||||
inline bool path_is_dot_or_dotdot(_In_ PCWSTR fileName)
|
||||
@ -83,7 +85,7 @@ namespace wil
|
||||
return false;
|
||||
}
|
||||
|
||||
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
|
||||
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && (_WIN32_WINNT >= _WIN32_WINNT_WIN7)
|
||||
|
||||
// PathCch.h APIs are only in desktop API for now.
|
||||
|
||||
@ -111,7 +113,7 @@ namespace wil
|
||||
{
|
||||
if (::CreateDirectoryW(path, nullptr) == FALSE)
|
||||
{
|
||||
DWORD const lastError = ::GetLastError();
|
||||
DWORD lastError = ::GetLastError();
|
||||
if (lastError == ERROR_PATH_NOT_FOUND)
|
||||
{
|
||||
size_t parentLength;
|
||||
@ -120,9 +122,16 @@ namespace wil
|
||||
wistd::unique_ptr<wchar_t[]> parent(new (std::nothrow) wchar_t[parentLength + 1]);
|
||||
RETURN_IF_NULL_ALLOC(parent.get());
|
||||
RETURN_IF_FAILED(StringCchCopyNW(parent.get(), parentLength + 1, path, parentLength));
|
||||
CreateDirectoryDeepNoThrow(parent.get()); // recurs
|
||||
RETURN_IF_FAILED(CreateDirectoryDeepNoThrow(parent.get())); // recurs
|
||||
}
|
||||
if (::CreateDirectoryW(path, nullptr) == FALSE)
|
||||
{
|
||||
lastError = ::GetLastError();
|
||||
if (lastError != ERROR_ALREADY_EXISTS)
|
||||
{
|
||||
RETURN_WIN32(lastError);
|
||||
}
|
||||
}
|
||||
RETURN_IF_WIN32_BOOL_FALSE(::CreateDirectoryW(path, nullptr));
|
||||
}
|
||||
else if (lastError != ERROR_ALREADY_EXISTS)
|
||||
{
|
||||
@ -183,13 +192,53 @@ namespace wil
|
||||
enum class RemoveDirectoryOptions
|
||||
{
|
||||
None = 0,
|
||||
KeepRootDirectory = 0x1
|
||||
KeepRootDirectory = 0x1,
|
||||
RemoveReadOnly = 0x2,
|
||||
};
|
||||
DEFINE_ENUM_FLAG_OPERATORS(RemoveDirectoryOptions);
|
||||
|
||||
namespace details
|
||||
{
|
||||
// Reparse points should not be traversed in most recursive walks of the file system,
|
||||
// unless allowed through the appropriate reparse tag.
|
||||
inline bool CanRecurseIntoDirectory(const FILE_ATTRIBUTE_TAG_INFO& info)
|
||||
{
|
||||
return (WI_IsFlagSet(info.FileAttributes, FILE_ATTRIBUTE_DIRECTORY) &&
|
||||
(WI_IsFlagClear(info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT) ||
|
||||
(IsReparseTagDirectory(info.ReparseTag) || (info.ReparseTag == IO_REPARSE_TAG_WCI))));
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve a handle to a directory only if it is safe to recurse into.
|
||||
inline wil::unique_hfile TryCreateFileCanRecurseIntoDirectory(PCWSTR path, PWIN32_FIND_DATAW fileFindData, DWORD access = GENERIC_READ | /*DELETE*/ 0x00010000L, DWORD share = FILE_SHARE_READ)
|
||||
{
|
||||
wil::unique_hfile result(CreateFileW(path, access, share,
|
||||
nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr));
|
||||
if (result)
|
||||
{
|
||||
FILE_ATTRIBUTE_TAG_INFO fati;
|
||||
if (GetFileInformationByHandleEx(result.get(), FileAttributeTagInfo, &fati, sizeof(fati)) &&
|
||||
details::CanRecurseIntoDirectory(fati))
|
||||
{
|
||||
if (fileFindData)
|
||||
{
|
||||
// Refresh the found file's data now that we have secured the directory from external manipulation.
|
||||
fileFindData->dwFileAttributes = fati.FileAttributes;
|
||||
fileFindData->dwReserved0 = fati.ReparseTag;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.reset();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// If inputPath is a non-normalized name be sure to pass an extended length form to ensure
|
||||
// it can be addressed and deleted.
|
||||
inline HRESULT RemoveDirectoryRecursiveNoThrow(PCWSTR inputPath, RemoveDirectoryOptions options = RemoveDirectoryOptions::None) WI_NOEXCEPT
|
||||
inline HRESULT RemoveDirectoryRecursiveNoThrow(PCWSTR inputPath, RemoveDirectoryOptions options = RemoveDirectoryOptions::None, HANDLE deleteHandle = INVALID_HANDLE_VALUE) WI_NOEXCEPT
|
||||
{
|
||||
wil::unique_hlocal_string path;
|
||||
PATHCCH_OPTIONS combineOptions = PATHCCH_NONE;
|
||||
@ -228,14 +277,50 @@ namespace wil
|
||||
PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH | PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, &pathToDelete));
|
||||
if (WI_IsFlagSet(fd.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY))
|
||||
{
|
||||
RemoveDirectoryOptions localOptions = options;
|
||||
RETURN_IF_FAILED(RemoveDirectoryRecursiveNoThrow(pathToDelete.get(), WI_ClearFlag(localOptions, RemoveDirectoryOptions::KeepRootDirectory)));
|
||||
// Get a handle to the directory to delete, preventing it from being replaced to prevent writes which could be used
|
||||
// to bypass permission checks, and verify that it is not a name surrogate (e.g. symlink, mount point, etc).
|
||||
wil::unique_hfile recursivelyDeletableDirectoryHandle = TryCreateFileCanRecurseIntoDirectory(pathToDelete.get(), &fd);
|
||||
if (recursivelyDeletableDirectoryHandle)
|
||||
{
|
||||
RemoveDirectoryOptions localOptions = options;
|
||||
RETURN_IF_FAILED(RemoveDirectoryRecursiveNoThrow(pathToDelete.get(), WI_ClearFlag(localOptions, RemoveDirectoryOptions::KeepRootDirectory), recursivelyDeletableDirectoryHandle.get()));
|
||||
}
|
||||
else if (WI_IsFlagSet(fd.dwFileAttributes, FILE_ATTRIBUTE_REPARSE_POINT))
|
||||
{
|
||||
// This is a directory reparse point that should not be recursed. Delete it without traversing into it.
|
||||
RETURN_IF_WIN32_BOOL_FALSE(::RemoveDirectoryW(pathToDelete.get()));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Failed to grab a handle to the file or to read its attributes. This is not safe to recurse.
|
||||
RETURN_WIN32(::GetLastError());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// note: if pathToDelete is read-only this will fail, consider adding
|
||||
// RemoveDirectoryOptions::RemoveReadOnly to enable this behavior.
|
||||
RETURN_IF_WIN32_BOOL_FALSE(::DeleteFileW(pathToDelete.get()));
|
||||
// Try a DeleteFile. Some errors may be recoverable.
|
||||
if (!::DeleteFileW(pathToDelete.get()))
|
||||
{
|
||||
// Fail for anything other than ERROR_ACCESS_DENIED with option to RemoveReadOnly available
|
||||
bool potentiallyFixableReadOnlyProblem =
|
||||
WI_IsFlagSet(options, RemoveDirectoryOptions::RemoveReadOnly) && ::GetLastError() == ERROR_ACCESS_DENIED;
|
||||
RETURN_LAST_ERROR_IF(!potentiallyFixableReadOnlyProblem);
|
||||
|
||||
// Fail if the file does not have read-only set, likely just an ACL problem
|
||||
DWORD fileAttr = ::GetFileAttributesW(pathToDelete.get());
|
||||
RETURN_LAST_ERROR_IF(!WI_IsFlagSet(fileAttr, FILE_ATTRIBUTE_READONLY));
|
||||
|
||||
// Remove read-only flag, setting to NORMAL if completely empty
|
||||
WI_ClearFlag(fileAttr, FILE_ATTRIBUTE_READONLY);
|
||||
if (fileAttr == 0)
|
||||
{
|
||||
fileAttr = FILE_ATTRIBUTE_NORMAL;
|
||||
}
|
||||
|
||||
// Set the new attributes and try to delete the file again, returning any failure
|
||||
::SetFileAttributesW(pathToDelete.get(), fileAttr);
|
||||
RETURN_IF_WIN32_BOOL_FALSE(::DeleteFileW(pathToDelete.get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -252,7 +337,35 @@ namespace wil
|
||||
|
||||
if (WI_IsFlagClear(options, RemoveDirectoryOptions::KeepRootDirectory))
|
||||
{
|
||||
RETURN_IF_WIN32_BOOL_FALSE(::RemoveDirectoryW(path.get()));
|
||||
if (deleteHandle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
#if (NTDDI_VERSION >= NTDDI_WIN10_RS1)
|
||||
// DeleteFile and RemoveDirectory use POSIX delete, falling back to non-POSIX on most errors. Do the same here.
|
||||
FILE_DISPOSITION_INFO_EX fileInfoEx{};
|
||||
fileInfoEx.Flags = FILE_DISPOSITION_FLAG_DELETE | FILE_DISPOSITION_FLAG_POSIX_SEMANTICS;
|
||||
if (!SetFileInformationByHandle(deleteHandle, FileDispositionInfoEx, &fileInfoEx, sizeof(fileInfoEx)))
|
||||
{
|
||||
auto const err = ::GetLastError();
|
||||
// The real error we're looking for is STATUS_CANNOT_DELETE, but that's mapped to ERROR_ACCESS_DENIED.
|
||||
if (err != ERROR_ACCESS_DENIED)
|
||||
{
|
||||
#endif
|
||||
FILE_DISPOSITION_INFO fileInfo{};
|
||||
fileInfo.DeleteFile = TRUE;
|
||||
RETURN_IF_WIN32_BOOL_FALSE(SetFileInformationByHandle(deleteHandle, FileDispositionInfo, &fileInfo, sizeof(fileInfo)));
|
||||
#if (NTDDI_VERSION >= NTDDI_WIN10_RS1)
|
||||
}
|
||||
else
|
||||
{
|
||||
RETURN_WIN32(err);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
RETURN_IF_WIN32_BOOL_FALSE(::RemoveDirectoryW(path.get()));
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
@ -552,7 +665,7 @@ namespace wil
|
||||
OVERLAPPED m_overlapped{};
|
||||
TP_IO *m_tpIo = __nullptr;
|
||||
srwlock m_cancelLock;
|
||||
char m_readBuffer[4096]; // Consider alternative buffer sizes. With 512 byte buffer i was not able to observe overflow.
|
||||
unsigned char m_readBuffer[4096]; // Consider alternative buffer sizes. With 512 byte buffer i was not able to observe overflow.
|
||||
};
|
||||
|
||||
inline void delete_folder_change_reader_state(_In_opt_ folder_change_reader_state *storage) { delete storage; }
|
||||
@ -596,7 +709,6 @@ namespace wil
|
||||
auto readerState = static_cast<details::folder_change_reader_state *>(context);
|
||||
// WI_ASSERT(overlapped == &readerState->m_overlapped);
|
||||
|
||||
bool requeue = true;
|
||||
if (result == ERROR_SUCCESS)
|
||||
{
|
||||
for (auto const& info : create_next_entry_offset_iterator(reinterpret_cast<FILE_NOTIFY_INFORMATION *>(readerState->m_readBuffer)))
|
||||
@ -613,19 +725,17 @@ namespace wil
|
||||
}
|
||||
else
|
||||
{
|
||||
requeue = false;
|
||||
// No need to requeue
|
||||
return;
|
||||
}
|
||||
|
||||
if (requeue)
|
||||
// If the lock is held non-shared or the TP IO is nullptr, this
|
||||
// structure is being torn down. Otherwise, monitor for further
|
||||
// changes.
|
||||
auto autoLock = readerState->m_cancelLock.try_lock_shared();
|
||||
if (autoLock && readerState->m_tpIo)
|
||||
{
|
||||
// If the lock is held non-shared or the TP IO is nullptr, this
|
||||
// structure is being torn down. Otherwise, monitor for further
|
||||
// changes.
|
||||
auto autoLock = readerState->m_cancelLock.try_lock_shared();
|
||||
if (autoLock && readerState->m_tpIo)
|
||||
{
|
||||
readerState->StartIo(); // ignoring failure here
|
||||
}
|
||||
readerState->StartIo(); // ignoring failure here
|
||||
}
|
||||
}
|
||||
|
||||
@ -798,7 +908,7 @@ namespace wil
|
||||
|
||||
// Type unsafe version used in the implementation to avoid template bloat.
|
||||
inline HRESULT GetFileInfo(HANDLE fileHandle, FILE_INFO_BY_HANDLE_CLASS infoClass, size_t allocationSize,
|
||||
_Outptr_result_nullonfailure_ void **result)
|
||||
_Outptr_result_maybenull_ void **result)
|
||||
{
|
||||
*result = nullptr;
|
||||
|
||||
@ -875,6 +985,36 @@ namespace wil
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Verifies that the given file path is not a hard or a soft link. If the file is present at the path, returns
|
||||
// a handle to it without delete permissions to block an attacker from swapping the file.
|
||||
inline HRESULT CreateFileAndEnsureNotLinked(PCWSTR path, wil::unique_hfile& fileHandle)
|
||||
{
|
||||
// Open handles to the original path and to the final path and compare each file's information
|
||||
// to verify they are the same file. If they are different, the file is a soft link.
|
||||
fileHandle.reset(CreateFileW(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr));
|
||||
RETURN_LAST_ERROR_IF(!fileHandle);
|
||||
BY_HANDLE_FILE_INFORMATION fileInfo;
|
||||
RETURN_IF_WIN32_BOOL_FALSE(GetFileInformationByHandle(fileHandle.get(), &fileInfo));
|
||||
|
||||
// Open a handle without the reparse point flag to get the final path in case it is a soft link.
|
||||
wil::unique_hfile finalPathHandle(CreateFileW(path, 0, 0, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr));
|
||||
RETURN_LAST_ERROR_IF(!finalPathHandle);
|
||||
BY_HANDLE_FILE_INFORMATION finalFileInfo;
|
||||
RETURN_IF_WIN32_BOOL_FALSE(GetFileInformationByHandle(finalPathHandle.get(), &finalFileInfo));
|
||||
finalPathHandle.reset();
|
||||
|
||||
// The low and high indices and volume serial number uniquely identify a file. These must match if they are the same file.
|
||||
const bool isSoftLink =
|
||||
((fileInfo.nFileIndexLow != finalFileInfo.nFileIndexLow) ||
|
||||
(fileInfo.nFileIndexHigh != finalFileInfo.nFileIndexHigh) ||
|
||||
(fileInfo.dwVolumeSerialNumber != finalFileInfo.dwVolumeSerialNumber));
|
||||
|
||||
// Return failure if it is a soft link or a hard link (number of links greater than 1).
|
||||
RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME), (isSoftLink || fileInfo.nNumberOfLinks > 1));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#ifdef _CPPUNWIND
|
||||
/** Get file information for a fixed sized structure, throws on failure.
|
||||
~~~
|
||||
@ -902,7 +1042,7 @@ namespace wil
|
||||
return result;
|
||||
}
|
||||
#endif // _CPPUNWIND
|
||||
#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
|
||||
#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && (_WIN32_WINNT >= _WIN32_WINNT_WIN7)
|
||||
}
|
||||
|
||||
#endif // __WIL_FILESYSTEM_INCLUDED
|
||||
|
168
Externals/WIL/include/wil/nt_result_macros.h
vendored
Normal file
168
Externals/WIL/include/wil/nt_result_macros.h
vendored
Normal file
@ -0,0 +1,168 @@
|
||||
//*********************************************************
|
||||
//
|
||||
// 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_NT_RESULTMACROS_INCLUDED
|
||||
#define __WIL_NT_RESULTMACROS_INCLUDED
|
||||
|
||||
#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; } __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
|
||||
//*****************************************************************************
|
||||
|
||||
// Always returns a known result (NTSTATUS) - always logs failures
|
||||
#define NT_RETURN_NTSTATUS(status) __NT_RETURN_NTSTATUS(wil::verify_ntstatus(status), #status)
|
||||
|
||||
// Always returns a known failure (NTSTATUS) - always logs a var-arg message on failure
|
||||
#define NT_RETURN_NTSTATUS_MSG(status, fmt, ...) __NT_RETURN_NTSTATUS_MSG(wil::verify_ntstatus(status), #status, fmt, ##__VA_ARGS__)
|
||||
|
||||
// Conditionally returns failures (NTSTATUS) - always logs failures
|
||||
#define NT_RETURN_IF_NTSTATUS_FAILED(status) __WI_SUPPRESS_4127_S do { const auto __statusRet = wil::verify_ntstatus(status); if (FAILED_NTSTATUS(__statusRet)) { __NT_RETURN_NTSTATUS(__statusRet, #status); }} __WI_SUPPRESS_4127_E while ((void)0, 0)
|
||||
|
||||
// Conditionally returns failures (NTSTATUS) - always logs a var-arg message on failure
|
||||
#define NT_RETURN_IF_NTSTATUS_FAILED_MSG(status, fmt, ...) __WI_SUPPRESS_4127_S do { const auto __statusRet = wil::verify_ntstatus(status); if (FAILED_NTSTATUS(__statusRet)) { __NT_RETURN_NTSTATUS_MSG(__statusRet, #status, fmt, ##__VA_ARGS__); }} __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 NT_RETURN_CAUGHT_EXCEPTION() return __R_FN(Nt_Return_CaughtException)(__R_INFO_ONLY(nullptr))
|
||||
#define NT_RETURN_CAUGHT_EXCEPTION_MSG(fmt, ...) return __R_FN(Nt_Return_CaughtExceptionMsg)(__R_INFO(nullptr) fmt, ##__VA_ARGS__)
|
||||
|
||||
// Use these macros in place of a catch block to handle exceptions
|
||||
#define NT_CATCH_RETURN() catch (...) { NT_RETURN_CAUGHT_EXCEPTION(); }
|
||||
#define NT_CATCH_RETURN_MSG(fmt, ...) catch (...) { NT_RETURN_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); }
|
||||
|
||||
|
||||
namespace wil
|
||||
{
|
||||
//*****************************************************************************
|
||||
// Public Helpers that catch -- mostly only enabled when exceptions are enabled
|
||||
//*****************************************************************************
|
||||
|
||||
// StatusFromCaughtException 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 an NTSTATUS. If an exception is of an unrecognized type
|
||||
// the function will fail fast.
|
||||
//
|
||||
// try
|
||||
// {
|
||||
// // Code
|
||||
// }
|
||||
// catch (...)
|
||||
// {
|
||||
// status = wil::StatusFromCaughtException();
|
||||
// }
|
||||
_Always_(_Post_satisfies_(return < 0))
|
||||
__declspec(noinline) inline NTSTATUS StatusFromCaughtException() WI_NOEXCEPT
|
||||
{
|
||||
bool isNormalized = false;
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
if (details::g_pfnResultFromCaughtExceptionInternal)
|
||||
{
|
||||
status = details::g_pfnResultFromCaughtExceptionInternal(nullptr, 0, &isNormalized).status;
|
||||
}
|
||||
if (FAILED_NTSTATUS(status))
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
// Caller bug: an unknown exception was thrown
|
||||
__WIL_PRIVATE_FAIL_FAST_HR_IF(__HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION), g_fResultFailFastUnknownExceptions);
|
||||
return wil::details::HrToNtStatus(__HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION));
|
||||
}
|
||||
|
||||
namespace details
|
||||
{
|
||||
template<FailureType>
|
||||
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtException(__R_FN_PARAMS_FULL, SupportedExceptions supported = SupportedExceptions::Default);
|
||||
template<FailureType>
|
||||
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtExceptionMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList);
|
||||
|
||||
namespace __R_NS_NAME
|
||||
{
|
||||
#ifdef WIL_ENABLE_EXCEPTIONS
|
||||
__R_DIRECT_METHOD(NTSTATUS, Nt_Return_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT
|
||||
{
|
||||
__R_FN_LOCALS;
|
||||
return wil::details::ReportStatus_CaughtException<FailureType::Return>(__R_DIRECT_FN_CALL_ONLY);
|
||||
}
|
||||
|
||||
__R_DIRECT_METHOD(NTSTATUS, Nt_Return_CaughtExceptionMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
||||
{
|
||||
va_list argList;
|
||||
va_start(argList, formatString);
|
||||
__R_FN_LOCALS;
|
||||
return wil::details::ReportStatus_CaughtExceptionMsg<FailureType::Return>(__R_DIRECT_FN_CALL formatString, argList);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template<FailureType T>
|
||||
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtException(__R_FN_PARAMS_FULL, SupportedExceptions supported)
|
||||
{
|
||||
wchar_t message[2048];
|
||||
message[0] = L'\0';
|
||||
return ReportFailure_CaughtExceptionCommon<T>(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported).status;
|
||||
}
|
||||
|
||||
template<>
|
||||
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtException<FailureType::FailFast>(__R_FN_PARAMS_FULL, SupportedExceptions supported)
|
||||
{
|
||||
wchar_t message[2048];
|
||||
message[0] = L'\0';
|
||||
RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon<FailureType::FailFast>(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported).status);
|
||||
}
|
||||
|
||||
template<>
|
||||
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtException<FailureType::Exception>(__R_FN_PARAMS_FULL, SupportedExceptions supported)
|
||||
{
|
||||
wchar_t message[2048];
|
||||
message[0] = L'\0';
|
||||
RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon<FailureType::Exception>(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported).status);
|
||||
}
|
||||
|
||||
template<FailureType T>
|
||||
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtExceptionMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
|
||||
{
|
||||
// Pre-populate the buffer with our message, the exception message will be added to it...
|
||||
wchar_t message[2048];
|
||||
PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);
|
||||
StringCchCatW(message, ARRAYSIZE(message), L" -- ");
|
||||
return ReportFailure_CaughtExceptionCommon<T>(__R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default).status;
|
||||
}
|
||||
|
||||
template<>
|
||||
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtExceptionMsg<FailureType::FailFast>(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
|
||||
{
|
||||
// Pre-populate the buffer with our message, the exception message will be added to it...
|
||||
wchar_t message[2048];
|
||||
PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);
|
||||
StringCchCatW(message, ARRAYSIZE(message), L" -- ");
|
||||
RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon<FailureType::FailFast>(__R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default).status);
|
||||
}
|
||||
|
||||
template<>
|
||||
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtExceptionMsg<FailureType::Exception>(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
|
||||
{
|
||||
// Pre-populate the buffer with our message, the exception message will be added to it...
|
||||
wchar_t message[2048];
|
||||
PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);
|
||||
StringCchCatW(message, ARRAYSIZE(message), L" -- ");
|
||||
RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon<FailureType::Exception>(__R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default).status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __WIL_NT_RESULTMACROS_INCLUDED
|
1364
Externals/WIL/include/wil/resource.h
vendored
1364
Externals/WIL/include/wil/resource.h
vendored
File diff suppressed because it is too large
Load Diff
41
Externals/WIL/include/wil/result.h
vendored
41
Externals/WIL/include/wil/result.h
vendored
@ -252,7 +252,8 @@ namespace wil
|
||||
if (ProcessShutdownInProgress())
|
||||
{
|
||||
// There are no other threads to contend with.
|
||||
if (--m_refCount == 0)
|
||||
m_refCount = m_refCount - 1;
|
||||
if (m_refCount == 0)
|
||||
{
|
||||
m_data.ProcessShutdown();
|
||||
}
|
||||
@ -260,7 +261,8 @@ namespace wil
|
||||
else
|
||||
{
|
||||
auto lock = m_mutex.acquire();
|
||||
if (--m_refCount == 0)
|
||||
m_refCount = m_refCount - 1;
|
||||
if (m_refCount == 0)
|
||||
{
|
||||
// We must explicitly destroy our semaphores while holding the mutex
|
||||
m_value.Destroy();
|
||||
@ -281,7 +283,7 @@ namespace wil
|
||||
|
||||
const DWORD size = static_cast<DWORD>(sizeof(ProcessLocalStorageData<T>));
|
||||
wchar_t name[MAX_PATH];
|
||||
WI_VERIFY(SUCCEEDED(StringCchPrintfW(name, ARRAYSIZE(name), L"Local\\SM0:%d:%d:%hs", ::GetCurrentProcessId(), size, staticNameWithVersion)));
|
||||
WI_VERIFY(SUCCEEDED(StringCchPrintfW(name, ARRAYSIZE(name), L"Local\\SM0:%lu:%lu:%hs", ::GetCurrentProcessId(), size, staticNameWithVersion)));
|
||||
|
||||
unique_mutex_nothrow mutex;
|
||||
mutex.reset(::CreateMutexExW(nullptr, name, 0, MUTEX_ALL_ACCESS));
|
||||
@ -295,7 +297,7 @@ namespace wil
|
||||
if (pointer)
|
||||
{
|
||||
*data = reinterpret_cast<ProcessLocalStorageData<T>*>(pointer);
|
||||
(*data)->m_refCount++;
|
||||
(*data)->m_refCount = (*data)->m_refCount + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -312,13 +314,13 @@ namespace wil
|
||||
SemaphoreValue m_value;
|
||||
T m_data;
|
||||
|
||||
static HRESULT MakeAndInitialize(PCWSTR name, unique_mutex_nothrow&& mutex, ProcessLocalStorageData<T>** data)
|
||||
static HRESULT MakeAndInitialize(PCWSTR name, unique_mutex_nothrow&& mutex, _Outptr_result_nullonfailure_ ProcessLocalStorageData<T>** data)
|
||||
{
|
||||
*data = nullptr;
|
||||
|
||||
const DWORD size = static_cast<DWORD>(sizeof(ProcessLocalStorageData<T>));
|
||||
|
||||
unique_process_heap_ptr<ProcessLocalStorageData<T>> dataAlloc(static_cast<ProcessLocalStorageData<T>*>(::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, size)));
|
||||
unique_process_heap_ptr<ProcessLocalStorageData<T>> dataAlloc(static_cast<ProcessLocalStorageData<T>*>(details::ProcessHeapAlloc(HEAP_ZERO_MEMORY, size)));
|
||||
__WIL_PRIVATE_RETURN_IF_NULL_ALLOC(dataAlloc);
|
||||
|
||||
SemaphoreValue semaphoreValue;
|
||||
@ -406,10 +408,9 @@ namespace wil
|
||||
|
||||
if (shouldAllocate)
|
||||
{
|
||||
Node *pNew = reinterpret_cast<Node *>(::HeapAlloc(::GetProcessHeap(), 0, sizeof(Node)));
|
||||
if (pNew != nullptr)
|
||||
if (auto pNewRaw = details::ProcessHeapAlloc(0, sizeof(Node)))
|
||||
{
|
||||
new(pNew)Node{ threadId };
|
||||
auto pNew = new (pNewRaw) Node{ threadId };
|
||||
|
||||
Node *pFirst;
|
||||
do
|
||||
@ -428,7 +429,7 @@ namespace wil
|
||||
|
||||
struct Node
|
||||
{
|
||||
DWORD threadId;
|
||||
DWORD threadId = ULONG_MAX;
|
||||
Node* pNext = nullptr;
|
||||
T value{};
|
||||
};
|
||||
@ -487,7 +488,7 @@ namespace wil
|
||||
|
||||
if (!stringBuffer || (stringBufferSize < neededSize))
|
||||
{
|
||||
auto newBuffer = ::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, neededSize);
|
||||
auto newBuffer = details::ProcessHeapAlloc(HEAP_ZERO_MEMORY, neededSize);
|
||||
if (newBuffer)
|
||||
{
|
||||
::HeapFree(::GetProcessHeap(), 0, stringBuffer);
|
||||
@ -508,7 +509,7 @@ namespace wil
|
||||
}
|
||||
}
|
||||
|
||||
void Get(FailureInfo& info)
|
||||
void Get(FailureInfo& info) const
|
||||
{
|
||||
::ZeroMemory(&info, sizeof(info));
|
||||
|
||||
@ -565,7 +566,7 @@ namespace wil
|
||||
if (!errors && create)
|
||||
{
|
||||
const unsigned short errorCount = 5;
|
||||
errors = reinterpret_cast<ThreadLocalFailureInfo *>(::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, errorCount * sizeof(ThreadLocalFailureInfo)));
|
||||
errors = reinterpret_cast<ThreadLocalFailureInfo *>(details::ProcessHeapAlloc(HEAP_ZERO_MEMORY, errorCount * sizeof(ThreadLocalFailureInfo)));
|
||||
if (errors)
|
||||
{
|
||||
errorAllocCount = errorCount;
|
||||
@ -611,7 +612,7 @@ namespace wil
|
||||
errors[errorCurrentIndex].Set(info, ::InterlockedIncrementNoFence(failureSequenceId));
|
||||
}
|
||||
|
||||
bool GetLastError(_Inout_ wil::FailureInfo& info, unsigned int minSequenceId, HRESULT matchRequirement)
|
||||
bool GetLastError(_Inout_ wil::FailureInfo& info, unsigned int minSequenceId, HRESULT matchRequirement) const
|
||||
{
|
||||
if (!errors)
|
||||
{
|
||||
@ -678,7 +679,7 @@ namespace wil
|
||||
// NOTE: FailureType::Log as it's only informative (no action) and SupportedExceptions::All as it's not a barrier, only recognition.
|
||||
wchar_t message[2048];
|
||||
message[0] = L'\0';
|
||||
const HRESULT hr = details::ReportFailure_CaughtExceptionCommon<FailureType::Log>(__R_DIAGNOSTICS_RA(source, returnAddress), message, ARRAYSIZE(message), SupportedExceptions::All);
|
||||
const HRESULT hr = details::ReportFailure_CaughtExceptionCommon<FailureType::Log>(__R_DIAGNOSTICS_RA(source, returnAddress), message, ARRAYSIZE(message), SupportedExceptions::All).hr;
|
||||
|
||||
// Now that the exception was logged, we should be able to fetch it.
|
||||
return GetLastError(info, minSequenceId, hr);
|
||||
@ -958,7 +959,7 @@ namespace wil
|
||||
m_ppThreadList = nullptr;
|
||||
}
|
||||
|
||||
bool IsWatching()
|
||||
bool IsWatching() const
|
||||
{
|
||||
return (m_threadId != 0);
|
||||
}
|
||||
@ -1044,7 +1045,9 @@ namespace wil
|
||||
|
||||
if (g_pfnTelemetryCallback != nullptr)
|
||||
{
|
||||
g_pfnTelemetryCallback(reportedTelemetry, *pFailure);
|
||||
// If the telemetry was requested to be suppressed,
|
||||
// pretend like it has already been reported to the fallback callback
|
||||
g_pfnTelemetryCallback(reportedTelemetry || WI_IsFlagSet(pFailure->flags, FailureFlags::RequestSuppressTelemetry), *pFailure);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1079,7 +1082,7 @@ namespace wil
|
||||
{
|
||||
}
|
||||
|
||||
bool NotifyFailure(FailureInfo const &failure) WI_NOEXCEPT
|
||||
bool NotifyFailure(FailureInfo const &failure) WI_NOEXCEPT override
|
||||
{
|
||||
return m_errorFunction(failure);
|
||||
}
|
||||
@ -1251,7 +1254,7 @@ namespace wil
|
||||
return (FAILED(m_failure.GetFailureInfo().hr) ? &(m_failure.GetFailureInfo()) : nullptr);
|
||||
}
|
||||
|
||||
bool NotifyFailure(FailureInfo const &failure) WI_NOEXCEPT
|
||||
bool NotifyFailure(FailureInfo const &failure) WI_NOEXCEPT override
|
||||
{
|
||||
// When we "cache" a failure, we bias towards trying to find the origin of the last HRESULT
|
||||
// generated, so we ignore subsequent failures on the same error code (assuming propagation).
|
||||
|
678
Externals/WIL/include/wil/result_macros.h
vendored
678
Externals/WIL/include/wil/result_macros.h
vendored
File diff suppressed because it is too large
Load Diff
35
Externals/WIL/include/wil/result_originate.h
vendored
35
Externals/WIL/include/wil/result_originate.h
vendored
@ -31,7 +31,6 @@
|
||||
#include "com.h"
|
||||
#include <roerrorapi.h>
|
||||
|
||||
#ifndef __cplusplus_winrt // The CX runtime likes to originate errors already so we would conflict with them.
|
||||
namespace wil
|
||||
{
|
||||
namespace details
|
||||
@ -82,6 +81,36 @@ namespace wil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This method will check for the presence of stowed exception data on the current thread. If such data exists, and the HRESULT
|
||||
// matches the current failure, then we will call RoFailFastWithErrorContext. RoFailFastWithErrorContext in this situation will
|
||||
// result in -VASTLY- improved crash bucketing. It is hard to express just how much better. In other cases we just return and
|
||||
// the calling method fails fast the same way it always has.
|
||||
inline void __stdcall FailfastWithContextCallback(wil::FailureInfo const& failure) WI_NOEXCEPT
|
||||
{
|
||||
wil::com_ptr_nothrow<IRestrictedErrorInfo> restrictedErrorInformation;
|
||||
if (GetRestrictedErrorInfo(&restrictedErrorInformation) == S_OK)
|
||||
{
|
||||
wil::unique_bstr descriptionUnused;
|
||||
HRESULT existingHr = failure.hr;
|
||||
wil::unique_bstr restrictedDescriptionUnused;
|
||||
wil::unique_bstr capabilitySidUnused;
|
||||
if (SUCCEEDED(restrictedErrorInformation->GetErrorDetails(&descriptionUnused, &existingHr, &restrictedDescriptionUnused, &capabilitySidUnused)) &&
|
||||
(existingHr == failure.hr))
|
||||
{
|
||||
// GetRestrictedErrorInfo returns ownership of the error information. We want it to be available for RoFailFastWithErrorContext
|
||||
// so we must restore it via SetRestrictedErrorInfo first.
|
||||
SetRestrictedErrorInfo(restrictedErrorInformation.get());
|
||||
RoFailFastWithErrorContext(existingHr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The error didn't match the current failure. Put it back in thread-local storage even though we aren't failing fast
|
||||
// in this method, so it is available in the debugger just-in-case.
|
||||
SetRestrictedErrorInfo(restrictedErrorInformation.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace details
|
||||
} // namespace wil
|
||||
|
||||
@ -89,8 +118,8 @@ namespace wil
|
||||
WI_HEADER_INITITALIZATION_FUNCTION(ResultStowedExceptionInitialize, []
|
||||
{
|
||||
::wil::SetOriginateErrorCallback(::wil::details::RaiseRoOriginateOnWilExceptions);
|
||||
::wil::SetFailfastWithContextCallback(::wil::details::FailfastWithContextCallback);
|
||||
return 1;
|
||||
});
|
||||
#endif // __cplusplus_winrt
|
||||
})
|
||||
|
||||
#endif // __WIL_RESULT_ORIGINATE_INCLUDED
|
||||
|
140
Externals/WIL/include/wil/safecast.h
vendored
140
Externals/WIL/include/wil/safecast.h
vendored
@ -121,76 +121,76 @@ namespace wil
|
||||
// Mappings of all conversions defined in intsafe.h to intsafe_conversion
|
||||
// Note: Uppercase types (UINT, DWORD, SIZE_T, etc) and architecture dependent types resolve
|
||||
// to the base types. The base types are used since they do not vary based on architecture.
|
||||
template<> constexpr auto intsafe_conversion<__int64, char> = LongLongToChar;
|
||||
template<> constexpr auto intsafe_conversion<__int64, int> = LongLongToInt;
|
||||
template<> constexpr auto intsafe_conversion<__int64, long> = LongLongToLong;
|
||||
template<> constexpr auto intsafe_conversion<__int64, short> = LongLongToShort;
|
||||
template<> constexpr auto intsafe_conversion<__int64, signed char> = LongLongToInt8;
|
||||
template<> constexpr auto intsafe_conversion<__int64, unsigned __int64> = LongLongToULongLong;
|
||||
template<> constexpr auto intsafe_conversion<__int64, unsigned char> = LongLongToUChar;
|
||||
template<> constexpr auto intsafe_conversion<__int64, unsigned int> = LongLongToUInt;
|
||||
template<> constexpr auto intsafe_conversion<__int64, unsigned long> = LongLongToULong;
|
||||
template<> constexpr auto intsafe_conversion<__int64, unsigned short> = LongLongToUShort;
|
||||
template<> constexpr auto intsafe_conversion<int, char> = IntToChar;
|
||||
template<> constexpr auto intsafe_conversion<int, short> = IntToShort;
|
||||
template<> constexpr auto intsafe_conversion<int, signed char> = IntToInt8;
|
||||
template<> constexpr auto intsafe_conversion<int, unsigned __int64> = IntToULongLong;
|
||||
template<> constexpr auto intsafe_conversion<int, unsigned char> = IntToUChar;
|
||||
template<> constexpr auto intsafe_conversion<int, unsigned int> = IntToUInt;
|
||||
template<> constexpr auto intsafe_conversion<int, unsigned long> = IntToULong;
|
||||
template<> constexpr auto intsafe_conversion<int, unsigned short> = IntToUShort;
|
||||
template<> constexpr auto intsafe_conversion<long, char> = LongToChar;
|
||||
template<> constexpr auto intsafe_conversion<long, int> = LongToInt;
|
||||
template<> constexpr auto intsafe_conversion<long, short> = LongToShort;
|
||||
template<> constexpr auto intsafe_conversion<long, signed char> = LongToInt8;
|
||||
template<> constexpr auto intsafe_conversion<long, unsigned __int64> = LongToULongLong;
|
||||
template<> constexpr auto intsafe_conversion<long, unsigned char> = LongToUChar;
|
||||
template<> constexpr auto intsafe_conversion<long, unsigned int> = LongToUInt;
|
||||
template<> constexpr auto intsafe_conversion<long, unsigned long> = LongToULong;
|
||||
template<> constexpr auto intsafe_conversion<long, unsigned short> = LongToUShort;
|
||||
template<> constexpr auto intsafe_conversion<short, char> = ShortToChar;
|
||||
template<> constexpr auto intsafe_conversion<short, signed char> = ShortToInt8;
|
||||
template<> constexpr auto intsafe_conversion<short, unsigned __int64> = ShortToULongLong;
|
||||
template<> constexpr auto intsafe_conversion<short, unsigned char> = ShortToUChar;
|
||||
template<> constexpr auto intsafe_conversion<short, unsigned int> = ShortToUInt;
|
||||
template<> constexpr auto intsafe_conversion<short, unsigned long> = ShortToULong;
|
||||
template<> constexpr auto intsafe_conversion<short, unsigned short> = ShortToUShort;
|
||||
template<> constexpr auto intsafe_conversion<signed char, unsigned __int64> = Int8ToULongLong;
|
||||
template<> constexpr auto intsafe_conversion<signed char, unsigned char> = Int8ToUChar;
|
||||
template<> constexpr auto intsafe_conversion<signed char, unsigned int> = Int8ToUInt;
|
||||
template<> constexpr auto intsafe_conversion<signed char, unsigned long> = Int8ToULong;
|
||||
template<> constexpr auto intsafe_conversion<signed char, unsigned short> = Int8ToUShort;
|
||||
template<> constexpr auto intsafe_conversion<unsigned __int64, __int64> = ULongLongToLongLong;
|
||||
template<> constexpr auto intsafe_conversion<unsigned __int64, char> = ULongLongToChar;
|
||||
template<> constexpr auto intsafe_conversion<unsigned __int64, int> = ULongLongToInt;
|
||||
template<> constexpr auto intsafe_conversion<unsigned __int64, long> = ULongLongToLong;
|
||||
template<> constexpr auto intsafe_conversion<unsigned __int64, short> = ULongLongToShort;
|
||||
template<> constexpr auto intsafe_conversion<unsigned __int64, signed char> = ULongLongToInt8;
|
||||
template<> constexpr auto intsafe_conversion<unsigned __int64, unsigned char> = ULongLongToUChar;
|
||||
template<> constexpr auto intsafe_conversion<unsigned __int64, unsigned int> = ULongLongToUInt;
|
||||
template<> constexpr auto intsafe_conversion<unsigned __int64, unsigned long> = ULongLongToULong;
|
||||
template<> constexpr auto intsafe_conversion<unsigned __int64, unsigned short> = ULongLongToUShort;
|
||||
template<> constexpr auto intsafe_conversion<unsigned char, char> = UInt8ToChar;
|
||||
template<> constexpr auto intsafe_conversion<unsigned char, signed char> = UIntToInt8;
|
||||
template<> constexpr auto intsafe_conversion<unsigned int, char> = UIntToChar;
|
||||
template<> constexpr auto intsafe_conversion<unsigned int, int> = UIntToInt;
|
||||
template<> constexpr auto intsafe_conversion<unsigned int, long> = UIntToLong;
|
||||
template<> constexpr auto intsafe_conversion<unsigned int, short> = UIntToShort;
|
||||
template<> constexpr auto intsafe_conversion<unsigned int, signed char> = UIntToInt8;
|
||||
template<> constexpr auto intsafe_conversion<unsigned int, unsigned char> = UIntToUChar;
|
||||
template<> constexpr auto intsafe_conversion<unsigned int, unsigned short> = UIntToUShort;
|
||||
template<> constexpr auto intsafe_conversion<unsigned long, char> = ULongToChar;
|
||||
template<> constexpr auto intsafe_conversion<unsigned long, int> = ULongToInt;
|
||||
template<> constexpr auto intsafe_conversion<unsigned long, long> = ULongToLong;
|
||||
template<> constexpr auto intsafe_conversion<unsigned long, short> = ULongToShort;
|
||||
template<> constexpr auto intsafe_conversion<unsigned long, signed char> = ULongToInt8;
|
||||
template<> constexpr auto intsafe_conversion<unsigned long, unsigned char> = ULongToUChar;
|
||||
template<> constexpr auto intsafe_conversion<unsigned long, unsigned int> = ULongToUInt;
|
||||
template<> constexpr auto intsafe_conversion<unsigned long, unsigned short> = ULongToUShort;
|
||||
template<> constexpr auto intsafe_conversion<unsigned short, char> = UShortToChar;
|
||||
template<> constexpr auto intsafe_conversion<unsigned short, short> = UShortToShort;
|
||||
template<> constexpr auto intsafe_conversion<unsigned short, signed char> = UShortToInt8;
|
||||
template<> constexpr auto intsafe_conversion<unsigned short, unsigned char> = UShortToUChar;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, char> = LongLongToChar;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, int> = LongLongToInt;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, long> = LongLongToLong;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, short> = LongLongToShort;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, signed char> = LongLongToInt8;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, unsigned __int64> = LongLongToULongLong;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, unsigned char> = LongLongToUChar;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, unsigned int> = LongLongToUInt;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, unsigned long> = LongLongToULong;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, unsigned short> = LongLongToUShort;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, char> = IntToChar;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, short> = IntToShort;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, signed char> = IntToInt8;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, unsigned __int64> = IntToULongLong;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, unsigned char> = IntToUChar;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, unsigned int> = IntToUInt;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, unsigned long> = IntToULong;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, unsigned short> = IntToUShort;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, char> = LongToChar;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, int> = LongToInt;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, short> = LongToShort;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, signed char> = LongToInt8;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, unsigned __int64> = LongToULongLong;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, unsigned char> = LongToUChar;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, unsigned int> = LongToUInt;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, unsigned long> = LongToULong;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, unsigned short> = LongToUShort;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<short, char> = ShortToChar;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<short, signed char> = ShortToInt8;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<short, unsigned __int64> = ShortToULongLong;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<short, unsigned char> = ShortToUChar;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<short, unsigned int> = ShortToUInt;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<short, unsigned long> = ShortToULong;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<short, unsigned short> = ShortToUShort;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<signed char, unsigned __int64> = Int8ToULongLong;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<signed char, unsigned char> = Int8ToUChar;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<signed char, unsigned int> = Int8ToUInt;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<signed char, unsigned long> = Int8ToULong;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<signed char, unsigned short> = Int8ToUShort;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, __int64> = ULongLongToLongLong;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, char> = ULongLongToChar;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, int> = ULongLongToInt;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, long> = ULongLongToLong;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, short> = ULongLongToShort;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, signed char> = ULongLongToInt8;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, unsigned char> = ULongLongToUChar;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, unsigned int> = ULongLongToUInt;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, unsigned long> = ULongLongToULong;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, unsigned short> = ULongLongToUShort;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned char, char> = UInt8ToChar;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned char, signed char> = UIntToInt8;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned int, char> = UIntToChar;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned int, int> = UIntToInt;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned int, long> = UIntToLong;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned int, short> = UIntToShort;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned int, signed char> = UIntToInt8;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned int, unsigned char> = UIntToUChar;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned int, unsigned short> = UIntToUShort;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, char> = ULongToChar;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, int> = ULongToInt;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, long> = ULongToLong;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, short> = ULongToShort;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, signed char> = ULongToInt8;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, unsigned char> = ULongToUChar;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, unsigned int> = ULongToUInt;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, unsigned short> = ULongToUShort;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned short, char> = UShortToChar;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned short, short> = UShortToShort;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned short, signed char> = UShortToInt8;
|
||||
template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned short, unsigned char> = UShortToUChar;
|
||||
}
|
||||
|
||||
// Unsafe conversion where failure results in fail fast.
|
||||
|
96
Externals/WIL/include/wil/stl.h
vendored
96
Externals/WIL/include/wil/stl.h
vendored
@ -15,19 +15,17 @@
|
||||
#include "resource.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#if _HAS_CXX17
|
||||
#include <string_view>
|
||||
#endif
|
||||
|
||||
#ifndef WI_STL_FAIL_FAST_IF
|
||||
#define WI_STL_FAIL_FAST_IF FAIL_FAST_IF
|
||||
#endif
|
||||
|
||||
#if defined(WIL_ENABLE_EXCEPTIONS)
|
||||
namespace std
|
||||
{
|
||||
template<class _Ty, class _Alloc>
|
||||
class vector;
|
||||
|
||||
template<class _Elem>
|
||||
struct char_traits;
|
||||
|
||||
template<class _Elem, class _Traits, class _Alloc>
|
||||
class basic_string;
|
||||
} // namespace std
|
||||
|
||||
namespace wil
|
||||
{
|
||||
@ -42,7 +40,7 @@ namespace wil
|
||||
template<typename Other>
|
||||
struct rebind
|
||||
{
|
||||
typedef secure_allocator<Other> other;
|
||||
using other = secure_allocator<Other>;
|
||||
};
|
||||
|
||||
secure_allocator()
|
||||
@ -100,6 +98,8 @@ namespace wil
|
||||
|
||||
wchar_t* buffer() { return &m_value[0]; }
|
||||
|
||||
HRESULT trim_at_existing_null(size_t length) { m_value.erase(length); return S_OK; }
|
||||
|
||||
std::wstring release() { return std::wstring(std::move(m_value)); }
|
||||
|
||||
static PCWSTR get(const std::wstring& value) { return value.c_str(); }
|
||||
@ -117,6 +117,78 @@ namespace wil
|
||||
return str.c_str();
|
||||
}
|
||||
|
||||
#if _HAS_CXX17
|
||||
/**
|
||||
zstring_view. A zstring_view is identical to a std::string_view except it is always nul-terminated (unless empty).
|
||||
* zstring_view can be used for storing string literals without "forgetting" the length or that it is nul-terminated.
|
||||
* A zstring_view can be converted implicitly to a std::string_view because it is always safe to use a nul-terminated
|
||||
string_view as a plain string view.
|
||||
* A zstring_view can be constructed from a std::string because the data in std::string is nul-terminated.
|
||||
*/
|
||||
template<class TChar>
|
||||
class basic_zstring_view : public std::basic_string_view<TChar>
|
||||
{
|
||||
using size_type = typename std::basic_string_view<TChar>::size_type;
|
||||
|
||||
public:
|
||||
constexpr basic_zstring_view() noexcept = default;
|
||||
constexpr basic_zstring_view(const basic_zstring_view&) noexcept = default;
|
||||
constexpr basic_zstring_view& operator=(const basic_zstring_view&) noexcept = default;
|
||||
|
||||
constexpr basic_zstring_view(const TChar* pStringData, size_type stringLength) noexcept
|
||||
: std::basic_string_view<TChar>(pStringData, stringLength)
|
||||
{
|
||||
if (pStringData[stringLength] != 0) { WI_STL_FAIL_FAST_IF(true); }
|
||||
}
|
||||
|
||||
template<size_t stringArrayLength>
|
||||
constexpr basic_zstring_view(const TChar(&stringArray)[stringArrayLength]) noexcept
|
||||
: std::basic_string_view<TChar>(&stringArray[0], length_n(&stringArray[0], stringArrayLength))
|
||||
{
|
||||
}
|
||||
|
||||
// Construct from nul-terminated char ptr. To prevent this from overshadowing array construction,
|
||||
// we disable this constructor if the value is an array (including string literal).
|
||||
template<typename TPtr, std::enable_if_t<
|
||||
std::is_convertible<TPtr, const TChar*>::value && !std::is_array<TPtr>::value>* = nullptr>
|
||||
constexpr basic_zstring_view(TPtr&& pStr) noexcept
|
||||
: std::basic_string_view<TChar>(std::forward<TPtr>(pStr)) {}
|
||||
|
||||
constexpr basic_zstring_view(const std::basic_string<TChar>& str) noexcept
|
||||
: std::basic_string_view<TChar>(&str[0], str.size()) {}
|
||||
|
||||
// basic_string_view [] precondition won't let us read view[view.size()]; so we define our own.
|
||||
constexpr const TChar& operator[](size_type idx) const noexcept
|
||||
{
|
||||
WI_ASSERT(idx <= this->size() && this->data() != nullptr);
|
||||
return this->data()[idx];
|
||||
}
|
||||
|
||||
constexpr const TChar* c_str() const noexcept
|
||||
{
|
||||
WI_ASSERT(this->data() == nullptr || this->data()[this->size()] == 0);
|
||||
return this->data();
|
||||
}
|
||||
|
||||
private:
|
||||
// Bounds-checked version of char_traits::length, like strnlen. Requires that the input contains a null terminator.
|
||||
static constexpr size_type length_n(_In_reads_opt_(buf_size) const TChar* str, size_type buf_size) noexcept
|
||||
{
|
||||
const std::basic_string_view<TChar> view(str, buf_size);
|
||||
auto pos = view.find_first_of(TChar());
|
||||
if (pos == view.npos) { WI_STL_FAIL_FAST_IF(true); }
|
||||
return pos;
|
||||
}
|
||||
|
||||
// The following basic_string_view methods must not be allowed because they break the nul-termination.
|
||||
using std::basic_string_view<TChar>::swap;
|
||||
using std::basic_string_view<TChar>::remove_suffix;
|
||||
};
|
||||
|
||||
using zstring_view = basic_zstring_view<char>;
|
||||
using zwstring_view = basic_zstring_view<wchar_t>;
|
||||
#endif // _HAS_CXX17
|
||||
|
||||
} // namespace wil
|
||||
|
||||
#endif // WIL_ENABLE_EXCEPTIONS
|
||||
|
47
Externals/WIL/include/wil/token_helpers.h
vendored
47
Externals/WIL/include/wil/token_helpers.h
vendored
@ -21,7 +21,9 @@
|
||||
#include <processthreadsapi.h>
|
||||
|
||||
// for GetUserNameEx()
|
||||
#ifndef SECURITY_WIN32
|
||||
#define SECURITY_WIN32
|
||||
#endif
|
||||
#include <Security.h>
|
||||
|
||||
namespace wil
|
||||
@ -34,25 +36,25 @@ namespace wil
|
||||
// be an info class value that uses the same structure. That is the case for the file
|
||||
// system information.
|
||||
template<typename T> struct MapTokenStructToInfoClass;
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_ACCESS_INFORMATION> { static const TOKEN_INFORMATION_CLASS infoClass = TokenAccessInformation; static const bool FixedSize = false; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_APPCONTAINER_INFORMATION> { static const TOKEN_INFORMATION_CLASS infoClass = TokenAppContainerSid; static const bool FixedSize = false; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_DEFAULT_DACL> { static const TOKEN_INFORMATION_CLASS infoClass = TokenDefaultDacl; static const bool FixedSize = false; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_GROUPS_AND_PRIVILEGES> { static const TOKEN_INFORMATION_CLASS infoClass = TokenGroupsAndPrivileges; static const bool FixedSize = false; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_MANDATORY_LABEL> { static const TOKEN_INFORMATION_CLASS infoClass = TokenIntegrityLevel; static const bool FixedSize = false; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_OWNER> { static const TOKEN_INFORMATION_CLASS infoClass = TokenOwner; static const bool FixedSize = false; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_PRIMARY_GROUP> { static const TOKEN_INFORMATION_CLASS infoClass = TokenPrimaryGroup; static const bool FixedSize = false; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_PRIVILEGES> { static const TOKEN_INFORMATION_CLASS infoClass = TokenPrivileges; static const bool FixedSize = false; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_USER> { static const TOKEN_INFORMATION_CLASS infoClass = TokenUser; static const bool FixedSize = false; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_ACCESS_INFORMATION> { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenAccessInformation; static constexpr bool FixedSize = false; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_APPCONTAINER_INFORMATION> { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenAppContainerSid; static constexpr bool FixedSize = false; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_DEFAULT_DACL> { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenDefaultDacl; static constexpr bool FixedSize = false; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_GROUPS_AND_PRIVILEGES> { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenGroupsAndPrivileges; static constexpr bool FixedSize = false; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_MANDATORY_LABEL> { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenIntegrityLevel; static constexpr bool FixedSize = false; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_OWNER> { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenOwner; static constexpr bool FixedSize = false; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_PRIMARY_GROUP> { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenPrimaryGroup; static constexpr bool FixedSize = false; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_PRIVILEGES> { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenPrivileges; static constexpr bool FixedSize = false; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_USER> { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenUser; static constexpr bool FixedSize = false; };
|
||||
|
||||
// fixed size cases
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_ELEVATION_TYPE> { static const TOKEN_INFORMATION_CLASS infoClass = TokenElevationType; static const bool FixedSize = true; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_MANDATORY_POLICY> { static const TOKEN_INFORMATION_CLASS infoClass = TokenMandatoryPolicy; static const bool FixedSize = true; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_ORIGIN> { static const TOKEN_INFORMATION_CLASS infoClass = TokenOrigin; static const bool FixedSize = true; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_SOURCE> { static const TOKEN_INFORMATION_CLASS infoClass = TokenSource; static const bool FixedSize = true; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_STATISTICS> { static const TOKEN_INFORMATION_CLASS infoClass = TokenStatistics; static const bool FixedSize = true; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_TYPE> { static const TOKEN_INFORMATION_CLASS infoClass = TokenType; static const bool FixedSize = true; };
|
||||
template<> struct MapTokenStructToInfoClass<SECURITY_IMPERSONATION_LEVEL> { static const TOKEN_INFORMATION_CLASS infoClass = TokenImpersonationLevel; static const bool FixedSize = true; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_ELEVATION> { static const TOKEN_INFORMATION_CLASS infoClass = TokenElevation; static const bool FixedSize = true; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_ELEVATION_TYPE> { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenElevationType; static constexpr bool FixedSize = true; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_MANDATORY_POLICY> { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenMandatoryPolicy; static constexpr bool FixedSize = true; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_ORIGIN> { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenOrigin; static constexpr bool FixedSize = true; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_SOURCE> { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenSource; static constexpr bool FixedSize = true; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_STATISTICS> { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenStatistics; static constexpr bool FixedSize = true; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_TYPE> { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenType; static constexpr bool FixedSize = true; };
|
||||
template<> struct MapTokenStructToInfoClass<SECURITY_IMPERSONATION_LEVEL> { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenImpersonationLevel; static constexpr bool FixedSize = true; };
|
||||
template<> struct MapTokenStructToInfoClass<TOKEN_ELEVATION> { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenElevation; static constexpr bool FixedSize = true; };
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
@ -85,13 +87,12 @@ namespace wil
|
||||
or privilege-adjustment are examples of uses.
|
||||
~~~~
|
||||
wil::unique_handle callerToken;
|
||||
RETURN_IF_FAILED(wil::open_current_access_token_nothrow(&theToken, TOKEN_QUERY | TOKEN_IMPERSONATE, true));
|
||||
RETURN_IF_FAILED(wil::open_current_access_token_nothrow(&theToken, TOKEN_QUERY | TOKEN_IMPERSONATE, OpenThreadTokenAs::Self));
|
||||
~~~~
|
||||
@param tokenHandle Receives the token opened during the operation. Must be CloseHandle'd by the caller, or
|
||||
(preferably) stored in a wil::unique_handle
|
||||
@param access Bits from the TOKEN_* access mask which are passed to OpenThreadToken/OpenProcessToken
|
||||
@param asSelf When true, and if the thread is impersonating, the thread token is opened using the
|
||||
process token's rights.
|
||||
@param openAs Current to use current thread security context, or Self to use process security context.
|
||||
*/
|
||||
inline HRESULT open_current_access_token_nothrow(_Out_ HANDLE* tokenHandle, unsigned long access = TOKEN_QUERY, OpenThreadTokenAs openAs = OpenThreadTokenAs::Current)
|
||||
{
|
||||
@ -122,6 +123,7 @@ namespace wil
|
||||
}
|
||||
#endif // WIL_ENABLE_EXCEPTIONS
|
||||
|
||||
#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
|
||||
// Returns tokenHandle or the effective thread token if tokenHandle is null.
|
||||
// Note, this returns an token handle who's lifetime is managed independently
|
||||
// and it may be a pseudo token, don't free it!
|
||||
@ -287,11 +289,12 @@ namespace wil
|
||||
return tokenInfo;
|
||||
}
|
||||
#endif
|
||||
#endif // _WIN32_WINNT >= _WIN32_WINNT_WIN8
|
||||
|
||||
/// @cond
|
||||
namespace details
|
||||
{
|
||||
inline void RevertImpersonateToken(_Pre_opt_valid_ _Frees_ptr_opt_ HANDLE oldToken)
|
||||
inline void RevertImpersonateToken(_In_ _Post_ptr_invalid_ HANDLE oldToken)
|
||||
{
|
||||
FAIL_FAST_IMMEDIATE_IF(!::SetThreadToken(nullptr, oldToken));
|
||||
|
||||
@ -524,6 +527,7 @@ namespace wil
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
|
||||
/** Determine whether a token represents an app container
|
||||
This method uses the passed in token and emits a boolean indicating that
|
||||
whether TokenIsAppContainer is true.
|
||||
@ -573,6 +577,7 @@ namespace wil
|
||||
return value;
|
||||
}
|
||||
#endif // WIL_ENABLE_EXCEPTIONS
|
||||
#endif // _WIN32_WINNT >= _WIN32_WINNT_WIN8
|
||||
|
||||
template<typename... Ts> bool test_token_membership_failfast(_In_opt_ HANDLE token,
|
||||
const SID_IDENTIFIER_AUTHORITY& sidAuthority, Ts&&... subAuthorities)
|
||||
|
71
Externals/WIL/include/wil/traceloggingconfig.h
vendored
Normal file
71
Externals/WIL/include/wil/traceloggingconfig.h
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
//*********************************************************
|
||||
//
|
||||
// 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_TRACELOGGING_CONFIG_H
|
||||
#define __WIL_TRACELOGGING_CONFIG_H
|
||||
|
||||
// Configuration macro for use in TRACELOGGING_DEFINE_PROVIDER. The definition
|
||||
// in this file configures the provider as a normal (non-telemetry) provider.
|
||||
#define TraceLoggingOptionMicrosoftTelemetry() \
|
||||
// Empty definition for TraceLoggingOptionMicrosoftTelemetry
|
||||
|
||||
// Configuration macro for use in TRACELOGGING_DEFINE_PROVIDER. The definition
|
||||
// in this file configures the provider as a normal (non-telemetry) provider.
|
||||
#define TraceLoggingOptionWindowsCoreTelemetry() \
|
||||
// Empty definition for TraceLoggingOptionWindowsCoreTelemetry
|
||||
|
||||
// Event privacy tags. Use the PDT macro values for the tag parameter, e.g.:
|
||||
// TraceLoggingWrite(...,
|
||||
// TelemetryPrivacyDataTag(PDT_BrowsingHistory | PDT_ProductAndServiceUsage),
|
||||
// ...);
|
||||
#define TelemetryPrivacyDataTag(tag) TraceLoggingUInt64((tag), "PartA_PrivTags")
|
||||
#define PDT_BrowsingHistory 0x0000000000000002u
|
||||
#define PDT_DeviceConnectivityAndConfiguration 0x0000000000000800u
|
||||
#define PDT_InkingTypingAndSpeechUtterance 0x0000000000020000u
|
||||
#define PDT_ProductAndServicePerformance 0x0000000001000000u
|
||||
#define PDT_ProductAndServiceUsage 0x0000000002000000u
|
||||
#define PDT_SoftwareSetupAndInventory 0x0000000080000000u
|
||||
|
||||
// Event categories specified via keywords, e.g.:
|
||||
// TraceLoggingWrite(...,
|
||||
// TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
// ...);
|
||||
#define MICROSOFT_KEYWORD_CRITICAL_DATA 0x0000800000000000 // Bit 47
|
||||
#define MICROSOFT_KEYWORD_MEASURES 0x0000400000000000 // Bit 46
|
||||
#define MICROSOFT_KEYWORD_TELEMETRY 0x0000200000000000 // Bit 45
|
||||
#define MICROSOFT_KEYWORD_RESERVED_44 0x0000100000000000 // Bit 44 (reserved for future assignment)
|
||||
|
||||
// Event categories specified via event tags, e.g.:
|
||||
// TraceLoggingWrite(...,
|
||||
// TraceLoggingEventTag(MICROSOFT_EVENTTAG_REALTIME_LATENCY),
|
||||
// ...);
|
||||
#define MICROSOFT_EVENTTAG_DROP_USER_IDS 0x00008000
|
||||
#define MICROSOFT_EVENTTAG_AGGREGATE 0x00010000
|
||||
#define MICROSOFT_EVENTTAG_DROP_PII_EXCEPT_IP 0x00020000
|
||||
#define MICROSOFT_EVENTTAG_COSTDEFERRED_LATENCY 0x00040000
|
||||
#define MICROSOFT_EVENTTAG_CORE_DATA 0x00080000
|
||||
#define MICROSOFT_EVENTTAG_INJECT_XTOKEN 0x00100000
|
||||
#define MICROSOFT_EVENTTAG_REALTIME_LATENCY 0x00200000
|
||||
#define MICROSOFT_EVENTTAG_NORMAL_LATENCY 0x00400000
|
||||
#define MICROSOFT_EVENTTAG_CRITICAL_PERSISTENCE 0x00800000
|
||||
#define MICROSOFT_EVENTTAG_NORMAL_PERSISTENCE 0x01000000
|
||||
#define MICROSOFT_EVENTTAG_DROP_PII 0x02000000
|
||||
#define MICROSOFT_EVENTTAG_HASH_PII 0x04000000
|
||||
#define MICROSOFT_EVENTTAG_MARK_PII 0x08000000
|
||||
|
||||
// Field categories specified via field tags, e.g.:
|
||||
// TraceLoggingWrite(...,
|
||||
// TraceLoggingString(szUser, "UserName", "User's name", MICROSOFT_FIELDTAG_HASH_PII),
|
||||
// ...);
|
||||
#define MICROSOFT_FIELDTAG_DROP_PII 0x04000000
|
||||
#define MICROSOFT_FIELDTAG_HASH_PII 0x08000000
|
||||
#endif // __WIL_TRACELOGGING_CONFIG_H
|
489
Externals/WIL/include/wil/win32_helpers.h
vendored
489
Externals/WIL/include/wil/win32_helpers.h
vendored
@ -15,33 +15,177 @@
|
||||
#include <sysinfoapi.h> // GetSystemTimeAsFileTime
|
||||
#include <libloaderapi.h> // GetProcAddress
|
||||
#include <Psapi.h> // GetModuleFileNameExW (macro), K32GetModuleFileNameExW
|
||||
#include <PathCch.h>
|
||||
#include <winreg.h>
|
||||
#include <objbase.h>
|
||||
|
||||
// detect std::bit_cast
|
||||
#ifdef __has_include
|
||||
# if (__cplusplus >= 202002L || _MSVC_LANG >= 202002L) && __has_include(<bit>)
|
||||
# include <bit>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if __cpp_lib_bit_cast >= 201806L
|
||||
# define __WI_CONSTEXPR_BIT_CAST constexpr
|
||||
#else
|
||||
# define __WI_CONSTEXPR_BIT_CAST inline
|
||||
#endif
|
||||
|
||||
#include "result.h"
|
||||
#include "resource.h"
|
||||
#include "wistd_functional.h"
|
||||
#include "wistd_type_traits.h"
|
||||
|
||||
#if _HAS_CXX20 && defined(_STRING_VIEW_) && defined(_COMPARE_)
|
||||
// If we're using c++20, then <compare> must be included to use the string ordinal functions
|
||||
# define __WI_DEFINE_STRING_ORDINAL_FUNCTIONS
|
||||
#elif !_HAS_CXX20 && defined(_STRING_VIEW_)
|
||||
# define __WI_DEFINE_STRING_ORDINAL_FUNCTIONS
|
||||
#endif
|
||||
|
||||
namespace wistd
|
||||
{
|
||||
#if defined(__WI_DEFINE_STRING_ORDINAL_FUNCTIONS)
|
||||
|
||||
#if _HAS_CXX20
|
||||
|
||||
using weak_ordering = std::weak_ordering;
|
||||
|
||||
#else // _HAS_CXX20
|
||||
|
||||
struct weak_ordering
|
||||
{
|
||||
static const weak_ordering less;
|
||||
static const weak_ordering equivalent;
|
||||
static const weak_ordering greater;
|
||||
|
||||
[[nodiscard]] friend constexpr bool operator==(const weak_ordering left, std::nullptr_t) noexcept
|
||||
{
|
||||
return left.m_value == 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr bool operator!=(const weak_ordering left, std::nullptr_t) noexcept
|
||||
{
|
||||
return left.m_value != 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr bool operator<(const weak_ordering left, std::nullptr_t) noexcept
|
||||
{
|
||||
return left.m_value < 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr bool operator>(const weak_ordering left, std::nullptr_t) noexcept
|
||||
{
|
||||
return left.m_value > 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr bool operator<=(const weak_ordering left, std::nullptr_t) noexcept
|
||||
{
|
||||
return left.m_value <= 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr bool operator>=(const weak_ordering left, std::nullptr_t) noexcept
|
||||
{
|
||||
return left.m_value >= 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr bool operator==(std::nullptr_t, const weak_ordering right) noexcept
|
||||
{
|
||||
return right == 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr bool operator!=(std::nullptr_t, const weak_ordering right) noexcept
|
||||
{
|
||||
return right != 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr bool operator<(std::nullptr_t, const weak_ordering right) noexcept
|
||||
{
|
||||
return right > 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr bool operator>(std::nullptr_t, const weak_ordering right) noexcept
|
||||
{
|
||||
return right < 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr bool operator<=(std::nullptr_t, const weak_ordering right) noexcept
|
||||
{
|
||||
return right >= 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr bool operator>=(std::nullptr_t, const weak_ordering right) noexcept
|
||||
{
|
||||
return right <= 0;
|
||||
}
|
||||
|
||||
signed char m_value;
|
||||
};
|
||||
|
||||
inline constexpr weak_ordering weak_ordering::less{static_cast<signed char>(-1)};
|
||||
inline constexpr weak_ordering weak_ordering::equivalent{static_cast<signed char>(0)};
|
||||
inline constexpr weak_ordering weak_ordering::greater{static_cast<signed char>(1)};
|
||||
|
||||
#endif // !_HAS_CXX20
|
||||
|
||||
#endif // defined(__WI_DEFINE_STRING_ORDINAL_FUNCTIONS)
|
||||
|
||||
}
|
||||
|
||||
namespace wil
|
||||
{
|
||||
//! Strictly a function of the file system but this is the value for all known file system, NTFS, FAT.
|
||||
//! CDFs has a limit of 254.
|
||||
size_t const max_path_segment_length = 255;
|
||||
constexpr size_t max_path_segment_length = 255;
|
||||
|
||||
//! Character length not including the null, MAX_PATH (260) includes the null.
|
||||
size_t const max_path_length = 259;
|
||||
constexpr size_t max_path_length = 259;
|
||||
|
||||
//! 32743 Character length not including the null. This is a system defined limit.
|
||||
//! The 24 is for the expansion of the roots from "C:" to "\Device\HarddiskVolume4"
|
||||
//! It will be 25 when there are more than 9 disks.
|
||||
size_t const max_extended_path_length = 0x7FFF - 24;
|
||||
constexpr size_t max_extended_path_length = 0x7FFF - 24;
|
||||
|
||||
//! For {guid} string form. Includes space for the null terminator.
|
||||
size_t const guid_string_buffer_length = 39;
|
||||
constexpr size_t guid_string_buffer_length = 39;
|
||||
|
||||
//! For {guid} string form. Not including the null terminator.
|
||||
size_t const guid_string_length = 38;
|
||||
constexpr size_t guid_string_length = 38;
|
||||
|
||||
#pragma region String and identifier comparisons
|
||||
// Using CompareStringOrdinal functions:
|
||||
//
|
||||
// Indentifiers require a locale-less (ordinal), and often case-insensitive, comparison (filenames, registry keys, XML node names, etc).
|
||||
// DO NOT use locale-sensitive (lexical) comparisons for resource identifiers (e.g.wcs*() functions in the CRT).
|
||||
|
||||
#if defined(__WI_DEFINE_STRING_ORDINAL_FUNCTIONS)
|
||||
|
||||
namespace details
|
||||
{
|
||||
[[nodiscard]] inline int CompareStringOrdinal(std::wstring_view left, std::wstring_view right, bool caseInsensitive) WI_NOEXCEPT
|
||||
{
|
||||
// Casting from size_t (unsigned) to int (signed) should be safe from overrun to a negative,
|
||||
// merely truncating the string. CompareStringOrdinal should be resilient to negatives.
|
||||
return ::CompareStringOrdinal(left.data(), static_cast<int>(left.size()), right.data(), static_cast<int>(right.size()), caseInsensitive);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] inline wistd::weak_ordering compare_string_ordinal(std::wstring_view left, std::wstring_view right, bool caseInsensitive) WI_NOEXCEPT
|
||||
{
|
||||
switch (wil::details::CompareStringOrdinal(left, right, caseInsensitive))
|
||||
{
|
||||
case CSTR_LESS_THAN:
|
||||
return wistd::weak_ordering::less;
|
||||
case CSTR_GREATER_THAN:
|
||||
return wistd::weak_ordering::greater;
|
||||
default:
|
||||
return wistd::weak_ordering::equivalent;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // defined(__WI_DEFINE_STRING_ORDINAL_FUNCTIONS)
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region FILETIME helpers
|
||||
// FILETIME duration values. FILETIME is in 100 nanosecond units.
|
||||
@ -56,36 +200,126 @@ namespace wil
|
||||
|
||||
namespace filetime
|
||||
{
|
||||
inline unsigned long long to_int64(const FILETIME &ft)
|
||||
constexpr unsigned long long to_int64(const FILETIME &ft) WI_NOEXCEPT
|
||||
{
|
||||
#if __cpp_lib_bit_cast >= 201806L
|
||||
return std::bit_cast<unsigned long long>(ft);
|
||||
#else
|
||||
// Cannot reinterpret_cast FILETIME* to unsigned long long*
|
||||
// due to alignment differences.
|
||||
return (static_cast<unsigned long long>(ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline FILETIME from_int64(unsigned long long i64)
|
||||
__WI_CONSTEXPR_BIT_CAST FILETIME from_int64(unsigned long long i64) WI_NOEXCEPT
|
||||
{
|
||||
#if __cpp_lib_bit_cast >= 201806L
|
||||
return std::bit_cast<FILETIME>(i64);
|
||||
#else
|
||||
static_assert(sizeof(i64) == sizeof(FILETIME), "sizes don't match");
|
||||
static_assert(__alignof(unsigned long long) >= __alignof(FILETIME), "alignment not compatible with type pun");
|
||||
return *reinterpret_cast<FILETIME *>(&i64);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline FILETIME add(_In_ FILETIME const &ft, long long delta)
|
||||
__WI_CONSTEXPR_BIT_CAST FILETIME add(_In_ FILETIME const &ft, long long delta100ns) WI_NOEXCEPT
|
||||
{
|
||||
return from_int64(to_int64(ft) + delta);
|
||||
return from_int64(to_int64(ft) + delta100ns);
|
||||
}
|
||||
|
||||
inline bool is_empty(const FILETIME &ft)
|
||||
constexpr bool is_empty(const FILETIME &ft) WI_NOEXCEPT
|
||||
{
|
||||
return (ft.dwHighDateTime == 0) && (ft.dwLowDateTime == 0);
|
||||
}
|
||||
|
||||
inline FILETIME get_system_time()
|
||||
inline FILETIME get_system_time() WI_NOEXCEPT
|
||||
{
|
||||
FILETIME ft;
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
return ft;
|
||||
}
|
||||
|
||||
/// Convert time as units of 100 nanoseconds to milliseconds. Fractional milliseconds are truncated.
|
||||
constexpr unsigned long long convert_100ns_to_msec(unsigned long long time100ns) WI_NOEXCEPT
|
||||
{
|
||||
return time100ns / filetime_duration::one_millisecond;
|
||||
}
|
||||
|
||||
/// Convert time as milliseconds to units of 100 nanoseconds.
|
||||
constexpr unsigned long long convert_msec_to_100ns(unsigned long long timeMsec) WI_NOEXCEPT
|
||||
{
|
||||
return timeMsec * filetime_duration::one_millisecond;
|
||||
}
|
||||
|
||||
#if defined(_APISETREALTIME_) && (_WIN32_WINNT >= _WIN32_WINNT_WIN7)
|
||||
/// Returns the current unbiased interrupt-time count, in units of 100 nanoseconds. The unbiased interrupt-time count does not include time the system spends in sleep or hibernation.
|
||||
///
|
||||
/// This API avoids prematurely shortcircuiting timing loops due to system sleep/hibernation.
|
||||
///
|
||||
/// This is equivalent to GetTickCount64() except it returns units of 100 nanoseconds instead of milliseconds, and it doesn't include time the system spends in sleep or hibernation.
|
||||
/// For example
|
||||
///
|
||||
/// start = GetTickCount64();
|
||||
/// hibernate();
|
||||
/// ...wake from hibernation 30 minutes later...;
|
||||
/// elapsed = GetTickCount64() - start;
|
||||
/// // elapsed = 30min
|
||||
///
|
||||
/// Do the same using unbiased interrupt-time and elapsed is 0 (or nearly so).
|
||||
///
|
||||
/// @note This is identical to QueryUnbiasedInterruptTime() but returns the value as a return value (rather than an out parameter).
|
||||
/// @see https://msdn.microsoft.com/en-us/library/windows/desktop/ee662307(v=vs.85).aspx
|
||||
inline unsigned long long QueryUnbiasedInterruptTimeAs100ns() WI_NOEXCEPT
|
||||
{
|
||||
ULONGLONG now{};
|
||||
QueryUnbiasedInterruptTime(&now);
|
||||
return now;
|
||||
}
|
||||
|
||||
/// Returns the current unbiased interrupt-time count, in units of milliseconds. The unbiased interrupt-time count does not include time the system spends in sleep or hibernation.
|
||||
/// @see QueryUnbiasedInterruptTimeAs100ns
|
||||
inline unsigned long long QueryUnbiasedInterruptTimeAsMSec() WI_NOEXCEPT
|
||||
{
|
||||
return convert_100ns_to_msec(QueryUnbiasedInterruptTimeAs100ns());
|
||||
}
|
||||
#endif // _APISETREALTIME_
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
#pragma region RECT helpers
|
||||
template<typename rect_type>
|
||||
constexpr auto rect_width(rect_type const& rect)
|
||||
{
|
||||
return rect.right - rect.left;
|
||||
}
|
||||
|
||||
template<typename rect_type>
|
||||
constexpr auto rect_height(rect_type const& rect)
|
||||
{
|
||||
return rect.bottom - rect.top;
|
||||
}
|
||||
|
||||
template<typename rect_type>
|
||||
constexpr auto rect_is_empty(rect_type const& rect)
|
||||
{
|
||||
return (rect.left >= rect.right) || (rect.top >= rect.bottom);
|
||||
}
|
||||
|
||||
template<typename rect_type, typename point_type>
|
||||
constexpr auto rect_contains_point(rect_type const& rect, point_type const& point)
|
||||
{
|
||||
return (point.x >= rect.left) && (point.x < rect.right) && (point.y >= rect.top) && (point.y < rect.bottom);
|
||||
}
|
||||
|
||||
template<typename rect_type, typename length_type>
|
||||
constexpr rect_type rect_from_size(length_type x, length_type y, length_type width, length_type height)
|
||||
{
|
||||
rect_type rect;
|
||||
rect.left = x;
|
||||
rect.top = y;
|
||||
rect.right = x + width;
|
||||
rect.bottom = y + height;
|
||||
return rect;
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
@ -95,7 +329,7 @@ namespace wil
|
||||
// Adjust stackBufferLength based on typical result sizes to optimize use and
|
||||
// to test the boundary cases.
|
||||
template <typename string_type, size_t stackBufferLength = 256>
|
||||
HRESULT AdaptFixedSizeToAllocatedResult(string_type& result, wistd::function<HRESULT(PWSTR, size_t, size_t*)> callback)
|
||||
HRESULT AdaptFixedSizeToAllocatedResult(string_type& result, wistd::function<HRESULT(PWSTR, size_t, size_t*)> callback) WI_NOEXCEPT
|
||||
{
|
||||
details::string_maker<string_type> maker;
|
||||
|
||||
@ -112,14 +346,24 @@ namespace wil
|
||||
else
|
||||
{
|
||||
// Did not fit in the stack allocated buffer, need to do 2 phase construction.
|
||||
// valueLengthNeededWithNull includes the null so subtract that as make() will add space for it.
|
||||
RETURN_IF_FAILED(maker.make(nullptr, valueLengthNeededWithNull - 1));
|
||||
// May need to loop more than once if external conditions cause the value to change.
|
||||
size_t bufferLength;
|
||||
do
|
||||
{
|
||||
bufferLength = valueLengthNeededWithNull;
|
||||
// bufferLength includes the null so subtract that as make() will add space for it.
|
||||
RETURN_IF_FAILED(maker.make(nullptr, bufferLength - 1));
|
||||
|
||||
size_t secondLength{};
|
||||
RETURN_IF_FAILED(callback(maker.buffer(), valueLengthNeededWithNull, &secondLength));
|
||||
RETURN_IF_FAILED_EXPECTED(callback(maker.buffer(), bufferLength, &valueLengthNeededWithNull));
|
||||
WI_ASSERT(valueLengthNeededWithNull > 0);
|
||||
|
||||
// Ensure callback produces consistent result.
|
||||
FAIL_FAST_IF(valueLengthNeededWithNull != secondLength);
|
||||
// If the value shrunk, then adjust the string to trim off the excess buffer.
|
||||
if (valueLengthNeededWithNull < bufferLength)
|
||||
{
|
||||
RETURN_IF_FAILED(maker.trim_at_existing_null(valueLengthNeededWithNull - 1));
|
||||
}
|
||||
}
|
||||
while (valueLengthNeededWithNull > bufferLength);
|
||||
}
|
||||
result = maker.release();
|
||||
return S_OK;
|
||||
@ -167,9 +411,6 @@ namespace wil
|
||||
});
|
||||
}
|
||||
|
||||
// This function does not work beyond the default stack buffer size (255).
|
||||
// Needs to to retry in a loop similar to wil::GetModuleFileNameExW
|
||||
// These updates and unit tests are tracked by https://github.com/Microsoft/wil/issues/3
|
||||
template <typename string_type, size_t stackBufferLength = 256>
|
||||
HRESULT QueryFullProcessImageNameW(HANDLE processHandle, _In_ DWORD flags, string_type& result) WI_NOEXCEPT
|
||||
{
|
||||
@ -179,8 +420,9 @@ namespace wil
|
||||
DWORD lengthToUse = static_cast<DWORD>(valueLength);
|
||||
BOOL const success = ::QueryFullProcessImageNameW(processHandle, flags, value, &lengthToUse);
|
||||
RETURN_LAST_ERROR_IF((success == FALSE) && (::GetLastError() != ERROR_INSUFFICIENT_BUFFER));
|
||||
// On both success or insufficient buffer case, add +1 for the null-terminating character
|
||||
*valueLengthNeededWithNul = lengthToUse + 1;
|
||||
|
||||
// On success, return the amount used; on failure, try doubling
|
||||
*valueLengthNeededWithNul = success ? (lengthToUse + 1) : (lengthToUse * 2);
|
||||
return S_OK;
|
||||
});
|
||||
}
|
||||
@ -201,13 +443,11 @@ namespace wil
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Looks up the environment variable 'key' and fails if it is not found.
|
||||
'key' should not have '%' prefix and suffix.
|
||||
Dangerous since environment variable generally are optional. */
|
||||
template <typename string_type>
|
||||
/** Looks up the environment variable 'key' and fails if it is not found. */
|
||||
template <typename string_type, size_t initialBufferLength = 128>
|
||||
inline HRESULT GetEnvironmentVariableW(_In_ PCWSTR key, string_type& result) WI_NOEXCEPT
|
||||
{
|
||||
return wil::AdaptFixedSizeToAllocatedResult(result,
|
||||
return wil::AdaptFixedSizeToAllocatedResult<string_type, initialBufferLength>(result,
|
||||
[&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNul) -> HRESULT
|
||||
{
|
||||
// If the function succeeds, the return value is the number of characters stored in the buffer
|
||||
@ -232,12 +472,11 @@ namespace wil
|
||||
});
|
||||
}
|
||||
|
||||
/** Looks up the environment variable 'key' and returns null if it is not found.
|
||||
'key' should not have '%' prefix and suffix. */
|
||||
template <typename string_type>
|
||||
/** Looks up the environment variable 'key' and returns null if it is not found. */
|
||||
template <typename string_type, size_t initialBufferLength = 128>
|
||||
HRESULT TryGetEnvironmentVariableW(_In_ PCWSTR key, string_type& result) WI_NOEXCEPT
|
||||
{
|
||||
const auto hr = wil::GetEnvironmentVariableW<string_type>(key, result);
|
||||
const auto hr = wil::GetEnvironmentVariableW<string_type, initialBufferLength>(key, result);
|
||||
RETURN_HR_IF(hr, FAILED(hr) && (hr != HRESULT_FROM_WIN32(ERROR_ENVVAR_NOT_FOUND)));
|
||||
return S_OK;
|
||||
}
|
||||
@ -245,68 +484,44 @@ namespace wil
|
||||
/** Retrieves the fully qualified path for the file containing the specified module loaded
|
||||
by a given process. Note GetModuleFileNameExW is a macro.*/
|
||||
template <typename string_type, size_t initialBufferLength = 128>
|
||||
HRESULT GetModuleFileNameExW(_In_opt_ HANDLE process, _In_opt_ HMODULE module, string_type& path)
|
||||
HRESULT GetModuleFileNameExW(_In_opt_ HANDLE process, _In_opt_ HMODULE module, string_type& path) WI_NOEXCEPT
|
||||
{
|
||||
// initialBufferLength is a template parameter to allow for testing. It creates some waste for
|
||||
// shorter paths, but avoids iteration through the loop in common cases where paths are less
|
||||
// than 128 characters.
|
||||
// wil::max_extended_path_length + 1 (for the null char)
|
||||
// + 1 (to be certain GetModuleFileNameExW didn't truncate)
|
||||
size_t const ensureNoTrucation = (process != nullptr) ? 1 : 0;
|
||||
size_t const maxExtendedPathLengthWithNull = wil::max_extended_path_length + 1 + ensureNoTrucation;
|
||||
|
||||
details::string_maker<string_type> maker;
|
||||
|
||||
for (size_t lengthWithNull = initialBufferLength;
|
||||
lengthWithNull <= maxExtendedPathLengthWithNull;
|
||||
lengthWithNull = (wistd::min)(lengthWithNull * 2, maxExtendedPathLengthWithNull))
|
||||
auto adapter = [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNul) -> HRESULT
|
||||
{
|
||||
// make() adds space for the trailing null
|
||||
RETURN_IF_FAILED(maker.make(nullptr, lengthWithNull - 1));
|
||||
|
||||
DWORD copiedCount;
|
||||
size_t valueUsedWithNul;
|
||||
bool copyFailed;
|
||||
bool copySucceededWithNoTruncation;
|
||||
|
||||
if (process != nullptr)
|
||||
{
|
||||
// GetModuleFileNameExW truncates and provides no error or other indication it has done so.
|
||||
// The only way to be sure it didn't truncate is if it didn't need the whole buffer.
|
||||
copiedCount = ::GetModuleFileNameExW(process, module, maker.buffer(), static_cast<DWORD>(lengthWithNull));
|
||||
// The only way to be sure it didn't truncate is if it didn't need the whole buffer. The
|
||||
// count copied to the buffer includes the nul-character as well.
|
||||
copiedCount = ::GetModuleFileNameExW(process, module, value, static_cast<DWORD>(valueLength));
|
||||
valueUsedWithNul = copiedCount + 1;
|
||||
copyFailed = (0 == copiedCount);
|
||||
copySucceededWithNoTruncation = !copyFailed && (copiedCount < lengthWithNull - 1);
|
||||
copySucceededWithNoTruncation = !copyFailed && (copiedCount < valueLength - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// In cases of insufficient buffer, GetModuleFileNameW will return a value equal to lengthWithNull
|
||||
// and set the last error to ERROR_INSUFFICIENT_BUFFER.
|
||||
copiedCount = ::GetModuleFileNameW(module, maker.buffer(), static_cast<DWORD>(lengthWithNull));
|
||||
// and set the last error to ERROR_INSUFFICIENT_BUFFER. The count returned does not include
|
||||
// the nul-character
|
||||
copiedCount = ::GetModuleFileNameW(module, value, static_cast<DWORD>(valueLength));
|
||||
valueUsedWithNul = copiedCount + 1;
|
||||
copyFailed = (0 == copiedCount);
|
||||
copySucceededWithNoTruncation = !copyFailed && (copiedCount < lengthWithNull);
|
||||
copySucceededWithNoTruncation = !copyFailed && (copiedCount < valueLength);
|
||||
}
|
||||
|
||||
if (copyFailed)
|
||||
{
|
||||
RETURN_LAST_ERROR();
|
||||
}
|
||||
else if (copySucceededWithNoTruncation)
|
||||
{
|
||||
path = maker.release();
|
||||
return S_OK;
|
||||
}
|
||||
RETURN_LAST_ERROR_IF(copyFailed);
|
||||
|
||||
WI_ASSERT((process != nullptr) || (::GetLastError() == ERROR_INSUFFICIENT_BUFFER));
|
||||
// When the copy truncated, request another try with more space.
|
||||
*valueLengthNeededWithNul = copySucceededWithNoTruncation ? valueUsedWithNul : (valueLength * 2);
|
||||
|
||||
if (lengthWithNull == maxExtendedPathLengthWithNull)
|
||||
{
|
||||
// If we've reached this point, there's no point in trying a larger buffer size.
|
||||
break;
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
};
|
||||
|
||||
// Any path should fit into the maximum max_extended_path_length. If we reached here, something went
|
||||
// terribly wrong.
|
||||
FAIL_FAST();
|
||||
return wil::AdaptFixedSizeToAllocatedResult<string_type, initialBufferLength>(path, wistd::move(adapter));
|
||||
}
|
||||
|
||||
/** Retrieves the fully qualified path for the file that contains the specified module.
|
||||
@ -314,7 +529,7 @@ namespace wil
|
||||
same format that was specified when the module was loaded. Therefore, the path can be a
|
||||
long or short file name, and can have the prefix '\\?\'. */
|
||||
template <typename string_type, size_t initialBufferLength = 128>
|
||||
HRESULT GetModuleFileNameW(HMODULE module, string_type& path)
|
||||
HRESULT GetModuleFileNameW(HMODULE module, string_type& path) WI_NOEXCEPT
|
||||
{
|
||||
return wil::GetModuleFileNameExW<string_type, initialBufferLength>(nullptr, module, path);
|
||||
}
|
||||
@ -357,50 +572,134 @@ namespace wil
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Looks up the environment variable 'key' and fails if it is not found.
|
||||
'key' should not have '%' prefix and suffix.
|
||||
Dangerous since environment variable generally are optional. */
|
||||
template <typename string_type = wil::unique_cotaskmem_string>
|
||||
/** Looks up the environment variable 'key' and fails if it is not found. */
|
||||
template <typename string_type = wil::unique_cotaskmem_string, size_t initialBufferLength = 128>
|
||||
string_type GetEnvironmentVariableW(_In_ PCWSTR key)
|
||||
{
|
||||
string_type result;
|
||||
THROW_IF_FAILED(wil::GetEnvironmentVariableW<string_type>(key, result));
|
||||
THROW_IF_FAILED((wil::GetEnvironmentVariableW<string_type, initialBufferLength>(key, result)));
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Looks up the environment variable 'key' and returns null if it is not found.
|
||||
'key' should not have '%' prefix and suffix. */
|
||||
template <typename string_type = wil::unique_cotaskmem_string>
|
||||
/** Looks up the environment variable 'key' and returns null if it is not found. */
|
||||
template <typename string_type = wil::unique_cotaskmem_string, size_t initialBufferLength = 128>
|
||||
string_type TryGetEnvironmentVariableW(_In_ PCWSTR key)
|
||||
{
|
||||
string_type result;
|
||||
THROW_IF_FAILED(wil::TryGetEnvironmentVariableW<string_type>(key, result));
|
||||
THROW_IF_FAILED((wil::TryGetEnvironmentVariableW<string_type, initialBufferLength>(key, result)));
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename string_type = wil::unique_cotaskmem_string>
|
||||
string_type GetModuleFileNameW(HMODULE module)
|
||||
template <typename string_type = wil::unique_cotaskmem_string, size_t initialBufferLength = 128>
|
||||
string_type GetModuleFileNameW(HMODULE module = nullptr /* current process module */)
|
||||
{
|
||||
string_type result;
|
||||
THROW_IF_FAILED(wil::GetModuleFileNameW(module, result));
|
||||
THROW_IF_FAILED((wil::GetModuleFileNameW<string_type, initialBufferLength>(module, result)));
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename string_type = wil::unique_cotaskmem_string>
|
||||
template <typename string_type = wil::unique_cotaskmem_string, size_t initialBufferLength = 128>
|
||||
string_type GetModuleFileNameExW(HANDLE process, HMODULE module)
|
||||
{
|
||||
string_type result;
|
||||
THROW_IF_FAILED(wil::GetModuleFileNameExW(process, module, result));
|
||||
THROW_IF_FAILED((wil::GetModuleFileNameExW<string_type, initialBufferLength>(process, module, result)));
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename string_type = wil::unique_cotaskmem_string, size_t stackBufferLength = 256>
|
||||
string_type QueryFullProcessImageNameW(HANDLE processHandle = GetCurrentProcess(), DWORD flags = 0)
|
||||
{
|
||||
string_type result;
|
||||
THROW_IF_FAILED((wil::QueryFullProcessImageNameW<string_type, stackBufferLength>(processHandle, flags, result)));
|
||||
return result;
|
||||
}
|
||||
|
||||
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
|
||||
|
||||
// Lookup a DWORD value under HKLM\...\Image File Execution Options\<current process name>
|
||||
inline DWORD GetCurrentProcessExecutionOption(PCWSTR valueName, DWORD defaultValue = 0)
|
||||
{
|
||||
auto filePath = wil::GetModuleFileNameW<wil::unique_cotaskmem_string>();
|
||||
if (auto lastSlash = wcsrchr(filePath.get(), L'\\'))
|
||||
{
|
||||
const auto fileName = lastSlash + 1;
|
||||
auto keyPath = wil::str_concat<wil::unique_cotaskmem_string>(LR"(SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\)",
|
||||
fileName);
|
||||
DWORD value{}, sizeofValue = sizeof(value);
|
||||
if (::RegGetValueW(HKEY_LOCAL_MACHINE, keyPath.get(), valueName,
|
||||
#ifdef RRF_SUBKEY_WOW6464KEY
|
||||
RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6464KEY,
|
||||
#else
|
||||
RRF_RT_REG_DWORD,
|
||||
#endif
|
||||
nullptr, &value, &sizeofValue) == ERROR_SUCCESS)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
// Waits for a debugger to attach to the current process based on registry configuration.
|
||||
//
|
||||
// Example:
|
||||
// HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\explorer.exe
|
||||
// WaitForDebuggerPresent=1
|
||||
//
|
||||
// REG_DWORD value of
|
||||
// missing or 0 -> don't break
|
||||
// 1 -> wait for the debugger, continue execution once it is attached
|
||||
// 2 -> wait for the debugger, break here once attached.
|
||||
inline void WaitForDebuggerPresent(bool checkRegistryConfig = true)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
auto configValue = checkRegistryConfig ? GetCurrentProcessExecutionOption(L"WaitForDebuggerPresent") : 1;
|
||||
if (configValue == 0)
|
||||
{
|
||||
return; // not configured, don't wait
|
||||
}
|
||||
|
||||
if (IsDebuggerPresent())
|
||||
{
|
||||
if (configValue == 2)
|
||||
{
|
||||
DebugBreak(); // debugger attached, SHIFT+F11 to return to the caller
|
||||
}
|
||||
return; // debugger now attached, continue executing
|
||||
}
|
||||
Sleep(500);
|
||||
}
|
||||
}
|
||||
#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
|
||||
|
||||
#endif
|
||||
|
||||
/** Retrieve the HINSTANCE for the current DLL or EXE using this symbol that
|
||||
the linker provides for every module. This avoids the need for a global HINSTANCE variable
|
||||
and provides access to this value for static libraries. */
|
||||
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
|
||||
inline HINSTANCE GetModuleInstanceHandle() { return reinterpret_cast<HINSTANCE>(&__ImageBase); }
|
||||
inline HINSTANCE GetModuleInstanceHandle() WI_NOEXCEPT { return reinterpret_cast<HINSTANCE>(&__ImageBase); }
|
||||
|
||||
// GetModuleHandleExW was added to the app partition in version 22000 of the SDK
|
||||
#if defined(NTDDI_WIN10_CO) ? \
|
||||
WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) : \
|
||||
WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES)
|
||||
// Use this in threads that can outlive the object or API call that created them.
|
||||
// Without this COM, or the API caller, can unload the DLL, resulting in a crash.
|
||||
// It is very important that this be the first object created in the thread proc
|
||||
// as when this runs down the thread exits and no destructors of objects created before
|
||||
// it will run.
|
||||
[[nodiscard]] inline auto get_module_reference_for_thread() noexcept
|
||||
{
|
||||
HMODULE thisModule{};
|
||||
FAIL_FAST_IF(!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, L"", &thisModule));
|
||||
return wil::scope_exit([thisModule]
|
||||
{
|
||||
FreeLibraryAndExitThread(thisModule, 0);
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @cond
|
||||
namespace details
|
||||
@ -410,19 +709,19 @@ namespace wil
|
||||
INIT_ONCE& m_once;
|
||||
unsigned long m_flags = INIT_ONCE_INIT_FAILED;
|
||||
public:
|
||||
init_once_completer(_In_ INIT_ONCE& once) : m_once(once)
|
||||
init_once_completer(_In_ INIT_ONCE& once) WI_NOEXCEPT : m_once(once)
|
||||
{
|
||||
}
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4702) // https://github.com/Microsoft/wil/issues/2
|
||||
void success()
|
||||
void success() WI_NOEXCEPT
|
||||
{
|
||||
m_flags = 0;
|
||||
}
|
||||
#pragma warning(pop)
|
||||
|
||||
~init_once_completer()
|
||||
~init_once_completer() WI_NOEXCEPT
|
||||
{
|
||||
::InitOnceComplete(&m_once, m_flags, nullptr);
|
||||
}
|
||||
|
104
Externals/WIL/include/wil/win32_result_macros.h
vendored
Normal file
104
Externals/WIL/include/wil/win32_result_macros.h
vendored
Normal file
@ -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<FailureType::Return>(__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<FailureType::Return>(__R_DIRECT_FN_CALL_ONLY));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __WIL_WIN32_RESULTMACROS_INCLUDED
|
199
Externals/WIL/include/wil/winrt.h
vendored
199
Externals/WIL/include/wil/winrt.h
vendored
@ -19,24 +19,40 @@
|
||||
#include "result.h"
|
||||
#include "com.h"
|
||||
#include "resource.h"
|
||||
#include <windows.foundation.h>
|
||||
#include <windows.foundation.collections.h>
|
||||
|
||||
#ifdef __cplusplus_winrt
|
||||
#include <collection.h> // bring in the CRT iterator for support for C++ CX code
|
||||
#endif
|
||||
|
||||
#ifdef WIL_ENABLE_EXCEPTIONS
|
||||
/// @cond
|
||||
#if defined(WIL_ENABLE_EXCEPTIONS) && !defined(__WI_HAS_STD_LESS)
|
||||
#ifdef __has_include
|
||||
#if __has_include(<functional>)
|
||||
#define __WI_HAS_STD_LESS 1
|
||||
#include <functional>
|
||||
#endif // Otherwise, not using STL; don't specialize std::less
|
||||
#else
|
||||
// Fall back to the old way of forward declaring std::less
|
||||
#define __WI_HAS_STD_LESS 1
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4643) // Forward declaring '...' in namespace std is not permitted by the C++ Standard.
|
||||
namespace std
|
||||
{
|
||||
template<class _Elem, class _Traits, class _Alloc>
|
||||
class basic_string;
|
||||
|
||||
template<class _Ty>
|
||||
struct less;
|
||||
}
|
||||
/// @endcond
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
#endif
|
||||
#if defined(WIL_ENABLE_EXCEPTIONS) && defined(__has_include)
|
||||
#if __has_include(<vector>)
|
||||
#define __WI_HAS_STD_VECTOR 1
|
||||
#include <vector>
|
||||
#endif
|
||||
#endif
|
||||
/// @endcond
|
||||
|
||||
// This enables this code to be used in code that uses the ABI prefix or not.
|
||||
// Code using the public SDK and C++ CX code has the ABI prefix, windows internal
|
||||
@ -50,10 +66,9 @@ namespace std
|
||||
|
||||
namespace wil
|
||||
{
|
||||
#ifdef _INC_TIME
|
||||
// time_t is the number of 1 - second intervals since January 1, 1970.
|
||||
long long const SecondsToStartOf1970 = 0x2b6109100;
|
||||
long long const HundredNanoSecondsInSecond = 10000000LL;
|
||||
constexpr long long SecondsToStartOf1970 = 0x2b6109100;
|
||||
constexpr long long HundredNanoSecondsInSecond = 10000000LL;
|
||||
|
||||
inline __time64_t DateTime_to_time_t(ABI::Windows::Foundation::DateTime dateTime)
|
||||
{
|
||||
@ -67,7 +82,6 @@ namespace wil
|
||||
dateTime.UniversalTime = (timeT + SecondsToStartOf1970) * HundredNanoSecondsInSecond;
|
||||
return dateTime;
|
||||
}
|
||||
#endif // _INC_TIME
|
||||
|
||||
#pragma region HSTRING Helpers
|
||||
/// @cond
|
||||
@ -145,16 +159,17 @@ namespace wil
|
||||
return str;
|
||||
}
|
||||
|
||||
#ifdef WIL_ENABLE_EXCEPTIONS
|
||||
template<class TraitsT, class AllocT>
|
||||
static const wchar_t* get_buffer(
|
||||
const std::basic_string<wchar_t, TraitsT, AllocT>& str,
|
||||
UINT32* length) WI_NOEXCEPT
|
||||
// Overload for std::wstring, or at least things that behave like std::wstring, without adding a dependency
|
||||
// on STL headers
|
||||
template <typename StringT>
|
||||
static wistd::enable_if_t<wistd::conjunction_v<
|
||||
wistd::is_same<const wchar_t*, decltype(wistd::declval<StringT>().c_str())>,
|
||||
wistd::is_same<typename StringT::size_type, decltype(wistd::declval<StringT>().length())>>,
|
||||
const wchar_t*> get_buffer(const StringT& str, UINT32* length) WI_NOEXCEPT
|
||||
{
|
||||
*length = static_cast<UINT32>(str.length());
|
||||
return str.c_str();
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename LhsT, typename RhsT>
|
||||
static auto compare(LhsT&& lhs, RhsT&& rhs) ->
|
||||
@ -224,8 +239,8 @@ namespace wil
|
||||
//! Detects if one or more embedded null is present in an HSTRING.
|
||||
inline bool HasEmbeddedNull(_In_opt_ HSTRING value)
|
||||
{
|
||||
BOOL hasEmbeddedNull;
|
||||
WindowsStringHasEmbeddedNull(value, &hasEmbeddedNull);
|
||||
BOOL hasEmbeddedNull = FALSE;
|
||||
(void)WindowsStringHasEmbeddedNull(value, &hasEmbeddedNull);
|
||||
return hasEmbeddedNull != FALSE;
|
||||
}
|
||||
|
||||
@ -429,14 +444,14 @@ namespace wil
|
||||
#pragma warning(disable:4702) // https://github.com/Microsoft/wil/issues/2
|
||||
struct type // T holder
|
||||
{
|
||||
type() {};
|
||||
type(T&& value) : m_value(wistd::forward<T>(value)) {};
|
||||
type() = default;
|
||||
type(T&& value) : m_value(wistd::forward<T>(value)) {}
|
||||
operator T() const { return m_value; }
|
||||
type& operator=(T&& value) { m_value = wistd::forward<T>(value); return *this; }
|
||||
T Get() const { return m_value; }
|
||||
|
||||
// Returning T&& to support move only types
|
||||
// In case of absense of T::operator=(T&&) a call to T::operator=(const T&) will happen
|
||||
// In case of absence of T::operator=(T&&) a call to T::operator=(const T&) will happen
|
||||
T&& Get() { return wistd::move(m_value); }
|
||||
|
||||
HRESULT CopyTo(T* result) const { *result = m_value; return S_OK; }
|
||||
@ -730,7 +745,7 @@ namespace wil
|
||||
vector_range_nothrow(const vector_range_nothrow&) = delete;
|
||||
vector_range_nothrow& operator=(const vector_range_nothrow&) = delete;
|
||||
|
||||
vector_range_nothrow(vector_range_nothrow&& other) :
|
||||
vector_range_nothrow(vector_range_nothrow&& other) WI_NOEXCEPT :
|
||||
m_v(other.m_v), m_size(other.m_size), m_result(other.m_result), m_resultStorage(other.m_resultStorage),
|
||||
m_currentElement(wistd::move(other.m_currentElement))
|
||||
{
|
||||
@ -985,6 +1000,39 @@ namespace wil
|
||||
};
|
||||
#pragma endregion
|
||||
|
||||
#if defined(__WI_HAS_STD_VECTOR)
|
||||
/** Converts WinRT vectors to std::vector by requesting the collection's data in a single
|
||||
operation. This can be more efficient in terms of IPC cost than iteratively processing it.
|
||||
~~~
|
||||
ComPtr<IVector<IPropertyValue*>> values = GetValues();
|
||||
std::vector<ComPtr<IPropertyValue>> allData = wil::to_vector(values);
|
||||
for (ComPtr<IPropertyValue> const& item : allData)
|
||||
{
|
||||
// use item
|
||||
}
|
||||
Can be used for ABI::Windows::Foundation::Collections::IVector<T> and
|
||||
ABI::Windows::Foundation::Collections::IVectorView<T>
|
||||
*/
|
||||
template<typename VectorType> auto to_vector(VectorType* src)
|
||||
{
|
||||
using TResult = typename details::MapVectorResultType<VectorType>::type;
|
||||
using TSmart = typename details::MapToSmartType<TResult>::type;
|
||||
static_assert(sizeof(TResult) == sizeof(TSmart), "result and smart sizes are different");
|
||||
std::vector<TSmart> output;
|
||||
UINT32 expected = 0;
|
||||
THROW_IF_FAILED(src->get_Size(&expected));
|
||||
if (expected > 0)
|
||||
{
|
||||
output.resize(expected + 1);
|
||||
UINT32 fetched = 0;
|
||||
THROW_IF_FAILED(src->GetMany(0, static_cast<UINT32>(output.size()), reinterpret_cast<TResult*>(output.data()), &fetched));
|
||||
THROW_HR_IF(E_CHANGED_STATE, fetched > expected);
|
||||
output.resize(fetched);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma region error code base IIterable<>
|
||||
template <typename T>
|
||||
class iterable_range_nothrow
|
||||
@ -998,7 +1046,7 @@ namespace wil
|
||||
iterable_range_nothrow& operator=(const iterable_range_nothrow&) = delete;
|
||||
iterable_range_nothrow& operator=(iterable_range_nothrow &&) = delete;
|
||||
|
||||
iterable_range_nothrow(iterable_range_nothrow&& other) :
|
||||
iterable_range_nothrow(iterable_range_nothrow&& other) WI_NOEXCEPT :
|
||||
m_iterator(wistd::move(other.m_iterator)), m_element(wistd::move(other.m_element)),
|
||||
m_resultStorage(other.m_resultStorage)
|
||||
{
|
||||
@ -1274,9 +1322,9 @@ namespace details
|
||||
// LastType<int, bool>::type boolValue;
|
||||
template <typename... Ts> struct LastType
|
||||
{
|
||||
template<typename T, typename... Ts> struct LastTypeOfTs
|
||||
template<typename T, typename... OtherTs> struct LastTypeOfTs
|
||||
{
|
||||
typedef typename LastTypeOfTs<Ts...>::type type;
|
||||
typedef typename LastTypeOfTs<OtherTs...>::type type;
|
||||
};
|
||||
|
||||
template<typename T> struct LastTypeOfTs<T>
|
||||
@ -1284,8 +1332,8 @@ namespace details
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<typename... Ts>
|
||||
static typename LastTypeOfTs<Ts...>::type LastTypeOfTsFunc() {}
|
||||
template<typename... OtherTs>
|
||||
static typename LastTypeOfTs<OtherTs...>::type LastTypeOfTsFunc() {}
|
||||
typedef decltype(LastTypeOfTsFunc<Ts...>()) type;
|
||||
};
|
||||
|
||||
@ -1315,14 +1363,28 @@ namespace details
|
||||
typedef wistd::remove_pointer_t<decltype(GetAsyncDelegateType(operation))> TIDelegate;
|
||||
|
||||
auto callback = Callback<Implements<RuntimeClassFlags<ClassicCom>, TIDelegate, TBaseAgility>>(
|
||||
[func = wistd::forward<TFunction>(func)](TIOperation operation, AsyncStatus status) mutable -> HRESULT
|
||||
[func = wistd::forward<TFunction>(func)](TIOperation operation, ABI::Windows::Foundation::AsyncStatus status) mutable -> HRESULT
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
if (status != AsyncStatus::Completed) // avoid a potentially costly marshaled QI / call if we completed successfully
|
||||
if (status != ABI::Windows::Foundation::AsyncStatus::Completed) // avoid a potentially costly marshaled QI / call if we completed successfully
|
||||
{
|
||||
ComPtr<IAsyncInfo> asyncInfo;
|
||||
operation->QueryInterface(IID_PPV_ARGS(&asyncInfo)); // All must implement IAsyncInfo
|
||||
asyncInfo->get_ErrorCode(&hr);
|
||||
// QI to the IAsyncInfo interface. While all operations implement this, it is
|
||||
// possible that the stub has disconnected, causing the QI to fail.
|
||||
ComPtr<ABI::Windows::Foundation::IAsyncInfo> asyncInfo;
|
||||
hr = operation->QueryInterface(IID_PPV_ARGS(&asyncInfo));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Save the error code result in a temporary variable to allow us
|
||||
// to also retrieve the result of the COM call. If the stub has
|
||||
// disconnected, this call may fail.
|
||||
HRESULT errorCode = E_UNEXPECTED;
|
||||
hr = asyncInfo->get_ErrorCode(&errorCode);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Return the operations error code to the caller.
|
||||
hr = errorCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CallAndHandleErrors(func, hr);
|
||||
@ -1340,21 +1402,35 @@ namespace details
|
||||
typedef wistd::remove_pointer_t<decltype(GetAsyncDelegateType(operation))> TIDelegate;
|
||||
|
||||
auto callback = Callback<Implements<RuntimeClassFlags<ClassicCom>, TIDelegate, TBaseAgility>>(
|
||||
[func = wistd::forward<TFunction>(func)](TIOperation operation, AsyncStatus status) mutable -> HRESULT
|
||||
[func = wistd::forward<TFunction>(func)](TIOperation operation, ABI::Windows::Foundation::AsyncStatus status) mutable -> HRESULT
|
||||
{
|
||||
typename details::MapToSmartType<typename GetAbiType<typename wistd::remove_pointer<TIOperation>::type::TResult_complex>::type>::type result;
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
if (status == AsyncStatus::Completed)
|
||||
// avoid a potentially costly marshaled QI / call if we completed successfully
|
||||
if (status == ABI::Windows::Foundation::AsyncStatus::Completed)
|
||||
{
|
||||
hr = operation->GetResults(result.GetAddressOf());
|
||||
}
|
||||
else
|
||||
{
|
||||
// avoid a potentially costly marshaled QI / call if we completed successfully
|
||||
ComPtr<IAsyncInfo> asyncInfo;
|
||||
operation->QueryInterface(IID_PPV_ARGS(&asyncInfo)); // all must implement this
|
||||
asyncInfo->get_ErrorCode(&hr);
|
||||
// QI to the IAsyncInfo interface. While all operations implement this, it is
|
||||
// possible that the stub has disconnected, causing the QI to fail.
|
||||
ComPtr<ABI::Windows::Foundation::IAsyncInfo> asyncInfo;
|
||||
hr = operation->QueryInterface(IID_PPV_ARGS(&asyncInfo));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Save the error code result in a temporary variable to allow us
|
||||
// to also retrieve the result of the COM call. If the stub has
|
||||
// disconnected, this call may fail.
|
||||
HRESULT errorCode = E_UNEXPECTED;
|
||||
hr = asyncInfo->get_ErrorCode(&errorCode);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Return the operations error code to the caller.
|
||||
hr = errorCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CallAndHandleErrors(func, hr, result.Get());
|
||||
@ -1378,7 +1454,7 @@ namespace details
|
||||
RETURN_HR(m_completedEventHandle.create());
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Invoke(_In_ TIOperation, AsyncStatus status) override
|
||||
HRESULT STDMETHODCALLTYPE Invoke(_In_ TIOperation, ABI::Windows::Foundation::AsyncStatus status) override
|
||||
{
|
||||
m_status = status;
|
||||
m_completedEventHandle.SetEvent();
|
||||
@ -1390,13 +1466,13 @@ namespace details
|
||||
return m_completedEventHandle.get();
|
||||
}
|
||||
|
||||
AsyncStatus GetStatus() const
|
||||
ABI::Windows::Foundation::AsyncStatus GetStatus() const
|
||||
{
|
||||
return m_status;
|
||||
}
|
||||
|
||||
private:
|
||||
volatile AsyncStatus m_status = AsyncStatus::Started;
|
||||
volatile ABI::Windows::Foundation::AsyncStatus m_status = ABI::Windows::Foundation::AsyncStatus::Started;
|
||||
wil::unique_event_nothrow m_completedEventHandle;
|
||||
};
|
||||
|
||||
@ -1419,12 +1495,25 @@ namespace details
|
||||
}
|
||||
RETURN_IF_FAILED(hr);
|
||||
|
||||
if (completedDelegate->GetStatus() != AsyncStatus::Completed)
|
||||
if (completedDelegate->GetStatus() != ABI::Windows::Foundation::AsyncStatus::Completed)
|
||||
{
|
||||
Microsoft::WRL::ComPtr<IAsyncInfo> asyncInfo;
|
||||
operation->QueryInterface(IID_PPV_ARGS(&asyncInfo)); // all must implement this
|
||||
hr = E_UNEXPECTED;
|
||||
asyncInfo->get_ErrorCode(&hr); // error return ignored, ok?
|
||||
// QI to the IAsyncInfo interface. While all operations implement this, it is
|
||||
// possible that the stub has disconnected, causing the QI to fail.
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> asyncInfo;
|
||||
hr = operation->QueryInterface(IID_PPV_ARGS(&asyncInfo));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Save the error code result in a temporary variable to allow us
|
||||
// to also retrieve the result of the COM call. If the stub has
|
||||
// disconnected, this call may fail.
|
||||
HRESULT errorCode = E_UNEXPECTED;
|
||||
hr = asyncInfo->get_ErrorCode(&errorCode);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Return the operations error code to the caller.
|
||||
hr = errorCode;
|
||||
}
|
||||
}
|
||||
return hr; // leave it to the caller to log failures.
|
||||
}
|
||||
return S_OK;
|
||||
@ -1669,7 +1758,7 @@ namespace details
|
||||
|
||||
IFACEMETHODIMP put_Completed(ABI::Windows::Foundation::IAsyncOperationCompletedHandler<TResult>* competed) override
|
||||
{
|
||||
competed->Invoke(this, AsyncStatus::Completed);
|
||||
competed->Invoke(this, ABI::Windows::Foundation::AsyncStatus::Completed);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@ -1708,7 +1797,7 @@ namespace details
|
||||
public:
|
||||
IFACEMETHODIMP put_Completed(ABI::Windows::Foundation::IAsyncActionCompletedHandler* competed) override
|
||||
{
|
||||
competed->Invoke(this, AsyncStatus::Completed);
|
||||
competed->Invoke(this, ABI::Windows::Foundation::AsyncStatus::Completed);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@ -1866,7 +1955,19 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
auto resolvedSender = m_weakSender.Resolve<T>();
|
||||
auto resolvedSender = [&]()
|
||||
{
|
||||
try
|
||||
{
|
||||
return m_weakSender.Resolve<T>();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Ignore RPC or other failures that are unavoidable in some cases
|
||||
// matching wil::unique_winrt_event_token and winrt::event_revoker
|
||||
return static_cast<T^>(nullptr);
|
||||
}
|
||||
}();
|
||||
if (resolvedSender)
|
||||
{
|
||||
(resolvedSender->*m_removalFunction)(m_token);
|
||||
@ -2205,7 +2306,7 @@ struct ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler<ABI
|
||||
#pragma pop_macro("ABI")
|
||||
#endif
|
||||
|
||||
#ifdef WIL_ENABLE_EXCEPTIONS
|
||||
#if __WI_HAS_STD_LESS
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
39
Externals/WIL/include/wil/wistd_config.h
vendored
39
Externals/WIL/include/wil/wistd_config.h
vendored
@ -39,7 +39,7 @@
|
||||
#define _WISTD_CONFIG_H_
|
||||
|
||||
// DO NOT add *any* additional includes to this file -- there should be no dependencies from its usage
|
||||
#include <stddef.h> // For size_t and other necessary types
|
||||
#include <cstddef> // For size_t and other necessary types
|
||||
|
||||
/// @cond
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
@ -107,6 +107,29 @@
|
||||
# define __WI_LIBCPP_COMPILER_IBM
|
||||
#endif
|
||||
|
||||
#if defined(__WI_LIBCPP_COMPILER_MSVC)
|
||||
#define __WI_PUSH_WARNINGS __pragma(warning(push))
|
||||
#define __WI_POP_WARNINGS __pragma(warning(pop))
|
||||
#elif defined(__WI_LIBCPP_COMPILER_CLANG)
|
||||
#define __WI_PUSH_WARNINGS __pragma(clang diagnostic push)
|
||||
#define __WI_POP_WARNINGS __pragma(clang diagnostic pop)
|
||||
#else
|
||||
#define __WI_PUSH_WARNINGS
|
||||
#define __WI_POP_WARNINGS
|
||||
#endif
|
||||
|
||||
#ifdef __WI_LIBCPP_COMPILER_MSVC
|
||||
#define __WI_MSVC_DISABLE_WARNING(id) __pragma(warning(disable: id))
|
||||
#else
|
||||
#define __WI_MSVC_DISABLE_WARNING(id)
|
||||
#endif
|
||||
|
||||
#ifdef __WI_LIBCPP_COMPILER_CLANG
|
||||
#define __WI_CLANG_DISABLE_WARNING(warning) __pragma(clang diagnostic ignored #warning)
|
||||
#else
|
||||
#define __WI_CLANG_DISABLE_WARNING(warning)
|
||||
#endif
|
||||
|
||||
// NOTE: MSVC, which is what we primarily target, is severly underrepresented in libc++ and checks such as
|
||||
// __has_feature(...) are always false for MSVC, even when the feature being tested _is_ present in MSVC. Therefore, we
|
||||
// instead modify all checks to be __WI_HAS_FEATURE_IS_UNION, etc., which provides the correct value for MSVC and falls
|
||||
@ -448,7 +471,7 @@
|
||||
|
||||
namespace wistd // ("Windows Implementation" std)
|
||||
{
|
||||
typedef decltype(__nullptr) nullptr_t;
|
||||
using nullptr_t = decltype(__nullptr);
|
||||
|
||||
template <class _T1, class _T2 = _T1>
|
||||
struct __less
|
||||
@ -531,18 +554,18 @@ namespace wistd // ("Windows Implementation" std)
|
||||
template <class _Arg, class _Result>
|
||||
struct __WI_LIBCPP_TEMPLATE_VIS unary_function
|
||||
{
|
||||
typedef _Arg argument_type;
|
||||
typedef _Result result_type;
|
||||
using argument_type = _Arg;
|
||||
using result_type = _Result;
|
||||
};
|
||||
|
||||
template <class _Arg1, class _Arg2, class _Result>
|
||||
struct __WI_LIBCPP_TEMPLATE_VIS binary_function
|
||||
{
|
||||
typedef _Arg1 first_argument_type;
|
||||
typedef _Arg2 second_argument_type;
|
||||
typedef _Result result_type;
|
||||
using first_argument_type = _Arg1;
|
||||
using second_argument_type = _Arg2;
|
||||
using result_type = _Result;
|
||||
};
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
#endif _WISTD_CONFIG_H_
|
||||
#endif // _WISTD_CONFIG_H_
|
||||
|
43
Externals/WIL/include/wil/wistd_functional.h
vendored
43
Externals/WIL/include/wil/wistd_functional.h
vendored
@ -46,6 +46,7 @@
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4324)
|
||||
#pragma warning(disable: 4800)
|
||||
|
||||
/// @cond
|
||||
namespace wistd // ("Windows Implementation" std)
|
||||
@ -249,25 +250,28 @@ namespace wistd // ("Windows Implementation" std)
|
||||
return _Invoker::__call(__f_, wistd::forward<_ArgTypes>(__arg)...);
|
||||
}
|
||||
|
||||
} // __function
|
||||
|
||||
template<class _Rp, class ..._ArgTypes>
|
||||
class __WI_LIBCPP_TEMPLATE_VIS function<_Rp(_ArgTypes...)>
|
||||
: public __function::__maybe_derive_from_unary_function<_Rp(_ArgTypes...)>,
|
||||
public __function::__maybe_derive_from_binary_function<_Rp(_ArgTypes...)>
|
||||
{
|
||||
// 'wistd::function' is most similar to 'inplace_function' in that it _only_ permits holding function objects
|
||||
// that can fit within its internal buffer. Therefore, we expand this size to accommodate space for at least 12
|
||||
// pointers (__base vtable takes an additional one).
|
||||
static constexpr size_t __buffer_size = 13 * sizeof(void*);
|
||||
constexpr const size_t __buffer_size = 13 * sizeof(void*);
|
||||
|
||||
typedef __function::__base<_Rp(_ArgTypes...)> __base;
|
||||
} // __function
|
||||
|
||||
// NOTE: The extra 'alignas' here is to work around the x86 compiler bug mentioned in
|
||||
// https://github.com/microsoft/STL/issues/1533 to force alignment on the stack
|
||||
template<class _Rp, class ..._ArgTypes>
|
||||
class __WI_LIBCPP_TEMPLATE_VIS __WI_ALIGNAS(typename aligned_storage<__function::__buffer_size>::type)
|
||||
function<_Rp(_ArgTypes...)>
|
||||
: public __function::__maybe_derive_from_unary_function<_Rp(_ArgTypes...)>,
|
||||
public __function::__maybe_derive_from_binary_function<_Rp(_ArgTypes...)>
|
||||
{
|
||||
using __base = __function::__base<_Rp(_ArgTypes...)>;
|
||||
__WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS
|
||||
typename aligned_storage<__buffer_size>::type __buf_;
|
||||
typename aligned_storage<__function::__buffer_size>::type __buf_;
|
||||
__base* __f_;
|
||||
|
||||
__WI_LIBCPP_NO_CFI static __base *__as_base(void *p) {
|
||||
return reinterpret_cast<__base*>(p);
|
||||
return static_cast<__base*>(p);
|
||||
}
|
||||
|
||||
template <class _Fp, bool>
|
||||
@ -281,7 +285,7 @@ namespace wistd // ("Windows Implementation" std)
|
||||
template <class _Fp>
|
||||
struct __callable_imp<_Fp, false>
|
||||
{
|
||||
static const bool value = false;
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
template <class _Fp>
|
||||
@ -296,11 +300,12 @@ namespace wistd // ("Windows Implementation" std)
|
||||
template <class _Fp>
|
||||
using _EnableIfCallable = typename enable_if<__callable<_Fp>::value>::type;
|
||||
public:
|
||||
typedef _Rp result_type;
|
||||
using result_type = _Rp;
|
||||
|
||||
// construct/copy/destroy:
|
||||
__WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS
|
||||
function() WI_NOEXCEPT : __f_(0) {}
|
||||
|
||||
__WI_LIBCPP_INLINE_VISIBILITY
|
||||
function(nullptr_t) WI_NOEXCEPT : __f_(0) {}
|
||||
function(const function&);
|
||||
@ -340,7 +345,7 @@ namespace wistd // ("Windows Implementation" std)
|
||||
__WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS
|
||||
function<_Rp(_ArgTypes...)>::function(const function& __f)
|
||||
{
|
||||
if (__f.__f_ == 0)
|
||||
if (__f.__f_ == nullptr)
|
||||
__f_ = 0;
|
||||
else
|
||||
{
|
||||
@ -353,7 +358,7 @@ namespace wistd // ("Windows Implementation" std)
|
||||
__WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS __WI_LIBCPP_SUPPRESS_NOEXCEPT_ANALYSIS
|
||||
function<_Rp(_ArgTypes...)>::function(function&& __f)
|
||||
{
|
||||
if (__f.__f_ == 0)
|
||||
if (__f.__f_ == nullptr)
|
||||
__f_ = 0;
|
||||
else
|
||||
{
|
||||
@ -368,14 +373,14 @@ namespace wistd // ("Windows Implementation" std)
|
||||
template <class _Fp, class>
|
||||
__WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS
|
||||
function<_Rp(_ArgTypes...)>::function(_Fp __f)
|
||||
: __f_(0)
|
||||
: __f_(nullptr)
|
||||
{
|
||||
if (__function::__not_null(__f))
|
||||
{
|
||||
typedef __function::__func<_Fp, _Rp(_ArgTypes...)> _FF;
|
||||
static_assert(sizeof(_FF) <= sizeof(__buf_),
|
||||
"The sizeof(wistd::function) has grown too large for the reserved buffer (12 pointers). Refactor to reduce size of the capture.");
|
||||
__f_ = ::new((void*)&__buf_) _FF(wistd::move(__f));
|
||||
__f_ = ::new(static_cast<void*>(&__buf_)) _FF(wistd::move(__f));
|
||||
}
|
||||
}
|
||||
|
||||
@ -429,7 +434,7 @@ namespace wistd // ("Windows Implementation" std)
|
||||
typedef __function::__func<typename decay<_Fp>::type, _Rp(_ArgTypes...)> _FF;
|
||||
static_assert(sizeof(_FF) <= sizeof(__buf_),
|
||||
"The sizeof(wistd::function) has grown too large for the reserved buffer (12 pointers). Refactor to reduce size of the capture.");
|
||||
__f_ = ::new((void*)&__buf_) _FF(wistd::move(__f));
|
||||
__f_ = ::new(static_cast<void*>(&__buf_)) _FF(wistd::move(__f));
|
||||
}
|
||||
|
||||
return *this;
|
||||
@ -483,7 +488,7 @@ namespace wistd // ("Windows Implementation" std)
|
||||
_Rp
|
||||
function<_Rp(_ArgTypes...)>::operator()(_ArgTypes... __arg) const
|
||||
{
|
||||
if (__f_ == 0)
|
||||
if (__f_ == nullptr)
|
||||
__throw_bad_function_call();
|
||||
return (*__f_)(wistd::forward<_ArgTypes>(__arg)...);
|
||||
}
|
||||
|
66
Externals/WIL/include/wil/wistd_memory.h
vendored
66
Externals/WIL/include/wil/wistd_memory.h
vendored
@ -60,13 +60,13 @@ namespace wistd // ("Windows Implementation" std)
|
||||
template <class _Tp, class _Dp, bool = __has_pointer_type<_Dp>::value>
|
||||
struct __pointer_type
|
||||
{
|
||||
typedef typename _Dp::pointer type;
|
||||
using type = typename _Dp::pointer;
|
||||
};
|
||||
|
||||
template <class _Tp, class _Dp>
|
||||
struct __pointer_type<_Tp, _Dp, false>
|
||||
{
|
||||
typedef _Tp* type;
|
||||
using type = _Tp*;
|
||||
};
|
||||
|
||||
} // __pointer_type_imp
|
||||
@ -74,16 +74,16 @@ namespace wistd // ("Windows Implementation" std)
|
||||
template <class _Tp, class _Dp>
|
||||
struct __pointer_type
|
||||
{
|
||||
typedef typename __pointer_type_imp::__pointer_type<_Tp, typename remove_reference<_Dp>::type>::type type;
|
||||
using type = typename __pointer_type_imp::__pointer_type<_Tp, typename remove_reference<_Dp>::type>::type;
|
||||
};
|
||||
|
||||
template <class _Tp, int _Idx,
|
||||
bool _CanBeEmptyBase =
|
||||
is_empty<_Tp>::value && !__libcpp_is_final<_Tp>::value>
|
||||
struct __compressed_pair_elem {
|
||||
typedef _Tp _ParamT;
|
||||
typedef _Tp& reference;
|
||||
typedef const _Tp& const_reference;
|
||||
using _ParamT = _Tp;
|
||||
using reference = _Tp&;
|
||||
using const_reference = const _Tp&;
|
||||
|
||||
#ifndef __WI_LIBCPP_CXX03_LANG
|
||||
__WI_LIBCPP_INLINE_VISIBILITY constexpr __compressed_pair_elem() : __value_() {}
|
||||
@ -115,10 +115,10 @@ namespace wistd // ("Windows Implementation" std)
|
||||
|
||||
template <class _Tp, int _Idx>
|
||||
struct __compressed_pair_elem<_Tp, _Idx, true> : private _Tp {
|
||||
typedef _Tp _ParamT;
|
||||
typedef _Tp& reference;
|
||||
typedef const _Tp& const_reference;
|
||||
typedef _Tp __value_type;
|
||||
using _ParamT = _Tp;
|
||||
using reference = _Tp&;
|
||||
using const_reference = const _Tp&;
|
||||
using __value_type = _Tp;
|
||||
|
||||
#ifndef __WI_LIBCPP_CXX03_LANG
|
||||
__WI_LIBCPP_INLINE_VISIBILITY constexpr __compressed_pair_elem() = default;
|
||||
@ -149,10 +149,10 @@ namespace wistd // ("Windows Implementation" std)
|
||||
struct __second_tag {};
|
||||
|
||||
template <class _T1, class _T2>
|
||||
class __compressed_pair : private __compressed_pair_elem<_T1, 0>,
|
||||
private __compressed_pair_elem<_T2, 1> {
|
||||
typedef __compressed_pair_elem<_T1, 0> _Base1;
|
||||
typedef __compressed_pair_elem<_T2, 1> _Base2;
|
||||
class __declspec(empty_bases) __compressed_pair : private __compressed_pair_elem<_T1, 0>,
|
||||
private __compressed_pair_elem<_T2, 1> {
|
||||
using _Base1 = __compressed_pair_elem<_T1, 0>;
|
||||
using _Base2 = __compressed_pair_elem<_T2, 1>;
|
||||
|
||||
// NOTE: This static assert should never fire because __compressed_pair
|
||||
// is *almost never* used in a scenario where it's possible for T1 == T2.
|
||||
@ -271,7 +271,7 @@ namespace wistd // ("Windows Implementation" std)
|
||||
__WI_LIBCPP_INLINE_VISIBILITY
|
||||
default_delete(const default_delete<_Up>&,
|
||||
typename enable_if<is_convertible<_Up*, _Tp*>::value>::type* =
|
||||
0) WI_NOEXCEPT {}
|
||||
nullptr) WI_NOEXCEPT {}
|
||||
|
||||
__WI_LIBCPP_INLINE_VISIBILITY void operator()(_Tp* __ptr) const WI_NOEXCEPT {
|
||||
static_assert(sizeof(_Tp) > 0,
|
||||
@ -299,7 +299,7 @@ namespace wistd // ("Windows Implementation" std)
|
||||
template <class _Up>
|
||||
__WI_LIBCPP_INLINE_VISIBILITY
|
||||
default_delete(const default_delete<_Up[]>&,
|
||||
typename _EnableIfConvertible<_Up>::type* = 0) WI_NOEXCEPT {}
|
||||
typename _EnableIfConvertible<_Up>::type* = nullptr) WI_NOEXCEPT {}
|
||||
|
||||
template <class _Up>
|
||||
__WI_LIBCPP_INLINE_VISIBILITY
|
||||
@ -319,32 +319,32 @@ namespace wistd // ("Windows Implementation" std)
|
||||
template <class _Deleter>
|
||||
struct __unique_ptr_deleter_sfinae {
|
||||
static_assert(!is_reference<_Deleter>::value, "incorrect specialization");
|
||||
typedef const _Deleter& __lval_ref_type;
|
||||
typedef _Deleter&& __good_rval_ref_type;
|
||||
typedef true_type __enable_rval_overload;
|
||||
using __lval_ref_type = const _Deleter&;
|
||||
using __good_rval_ref_type = _Deleter&&;
|
||||
using __enable_rval_overload = true_type;
|
||||
};
|
||||
|
||||
template <class _Deleter>
|
||||
struct __unique_ptr_deleter_sfinae<_Deleter const&> {
|
||||
typedef const _Deleter& __lval_ref_type;
|
||||
typedef const _Deleter&& __bad_rval_ref_type;
|
||||
typedef false_type __enable_rval_overload;
|
||||
using __lval_ref_type = const _Deleter&;
|
||||
using __bad_rval_ref_type = const _Deleter&&;
|
||||
using __enable_rval_overload = false_type;
|
||||
};
|
||||
|
||||
template <class _Deleter>
|
||||
struct __unique_ptr_deleter_sfinae<_Deleter&> {
|
||||
typedef _Deleter& __lval_ref_type;
|
||||
typedef _Deleter&& __bad_rval_ref_type;
|
||||
typedef false_type __enable_rval_overload;
|
||||
using __lval_ref_type = _Deleter&;
|
||||
using __bad_rval_ref_type = _Deleter&&;
|
||||
using __enable_rval_overload = false_type;
|
||||
};
|
||||
#endif // !defined(__WI_LIBCPP_CXX03_LANG)
|
||||
|
||||
template <class _Tp, class _Dp = default_delete<_Tp> >
|
||||
class __WI_LIBCPP_TEMPLATE_VIS unique_ptr {
|
||||
public:
|
||||
typedef _Tp element_type;
|
||||
typedef _Dp deleter_type;
|
||||
typedef typename __pointer_type<_Tp, deleter_type>::type pointer;
|
||||
using element_type = _Tp;
|
||||
using deleter_type = _Dp;
|
||||
using pointer = typename __pointer_type<_Tp, deleter_type>::type;
|
||||
|
||||
static_assert(!is_rvalue_reference<deleter_type>::value,
|
||||
"the specified deleter type cannot be an rvalue reference");
|
||||
@ -355,7 +355,7 @@ namespace wistd // ("Windows Implementation" std)
|
||||
struct __nat { int __for_bool_; };
|
||||
|
||||
#ifndef __WI_LIBCPP_CXX03_LANG
|
||||
typedef __unique_ptr_deleter_sfinae<_Dp> _DeleterSFINAE;
|
||||
using _DeleterSFINAE = __unique_ptr_deleter_sfinae<_Dp>;
|
||||
|
||||
template <bool _Dummy>
|
||||
using _LValRefType =
|
||||
@ -582,9 +582,9 @@ namespace wistd // ("Windows Implementation" std)
|
||||
template <class _Tp, class _Dp>
|
||||
class __WI_LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp> {
|
||||
public:
|
||||
typedef _Tp element_type;
|
||||
typedef _Dp deleter_type;
|
||||
typedef typename __pointer_type<_Tp, deleter_type>::type pointer;
|
||||
using element_type = _Tp;
|
||||
using deleter_type = _Dp;
|
||||
using pointer = typename __pointer_type<_Tp, deleter_type>::type;
|
||||
|
||||
private:
|
||||
__compressed_pair<pointer, deleter_type> __ptr_;
|
||||
@ -602,7 +602,7 @@ namespace wistd // ("Windows Implementation" std)
|
||||
{};
|
||||
|
||||
#ifndef __WI_LIBCPP_CXX03_LANG
|
||||
typedef __unique_ptr_deleter_sfinae<_Dp> _DeleterSFINAE;
|
||||
using _DeleterSFINAE = __unique_ptr_deleter_sfinae<_Dp>;
|
||||
|
||||
template <bool _Dummy>
|
||||
using _LValRefType =
|
||||
|
43
Externals/WIL/include/wil/wrl.h
vendored
43
Externals/WIL/include/wil/wrl.h
vendored
@ -14,6 +14,11 @@
|
||||
#include <wrl.h>
|
||||
#include "result.h"
|
||||
#include "common.h" // wistd type_traits helpers
|
||||
#include <libloaderapi.h> // GetModuleHandleW
|
||||
|
||||
/// @cond
|
||||
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
|
||||
/// @endcond
|
||||
|
||||
namespace wil
|
||||
{
|
||||
@ -79,6 +84,44 @@ namespace wil
|
||||
return result;
|
||||
}
|
||||
#endif // WIL_ENABLE_EXCEPTIONS
|
||||
|
||||
/** Holds a reference to the host WRL module to prevent it from being unloaded.
|
||||
Normally, the reference is held implicitly because you are a member function
|
||||
of a DLL-hosted COM object, or because you retain a strong reference
|
||||
to some DLL-hosted COM object, but if those do not apply to you, then you
|
||||
will need to hold a reference explicitly. For examples (and for the C++/WinRT
|
||||
equivalent), see winrt_module_reference.
|
||||
*/
|
||||
struct [[nodiscard]] wrl_module_reference
|
||||
{
|
||||
wrl_module_reference()
|
||||
{
|
||||
if (auto modulePtr = ::Microsoft::WRL::GetModuleBase())
|
||||
{
|
||||
modulePtr->IncrementObjectCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef GET_MODULE_HANDLE_EX_FLAG_PIN
|
||||
// If this assertion fails, then you are using wrl_module_reference
|
||||
// from a DLL that does not host WRL objects, and the module reference
|
||||
// has no effect.
|
||||
WI_ASSERT(reinterpret_cast<HMODULE>(&__ImageBase) == GetModuleHandleW(nullptr));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
wrl_module_reference(wrl_module_reference const&) : wrl_module_reference() {}
|
||||
|
||||
~wrl_module_reference()
|
||||
{
|
||||
if (auto modulePtr = ::Microsoft::WRL::GetModuleBase())
|
||||
{
|
||||
modulePtr->DecrementObjectCount();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace wil
|
||||
|
||||
#endif // __WIL_WRL_INCLUDED
|
||||
|
Reference in New Issue
Block a user