//********************************************************* // // 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. // //********************************************************* #include "result_macros.h" #include "wistd_functional.h" #include "wistd_memory.h" #pragma warning(push) #pragma warning(disable:26135 26110) // Missing locking annotation, Caller failing to hold lock #pragma warning(disable:4714) // __forceinline not honored #ifndef __WIL_RESOURCE #define __WIL_RESOURCE // stdint.h and intsafe.h have conflicting definitions, so it's not safe to include either to pick up our dependencies, // so the definitions we need are copied below #ifdef _WIN64 #define __WI_SIZE_MAX 0xffffffffffffffffui64 // UINT64_MAX #else /* _WIN64 */ #define __WI_SIZE_MAX 0xffffffffui32 // UINT32_MAX #endif /* _WIN64 */ // Forward declaration /// @cond namespace Microsoft { namespace WRL { template class ComPtr; } } /// @endcond namespace wil { //! This type copies the current value of GetLastError at construction and resets the last error //! to that value when it is destroyed. //! //! This is useful in library code that runs during a value's destructor. If the library code could //! inadvertantly change the value of GetLastError (by calling a Win32 API or similar), it should //! instantiate a value of this type before calling the library function in order to preserve the //! GetLastError value the user would expect. //! //! This construct exists to hide kernel mode/user mode differences in wil library code. //! //! Example usage: //! //! if (!CreateFile(...)) //! { //! auto lastError = wil::last_error_context(); //! WriteFile(g_hlog, logdata); //! } //! class last_error_context { #ifndef WIL_KERNEL_MODE bool m_dismissed; DWORD m_error; public: last_error_context() WI_NOEXCEPT : m_dismissed(false), m_error(::GetLastError()) { } last_error_context(last_error_context&& other) WI_NOEXCEPT { operator=(wistd::move(other)); } last_error_context & operator=(last_error_context&& other) WI_NOEXCEPT { m_dismissed = wistd::exchange(other.m_dismissed, true); m_error = other.m_error; return *this; } ~last_error_context() WI_NOEXCEPT { if (!m_dismissed) { ::SetLastError(m_error); } } //! last_error_context doesn't own a concrete resource, so therefore //! it just disarms its destructor and returns void. void release() WI_NOEXCEPT { WI_ASSERT(!m_dismissed); m_dismissed = true; } #else public: void release() WI_NOEXCEPT { } #endif // WIL_KERNEL_MODE }; /// @cond namespace details { typedef wistd::integral_constant pointer_access_all; // get(), release(), addressof(), and '&' are available typedef wistd::integral_constant pointer_access_noaddress; // get() and release() are available typedef wistd::integral_constant pointer_access_none; // the raw pointer is not available template // nullptr_t if the invalid handle value is compatible with nullptr, otherwise pointer struct resource_policy { typedef pointer_storage pointer_storage; typedef pointer pointer; typedef pointer_invalid pointer_invalid; typedef pointer_access pointer_access; __forceinline static pointer_storage invalid_value() WI_NOEXCEPT { return (pointer)invalid; } __forceinline static bool is_valid(pointer_storage value) WI_NOEXCEPT { return (static_cast(value) != (pointer)invalid); } __forceinline static void close(pointer_storage value) WI_NOEXCEPT { wistd::invoke(close_fn, value); } inline static void close_reset(pointer_storage value) WI_NOEXCEPT { auto preserveError = last_error_context(); wistd::invoke(close_fn, value); } }; // This class provides the pointer storage behind the implementation of unique_any_t utilizing the given // resource_policy. It is separate from unique_any_t to allow a type-specific specialization class to plug // into the inheritance chain between unique_any_t and unique_storage. This allows classes like unique_event // to be a unique_any formed class, but also expose methods like SetEvent directly. template class unique_storage { protected: typedef policy policy; typedef typename policy::pointer_storage pointer_storage; typedef typename policy::pointer pointer; typedef unique_storage base_storage; unique_storage() WI_NOEXCEPT : m_ptr(policy::invalid_value()) { } explicit unique_storage(pointer_storage ptr) WI_NOEXCEPT : m_ptr(ptr) { } unique_storage(unique_storage &&other) WI_NOEXCEPT : m_ptr(wistd::move(other.m_ptr)) { other.m_ptr = policy::invalid_value(); } ~unique_storage() WI_NOEXCEPT { if (policy::is_valid(m_ptr)) { policy::close(m_ptr); } } void replace(unique_storage &&other) WI_NOEXCEPT { reset(other.m_ptr); other.m_ptr = policy::invalid_value(); } public: bool is_valid() const WI_NOEXCEPT { return policy::is_valid(m_ptr); } void reset(pointer_storage ptr = policy::invalid_value()) WI_NOEXCEPT { if (policy::is_valid(m_ptr)) { policy::close_reset(m_ptr); } m_ptr = ptr; } void reset(wistd::nullptr_t) WI_NOEXCEPT { static_assert(wistd::is_same::value, "reset(nullptr): valid only for handle types using nullptr as the invalid value"); reset(); } pointer get() const WI_NOEXCEPT { return static_cast(m_ptr); } pointer_storage release() WI_NOEXCEPT { static_assert(!wistd::is_same::value, "release(): the raw handle value is not available for this resource class"); auto ptr = m_ptr; m_ptr = policy::invalid_value(); return ptr; } pointer_storage *addressof() WI_NOEXCEPT { static_assert(wistd::is_same::value, "addressof(): the address of the raw handle is not available for this resource class"); return &m_ptr; } private: pointer_storage m_ptr; }; } // details /// @endcond // This class when paired with unique_storage and an optional type-specific specialization class implements // the same interface as STL's unique_ptr<> for resource handle types. It is a non-copyable, yet movable class // supporting attach (reset), detach (release), retrieval (get()). template class unique_any_t : public storage_t { public: typedef typename storage_t::policy policy; typedef typename policy::pointer_storage pointer_storage; typedef typename policy::pointer pointer; unique_any_t(unique_any_t const &) = delete; unique_any_t& operator=(unique_any_t const &) = delete; // Note that the default constructor really shouldn't be needed (taken care of by the forwarding constructor below), but // the forwarding constructor causes an internal compiler error when the class is used in a C++ array. Defining the default // constructor independent of the forwarding constructor removes the compiler limitation. unique_any_t() = default; // forwarding constructor: forwards all 'explicit' and multi-arg constructors to the base class template explicit unique_any_t(arg1 && first, args_t&&... args) : // should not be WI_NOEXCEPT (may forward to a throwing constructor) storage_t(wistd::forward(first), wistd::forward(args)...) { static_assert(wistd::is_same::value || wistd::is_same::value || wistd::is_same::value, "pointer_access policy must be a known pointer_access* integral type"); } unique_any_t(wistd::nullptr_t) WI_NOEXCEPT { static_assert(wistd::is_same::value, "nullptr constructor: valid only for handle types using nullptr as the invalid value"); } unique_any_t(unique_any_t &&other) WI_NOEXCEPT : storage_t(wistd::move(other)) { } unique_any_t& operator=(unique_any_t &&other) WI_NOEXCEPT { if (this != wistd::addressof(other)) { // cast to base_storage to 'skip' calling the (optional) specialization class that provides handle-specific functionality storage_t::replace(wistd::move(static_cast(other))); } return (*this); } unique_any_t& operator=(wistd::nullptr_t) WI_NOEXCEPT { static_assert(wistd::is_same::value, "nullptr assignment: valid only for handle types using nullptr as the invalid value"); storage_t::reset(); return (*this); } void swap(unique_any_t &other) WI_NOEXCEPT { unique_any_t self(wistd::move(*this)); operator=(wistd::move(other)); other = wistd::move(self); } explicit operator bool() const WI_NOEXCEPT { return storage_t::is_valid(); } //! ~~~~ //! BOOL OpenOrCreateWaffle(PCWSTR name, HWAFFLE* handle); //! wil::unique_any waffle; //! RETURN_IF_WIN32_BOOL_FALSE(OpenOrCreateWaffle(L"tasty.yum", waffle.put())); //! ~~~~ pointer_storage *put() WI_NOEXCEPT { static_assert(wistd::is_same::value, "operator & is not available for this handle"); storage_t::reset(); return storage_t::addressof(); } pointer_storage *operator&() WI_NOEXCEPT { return put(); } pointer get() const WI_NOEXCEPT { static_assert(!wistd::is_same::value, "get(): the raw handle value is not available for this resource class"); return storage_t::get(); } // The following functions are publicly exposed by their inclusion in the unique_storage base class // explicit unique_any_t(pointer_storage ptr) WI_NOEXCEPT // void reset(pointer_storage ptr = policy::invalid_value()) WI_NOEXCEPT // void reset(wistd::nullptr_t) WI_NOEXCEPT // pointer_storage release() WI_NOEXCEPT // not exposed for some resource types // pointer_storage *addressof() WI_NOEXCEPT // not exposed for some resource types }; template void swap(unique_any_t& left, unique_any_t& right) WI_NOEXCEPT { left.swap(right); } template bool operator==(const unique_any_t& left, const unique_any_t& right) WI_NOEXCEPT { return (left.get() == right.get()); } template bool operator==(const unique_any_t& left, wistd::nullptr_t) WI_NOEXCEPT { static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, "the resource class does not use nullptr as an invalid value"); return !left; } template bool operator==(wistd::nullptr_t, const unique_any_t& right) WI_NOEXCEPT { static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, "the resource class does not use nullptr as an invalid value"); return !right; } template bool operator!=(const unique_any_t& left, const unique_any_t& right) WI_NOEXCEPT { return (!(left.get() == right.get())); } template bool operator!=(const unique_any_t& left, wistd::nullptr_t) WI_NOEXCEPT { static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, "the resource class does not use nullptr as an invalid value"); return !!left; } template bool operator!=(wistd::nullptr_t, const unique_any_t& right) WI_NOEXCEPT { static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, "the resource class does not use nullptr as an invalid value"); return !!right; } template bool operator<(const unique_any_t& left, const unique_any_t& right) WI_NOEXCEPT { return (left.get() < right.get()); } template bool operator>=(const unique_any_t& left, const unique_any_t& right) WI_NOEXCEPT { return (!(left < right)); } template bool operator>(const unique_any_t& left, const unique_any_t& right) WI_NOEXCEPT { return (right < left); } template bool operator<=(const unique_any_t& left, const unique_any_t& right) WI_NOEXCEPT { return (!(right < left)); } // unique_any provides a template alias for easily building a unique_any_t from a unique_storage class with the given // template parameters for resource_policy. template // nullptr_t if the invalid handle value is compatible with nullptr, otherwise pointer using unique_any = unique_any_t>>; /// @cond namespace details { template class lambda_call { public: lambda_call(const lambda_call&) = delete; lambda_call& operator=(const lambda_call&) = delete; lambda_call& operator=(lambda_call&& other) = delete; explicit lambda_call(TLambda&& lambda) WI_NOEXCEPT : m_lambda(wistd::move(lambda)) { static_assert(wistd::is_same::value, "scope_exit lambdas must not have a return value"); static_assert(!wistd::is_lvalue_reference::value && !wistd::is_rvalue_reference::value, "scope_exit should only be directly used with a lambda"); } lambda_call(lambda_call&& other) WI_NOEXCEPT : m_lambda(wistd::move(other.m_lambda)), m_call(other.m_call) { other.m_call = false; } ~lambda_call() WI_NOEXCEPT { reset(); } // Ensures the scope_exit lambda will not be called void release() WI_NOEXCEPT { m_call = false; } // Executes the scope_exit lambda immediately if not yet run; ensures it will not run again void reset() WI_NOEXCEPT { if (m_call) { m_call = false; m_lambda(); } } // Returns true if the scope_exit lambda is still going to be executed explicit operator bool() const WI_NOEXCEPT { return m_call; } protected: TLambda m_lambda; bool m_call = true; }; #ifdef WIL_ENABLE_EXCEPTIONS template class lambda_call_log { public: lambda_call_log(const lambda_call_log&) = delete; lambda_call_log& operator=(const lambda_call_log&) = delete; lambda_call_log& operator=(lambda_call_log&& other) = delete; explicit lambda_call_log(void* address, const DiagnosticsInfo& info, TLambda&& lambda) WI_NOEXCEPT : m_address(address), m_info(info), m_lambda(wistd::move(lambda)) { static_assert(wistd::is_same::value, "scope_exit lambdas must return 'void'"); static_assert(!wistd::is_lvalue_reference::value && !wistd::is_rvalue_reference::value, "scope_exit should only be directly used with a lambda"); } lambda_call_log(lambda_call_log&& other) WI_NOEXCEPT : m_address(other.m_address), m_info(other.m_info), m_lambda(wistd::move(other.m_lambda)), m_call(other.m_call) { other.m_call = false; } ~lambda_call_log() WI_NOEXCEPT { reset(); } // Ensures the scope_exit lambda will not be called void release() WI_NOEXCEPT { m_call = false; } // Executes the scope_exit lambda immediately if not yet run; ensures it will not run again void reset() WI_NOEXCEPT { if (m_call) { m_call = false; try { m_lambda(); } catch (...) { ReportFailure_CaughtException(__R_DIAGNOSTICS(m_info), m_address); } } } // Returns true if the scope_exit lambda is still going to be executed explicit operator bool() const WI_NOEXCEPT { return m_call; } private: void* m_address; DiagnosticsInfo m_info; TLambda m_lambda; bool m_call = true; }; #endif // WIL_ENABLE_EXCEPTIONS } /// @endcond /** Returns an object that executes the given lambda when destroyed. Capture the object with 'auto'; use reset() to execute the lambda early or release() to avoid execution. Exceptions thrown in the lambda will fail-fast; use scope_exit_log to avoid. */ template WI_NODISCARD inline auto scope_exit(TLambda&& lambda) WI_NOEXCEPT { return details::lambda_call(wistd::forward(lambda)); } #ifdef WIL_ENABLE_EXCEPTIONS /** Returns an object that executes the given lambda when destroyed; logs exceptions. Capture the object with 'auto'; use reset() to execute the lambda early or release() to avoid execution. Exceptions thrown in the lambda will be caught and logged without being propagated. */ template WI_NODISCARD inline __declspec(noinline) auto scope_exit_log(const DiagnosticsInfo& diagnostics, TLambda&& lambda) WI_NOEXCEPT { return details::lambda_call_log(_ReturnAddress(), diagnostics, wistd::forward(lambda)); } #endif // Forward declaration... template class com_ptr_t; //! Type traits class that identifies the inner type of any smart pointer. template struct smart_pointer_details { typedef typename Ptr::pointer pointer; }; /// @cond template struct smart_pointer_details> { typedef T* pointer; }; /// @endcond /** Generically detaches a raw pointer from any smart pointer. Caller takes ownership of the returned raw pointer; calls the correct release(), detach(), or Detach() method based on the smart pointer type */ template WI_NODISCARD typename TSmartPointer::pointer detach_from_smart_pointer(TSmartPointer& smartPtr) { return smartPtr.release(); } /// @cond // Generically detaches a raw pointer from any smart pointer template WI_NODISCARD T* detach_from_smart_pointer(wil::com_ptr_t& smartPtr) { return smartPtr.detach(); } // Generically detaches a raw pointer from any smart pointer template WI_NODISCARD T* detach_from_smart_pointer(Microsoft::WRL::ComPtr& smartPtr) { return smartPtr.Detach(); } template class com_ptr_t; // forward namespace details { // The first two attach_to_smart_pointer() overloads are ambiguous when passed a com_ptr_t. // To solve that use this functions return type to elminate the reset form for com_ptr_t. template wistd::false_type use_reset(wil::com_ptr_t*) { return wistd::false_type(); } template wistd::true_type use_reset(T*) { return wistd::true_type(); } } /// @endcond /** Generically attach a raw pointer to a compatible smart pointer. Calls the correct reset(), attach(), or Attach() method based on samrt pointer type. */ template (nullptr)))::value>> void attach_to_smart_pointer(TSmartPointer& smartPtr, typename TSmartPointer::pointer rawPtr) { smartPtr.reset(rawPtr); } /// @cond // Generically attach a raw pointer to a compatible smart pointer. template void attach_to_smart_pointer(wil::com_ptr_t& smartPtr, T* rawPtr) { smartPtr.attach(rawPtr); } // Generically attach a raw pointer to a compatible smart pointer. template void attach_to_smart_pointer(Microsoft::WRL::ComPtr& smartPtr, T* rawPtr) { smartPtr.Attach(rawPtr); } /// @endcond //! @ingroup outparam /** Detach a smart pointer resource to an optional output pointer parameter. Avoids cluttering code with nullptr tests; works generically for any smart pointer */ template inline void detach_to_opt_param(_Out_opt_ T* outParam, TSmartPointer&& smartPtr) { if (outParam) { *outParam = detach_from_smart_pointer(smartPtr); } } /// @cond namespace details { template struct out_param_t { typedef typename wil::smart_pointer_details::pointer pointer; T &wrapper; pointer pRaw; bool replace = true; out_param_t(_Inout_ T &output) : wrapper(output), pRaw(nullptr) { } out_param_t(out_param_t&& other) : wrapper(other.wrapper), pRaw(other.pRaw) { WI_ASSERT(other.replace); other.replace = false; } operator pointer*() { WI_ASSERT(replace); return &pRaw; } ~out_param_t() { if (replace) { attach_to_smart_pointer(wrapper, pRaw); } } out_param_t(out_param_t const &other) = delete; out_param_t &operator=(out_param_t const &other) = delete; }; template struct out_param_ptr_t { typedef typename wil::smart_pointer_details::pointer pointer; T &wrapper; pointer pRaw; bool replace = true; out_param_ptr_t(_Inout_ T &output) : wrapper(output), pRaw(nullptr) { } out_param_ptr_t(out_param_ptr_t&& other) : wrapper(other.wrapper), pRaw(other.pRaw) { WI_ASSERT(other.replace); other.replace = false; } operator Tcast() { WI_ASSERT(replace); return reinterpret_cast(&pRaw); } ~out_param_ptr_t() { if (replace) { attach_to_smart_pointer(wrapper, pRaw); } } out_param_ptr_t(out_param_ptr_t const &other) = delete; out_param_ptr_t &operator=(out_param_ptr_t const &other) = delete; }; } // details /// @endcond /** Use to retrieve raw out parameter pointers into smart pointers that do not support the '&' operator. This avoids multi-step handling of a raw resource to establish the smart pointer. Example: `GetFoo(out_param(foo));` */ template details::out_param_t out_param(T& p) { return details::out_param_t(p); } /** Use to retrieve raw out parameter pointers (with a required cast) into smart pointers that do not support the '&' operator. Use only when the smart pointer's &handle is not equal to the output type a function requries, necessitating a cast. Example: `wil::out_param_ptr(securityDescriptor)` */ template details::out_param_ptr_t out_param_ptr(T& p) { return details::out_param_ptr_t(p); } /** Use unique_struct to define an RAII type for a trivial struct that references resources that must be cleaned up. Unique_struct wraps a trivial struct using a custom clean up function and, optionally, custom initializer function. If no custom initialier function is defined in the template then ZeroMemory is used. Unique_struct is modeled off of std::unique_ptr. However, unique_struct inherits from the defined type instead of managing the struct through a private member variable. If the type you're wrapping is a system type, you can share the code by declaring it in this file (Resource.h). Send requests to wildisc. Otherwise, if the type is local to your project, declare it locally. @tparam struct_t The struct you want to manage @tparam close_fn_t The type of the function to clean up the struct. Takes one parameter: a pointer of struct_t. Return values are ignored. @tparam close_fn The function of type close_fn_t. This is called in the destructor and reset functions. @tparam init_fn_t Optional:The type of the function to initialize the struct. Takes one parameter: a pointer of struct_t. Return values are ignored. @tparam init_fn Optional:The function of type init_fn_t. This is called in the constructor, reset, and release functions. The default is ZeroMemory to initialize the struct. Defined using the default zero memory initializer ~~~ typedef wil::unique_struct unique_prop_variant_default_init; unique_prop_variant propvariant; SomeFunction(&propvariant); ~~~ Defined using a custom initializer ~~~ typedef wil::unique_struct unique_prop_variant; unique_prop_variant propvariant; SomeFunction(&propvariant); ~~~ */ template class unique_struct : public struct_t { public: //! Initializes the managed struct using the user-provided initialization function, or ZeroMemory if no function is specified unique_struct() { call_init(use_default_init_fn()); } //! Takes ownership of the struct by doing a shallow copy. Must explicitly be type struct_t explicit unique_struct(const struct_t& other) WI_NOEXCEPT : struct_t(other) {} //! Initializes the managed struct by taking the ownership of the other managed struct //! Then resets the other managed struct by calling the custom close function unique_struct(unique_struct&& other) WI_NOEXCEPT : struct_t(other.release()) {} //! Resets this managed struct by calling the custom close function and takes ownership of the other managed struct //! Then resets the other managed struct by calling the custom close function unique_struct & operator=(unique_struct&& other) WI_NOEXCEPT { if (this != wistd::addressof(other)) { reset(other.release()); } return *this; } //! Calls the custom close function ~unique_struct() WI_NOEXCEPT { wistd::invoke(close_fn, this); } void reset(const unique_struct&) = delete; //! Resets this managed struct by calling the custom close function and begins management of the other struct void reset(const struct_t& other) WI_NOEXCEPT { { auto preserveError = last_error_context(); wistd::invoke(close_fn, this); } struct_t::operator=(other); } //! Resets this managed struct by calling the custom close function //! Then initializes this managed struct using the user-provided initialization function, or ZeroMemory if no function is specified void reset() WI_NOEXCEPT { wistd::invoke(close_fn, this); call_init(use_default_init_fn()); } void swap(struct_t&) = delete; //! Swaps the managed structs void swap(unique_struct& other) WI_NOEXCEPT { struct_t self(*this); struct_t::operator=(other); *(other.addressof()) = self; } //! Returns the managed struct //! Then initializes this managed struct using the user-provided initialization function, or ZeroMemory if no function is specified struct_t release() WI_NOEXCEPT { struct_t value(*this); call_init(use_default_init_fn()); return value; } //! Returns address of the managed struct struct_t * addressof() WI_NOEXCEPT { return this; } //! Resets this managed struct by calling the custom close function //! Then initializes this managed struct using the user-provided initialization function, or ZeroMemory if no function is specified //! Returns address of the managed struct struct_t * reset_and_addressof() WI_NOEXCEPT { reset(); return this; } unique_struct(const unique_struct&) = delete; unique_struct& operator=(const unique_struct&) = delete; unique_struct& operator=(const struct_t&) = delete; private: typedef typename wistd::is_same::type use_default_init_fn; void call_init(wistd::true_type) { RtlZeroMemory(this, sizeof(*this)); } void call_init(wistd::false_type) { init_fn(this); } }; struct empty_deleter { template void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T) const { } }; /** unique_any_array_ptr is a RAII type for managing conformant arrays that need to be freed and have elements that may need to be freed. The intented use for this RAII type would be to capture out params from API like IPropertyValue::GetStringArray. This class also maintains the size of the array, so it can iterate over the members and deallocate them before it deallocates the base array pointer. If the type you're wrapping is a system type, you can share the code by declaring it in this file (Resource.h). Send requests to wildisc. Otherwise, if the type is local to your project, declare it locally. @tparam ValueType: The type of array you want to manage. @tparam ArrayDeleter: The type of the function to clean up the array. Takes one parameter of type T[] or T*. Return values are ignored. This is called in the destructor and reset functions. @tparam ElementDeleter: The type of the function to clean up the array elements. Takes one parameter of type T. Return values are ignored. This is called in the destructor and reset functions. ~~~ void GetSomeArray(_Out_ size_t*, _Out_ NOTMYTYPE**); struct not_my_deleter { void operator()(NOTMYTYPE p) const { destroy(p); } }; wil::unique_any_array_ptr myArray; GetSomeArray(myArray.size_address(), &myArray); ~~~ */ template class unique_any_array_ptr { public: typedef ValueType value_type; typedef size_t size_type; typedef ptrdiff_t difference_type; typedef ValueType *pointer; typedef const ValueType *const_pointer; typedef ValueType& reference; typedef const ValueType& const_reference; typedef ValueType* iterator; typedef const ValueType* const_iterator; unique_any_array_ptr() = default; unique_any_array_ptr(const unique_any_array_ptr&) = delete; unique_any_array_ptr& operator=(const unique_any_array_ptr&) = delete; unique_any_array_ptr(wistd::nullptr_t) WI_NOEXCEPT { } unique_any_array_ptr& operator=(wistd::nullptr_t) WI_NOEXCEPT { reset(); return *this; } unique_any_array_ptr(pointer ptr, size_t size) WI_NOEXCEPT : m_ptr(ptr), m_size(size) { } unique_any_array_ptr(unique_any_array_ptr&& other) WI_NOEXCEPT : m_ptr(other.m_ptr), m_size(other.m_size) { other.m_ptr = nullptr; other.m_size = size_type{}; } unique_any_array_ptr& operator=(unique_any_array_ptr&& other) WI_NOEXCEPT { if (this != wistd::addressof(other)) { reset(); swap(other); } return *this; } ~unique_any_array_ptr() WI_NOEXCEPT { reset(); } void swap(unique_any_array_ptr& other) WI_NOEXCEPT { auto ptr = m_ptr; auto size = m_size; m_ptr = other.m_ptr; m_size = other.m_size; other.m_ptr = ptr; other.m_size = size; } iterator begin() WI_NOEXCEPT { return (iterator(m_ptr)); } const_iterator begin() const WI_NOEXCEPT { return (const_iterator(m_ptr)); } iterator end() WI_NOEXCEPT { return (iterator(m_ptr + m_size)); } const_iterator end() const WI_NOEXCEPT { return (const_iterator(m_ptr + m_size)); } const_iterator cbegin() const WI_NOEXCEPT { return (begin()); } const_iterator cend() const WI_NOEXCEPT { return (end()); } size_type size() const WI_NOEXCEPT { return (m_size); } bool empty() const WI_NOEXCEPT { return (size() == size_type{}); } reference operator[](size_type position) { WI_ASSERT(position < m_size); _Analysis_assume_(position < m_size); return (m_ptr[position]); } const_reference operator[](size_type position) const { WI_ASSERT(position < m_size); _Analysis_assume_(position < m_size); return (m_ptr[position]); } reference front() { WI_ASSERT(!empty()); return (m_ptr[0]); } const_reference front() const { WI_ASSERT(!empty()); return (m_ptr[0]); } reference back() { WI_ASSERT(!empty()); return (m_ptr[m_size - 1]); } const_reference back() const { WI_ASSERT(!empty()); return (m_ptr[m_size - 1]); } ValueType* data() WI_NOEXCEPT { return (m_ptr); } const ValueType* data() const WI_NOEXCEPT { return (m_ptr); } pointer get() const WI_NOEXCEPT { return m_ptr; } explicit operator bool() const WI_NOEXCEPT { return (m_ptr != pointer()); } pointer release() WI_NOEXCEPT { auto result = m_ptr; m_ptr = nullptr; m_size = size_type{}; return result; } void reset() WI_NOEXCEPT { if (m_ptr) { reset_array(ElementDeleter()); ArrayDeleter()(m_ptr); m_ptr = nullptr; m_size = size_type{}; } } void reset(pointer ptr, size_t size) WI_NOEXCEPT { reset(); m_ptr = ptr; m_size = size; } pointer* addressof() WI_NOEXCEPT { return &m_ptr; } pointer* put() WI_NOEXCEPT { reset(); return addressof(); } pointer* operator&() WI_NOEXCEPT { return put(); } size_type* size_address() WI_NOEXCEPT { return &m_size; } template struct size_address_ptr { unique_any_array_ptr& wrapper; TSize size{}; bool replace = true; size_address_ptr(_Inout_ unique_any_array_ptr& output) : wrapper(output) { } size_address_ptr(size_address_ptr&& other) : wrapper(other.wrapper), size(other.size) { WI_ASSERT(other.replace); other.replace = false; } operator TSize*() { WI_ASSERT(replace); return &size; } ~size_address_ptr() { if (replace) { *wrapper.size_address() = static_cast(size); } } size_address_ptr(size_address_ptr const &other) = delete; size_address_ptr &operator=(size_address_ptr const &other) = delete; }; template size_address_ptr size_address() WI_NOEXCEPT { return size_address_ptr(*this); } private: pointer m_ptr = nullptr; size_type m_size{}; void reset_array(const empty_deleter&) { } template void reset_array(const T& deleter) { for (auto& element : make_range(m_ptr, m_size)) { deleter(element); } } }; // forward declaration template class com_ptr_t; /// @cond namespace details { template struct unique_any_array_deleter { template void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const { UniqueAnyType::policy::close_reset(p); } }; template struct unique_struct_array_deleter { template void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T& p) const { wistd::invoke(close_fn, &p); } }; struct com_unknown_deleter { template void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const { if (p) { p->Release(); } } }; template struct element_traits { typedef empty_deleter deleter; typedef T type; }; template struct element_traits> { typedef unique_any_array_deleter> deleter; typedef typename unique_any_t::pointer type; }; template struct element_traits> { typedef com_unknown_deleter deleter; typedef T* type; }; template struct element_traits> { typedef unique_struct_array_deleter deleter; typedef struct_t type; }; } /// @endcond template using unique_array_ptr = unique_any_array_ptr::type, ArrayDeleter, typename details::element_traits::deleter>; /** Adapter for single-parameter 'free memory' for `wistd::unique_ptr`. This struct provides a standard wrapper for calling a platform function to deallocate memory held by a `wistd::unique_ptr`, making declaring them as easy as declaring wil::unique_any<>. Consider this adapter in preference to `wil::unique_any<>` when the returned type is really a pointer or an array of items; `wistd::unique_ptr<>` exposes `operator->()` and `operator[]` for array-typed things safely. ~~~~ EXTERN_C VOID WINAPI MyDllFreeMemory(void* p); EXTERN_C HRESULT MyDllGetString(_Outptr_ PWSTR* pString); EXTERN_C HRESULT MyDllGetThing(_In_ PCWSTR pString, _Outptr_ PMYSTRUCT* ppThing); template using unique_mydll_ptr = wistd::unique_ptr>; HRESULT Test() { unique_mydll_ptr dllString; unique_mydll_ptr thing; RETURN_IF_FAILED(MyDllGetString(wil::out_param(dllString))); RETURN_IF_FAILED(MyDllGetThing(dllString.get(), wil::out_param(thing))); if (thing->Member) { // ... } return S_OK; } ~~~~ */ template struct function_deleter { template void operator()(_Frees_ptr_opt_ T* toFree) const { TDeleter(toFree); } }; /** Use unique_com_token to define an RAII type for a token-based resource that is managed by a COM interface. By comparison, unique_any_t has the requirement that the close function must be static. This works for functions such as CloseHandle(), but for any resource cleanup function that relies on a more complex interface, unique_com_token can be used. @tparam interface_t A COM interface pointer that will manage this resource type. @tparam token_t The token type that relates to the COM interface management functions. @tparam close_fn_t The type of the function that is called when the resource is destroyed. @tparam close_fn The function used to destroy the associated resource. This function should have the signature void(interface_t* source, token_t token). @tparam invalid_token Optional:An invalid token value. Defaults to default-constructed token_t(). Example ~~~ void __stdcall MyInterfaceCloseFunction(IMyInterface* source, DWORD token) { source->MyCloseFunction(token); } using unique_my_interface_token = wil::unique_com_token; ~~~ */ template class unique_com_token { public: unique_com_token() = default; unique_com_token(_In_opt_ interface_t* source, token_t token = invalid_token) WI_NOEXCEPT { reset(source, token); } unique_com_token(unique_com_token&& other) WI_NOEXCEPT : m_source(other.m_source), m_token(other.m_token) { other.m_source = nullptr; other.m_token = invalid_token; } unique_com_token& operator=(unique_com_token&& other) WI_NOEXCEPT { if (this != wistd::addressof(other)) { reset(); m_source = other.m_source; m_token = other.m_token; other.m_source = nullptr; other.m_token = invalid_token; } return *this; } ~unique_com_token() WI_NOEXCEPT { reset(); } //! Determine if the underlying source and token are valid explicit operator bool() const WI_NOEXCEPT { return (m_token != invalid_token) && m_source; } //! Associates a new source and releases the existing token if valid void associate(_In_opt_ interface_t* source) WI_NOEXCEPT { reset(source, invalid_token); } //! Assigns a new source and token void reset(_In_opt_ interface_t* source, token_t token) WI_NOEXCEPT { WI_ASSERT(source || (token == invalid_token)); // Determine if we need to call the close function on our previous token. if (m_token != invalid_token) { if ((m_source != source) || (m_token != token)) { wistd::invoke(close_fn, m_source, m_token); } } m_token = token; // Assign our new source and manage the reference counts if (m_source != source) { auto oldSource = m_source; m_source = source; if (m_source) { m_source->AddRef(); } if (oldSource) { oldSource->Release(); } } } //! Assigns a new token without modifying the source; associate must be called first void reset(token_t token) WI_NOEXCEPT { reset(m_source, token); } //! Closes the token and the releases the reference to the source void reset() WI_NOEXCEPT { reset(nullptr, invalid_token); } //! Exchanges values with another managed token void swap(unique_com_token& other) WI_NOEXCEPT { wistd::swap_wil(m_source, other.m_source); wistd::swap_wil(m_token, other.m_token); } //! Releases the held token to the caller without closing it and releases the reference to the source. //! Requires that the associated COM interface be kept alive externally or the released token may be invalidated token_t release() WI_NOEXCEPT { auto token = m_token; m_token = invalid_token; reset(); return token; } //! Returns address of the managed token; associate must be called first token_t* addressof() WI_NOEXCEPT { WI_ASSERT(m_source); return &m_token; } //! Releases the held token and allows attaching a new token; associate must be called first token_t* put() WI_NOEXCEPT { reset(invalid_token); return addressof(); } //! Releases the held token and allows attaching a new token; associate must be called first token_t* operator&() WI_NOEXCEPT { return put(); } //! Retrieves the token token_t get() const WI_NOEXCEPT { return m_token; } unique_com_token(const unique_com_token&) = delete; unique_com_token& operator=(const unique_com_token&) = delete; private: interface_t* m_source = nullptr; token_t m_token = invalid_token; }; /** Use unique_com_call to define an RAII type that demands a particular parameter-less method be called on a COM interface. This allows implementing an RAII type that can call a Close() method (think IClosable) or a SetSite(nullptr) method (think IObjectWithSite) or some other method when a basic interface call is required as part of the RAII contract. see wil::com_set_site in wil\com.h for the IObjectWithSite support. @tparam interface_t A COM interface pointer that provides context to make the call. @tparam close_fn_t The type of the function that is called to invoke the method. @tparam close_fn The function used to invoke the interface method. This function should have the signature void(interface_t* source). Example ~~~ void __stdcall CloseIClosable(IClosable* source) { source->Close(); } using unique_closable_call = wil::unique_com_call; ~~~ */ template class unique_com_call { public: unique_com_call() = default; explicit unique_com_call(_In_opt_ interface_t* ptr) WI_NOEXCEPT { reset(ptr); } unique_com_call(unique_com_call&& other) WI_NOEXCEPT { m_ptr = other.m_ptr; other.m_ptr = nullptr; } unique_com_call& operator=(unique_com_call&& other) WI_NOEXCEPT { if (this != wistd::addressof(other)) { reset(); m_ptr = other.m_ptr; other.m_ptr = nullptr; } return *this; } ~unique_com_call() WI_NOEXCEPT { reset(); } //! Assigns an interface to make a given call on void reset(_In_opt_ interface_t* ptr = nullptr) WI_NOEXCEPT { if (ptr != m_ptr) { auto oldSource = m_ptr; m_ptr = ptr; if (m_ptr) { m_ptr->AddRef(); } if (oldSource) { wistd::invoke(close_fn, oldSource); oldSource->Release(); } } } //! Exchanges values with another class void swap(unique_com_call& other) WI_NOEXCEPT { wistd::swap_wil(m_ptr, other.m_ptr); } //! Cancel the interface call that this class was expected to make void release() WI_NOEXCEPT { auto ptr = m_ptr; m_ptr = nullptr; if (ptr) { ptr->Release(); } } //! Returns true if the call this class was expected to make is still outstanding explicit operator bool() const WI_NOEXCEPT { return (m_ptr != nullptr); } //! Returns address of the internal interface interface_t** addressof() WI_NOEXCEPT { return &m_ptr; } //! Releases the held interface (first performing the interface call if required) //! and allows attaching a new interface interface_t** put() WI_NOEXCEPT { reset(); return addressof(); } //! Releases the held interface (first performing the interface call if required) //! and allows attaching a new interface interface_t** operator&() WI_NOEXCEPT { return put(); } unique_com_call(const unique_com_call&) = delete; unique_com_call& operator=(const unique_com_call&) = delete; private: interface_t* m_ptr = nullptr; }; /** Use unique_call to define an RAII type that demands a particular parameter-less global function be called. This allows implementing a RAII types that can call methods like CoUninitialize. @tparam close_fn_t The type of the function that is called to invoke the call. @tparam close_fn The function used to invoke the call. This function should have the signature void(). @tparam default_value Determines whether the unique_call is active or inactive when default-constructed or reset. Example ~~~ void __stdcall CoUninitializeFunction() { ::CoUninitialize(); } using unique_couninitialize_call = wil::unique_call; ~~~ */ template class unique_call { public: unique_call() = default; explicit unique_call(bool call) WI_NOEXCEPT : m_call(call) { } unique_call(unique_call&& other) WI_NOEXCEPT { m_call = other.m_call; other.m_call = false; } unique_call& operator=(unique_call&& other) WI_NOEXCEPT { if (this != wistd::addressof(other)) { reset(); m_call = other.m_call; other.m_call = false; } return *this; } ~unique_call() WI_NOEXCEPT { reset(); } //! Assigns a new ptr and token void reset() WI_NOEXCEPT { auto call = m_call; m_call = false; if (call) { wistd::invoke(close_fn); } } //! Exchanges values with raii class void swap(unique_call& other) WI_NOEXCEPT { wistd::swap_wil(m_call, other.m_call); } //! Make the interface call that was expected of this class void activate() WI_NOEXCEPT { m_call = true; } //! Do not make the interface call that was expected of this class void release() WI_NOEXCEPT { m_call = false; } //! Returns true if the call that was expected is still outstanding explicit operator bool() const WI_NOEXCEPT { return m_call; } unique_call(const unique_call&) = delete; unique_call& operator=(const unique_call&) = delete; private: bool m_call = default_value; }; // str_raw_ptr is an overloaded function that retrieves a const pointer to the first character in a string's buffer. // Overloads in this file support any string that is implicitly convertible to a PCWSTR, HSTRING, and any unique_any_t // that points to any other supported type (this covers unique_hstring, unique_cotaskmem_string, and similar). // An overload for std::wstring is available in stl.h. inline PCWSTR str_raw_ptr(PCWSTR str) { return str; } template PCWSTR str_raw_ptr(const unique_any_t& ua) { return str_raw_ptr(ua.get()); } namespace details { // Forward declaration template struct string_maker; // Concatenate any number of strings together and store it in an automatically allocated string. If a string is present // in the input buffer, it is overwritten. template HRESULT str_build_nothrow(string_type& result, _In_reads_(strCount) PCWSTR* strList, size_t strCount) { size_t lengthRequiredWithoutNull{}; for (auto& string : make_range(strList, strCount)) { lengthRequiredWithoutNull += string ? wcslen(string) : 0; } details::string_maker maker; RETURN_IF_FAILED(maker.make(nullptr, lengthRequiredWithoutNull)); auto buffer = maker.buffer(); auto bufferEnd = buffer + lengthRequiredWithoutNull + 1; for (auto& string : make_range(strList, strCount)) { if (string) { RETURN_IF_FAILED(StringCchCopyExW(buffer, (bufferEnd - buffer), string, &buffer, nullptr, STRSAFE_IGNORE_NULLS)); } } result = maker.release(); return S_OK; } // NOTE: 'Strings' must all be PCWSTR, or convertible to PCWSTR, but C++ doesn't allow us to express that cleanly template HRESULT str_build_nothrow(string_type& result, Strings... strings) { PCWSTR localStrings[] = { strings... }; return str_build_nothrow(result, localStrings, sizeof...(Strings)); } } // Concatenate any number of strings together and store it in an automatically allocated string. If a string is present // in the input buffer, the remaining strings are appended to it. template HRESULT str_concat_nothrow(string_type& buffer, const strings&... str) { static_assert(sizeof...(str) > 0, "attempting to concatenate no strings"); return details::str_build_nothrow(buffer, details::string_maker::get(buffer), str_raw_ptr(str)...); } #ifdef WIL_ENABLE_EXCEPTIONS // Concatenate any number of strings together and store it in an automatically allocated string. template string_type str_concat(arguments&&... args) { string_type result; THROW_IF_FAILED(str_concat_nothrow(result, wistd::forward(args)...)); return result; } #endif // WIL_ENABLE_EXCEPTIONS // Concatenate any number of strings together and store it in an automatically allocated string. template string_type str_concat_failfast(arguments&&... args) { string_type result; FAIL_FAST_IF_FAILED(str_concat_nothrow(result, wistd::forward(args)...)); return result; } namespace details { // Wraps StringCchPrintFExW and stores it in an automatically allocated string. Takes a buffer followed by the same format arguments // that StringCchPrintfExW takes. template HRESULT str_vprintf_nothrow(string_type& result, _Printf_format_string_ PCWSTR pszFormat, va_list& argsVL) { size_t lengthRequiredWithoutNull = _vscwprintf(pszFormat, argsVL); string_maker maker; RETURN_IF_FAILED(maker.make(nullptr, lengthRequiredWithoutNull)); auto buffer = maker.buffer(); RETURN_IF_FAILED(::StringCchVPrintfExW(buffer, lengthRequiredWithoutNull + 1, nullptr, nullptr, STRSAFE_NULL_ON_FAILURE, pszFormat, argsVL)); result = maker.release(); return S_OK; } } // Wraps StringCchPrintFExW and stores it in an automatically allocated string. Takes a buffer followed by the same format arguments // that StringCchPrintfExW takes. template HRESULT str_printf_nothrow(string_type& result, _Printf_format_string_ PCWSTR pszFormat, _In_ ...) { va_list argsVL; va_start(argsVL, pszFormat); auto hr = details::str_vprintf_nothrow(result, pszFormat, argsVL); va_end(argsVL); return hr; } #ifdef WIL_ENABLE_EXCEPTIONS // Wraps StringCchPrintFExW and stores it in an automatically allocated string. Takes a buffer followed by the same format arguments // that StringCchPrintfExW takes. template string_type str_printf(_Printf_format_string_ PCWSTR pszFormat, _In_ ...) { string_type result; va_list argsVL; va_start(argsVL, pszFormat); auto hr = details::str_vprintf_nothrow(result, pszFormat, argsVL); va_end(argsVL); THROW_IF_FAILED(hr); return result; } #endif // WIL_ENABLE_EXCEPTIONS // Wraps StringCchPrintFExW and stores it in an automatically allocated string. Takes a buffer followed by the same format arguments // that StringCchPrintfExW takes. template string_type str_printf_failfast(_Printf_format_string_ PCWSTR pszFormat, _In_ ...) { string_type result; va_list argsVL; va_start(argsVL, pszFormat); auto hr = details::str_vprintf_nothrow(result, pszFormat, argsVL); va_end(argsVL); FAIL_FAST_IF_FAILED(hr); return result; } } // namespace wil #endif // __WIL_RESOURCE // Hash deferral function for unique_any_t #if (defined(_UNORDERED_SET_) || defined(_UNORDERED_MAP_)) && !defined(__WIL_RESOURCE_UNIQUE_HASH) #define __WIL_RESOURCE_UNIQUE_HASH namespace std { template struct hash> { size_t operator()(wil::unique_any_t const &val) const { return (hash::pointer>()(val.get())); } }; } #endif // shared_any and weak_any implementation using STL header #if defined(_MEMORY_) && defined(WIL_ENABLE_EXCEPTIONS) && !defined(WIL_RESOURCE_STL) && !defined(RESOURCE_SUPPRESS_STL) #define WIL_RESOURCE_STL namespace wil { template class weak_any; /// @cond namespace details { // This class provides the pointer storage behind the implementation of shared_any_t utilizing the given // resource_policy. It is separate from shared_any_t to allow a type-specific specialization class to plug // into the inheritance chain between shared_any_t and shared_storage. This allows classes like shared_event // to be a shared_any formed class, but also expose methods like SetEvent directly. template class shared_storage { protected: typedef unique_t unique_t; typedef typename unique_t::policy policy; typedef typename policy::pointer_storage pointer_storage; typedef typename policy::pointer pointer; typedef shared_storage base_storage; shared_storage() = default; explicit shared_storage(pointer_storage ptr) { if (policy::is_valid(ptr)) { m_ptr = std::make_shared(unique_t(ptr)); // unique_t on the stack to prevent leak on throw } } shared_storage(unique_t &&other) { if (other) { m_ptr = std::make_shared(wistd::move(other)); } } shared_storage(const shared_storage &other) WI_NOEXCEPT : m_ptr(other.m_ptr) { } shared_storage& operator=(const shared_storage &other) WI_NOEXCEPT { m_ptr = other.m_ptr; return *this; } shared_storage(shared_storage &&other) WI_NOEXCEPT : m_ptr(wistd::move(other.m_ptr)) { } shared_storage(std::shared_ptr const &ptr) : m_ptr(ptr) { } void replace(shared_storage &&other) WI_NOEXCEPT { m_ptr = wistd::move(other.m_ptr); } public: bool is_valid() const WI_NOEXCEPT { return (m_ptr && m_ptr->is_valid()); } void reset(pointer_storage ptr = policy::invalid_value()) { if (policy::is_valid(ptr)) { m_ptr = std::make_shared(unique_t(ptr)); // unique_t on the stack to prevent leak on throw } else { m_ptr = nullptr; } } void reset(unique_t &&other) { m_ptr = std::make_shared(wistd::move(other)); } void reset(wistd::nullptr_t) WI_NOEXCEPT { static_assert(wistd::is_same::value, "reset(nullptr): valid only for handle types using nullptr as the invalid value"); reset(); } template ::value, int>::type = 0> pointer get() const WI_NOEXCEPT { return (m_ptr ? m_ptr->get() : policy::invalid_value()); } template ::value, int>::type = 0> pointer_storage *addressof() { if (!m_ptr) { m_ptr = std::make_shared(); } return m_ptr->addressof(); } long int use_count() const WI_NOEXCEPT { return m_ptr.use_count(); } private: template friend class ::wil::weak_any; std::shared_ptr m_ptr; }; } /// @endcond // This class when paired with shared_storage and an optional type-specific specialization class implements // the same interface as STL's shared_ptr<> for resource handle types. It is both copyable and movable, supporting // weak references and automatic closure of the handle upon release of the last shared_any. template class shared_any_t : public storage_t { public: typedef typename storage_t::policy policy; typedef typename policy::pointer_storage pointer_storage; typedef typename policy::pointer pointer; typedef typename storage_t::unique_t unique_t; // default and forwarding constructor: forwards default, all 'explicit' and multi-arg constructors to the base class template explicit shared_any_t(args_t&&... args) : // should not be WI_NOEXCEPT (may forward to a throwing constructor) storage_t(wistd::forward(args)...) { } shared_any_t(wistd::nullptr_t) WI_NOEXCEPT { static_assert(wistd::is_same::value, "nullptr constructor: valid only for handle types using nullptr as the invalid value"); } shared_any_t(shared_any_t &&other) WI_NOEXCEPT : storage_t(wistd::move(other)) { } shared_any_t(const shared_any_t &other) WI_NOEXCEPT : storage_t(other) { } shared_any_t& operator=(shared_any_t &&other) WI_NOEXCEPT { if (this != wistd::addressof(other)) { storage_t::replace(wistd::move(static_cast(other))); } return (*this); } shared_any_t& operator=(const shared_any_t& other) WI_NOEXCEPT { storage_t::operator=(other); return (*this); } shared_any_t(unique_t &&other) : storage_t(wistd::move(other)) { } shared_any_t& operator=(unique_t &&other) { storage_t::reset(wistd::move(other)); return (*this); } shared_any_t& operator=(wistd::nullptr_t) WI_NOEXCEPT { static_assert(wistd::is_same::value, "nullptr assignment: valid only for handle types using nullptr as the invalid value"); storage_t::reset(); return (*this); } void swap(shared_any_t &other) WI_NOEXCEPT { shared_any_t self(wistd::move(*this)); operator=(wistd::move(other)); other = wistd::move(self); } explicit operator bool() const WI_NOEXCEPT { return storage_t::is_valid(); } pointer_storage *put() { static_assert(wistd::is_same::value, "operator & is not available for this handle"); storage_t::reset(); return storage_t::addressof(); } pointer_storage *operator&() { return put(); } pointer get() const WI_NOEXCEPT { static_assert(!wistd::is_same::value, "get(): the raw handle value is not available for this resource class"); return storage_t::get(); } // The following functions are publicly exposed by their inclusion in the base class // void reset(pointer_storage ptr = policy::invalid_value()) WI_NOEXCEPT // void reset(wistd::nullptr_t) WI_NOEXCEPT // pointer_storage *addressof() WI_NOEXCEPT // (note: not exposed for opaque resource types) }; template void swap(shared_any_t& left, shared_any_t& right) WI_NOEXCEPT { left.swap(right); } template bool operator==(const shared_any_t& left, const shared_any_t& right) WI_NOEXCEPT { return (left.get() == right.get()); } template bool operator==(const shared_any_t& left, wistd::nullptr_t) WI_NOEXCEPT { static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, "the resource class does not use nullptr as an invalid value"); return !left; } template bool operator==(wistd::nullptr_t, const shared_any_t& right) WI_NOEXCEPT { static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, "the resource class does not use nullptr as an invalid value"); return !right; } template bool operator!=(const shared_any_t& left, const shared_any_t& right) WI_NOEXCEPT { return (!(left.get() == right.get())); } template bool operator!=(const shared_any_t& left, wistd::nullptr_t) WI_NOEXCEPT { static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, "the resource class does not use nullptr as an invalid value"); return !!left; } template bool operator!=(wistd::nullptr_t, const shared_any_t& right) WI_NOEXCEPT { static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, "the resource class does not use nullptr as an invalid value"); return !!right; } template bool operator<(const shared_any_t& left, const shared_any_t& right) WI_NOEXCEPT { return (left.get() < right.get()); } template bool operator>=(const shared_any_t& left, const shared_any_t& right) WI_NOEXCEPT { return (!(left < right)); } template bool operator>(const shared_any_t& left, const shared_any_t& right) WI_NOEXCEPT { return (right < left); } template bool operator<=(const shared_any_t& left, const shared_any_t& right) WI_NOEXCEPT { return (!(right < left)); } // This class provides weak_ptr<> support for shared_any<>, bringing the same weak reference counting and lock() acquire semantics // to shared_any. template class weak_any { public: typedef shared_t shared_t; weak_any() WI_NOEXCEPT { } weak_any(const shared_t &other) WI_NOEXCEPT : m_weakPtr(other.m_ptr) { } weak_any(const weak_any &other) WI_NOEXCEPT : m_weakPtr(other.m_weakPtr) { } weak_any& operator=(const weak_any &right) WI_NOEXCEPT { m_weakPtr = right.m_weakPtr; return (*this); } weak_any& operator=(const shared_t &right) WI_NOEXCEPT { m_weakPtr = right.m_ptr; return (*this); } void reset() WI_NOEXCEPT { m_weakPtr.reset(); } void swap(weak_any &other) WI_NOEXCEPT { m_weakPtr.swap(other.m_weakPtr); } bool expired() const WI_NOEXCEPT { return m_weakPtr.expired(); } shared_t lock() const WI_NOEXCEPT { return shared_t(m_weakPtr.lock()); } private: std::weak_ptr m_weakPtr; }; template void swap(weak_any& left, weak_any& right) WI_NOEXCEPT { left.swap(right); } template using shared_any = shared_any_t>; } // namespace wil #endif #if defined(WIL_RESOURCE_STL) && (defined(_UNORDERED_SET_) || defined(_UNORDERED_MAP_)) && !defined(__WIL_RESOURCE_SHARED_HASH) #define __WIL_RESOURCE_SHARED_HASH namespace std { template struct hash> { size_t operator()(wil::shared_any_t const &val) const { return (hash::pointer>()(val.get())); } }; } #endif namespace wil { #if defined(__NOTHROW_T_DEFINED) && !defined(__WIL__NOTHROW_T_DEFINED) #define __WIL__NOTHROW_T_DEFINED /** Provides `std::make_unique()` semantics for resources allocated in a context that may not throw upon allocation failure. `wil::make_unique_nothrow()` is identical to `std::make_unique()` except for the following: * It returns `wistd::unique_ptr`, rather than `std::unique_ptr` * It returns an empty (null) `wistd::unique_ptr` upon allocation failure, rather than throwing an exception Note that `wil::make_unique_nothrow()` is not marked WI_NOEXCEPT as it may be used to create an exception-based class that may throw in its constructor. ~~~ auto foo = wil::make_unique_nothrow(fooConstructorParam1, fooConstructorParam2); if (foo) { foo->Bar(); } ~~~ */ template inline typename wistd::enable_if::value, wistd::unique_ptr<_Ty> >::type make_unique_nothrow(_Types&&... _Args) { return (wistd::unique_ptr<_Ty>(new(std::nothrow) _Ty(wistd::forward<_Types>(_Args)...))); } /** Provides `std::make_unique()` semantics for array resources allocated in a context that may not throw upon allocation failure. See the overload of `wil::make_unique_nothrow()` for non-array types for more details. ~~~ const size_t size = 42; auto foos = wil::make_unique_nothrow(size); // the default constructor will be called on each Foo object if (foos) { for (auto& elem : wil::make_range(foos.get(), size)) { elem.Bar(); } } ~~~ */ template inline typename wistd::enable_if::value && wistd::extent<_Ty>::value == 0, wistd::unique_ptr<_Ty> >::type make_unique_nothrow(size_t _Size) { typedef typename wistd::remove_extent<_Ty>::type _Elem; return (wistd::unique_ptr<_Ty>(new(std::nothrow) _Elem[_Size]())); } template typename wistd::enable_if::value != 0, void>::type make_unique_nothrow(_Types&&...) = delete; #if !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE) /** Provides `std::make_unique()` semantics for resources allocated in a context that must fail fast upon allocation failure. See the overload of `wil::make_unique_nothrow()` for non-array types for more details. ~~~ auto foo = wil::make_unique_failfast(fooConstructorParam1, fooConstructorParam2); foo->Bar(); ~~~ */ template inline typename wistd::enable_if::value, wistd::unique_ptr<_Ty> >::type make_unique_failfast(_Types&&... _Args) { #pragma warning(suppress: 28193) // temporary must be inspected (it is within the called function) return (wistd::unique_ptr<_Ty>(FAIL_FAST_IF_NULL_ALLOC(new(std::nothrow) _Ty(wistd::forward<_Types>(_Args)...)))); } /** Provides `std::make_unique()` semantics for array resources allocated in a context that must fail fast upon allocation failure. See the overload of `wil::make_unique_nothrow()` for non-array types for more details. ~~~ const size_t size = 42; auto foos = wil::make_unique_nothrow(size); // the default constructor will be called on each Foo object for (auto& elem : wil::make_range(foos.get(), size)) { elem.Bar(); } ~~~ */ template inline typename wistd::enable_if::value && wistd::extent<_Ty>::value == 0, wistd::unique_ptr<_Ty> >::type make_unique_failfast(size_t _Size) { typedef typename wistd::remove_extent<_Ty>::type _Elem; #pragma warning(suppress: 28193) // temporary must be inspected (it is within the called function) return (wistd::unique_ptr<_Ty>(FAIL_FAST_IF_NULL_ALLOC(new(std::nothrow) _Elem[_Size]()))); } template typename wistd::enable_if::value != 0, void>::type make_unique_failfast(_Types&&...) = delete; #endif // !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE) #endif // __WIL__NOTHROW_T_DEFINED #if defined(_WINBASE_) && !defined(__WIL_WINBASE_) && !defined(WIL_KERNEL_MODE) #define __WIL_WINBASE_ /// @cond namespace details { inline void __stdcall SetEvent(HANDLE h) WI_NOEXCEPT { __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::SetEvent(h)); } inline void __stdcall ResetEvent(HANDLE h) WI_NOEXCEPT { __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::ResetEvent(h)); } inline void __stdcall CloseHandle(HANDLE h) WI_NOEXCEPT { __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::CloseHandle(h)); } inline void __stdcall ReleaseSemaphore(_In_ HANDLE h) WI_NOEXCEPT { __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::ReleaseSemaphore(h, 1, nullptr)); } inline void __stdcall ReleaseMutex(_In_ HANDLE h) WI_NOEXCEPT { __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::ReleaseMutex(h)); } inline void __stdcall CloseTokenLinkedToken(_In_ TOKEN_LINKED_TOKEN* linkedToken) WI_NOEXCEPT { if (linkedToken->LinkedToken && (linkedToken->LinkedToken != INVALID_HANDLE_VALUE)) { __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::CloseHandle(linkedToken->LinkedToken)); } } enum class PendingCallbackCancellationBehavior { Cancel, Wait, NoWait, }; template struct DestroyThreadPoolWait { static void Destroy(_In_ PTP_WAIT threadPoolWait) WI_NOEXCEPT { ::SetThreadpoolWait(threadPoolWait, nullptr, nullptr); ::WaitForThreadpoolWaitCallbacks(threadPoolWait, (cancellationBehavior == PendingCallbackCancellationBehavior::Cancel)); ::CloseThreadpoolWait(threadPoolWait); } }; template <> struct DestroyThreadPoolWait { static void Destroy(_In_ PTP_WAIT threadPoolWait) WI_NOEXCEPT { ::CloseThreadpoolWait(threadPoolWait); } }; template struct DestroyThreadPoolWork { static void Destroy(_In_ PTP_WORK threadpoolWork) WI_NOEXCEPT { ::WaitForThreadpoolWorkCallbacks(threadpoolWork, (cancellationBehavior == PendingCallbackCancellationBehavior::Cancel)); ::CloseThreadpoolWork(threadpoolWork); } }; template <> struct DestroyThreadPoolWork { static void Destroy(_In_ PTP_WORK threadpoolWork) WI_NOEXCEPT { ::CloseThreadpoolWork(threadpoolWork); } }; // Non-RTL implementation for threadpool_t parameter of DestroyThreadPoolTimer<> struct SystemThreadPoolMethods { static void WINAPI SetThreadpoolTimer(_Inout_ PTP_TIMER Timer, _In_opt_ PFILETIME DueTime, _In_ DWORD Period, _In_opt_ DWORD WindowLength) WI_NOEXCEPT { ::SetThreadpoolTimer(Timer, DueTime, Period, WindowLength); } static void WaitForThreadpoolTimerCallbacks(_Inout_ PTP_TIMER Timer, _In_ BOOL CancelPendingCallbacks) WI_NOEXCEPT { ::WaitForThreadpoolTimerCallbacks(Timer, CancelPendingCallbacks); } static void CloseThreadpoolTimer(_Inout_ PTP_TIMER Timer) WI_NOEXCEPT { ::CloseThreadpoolTimer(Timer); } }; // SetThreadpoolTimer(timer, nullptr, 0, 0) will cancel any pending callbacks, // then CloseThreadpoolTimer will asynchronusly close the timer if a callback is running. template struct DestroyThreadPoolTimer { static void Destroy(_In_ PTP_TIMER threadpoolTimer) WI_NOEXCEPT { threadpool_t::SetThreadpoolTimer(threadpoolTimer, nullptr, 0, 0); #pragma warning(suppress:4127) // conditional expression is constant if (cancellationBehavior != PendingCallbackCancellationBehavior::NoWait) { threadpool_t::WaitForThreadpoolTimerCallbacks(threadpoolTimer, (cancellationBehavior == PendingCallbackCancellationBehavior::Cancel)); } threadpool_t::CloseThreadpoolTimer(threadpoolTimer); } }; // PendingCallbackCancellationBehavior::NoWait explicitly does not block waiting for // callbacks when destructing. template struct DestroyThreadPoolTimer { static void Destroy(_In_ PTP_TIMER threadpoolTimer) WI_NOEXCEPT { threadpool_t::CloseThreadpoolTimer(threadpoolTimer); } }; template struct DestroyThreadPoolIo { static void Destroy(_In_ PTP_IO threadpoolIo) WI_NOEXCEPT { ::WaitForThreadpoolIoCallbacks(threadpoolIo, (cancellationBehavior == PendingCallbackCancellationBehavior::Cancel)); ::CloseThreadpoolIo(threadpoolIo); } }; template <> struct DestroyThreadPoolIo { static void Destroy(_In_ PTP_IO threadpoolIo) WI_NOEXCEPT { ::CloseThreadpoolIo(threadpoolIo); } }; template struct handle_invalid_resource_policy : resource_policy { __forceinline static bool is_valid(HANDLE ptr) WI_NOEXCEPT { return ((ptr != INVALID_HANDLE_VALUE) && (ptr != nullptr)); } }; template struct handle_null_resource_policy : resource_policy { __forceinline static bool is_valid(HANDLE ptr) WI_NOEXCEPT { return ((ptr != nullptr) && (ptr != INVALID_HANDLE_VALUE)); } }; template struct handle_null_only_resource_policy : resource_policy { __forceinline static bool is_valid(HANDLE ptr) WI_NOEXCEPT { return (ptr != nullptr); } }; typedef resource_policy handle_resource_policy; } /// @endcond template using unique_any_handle_invalid = unique_any_t>>; template using unique_any_handle_null = unique_any_t>>; template using unique_any_handle_null_only = unique_any_t>>; typedef unique_any_handle_invalid unique_hfile; typedef unique_any_handle_null unique_handle; typedef unique_any_handle_invalid unique_hfind; typedef unique_any unique_hmodule; typedef unique_any_handle_null_only unique_process_handle; typedef unique_struct unique_token_linked_token; #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) typedef unique_any unique_sid; #endif using unique_tool_help_snapshot = unique_hfile; typedef unique_any::Destroy> unique_threadpool_wait; typedef unique_any::Destroy> unique_threadpool_wait_nocancel; typedef unique_any::Destroy> unique_threadpool_wait_nowait; typedef unique_any::Destroy> unique_threadpool_work; typedef unique_any::Destroy> unique_threadpool_work_nocancel; typedef unique_any::Destroy> unique_threadpool_work_nowait; typedef unique_any::Destroy> unique_threadpool_timer; typedef unique_any::Destroy> unique_threadpool_timer_nocancel; typedef unique_any::Destroy> unique_threadpool_timer_nowait; typedef unique_any::Destroy> unique_threadpool_io; typedef unique_any::Destroy> unique_threadpool_io_nocancel; typedef unique_any::Destroy> unique_threadpool_io_nowait; #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) typedef unique_any_handle_invalid unique_hfind_change; #endif typedef unique_any event_set_scope_exit; typedef unique_any event_reset_scope_exit; // Guarantees a SetEvent on the given event handle when the returned object goes out of scope // Note: call SetEvent early with the reset() method on the returned object or abort the call with the release() method WI_NODISCARD inline event_set_scope_exit SetEvent_scope_exit(HANDLE hEvent) WI_NOEXCEPT { __FAIL_FAST_ASSERT__(hEvent != nullptr); return event_set_scope_exit(hEvent); } // Guarantees a ResetEvent on the given event handle when the returned object goes out of scope // Note: call ResetEvent early with the reset() method on the returned object or abort the call with the release() method WI_NODISCARD inline event_reset_scope_exit ResetEvent_scope_exit(HANDLE hEvent) WI_NOEXCEPT { __FAIL_FAST_ASSERT__(hEvent != nullptr); return event_reset_scope_exit(hEvent); } // Checks to see if the given *manual reset* event is currently signaled. The event must not be an auto-reset event. // Use when the event will only be set once (cancellation-style) or will only be reset by the polling thread inline bool event_is_signaled(HANDLE hEvent) WI_NOEXCEPT { auto status = ::WaitForSingleObjectEx(hEvent, 0, FALSE); // Fast fail will trip for wait failures, auto-reset events, or when the event is being both Set and Reset // from a thread other than the polling thread (use event_wait directly for those cases). __FAIL_FAST_ASSERT__((status == WAIT_TIMEOUT) || ((status == WAIT_OBJECT_0) && (WAIT_OBJECT_0 == ::WaitForSingleObjectEx(hEvent, 0, FALSE)))); return (status == WAIT_OBJECT_0); } // Waits on the given handle for the specified duration inline bool handle_wait(HANDLE hEvent, DWORD dwMilliseconds = INFINITE) WI_NOEXCEPT { DWORD status = ::WaitForSingleObjectEx(hEvent, dwMilliseconds, FALSE); __FAIL_FAST_ASSERT__((status == WAIT_TIMEOUT) || (status == WAIT_OBJECT_0)); return (status == WAIT_OBJECT_0); } enum class EventOptions { None = 0x0, ManualReset = 0x1, Signaled = 0x2 }; DEFINE_ENUM_FLAG_OPERATORS(EventOptions); template class event_t : public storage_t { public: // forward all base class constructors... template explicit event_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) {} // HRESULT or void error handling... typedef typename err_policy::result result; // Exception-based constructor to create an unnamed event event_t(EventOptions options) { static_assert(wistd::is_same::value, "this constructor requires exceptions or fail fast; use the create method"); create(options); } void ResetEvent() const WI_NOEXCEPT { details::ResetEvent(storage_t::get()); } void SetEvent() const WI_NOEXCEPT { details::SetEvent(storage_t::get()); } // Guarantees a SetEvent on the given event handle when the returned object goes out of scope // Note: call SetEvent early with the reset() method on the returned object or abort the call with the release() method WI_NODISCARD event_set_scope_exit SetEvent_scope_exit() const WI_NOEXCEPT { return wil::SetEvent_scope_exit(storage_t::get()); } // Guarantees a ResetEvent on the given event handle when the returned object goes out of scope // Note: call ResetEvent early with the reset() method on the returned object or abort the call with the release() method WI_NODISCARD event_reset_scope_exit ResetEvent_scope_exit() const WI_NOEXCEPT { return wil::ResetEvent_scope_exit(storage_t::get()); } // Checks if a *manual reset* event is currently signaled. The event must not be an auto-reset event. // Use when the event will only be set once (cancellation-style) or will only be reset by the polling thread bool is_signaled() const WI_NOEXCEPT { return wil::event_is_signaled(storage_t::get()); } // Basic WaitForSingleObject on the event handle with the given timeout bool wait(DWORD dwMilliseconds = INFINITE) const WI_NOEXCEPT { return wil::handle_wait(storage_t::get(), dwMilliseconds); } // Tries to create a named event -- returns false if unable to do so (gle may still be inspected with return=false) bool try_create(EventOptions options, PCWSTR name, _In_opt_ LPSECURITY_ATTRIBUTES pSecurity = nullptr, _Out_opt_ bool *pAlreadyExists = nullptr) { auto handle = ::CreateEventExW(pSecurity, name, (WI_IsFlagSet(options, EventOptions::ManualReset) ? CREATE_EVENT_MANUAL_RESET : 0) | (WI_IsFlagSet(options, EventOptions::Signaled) ? CREATE_EVENT_INITIAL_SET : 0), EVENT_ALL_ACCESS); if (!handle) { assign_to_opt_param(pAlreadyExists, false); return false; } assign_to_opt_param(pAlreadyExists, (::GetLastError() == ERROR_ALREADY_EXISTS)); storage_t::reset(handle); return true; } // Returns HRESULT for unique_event_nothrow, void with exceptions for shared_event and unique_event result create(EventOptions options = EventOptions::None, PCWSTR name = nullptr, _In_opt_ LPSECURITY_ATTRIBUTES pSecurity = nullptr, _Out_opt_ bool *pAlreadyExists = nullptr) { return err_policy::LastErrorIfFalse(try_create(options, name, pSecurity, pAlreadyExists)); } // Tries to open the named event -- returns false if unable to do so (gle may still be inspected with return=false) bool try_open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | EVENT_MODIFY_STATE, bool inheritHandle = false) { auto handle = ::OpenEventW(desiredAccess, inheritHandle, name); if (handle == nullptr) { return false; } storage_t::reset(handle); return true; } // Returns HRESULT for unique_event_nothrow, void with exceptions for shared_event and unique_event result open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | EVENT_MODIFY_STATE, bool inheritHandle = false) { return err_policy::LastErrorIfFalse(try_open(name, desiredAccess, inheritHandle)); } }; typedef unique_any_t, err_returncode_policy>> unique_event_nothrow; typedef unique_any_t, err_failfast_policy>> unique_event_failfast; #ifdef WIL_ENABLE_EXCEPTIONS typedef unique_any_t, err_exception_policy>> unique_event; #endif #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) enum class SlimEventType { AutoReset, ManualReset, }; /** A lean and mean event class. This class provides a very similar API to `wil::unique_event` but doesn't require a kernel object. The two variants of this class are: - `wil::slim_event_auto_reset` - `wil::slim_event_manual_reset` In addition, `wil::slim_event_auto_reset` has the alias `wil::slim_event`. Some key differences to `wil::unique_event` include: - There is no 'create()' function, as initialization occurs in the constructor and can't fail. - The move functions have been deleted. - For auto-reset events, the `is_signaled()` function doesn't reset the event. (Use `ResetEvent()` instead.) - The `ResetEvent()` function returns the previous state of the event. - To create a manual reset event, use `wil::slim_event_manual_reset'. ~~~~ wil::slim_event finished; std::thread doStuff([&finished] () { Sleep(10); finished.SetEvent(); }); finished.wait(); std::shared_ptr CreateSharedEvent(bool startSignaled) { return std::make_shared(startSignaled); } ~~~~ */ template class slim_event_t { public: slim_event_t() WI_NOEXCEPT = default; slim_event_t(bool isSignaled) WI_NOEXCEPT : m_isSignaled(isSignaled ? TRUE : FALSE) { } // Cannot change memory location. slim_event_t(const slim_event_t&) = delete; slim_event_t(slim_event_t&&) = delete; slim_event_t& operator=(const slim_event_t&) = delete; slim_event_t& operator=(slim_event_t&&) = delete; // Returns the previous state of the event. bool ResetEvent() WI_NOEXCEPT { return !!InterlockedExchange(&m_isSignaled, FALSE); } void SetEvent() WI_NOEXCEPT { // FYI: 'WakeByAddress*' invokes a full memory barrier. WriteRelease(&m_isSignaled, TRUE); #pragma warning(suppress:4127) // conditional expression is constant if (Type == SlimEventType::AutoReset) { WakeByAddressSingle(&m_isSignaled); } else { WakeByAddressAll(&m_isSignaled); } } // Checks if the event is currently signaled. // Note: Unlike Win32 auto-reset event objects, this will not reset the event. bool is_signaled() const WI_NOEXCEPT { return !!ReadAcquire(&m_isSignaled); } bool wait(DWORD timeoutMiliseconds) WI_NOEXCEPT { if (timeoutMiliseconds == 0) { return TryAcquireEvent(); } else if (timeoutMiliseconds == INFINITE) { return wait(); } UINT64 startTime; QueryUnbiasedInterruptTime(&startTime); UINT64 elapsedTimeMilliseconds = 0; while (!TryAcquireEvent()) { if (elapsedTimeMilliseconds >= timeoutMiliseconds) { return false; } DWORD newTimeout = static_cast(timeoutMiliseconds - elapsedTimeMilliseconds); if (!WaitForSignal(newTimeout)) { return false; } UINT64 currTime; QueryUnbiasedInterruptTime(&currTime); elapsedTimeMilliseconds = (currTime - startTime) / (10 * 1000); } return true; } bool wait() WI_NOEXCEPT { while (!TryAcquireEvent()) { if (!WaitForSignal(INFINITE)) { return false; } } return true; } private: bool TryAcquireEvent() WI_NOEXCEPT { #pragma warning(suppress:4127) // conditional expression is constant if (Type == SlimEventType::AutoReset) { return ResetEvent(); } else { return is_signaled(); } } bool WaitForSignal(DWORD timeoutMiliseconds) WI_NOEXCEPT { LONG falseValue = FALSE; BOOL waitResult = WaitOnAddress(&m_isSignaled, &falseValue, sizeof(m_isSignaled), timeoutMiliseconds); __FAIL_FAST_ASSERT__(waitResult || ::GetLastError() == ERROR_TIMEOUT); return !!waitResult; } LONG m_isSignaled = FALSE; }; /** An event object that will atomically revert to an unsignaled state anytime a `wait()` call succeeds (i.e. returns true). */ using slim_event_auto_reset = slim_event_t; /** An event object that once signaled remains that way forever, unless `ResetEvent()` is called. */ using slim_event_manual_reset = slim_event_t; /** An alias for `wil::slim_event_auto_reset`. */ using slim_event = slim_event_auto_reset; #endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) typedef unique_any mutex_release_scope_exit; WI_NODISCARD inline mutex_release_scope_exit ReleaseMutex_scope_exit(_In_ HANDLE hMutex) WI_NOEXCEPT { __FAIL_FAST_ASSERT__(hMutex != nullptr); return mutex_release_scope_exit(hMutex); } // For efficiency, avoid using mutexes when an srwlock or condition variable will do. template class mutex_t : public storage_t { public: // forward all base class constructors... template explicit mutex_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) {} // HRESULT or void error handling... typedef typename err_policy::result result; // Exception-based constructor to create a mutex (prefer unnamed (nullptr) for the name) mutex_t(_In_opt_ PCWSTR name) { static_assert(wistd::is_same::value, "this constructor requires exceptions or fail fast; use the create method"); create(name); } void ReleaseMutex() const WI_NOEXCEPT { details::ReleaseMutex(storage_t::get()); } WI_NODISCARD mutex_release_scope_exit ReleaseMutex_scope_exit() const WI_NOEXCEPT { return wil::ReleaseMutex_scope_exit(storage_t::get()); } WI_NODISCARD mutex_release_scope_exit acquire(_Out_opt_ DWORD *pStatus = nullptr, DWORD dwMilliseconds = INFINITE, BOOL bAlertable = FALSE) const WI_NOEXCEPT { auto handle = storage_t::get(); DWORD status = ::WaitForSingleObjectEx(handle, dwMilliseconds, bAlertable); assign_to_opt_param(pStatus, status); __FAIL_FAST_ASSERT__((status == WAIT_TIMEOUT) || (status == WAIT_OBJECT_0) || (status == WAIT_ABANDONED) || (bAlertable && (status == WAIT_IO_COMPLETION))); return mutex_release_scope_exit(((status == WAIT_OBJECT_0) || (status == WAIT_ABANDONED)) ? handle : nullptr); } // Tries to create a named mutex -- returns false if unable to do so (gle may still be inspected with return=false) bool try_create(_In_opt_ PCWSTR name, DWORD dwFlags = 0, DWORD desiredAccess = MUTEX_ALL_ACCESS, _In_opt_ PSECURITY_ATTRIBUTES pMutexAttributes = nullptr) { auto handle = ::CreateMutexExW(pMutexAttributes, name, dwFlags, desiredAccess); if (handle == nullptr) { return false; } storage_t::reset(handle); return true; } // Returns HRESULT for unique_mutex_nothrow, void with exceptions for shared_mutex and unique_mutex result create(_In_opt_ PCWSTR name = nullptr, DWORD dwFlags = 0, DWORD desiredAccess = MUTEX_ALL_ACCESS, _In_opt_ PSECURITY_ATTRIBUTES pMutexAttributes = nullptr) { return err_policy::LastErrorIfFalse(try_create(name, dwFlags, desiredAccess, pMutexAttributes)); } // Tries to open a named mutex -- returns false if unable to do so (gle may still be inspected with return=false) bool try_open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | MUTEX_MODIFY_STATE, bool inheritHandle = false) { auto handle = ::OpenMutexW(desiredAccess, inheritHandle, name); if (handle == nullptr) { return false; } storage_t::reset(handle); return true; } // Returns HRESULT for unique_mutex_nothrow, void with exceptions for shared_mutex and unique_mutex result open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | MUTEX_MODIFY_STATE, bool inheritHandle = false) { return err_policy::LastErrorIfFalse(try_open(name, desiredAccess, inheritHandle)); } }; typedef unique_any_t, err_returncode_policy>> unique_mutex_nothrow; typedef unique_any_t, err_failfast_policy>> unique_mutex_failfast; #ifdef WIL_ENABLE_EXCEPTIONS typedef unique_any_t, err_exception_policy>> unique_mutex; #endif typedef unique_any semaphore_release_scope_exit; WI_NODISCARD inline semaphore_release_scope_exit ReleaseSemaphore_scope_exit(_In_ HANDLE hSemaphore) WI_NOEXCEPT { __FAIL_FAST_ASSERT__(hSemaphore != nullptr); return semaphore_release_scope_exit(hSemaphore); } template class semaphore_t : public storage_t { public: // forward all base class constructors... template explicit semaphore_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) {} // HRESULT or void error handling... typedef typename err_policy::result result; // Note that for custom-constructors the type given the constructor has to match exactly as not all implicit conversions will make it through the // forwarding constructor. This constructor, for example, uses 'int' instead of 'LONG' as the count to ease that particular issue (const numbers are int by default). explicit semaphore_t(int initialCount, int maximumCount, _In_opt_ PCWSTR name = nullptr, DWORD desiredAccess = SEMAPHORE_ALL_ACCESS, _In_opt_ PSECURITY_ATTRIBUTES pSemaphoreAttributes = nullptr) { static_assert(wistd::is_same::value, "this constructor requires exceptions or fail fast; use the create method"); create(initialCount, maximumCount, name, desiredAccess, pSemaphoreAttributes); } void ReleaseSemaphore(long nReleaseCount = 1, _In_opt_ long *pnPreviousCount = nullptr) WI_NOEXCEPT { long nPreviousCount = 0; __FAIL_FAST_ASSERT__(::ReleaseSemaphore(storage_t::get(), nReleaseCount, &nPreviousCount)); assign_to_opt_param(pnPreviousCount, nPreviousCount); } WI_NODISCARD semaphore_release_scope_exit ReleaseSemaphore_scope_exit() WI_NOEXCEPT { return wil::ReleaseSemaphore_scope_exit(storage_t::get()); } WI_NODISCARD semaphore_release_scope_exit acquire(_Out_opt_ DWORD *pStatus = nullptr, DWORD dwMilliseconds = INFINITE, BOOL bAlertable = FALSE) WI_NOEXCEPT { auto handle = storage_t::get(); DWORD status = ::WaitForSingleObjectEx(handle, dwMilliseconds, bAlertable); assign_to_opt_param(pStatus, status); __FAIL_FAST_ASSERT__((status == WAIT_TIMEOUT) || (status == WAIT_OBJECT_0) || (bAlertable && (status == WAIT_IO_COMPLETION))); return semaphore_release_scope_exit((status == WAIT_OBJECT_0) ? handle : nullptr); } // Tries to create a named event -- returns false if unable to do so (gle may still be inspected with return=false) bool try_create(LONG lInitialCount, LONG lMaximumCount, _In_opt_ PCWSTR name, DWORD desiredAccess = SEMAPHORE_ALL_ACCESS, _In_opt_ PSECURITY_ATTRIBUTES pSemaphoreAttributes = nullptr) { auto handle = ::CreateSemaphoreExW(pSemaphoreAttributes, lInitialCount, lMaximumCount, name, 0, desiredAccess); if (handle == nullptr) { return false; } storage_t::reset(handle); return true; } // Returns HRESULT for unique_semaphore_nothrow, void with exceptions for shared_event and unique_event result create(LONG lInitialCount, LONG lMaximumCount, _In_opt_ PCWSTR name = nullptr, DWORD desiredAccess = SEMAPHORE_ALL_ACCESS, _In_opt_ PSECURITY_ATTRIBUTES pSemaphoreAttributes = nullptr) { return err_policy::LastErrorIfFalse(try_create(lInitialCount, lMaximumCount, name, desiredAccess, pSemaphoreAttributes)); } // Tries to open the named semaphore -- returns false if unable to do so (gle may still be inspected with return=false) bool try_open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | SEMAPHORE_MODIFY_STATE, bool inheritHandle = false) { auto handle = ::OpenSemaphoreW(desiredAccess, inheritHandle, name); if (handle == nullptr) { return false; } storage_t::reset(handle); return true; } // Returns HRESULT for unique_semaphore_nothrow, void with exceptions for shared_semaphore and unique_semaphore result open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | SEMAPHORE_MODIFY_STATE, bool inheritHandle = false) { return err_policy::LastErrorIfFalse(try_open(name, desiredAccess, inheritHandle)); } }; typedef unique_any_t, err_returncode_policy>> unique_semaphore_nothrow; typedef unique_any_t, err_failfast_policy>> unique_semaphore_failfast; #ifdef WIL_ENABLE_EXCEPTIONS typedef unique_any_t, err_exception_policy>> unique_semaphore; #endif typedef unique_any rwlock_release_exclusive_scope_exit; typedef unique_any rwlock_release_shared_scope_exit; WI_NODISCARD inline rwlock_release_exclusive_scope_exit AcquireSRWLockExclusive(_Inout_ SRWLOCK *plock) WI_NOEXCEPT { ::AcquireSRWLockExclusive(plock); return rwlock_release_exclusive_scope_exit(plock); } WI_NODISCARD inline rwlock_release_shared_scope_exit AcquireSRWLockShared(_Inout_ SRWLOCK *plock) WI_NOEXCEPT { ::AcquireSRWLockShared(plock); return rwlock_release_shared_scope_exit(plock); } WI_NODISCARD inline rwlock_release_exclusive_scope_exit TryAcquireSRWLockExclusive(_Inout_ SRWLOCK *plock) WI_NOEXCEPT { return rwlock_release_exclusive_scope_exit(::TryAcquireSRWLockExclusive(plock) ? plock : nullptr); } WI_NODISCARD inline rwlock_release_shared_scope_exit TryAcquireSRWLockShared(_Inout_ SRWLOCK *plock) WI_NOEXCEPT { return rwlock_release_shared_scope_exit(::TryAcquireSRWLockShared(plock) ? plock : nullptr); } class srwlock { public: srwlock(const srwlock&) = delete; srwlock(srwlock&&) = delete; srwlock& operator=(const srwlock&) = delete; srwlock& operator=(srwlock&&) = delete; srwlock() = default; WI_NODISCARD rwlock_release_exclusive_scope_exit lock_exclusive() WI_NOEXCEPT { return wil::AcquireSRWLockExclusive(&m_lock); } WI_NODISCARD rwlock_release_exclusive_scope_exit try_lock_exclusive() WI_NOEXCEPT { return wil::TryAcquireSRWLockExclusive(&m_lock); } WI_NODISCARD rwlock_release_shared_scope_exit lock_shared() WI_NOEXCEPT { return wil::AcquireSRWLockShared(&m_lock); } WI_NODISCARD rwlock_release_shared_scope_exit try_lock_shared() WI_NOEXCEPT { return wil::TryAcquireSRWLockShared(&m_lock); } private: SRWLOCK m_lock = SRWLOCK_INIT; }; typedef unique_any cs_leave_scope_exit; WI_NODISCARD inline cs_leave_scope_exit EnterCriticalSection(_Inout_ CRITICAL_SECTION *pcs) WI_NOEXCEPT { ::EnterCriticalSection(pcs); return cs_leave_scope_exit(pcs); } WI_NODISCARD inline cs_leave_scope_exit TryEnterCriticalSection(_Inout_ CRITICAL_SECTION *pcs) WI_NOEXCEPT { return cs_leave_scope_exit(::TryEnterCriticalSection(pcs) ? pcs : nullptr); } // Critical sections are worse than srwlocks in performance and memory usage (their only unique attribute // being recursive acquisition). Prefer srwlocks over critical sections when you don't need recursive acquisition. class critical_section { public: critical_section(const critical_section&) = delete; critical_section(critical_section&&) = delete; critical_section& operator=(const critical_section&) = delete; critical_section& operator=(critical_section&&) = delete; critical_section(ULONG spincount = 0) WI_NOEXCEPT { // Initialization will not fail without invalid params... ::InitializeCriticalSectionEx(&m_cs, spincount, 0); } ~critical_section() WI_NOEXCEPT { ::DeleteCriticalSection(&m_cs); } WI_NODISCARD cs_leave_scope_exit lock() WI_NOEXCEPT { return wil::EnterCriticalSection(&m_cs); } WI_NODISCARD cs_leave_scope_exit try_lock() WI_NOEXCEPT { return wil::TryEnterCriticalSection(&m_cs); } private: CRITICAL_SECTION m_cs; }; class condition_variable { public: condition_variable(const condition_variable&) = delete; condition_variable(condition_variable&&) = delete; condition_variable& operator=(const condition_variable&) = delete; condition_variable& operator=(condition_variable&&) = delete; condition_variable() = default; void notify_one() WI_NOEXCEPT { ::WakeConditionVariable(&m_cv); } void notify_all() WI_NOEXCEPT { ::WakeAllConditionVariable(&m_cv); } void wait(const cs_leave_scope_exit& lock) WI_NOEXCEPT { wait_for(lock, INFINITE); } void wait(const rwlock_release_exclusive_scope_exit& lock) WI_NOEXCEPT { wait_for(lock, INFINITE); } void wait(const rwlock_release_shared_scope_exit& lock) WI_NOEXCEPT { wait_for(lock, INFINITE); } bool wait_for(const cs_leave_scope_exit& lock, DWORD timeoutMs) WI_NOEXCEPT { bool result = !!::SleepConditionVariableCS(&m_cv, lock.get(), timeoutMs); __FAIL_FAST_ASSERT__(result || ::GetLastError() == ERROR_TIMEOUT); return result; } bool wait_for(const rwlock_release_exclusive_scope_exit& lock, DWORD timeoutMs) WI_NOEXCEPT { bool result = !!::SleepConditionVariableSRW(&m_cv, lock.get(), timeoutMs, 0); __FAIL_FAST_ASSERT__(result || ::GetLastError() == ERROR_TIMEOUT); return result; } bool wait_for(const rwlock_release_shared_scope_exit& lock, DWORD timeoutMs) WI_NOEXCEPT { bool result = !!::SleepConditionVariableSRW(&m_cv, lock.get(), timeoutMs, CONDITION_VARIABLE_LOCKMODE_SHARED); __FAIL_FAST_ASSERT__(result || ::GetLastError() == ERROR_TIMEOUT); return result; } private: CONDITION_VARIABLE m_cv = CONDITION_VARIABLE_INIT; }; /// @cond namespace details { template struct string_allocator { static void* allocate(size_t /*size*/) WI_NOEXCEPT { static_assert(!wistd::is_same::value, "This type did not provide a string_allocator, add a specialization of string_allocator to support your type."); return nullptr; } }; } /// @endcond // This string helper does not support the ansi wil string helpers template PCWSTR string_get_not_null(const string_type& string) { return string ? string.get() : L""; } #ifndef MAKE_UNIQUE_STRING_MAX_CCH #define MAKE_UNIQUE_STRING_MAX_CCH 2147483647 // max buffer size, in characters, that we support (same as INT_MAX) #endif /** Copies a string (up to the given length) into memory allocated with a specified allocator returning null on failure. Use `wil::make_unique_string_nothrow()` for string resources returned from APIs that must satisfy a memory allocation contract that requires use of a specific allocator and free function (CoTaskMemAlloc/CoTaskMemFree, LocalAlloc/LocalFree, GlobalAlloc/GlobalFree, etc.). ~~~ auto str = wil::make_unique_string_nothrow(L"a string of words", 8); RETURN_IF_NULL_ALLOC(str); std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" auto str = wil::make_unique_string_nothrow(L"a string"); RETURN_IF_NULL_ALLOC(str); std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" NOTE: If source is not null terminated, then length MUST be equal to or less than the size of the buffer pointed to by source. ~~~ */ template string_type make_unique_string_nothrow( _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) _When_((source != nullptr) && length == static_cast(-1), _In_z_) const wchar_t* source, size_t length = static_cast(-1)) WI_NOEXCEPT { // guard against invalid parameters (null source with -1 length) FAIL_FAST_IF(!source && (length == static_cast(-1))); // When the source string exists, calculate the number of characters to copy up to either // 1) the length that is given // 2) the length of the source string. When the source does not exist, use the given length // for calculating both the size of allocated buffer and the number of characters to copy. size_t lengthToCopy = length; if (source) { size_t maxLength = length < MAKE_UNIQUE_STRING_MAX_CCH ? length : MAKE_UNIQUE_STRING_MAX_CCH; PCWSTR endOfSource = source; while (maxLength && (*endOfSource != L'\0')) { endOfSource++; maxLength--; } lengthToCopy = endOfSource - source; } if (length == static_cast(-1)) { length = lengthToCopy; } const size_t allocatedBytes = (length + 1) * sizeof(*source); auto result = static_cast(details::string_allocator::allocate(allocatedBytes)); if (result) { if (source) { const size_t bytesToCopy = lengthToCopy * sizeof(*source); memcpy_s(result, allocatedBytes, source, bytesToCopy); result[lengthToCopy] = L'\0'; // ensure the copied string is zero terminated } else { *result = L'\0'; // ensure null terminated in the "reserve space" use case. } result[length] = L'\0'; // ensure the final char of the buffer is zero terminated } return string_type(result); } #ifndef WIL_NO_ANSI_STRINGS template string_type make_unique_ansistring_nothrow( _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT { // guard against invalid parameters (null source with -1 length) FAIL_FAST_IF(!source && (length == static_cast(-1))); if (length == static_cast(-1)) { length = strlen(source); } const size_t cb = (length + 1) * sizeof(*source); auto result = static_cast(details::string_allocator::allocate(cb)); if (result) { if (source) { memcpy_s(result, cb, source, cb - sizeof(*source)); } else { *result = '\0'; // ensure null terminated in the "reserve space" use case. } result[length] = '\0'; // ensure zero terminated } return string_type(result); } #endif // WIL_NO_ANSI_STRINGS /** Copies a given string into memory allocated with a specified allocator that will fail fast on failure. The use of variadic templates parameters supports the 2 forms of make_unique_string, see those for more details. */ template string_type make_unique_string_failfast( _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCWSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT { auto result(make_unique_string_nothrow(source, length)); FAIL_FAST_IF_NULL_ALLOC(result); return result; } #ifndef WIL_NO_ANSI_STRINGS template string_type make_unique_ansistring_failfast( _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT { auto result(make_unique_ansistring_nothrow(source, length)); FAIL_FAST_IF_NULL_ALLOC(result); return result; } #endif // WIL_NO_ANSI_STRINGS #ifdef WIL_ENABLE_EXCEPTIONS /** Copies a given string into memory allocated with a specified allocator that will throw on failure. The use of variadic templates parameters supports the 2 forms of make_unique_string, see those for more details. */ template string_type make_unique_string( _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCWSTR source, size_t length = static_cast(-1)) { auto result(make_unique_string_nothrow(source, length)); THROW_IF_NULL_ALLOC(result); return result; } #ifndef WIL_NO_ANSI_STRINGS template string_type make_unique_ansistring( _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCSTR source, size_t length = static_cast(-1)) { auto result(make_unique_ansistring_nothrow(source, length)); THROW_IF_NULL_ALLOC(result); return result; } #endif // WIL_NO_ANSI_STRINGS #endif // WIL_ENABLE_EXCEPTIONS /// @cond namespace details { // string_maker abstracts creating a string for common string types. This form supports the // wil::unique_xxx_string types. Specializations of other types like HSTRING and std::wstring // are found in wil\winrt.h and wil\stl.h. // This design supports creating the string in a single step or using two phase construction. template struct string_maker { HRESULT make( _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) _When_((source != nullptr) && length == static_cast(-1), _In_z_) const wchar_t* source, size_t length) { m_value = make_unique_string_nothrow(source, length); return m_value ? S_OK : E_OUTOFMEMORY; } wchar_t* buffer() { WI_ASSERT(m_value.get()); return m_value.get(); } string_type release() { return wistd::move(m_value); } // Utility to abstract access to the null terminated m_value of all string types. static PCWSTR get(const string_type& value) { return value.get(); } private: string_type m_value; // a wil::unique_xxx_string type. }; struct SecureZeroData { void *pointer; size_t sizeBytes; SecureZeroData(void *pointer_, size_t sizeBytes_ = 0) WI_NOEXCEPT { pointer = pointer_; sizeBytes = sizeBytes_; } operator void *() const WI_NOEXCEPT { return pointer; } static void Close(SecureZeroData data) WI_NOEXCEPT { ::SecureZeroMemory(data.pointer, data.sizeBytes); } }; } /// @endcond typedef unique_any secure_zero_memory_scope_exit; WI_NODISCARD inline secure_zero_memory_scope_exit SecureZeroMemory_scope_exit(_In_reads_bytes_(sizeBytes) void* pSource, size_t sizeBytes) { return secure_zero_memory_scope_exit(details::SecureZeroData(pSource, sizeBytes)); } WI_NODISCARD inline secure_zero_memory_scope_exit SecureZeroMemory_scope_exit(_In_ PWSTR initializedString) { return SecureZeroMemory_scope_exit(static_cast(initializedString), wcslen(initializedString) * sizeof(initializedString[0])); } /// @cond namespace details { inline void __stdcall FreeProcessHeap(_Pre_opt_valid_ _Frees_ptr_opt_ void* p) { ::HeapFree(::GetProcessHeap(), 0, p); } } /// @endcond struct process_heap_deleter { template void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const { details::FreeProcessHeap(p); } }; struct virtualalloc_deleter { template void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const { ::VirtualFree(p, 0, MEM_RELEASE); } }; struct mapview_deleter { template void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const { ::UnmapViewOfFile(p); } }; template using unique_process_heap_ptr = wistd::unique_ptr; typedef unique_any unique_process_heap_string; /// @cond namespace details { template<> struct string_allocator { static _Ret_opt_bytecap_(size) void* allocate(size_t size) WI_NOEXCEPT { return ::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, size); } }; } /// @endcond /** Manages a typed pointer allocated with VirtualAlloc A specialization of wistd::unique_ptr<> that frees via VirtualFree(p, 0, MEM_RELEASE). */ template using unique_virtualalloc_ptr = wistd::unique_ptr; /** Manages a typed pointer allocated with MapViewOfFile A specialization of wistd::unique_ptr<> that frees via UnmapViewOfFile(p). */ template using unique_mapview_ptr = wistd::unique_ptr; #endif // __WIL_WINBASE_ #if defined(__WIL_WINBASE_) && defined(__NOTHROW_T_DEFINED) && !defined(__WIL_WINBASE_NOTHROW_T_DEFINED) #define __WIL_WINBASE_NOTHROW_T_DEFINED // unique_event_watcher, unique_event_watcher_nothrow, unique_event_watcher_failfast // // Clients must include or to enable use of this class as it uses new(std::nothrow). // This is to avoid the dependency on those headers that some clients can't tolerate. // // These classes makes it easy to execute a provided function when an event // is signaled. It will create the event handle for you, take ownership of one // or duplicate a handle provided. It supports the ability to signal the // event using SetEvent() and SetEvent_scope_exit(); // // This can be used to support producer-consumer pattern // where a producer updates some state then signals the event when done. // The consumer will consume that state in the callback provided to unique_event_watcher. // // Note, multiple signals may coalesce into a single callback. // // Example use of throwing version: // auto globalStateWatcher = wil::make_event_watcher([] // { // currentState = GetGlobalState(); // }); // // UpdateGlobalState(value); // globalStateWatcher.SetEvent(); // signal observers so they can update // // Example use of non-throwing version: // auto globalStateWatcher = wil::make_event_watcher_nothrow([] // { // currentState = GetGlobalState(); // }); // RETURN_IF_NULL_ALLOC(globalStateWatcher); // // UpdateGlobalState(value); // globalStateWatcher.SetEvent(); // signal observers so they can update /// @cond namespace details { struct event_watcher_state { event_watcher_state(unique_event_nothrow &&eventHandle, wistd::function &&callback) : m_callback(wistd::move(callback)), m_event(wistd::move(eventHandle)) { } wistd::function m_callback; unique_event_nothrow m_event; // The thread pool must be last to ensure that the other members are valid // when it is destructed as it will reference them. unique_threadpool_wait m_threadPoolWait; }; inline void delete_event_watcher_state(_In_opt_ event_watcher_state *watcherStorage) { delete watcherStorage; } typedef resource_policy event_watcher_state_resource_policy; } /// @endcond template class event_watcher_t : public storage_t { public: // forward all base class constructors... template explicit event_watcher_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) {} // HRESULT or void error handling... typedef typename err_policy::result result; // Exception-based constructors template event_watcher_t(unique_any_t, err_policy>> &&eventHandle, wistd::function &&callback) { static_assert(wistd::is_same::value, "this constructor requires exceptions or fail fast; use the create method"); create(wistd::move(eventHandle), wistd::move(callback)); } event_watcher_t(_In_ HANDLE eventHandle, wistd::function &&callback) { static_assert(wistd::is_same::value, "this constructor requires exceptions or fail fast; use the create method"); create(eventHandle, wistd::move(callback)); } event_watcher_t(wistd::function &&callback) { static_assert(wistd::is_same::value, "this constructor requires exceptions or fail fast; use the create method"); create(wistd::move(callback)); } template result create(unique_any_t, event_err_policy>> &&eventHandle, wistd::function &&callback) { return err_policy::HResult(create_take_hevent_ownership(eventHandle.release(), wistd::move(callback))); } // Creates the event that you will be watching. result create(wistd::function &&callback) { unique_event_nothrow eventHandle; HRESULT hr = eventHandle.create(EventOptions::ManualReset); // auto-reset is supported too. if (FAILED(hr)) { return err_policy::HResult(hr); } return err_policy::HResult(create_take_hevent_ownership(eventHandle.release(), wistd::move(callback))); } // Input is an event handler that is duplicated into this class. result create(_In_ HANDLE eventHandle, wistd::function &&callback) { unique_event_nothrow ownedHandle; if (!DuplicateHandle(GetCurrentProcess(), eventHandle, GetCurrentProcess(), &ownedHandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) { return err_policy::LastError(); } return err_policy::HResult(create_take_hevent_ownership(ownedHandle.release(), wistd::move(callback))); } // Provide access to the inner event and the very common SetEvent() method on it. unique_event_nothrow const& get_event() const WI_NOEXCEPT { return storage_t::get()->m_event; } void SetEvent() const WI_NOEXCEPT { storage_t::get()->m_event.SetEvent(); } private: // Had to move this from a Lambda so it would compile in C++/CLI (which thought the Lambda should be a managed function for some reason). static void CALLBACK wait_callback(PTP_CALLBACK_INSTANCE, void *context, TP_WAIT *pThreadPoolWait, TP_WAIT_RESULT) { auto pThis = static_cast(context); // Manual events must be re-set to avoid missing the last notification. pThis->m_event.ResetEvent(); // Call the client before re-arming to ensure that multiple callbacks don't // run concurrently. pThis->m_callback(); SetThreadpoolWait(pThreadPoolWait, pThis->m_event.get(), nullptr); // valid params ensure success } // To avoid template expansion (if unique_event/unique_event_nothrow forms were used) this base // create function takes a raw handle and assumes its ownership, even on failure. HRESULT create_take_hevent_ownership(_In_ HANDLE rawHandleOwnershipTaken, wistd::function &&callback) { __FAIL_FAST_ASSERT__(rawHandleOwnershipTaken != nullptr); // invalid parameter unique_event_nothrow eventHandle(rawHandleOwnershipTaken); wistd::unique_ptr watcherState(new(std::nothrow) details::event_watcher_state(wistd::move(eventHandle), wistd::move(callback))); RETURN_IF_NULL_ALLOC(watcherState); watcherState->m_threadPoolWait.reset(CreateThreadpoolWait(wait_callback, watcherState.get(), nullptr)); RETURN_LAST_ERROR_IF(!watcherState->m_threadPoolWait); storage_t::reset(watcherState.release()); // no more failures after this, pass ownership SetThreadpoolWait(storage_t::get()->m_threadPoolWait.get(), storage_t::get()->m_event.get(), nullptr); return S_OK; } }; typedef unique_any_t, err_returncode_policy>> unique_event_watcher_nothrow; typedef unique_any_t, err_failfast_policy>> unique_event_watcher_failfast; template unique_event_watcher_nothrow make_event_watcher_nothrow(unique_any_t, err_policy>> &&eventHandle, wistd::function &&callback) WI_NOEXCEPT { unique_event_watcher_nothrow watcher; watcher.create(wistd::move(eventHandle), wistd::move(callback)); return watcher; // caller must test for success using if (watcher) } inline unique_event_watcher_nothrow make_event_watcher_nothrow(_In_ HANDLE eventHandle, wistd::function &&callback) WI_NOEXCEPT { unique_event_watcher_nothrow watcher; watcher.create(eventHandle, wistd::move(callback)); return watcher; // caller must test for success using if (watcher) } inline unique_event_watcher_nothrow make_event_watcher_nothrow(wistd::function &&callback) WI_NOEXCEPT { unique_event_watcher_nothrow watcher; watcher.create(wistd::move(callback)); return watcher; // caller must test for success using if (watcher) } template unique_event_watcher_failfast make_event_watcher_failfast(unique_any_t, err_policy>> &&eventHandle, wistd::function &&callback) { return unique_event_watcher_failfast(wistd::move(eventHandle), wistd::move(callback)); } inline unique_event_watcher_failfast make_event_watcher_failfast(_In_ HANDLE eventHandle, wistd::function &&callback) { return unique_event_watcher_failfast(eventHandle, wistd::move(callback)); } inline unique_event_watcher_failfast make_event_watcher_failfast(wistd::function &&callback) { return unique_event_watcher_failfast(wistd::move(callback)); } #ifdef WIL_ENABLE_EXCEPTIONS typedef unique_any_t, err_exception_policy>> unique_event_watcher; template unique_event_watcher make_event_watcher(unique_any_t, err_policy>> &&eventHandle, wistd::function &&callback) { return unique_event_watcher(wistd::move(eventHandle), wistd::move(callback)); } inline unique_event_watcher make_event_watcher(_In_ HANDLE eventHandle, wistd::function &&callback) { return unique_event_watcher(eventHandle, wistd::move(callback)); } inline unique_event_watcher make_event_watcher(wistd::function &&callback) { return unique_event_watcher(wistd::move(callback)); } #endif // WIL_ENABLE_EXCEPTIONS #endif // __WIL_WINBASE_NOTHROW_T_DEFINED #if defined(__WIL_WINBASE_) && !defined(__WIL_WINBASE_STL) && defined(WIL_RESOURCE_STL) #define __WIL_WINBASE_STL typedef shared_any_t>> shared_event; typedef shared_any_t>> shared_mutex; typedef shared_any_t>> shared_semaphore; typedef shared_any shared_hfile; typedef shared_any shared_handle; typedef shared_any shared_hfind; typedef shared_any shared_hmodule; #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) typedef shared_any shared_threadpool_wait; typedef shared_any shared_threadpool_wait_nocancel; typedef shared_any shared_threadpool_work; typedef shared_any shared_threadpool_work_nocancel; typedef shared_any shared_hfind_change; #endif typedef weak_any weak_event; typedef weak_any weak_mutex; typedef weak_any weak_semaphore; typedef weak_any weak_hfile; typedef weak_any weak_handle; typedef weak_any weak_hfind; typedef weak_any weak_hmodule; #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) typedef weak_any weak_threadpool_wait; typedef weak_any weak_threadpool_wait_nocancel; typedef weak_any weak_threadpool_work; typedef weak_any weak_threadpool_work_nocancel; typedef weak_any weak_hfind_change; #endif #endif // __WIL_WINBASE_STL #if defined(__WIL_WINBASE_) && defined(__NOTHROW_T_DEFINED) && !defined(__WIL_WINBASE_NOTHROW_T_DEFINED_STL) && defined(WIL_RESOURCE_STL) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #define __WIL_WINBASE_NOTHROW_T_DEFINED_STL typedef shared_any_t>> shared_event_watcher; typedef weak_any weak_event_watcher; #endif // __WIL_WINBASE_NOTHROW_T_DEFINED_STL #if defined(__WIL_WINBASE_) && !defined(__WIL_WINBASE_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #define __WIL_WINBASE_DESKTOP /// @cond namespace details { inline void __stdcall DestroyPrivateObjectSecurity(_Pre_opt_valid_ _Frees_ptr_opt_ PSECURITY_DESCRIPTOR pObjectDescriptor) WI_NOEXCEPT { ::DestroyPrivateObjectSecurity(&pObjectDescriptor); } } /// @endcond using hlocal_deleter = function_deleter; template using unique_hlocal_ptr = wistd::unique_ptr; /** Provides `std::make_unique()` semantics for resources allocated with `LocalAlloc()` in a context that may not throw upon allocation failure. Use `wil::make_unique_hlocal_nothrow()` for resources returned from APIs that must satisfy a memory allocation contract that requires the use of `LocalAlloc()` / `LocalFree()`. Use `wil::make_unique_nothrow()` when `LocalAlloc()` is not required. Allocations are initialized with placement new and will call constructors (if present), but this does not guarantee initialization. Note that `wil::make_unique_hlocal_nothrow()` is not marked WI_NOEXCEPT as it may be used to create an exception-based class that may throw in its constructor. ~~~ auto foo = wil::make_unique_hlocal_nothrow(); if (foo) { // initialize allocated Foo object as appropriate } ~~~ */ template inline typename wistd::enable_if::value, unique_hlocal_ptr>::type make_unique_hlocal_nothrow(Args&&... args) { static_assert(wistd::is_trivially_destructible::value, "T has a destructor that won't be run when used with this function; use make_unique instead"); unique_hlocal_ptr sp(static_cast(::LocalAlloc(LMEM_FIXED, sizeof(T)))); if (sp) { // use placement new to initialize memory from the previous allocation new (sp.get()) T(wistd::forward(args)...); } return sp; } /** Provides `std::make_unique()` semantics for array resources allocated with `LocalAlloc()` in a context that may not throw upon allocation failure. See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. ~~~ const size_t size = 42; auto foos = wil::make_unique_hlocal_nothrow(size); if (foos) { for (auto& elem : wil::make_range(foos.get(), size)) { // initialize allocated Foo objects as appropriate } } ~~~ */ template inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_hlocal_ptr>::type make_unique_hlocal_nothrow(size_t size) { typedef typename wistd::remove_extent::type E; static_assert(wistd::is_trivially_destructible::value, "E has a destructor that won't be run when used with this function; use make_unique instead"); FAIL_FAST_IF((__WI_SIZE_MAX / sizeof(E)) < size); size_t allocSize = sizeof(E) * size; unique_hlocal_ptr sp(static_cast(::LocalAlloc(LMEM_FIXED, allocSize))); if (sp) { // use placement new to initialize memory from the previous allocation; // note that array placement new cannot be used as the standard allows for operator new[] // to consume overhead in the allocation for internal bookkeeping for (auto& elem : make_range(static_cast(sp.get()), size)) { new (&elem) E(); } } return sp; } /** Provides `std::make_unique()` semantics for resources allocated with `LocalAlloc()` in a context that must fail fast upon allocation failure. See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. ~~~ auto foo = wil::make_unique_hlocal_failfast(); // initialize allocated Foo object as appropriate ~~~ */ template inline typename wistd::enable_if::value, unique_hlocal_ptr>::type make_unique_hlocal_failfast(Args&&... args) { unique_hlocal_ptr result(make_unique_hlocal_nothrow(wistd::forward(args)...)); FAIL_FAST_IF_NULL_ALLOC(result); return result; } /** Provides `std::make_unique()` semantics for array resources allocated with `LocalAlloc()` in a context that must fail fast upon allocation failure. See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. ~~~ const size_t size = 42; auto foos = wil::make_unique_hlocal_failfast(size); for (auto& elem : wil::make_range(foos.get(), size)) { // initialize allocated Foo objects as appropriate } ~~~ */ template inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_hlocal_ptr>::type make_unique_hlocal_failfast(size_t size) { unique_hlocal_ptr result(make_unique_hlocal_nothrow(size)); FAIL_FAST_IF_NULL_ALLOC(result); return result; } #ifdef WIL_ENABLE_EXCEPTIONS /** Provides `std::make_unique()` semantics for resources allocated with `LocalAlloc()`. See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. ~~~ auto foo = wil::make_unique_hlocal(); // initialize allocated Foo object as appropriate ~~~ */ template inline typename wistd::enable_if::value, unique_hlocal_ptr>::type make_unique_hlocal(Args&&... args) { unique_hlocal_ptr result(make_unique_hlocal_nothrow(wistd::forward(args)...)); THROW_IF_NULL_ALLOC(result); return result; } /** Provides `std::make_unique()` semantics for array resources allocated with `LocalAlloc()`. See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. ~~~ const size_t size = 42; auto foos = wil::make_unique_hlocal(size); for (auto& elem : wil::make_range(foos.get(), size)) { // initialize allocated Foo objects as appropriate } ~~~ */ template inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_hlocal_ptr>::type make_unique_hlocal(size_t size) { unique_hlocal_ptr result(make_unique_hlocal_nothrow(size)); THROW_IF_NULL_ALLOC(result); return result; } #endif // WIL_ENABLE_EXCEPTIONS typedef unique_any unique_hlocal; typedef unique_any unique_hlocal_string; #ifndef WIL_NO_ANSI_STRINGS typedef unique_any unique_hlocal_ansistring; #endif // WIL_NO_ANSI_STRINGS /// @cond namespace details { struct localalloc_allocator { static _Ret_opt_bytecap_(size) void* allocate(size_t size) WI_NOEXCEPT { return ::LocalAlloc(LMEM_FIXED, size); } }; template<> struct string_allocator : localalloc_allocator {}; #ifndef WIL_NO_ANSI_STRINGS template<> struct string_allocator : localalloc_allocator {}; #endif // WIL_NO_ANSI_STRINGS } /// @endcond inline auto make_hlocal_string_nothrow( _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCWSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT { return make_unique_string_nothrow(source, length); } inline auto make_hlocal_string_failfast( _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCWSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT { return make_unique_string_failfast(source, length); } #ifndef WIL_NO_ANSI_STRINGS inline auto make_hlocal_ansistring_nothrow( _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT { return make_unique_ansistring_nothrow(source, length); } inline auto make_hlocal_ansistring_failfast( _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT { return make_unique_ansistring_failfast(source, length); } #endif #ifdef WIL_ENABLE_EXCEPTIONS inline auto make_hlocal_string( _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCWSTR source, size_t length = static_cast(-1)) { return make_unique_string(source, length); } #ifndef WIL_NO_ANSI_STRINGS inline auto make_hlocal_ansistring( _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCSTR source, size_t length = static_cast(-1)) { return make_unique_ansistring(source, length); } #endif // WIL_NO_ANSI_STRINGS #endif // WIL_ENABLE_EXCEPTIONS struct hlocal_secure_deleter { template void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const { if (p) { #pragma warning(suppress: 26006 26007) // LocalSize() ensures proper buffer length ::SecureZeroMemory(p, ::LocalSize(p)); // this is safe since LocalSize() returns 0 on failure ::LocalFree(p); } } }; template using unique_hlocal_secure_ptr = wistd::unique_ptr; /** Provides `std::make_unique()` semantics for secure resources allocated with `LocalAlloc()` in a context that may not throw upon allocation failure. See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. ~~~ auto foo = wil::make_unique_hlocal_secure_nothrow(); if (foo) { // initialize allocated Foo object as appropriate } ~~~ */ template inline typename wistd::enable_if::value, unique_hlocal_secure_ptr>::type make_unique_hlocal_secure_nothrow(Args&&... args) { return unique_hlocal_secure_ptr(make_unique_hlocal_nothrow(wistd::forward(args)...).release()); } /** Provides `std::make_unique()` semantics for secure array resources allocated with `LocalAlloc()` in a context that may not throw upon allocation failure. See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. ~~~ const size_t size = 42; auto foos = wil::make_unique_hlocal_secure_nothrow(size); if (foos) { for (auto& elem : wil::make_range(foos.get(), size)) { // initialize allocated Foo objects as appropriate } } ~~~ */ template inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_hlocal_secure_ptr>::type make_unique_hlocal_secure_nothrow(size_t size) { return unique_hlocal_secure_ptr(make_unique_hlocal_nothrow(size).release()); } /** Provides `std::make_unique()` semantics for secure resources allocated with `LocalAlloc()` in a context that must fail fast upon allocation failure. See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. ~~~ auto foo = wil::make_unique_hlocal_secure_failfast(); // initialize allocated Foo object as appropriate ~~~ */ template inline typename wistd::enable_if::value, unique_hlocal_secure_ptr>::type make_unique_hlocal_secure_failfast(Args&&... args) { unique_hlocal_secure_ptr result(make_unique_hlocal_secure_nothrow(wistd::forward(args)...)); FAIL_FAST_IF_NULL_ALLOC(result); return result; } /** Provides `std::make_unique()` semantics for secure array resources allocated with `LocalAlloc()` in a context that must fail fast upon allocation failure. See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. ~~~ const size_t size = 42; auto foos = wil::make_unique_hlocal_secure_failfast(size); for (auto& elem : wil::make_range(foos.get(), size)) { // initialize allocated Foo objects as appropriate } ~~~ */ template inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_hlocal_secure_ptr>::type make_unique_hlocal_secure_failfast(size_t size) { unique_hlocal_secure_ptr result(make_unique_hlocal_secure_nothrow(size)); FAIL_FAST_IF_NULL_ALLOC(result); return result; } #ifdef WIL_ENABLE_EXCEPTIONS /** Provides `std::make_unique()` semantics for secure resources allocated with `LocalAlloc()`. See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. ~~~ auto foo = wil::make_unique_hlocal_secure(); // initialize allocated Foo object as appropriate ~~~ */ template inline typename wistd::enable_if::value, unique_hlocal_secure_ptr>::type make_unique_hlocal_secure(Args&&... args) { unique_hlocal_secure_ptr result(make_unique_hlocal_secure_nothrow(wistd::forward(args)...)); THROW_IF_NULL_ALLOC(result); return result; } /** Provides `std::make_unique()` semantics for secure array resources allocated with `LocalAlloc()`. See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. ~~~ const size_t size = 42; auto foos = wil::make_unique_hlocal_secure(size); for (auto& elem : wil::make_range(foos.get(), size)) { // initialize allocated Foo objects as appropriate } ~~~ */ template inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_hlocal_secure_ptr>::type make_unique_hlocal_secure(size_t size) { unique_hlocal_secure_ptr result(make_unique_hlocal_secure_nothrow(size)); THROW_IF_NULL_ALLOC(result); return result; } #endif // WIL_ENABLE_EXCEPTIONS typedef unique_hlocal_secure_ptr unique_hlocal_string_secure; /** Copies a given string into secure memory allocated with `LocalAlloc()` in a context that may not throw upon allocation failure. See the overload of `wil::make_hlocal_string_nothrow()` with supplied length for more details. ~~~ auto str = wil::make_hlocal_string_secure_nothrow(L"a string"); RETURN_IF_NULL_ALLOC(str); std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" ~~~ */ inline auto make_hlocal_string_secure_nothrow(_In_ PCWSTR source) WI_NOEXCEPT { return unique_hlocal_string_secure(make_hlocal_string_nothrow(source).release()); } /** Copies a given string into secure memory allocated with `LocalAlloc()` in a context that must fail fast upon allocation failure. See the overload of `wil::make_hlocal_string_nothrow()` with supplied length for more details. ~~~ auto str = wil::make_hlocal_string_secure_failfast(L"a string"); std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" ~~~ */ inline auto make_hlocal_string_secure_failfast(_In_ PCWSTR source) WI_NOEXCEPT { unique_hlocal_string_secure result(make_hlocal_string_secure_nothrow(source)); FAIL_FAST_IF_NULL_ALLOC(result); return result; } #ifdef WIL_ENABLE_EXCEPTIONS /** Copies a given string into secure memory allocated with `LocalAlloc()`. See the overload of `wil::make_hlocal_string_nothrow()` with supplied length for more details. ~~~ auto str = wil::make_hlocal_string_secure(L"a string"); std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" ~~~ */ inline auto make_hlocal_string_secure(_In_ PCWSTR source) { unique_hlocal_string_secure result(make_hlocal_string_secure_nothrow(source)); THROW_IF_NULL_ALLOC(result); return result; } #endif using hglobal_deleter = function_deleter; template using unique_hglobal_ptr = wistd::unique_ptr; typedef unique_any unique_hglobal; typedef unique_any unique_hglobal_string; #ifndef WIL_NO_ANSI_STRINGS typedef unique_any unique_hglobal_ansistring; #endif // WIL_NO_ANSI_STRINGS /// @cond namespace details { template<> struct string_allocator { static _Ret_opt_bytecap_(size) void* allocate(size_t size) WI_NOEXCEPT { return ::GlobalAlloc(GPTR, size); } }; } /// @endcond inline auto make_process_heap_string_nothrow( _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCWSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT { return make_unique_string_nothrow(source, length); } inline auto make_process_heap_string_failfast( _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCWSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT { return make_unique_string_failfast(source, length); } #ifdef WIL_ENABLE_EXCEPTIONS inline auto make_process_heap_string( _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCWSTR source, size_t length = static_cast(-1)) { return make_unique_string(source, length); } #endif // WIL_ENABLE_EXCEPTIONS typedef unique_any_handle_null unique_hheap; typedef unique_any unique_tls; typedef unique_any unique_hlocal_security_descriptor; typedef unique_any unique_private_security_descriptor; #if defined(_WINUSER_) && !defined(__WIL__WINUSER_) #define __WIL__WINUSER_ typedef unique_any unique_haccel; typedef unique_any unique_hcursor; typedef unique_any unique_hwnd; #if !defined(NOUSER) && !defined(NOWH) typedef unique_any unique_hhook; #endif #if !defined(NOWINABLE) typedef unique_any unique_hwineventhook; #endif #endif // __WIL__WINUSER_ #if !defined(NOGDI) && !defined(NODESKTOP) typedef unique_any unique_hdesk; typedef unique_any unique_hwinsta; #endif // !defined(NOGDI) && !defined(NODESKTOP) #endif #if defined(__WIL_WINBASE_DESKTOP) && !defined(__WIL_WINBASE_DESKTOP_STL) && defined(WIL_RESOURCE_STL) #define __WIL_WINBASE_DESKTOP_STL typedef shared_any shared_hheap; typedef shared_any shared_hlocal; typedef shared_any shared_tls; typedef shared_any shared_hlocal_security_descriptor; typedef shared_any shared_private_security_descriptor; typedef shared_any shared_haccel; typedef shared_any shared_hcursor; #if !defined(NOGDI) && !defined(NODESKTOP) typedef shared_any shared_hdesk; typedef shared_any shared_hwinsta; #endif // !defined(NOGDI) && !defined(NODESKTOP) typedef shared_any shared_hwnd; #if !defined(NOUSER) && !defined(NOWH) typedef shared_any shared_hhook; #endif #if !defined(NOWINABLE) typedef shared_any shared_hwineventhook; #endif typedef weak_any weak_hheap; typedef weak_any weak_hlocal; typedef weak_any weak_tls; typedef weak_any weak_hlocal_security_descriptor; typedef weak_any weak_private_security_descriptor; typedef weak_any weak_haccel; typedef weak_any weak_hcursor; #if !defined(NOGDI) && !defined(NODESKTOP) typedef weak_any weak_hdesk; typedef weak_any weak_hwinsta; #endif // !defined(NOGDI) && !defined(NODESKTOP) typedef weak_any weak_hwnd; #if !defined(NOUSER) && !defined(NOWH) typedef weak_any weak_hhook; #endif #if !defined(NOWINABLE) typedef weak_any weak_hwineventhook; #endif #endif // __WIL_WINBASE_DESKTOP_STL #if defined(_COMBASEAPI_H_) && !defined(__WIL__COMBASEAPI_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && !defined(WIL_KERNEL_MODE) #define __WIL__COMBASEAPI_H_ #if (NTDDI_VERSION >= NTDDI_WIN8) typedef unique_any unique_mta_usage_cookie; #endif typedef unique_any unique_com_class_object_cookie; /// @cond namespace details { inline void __stdcall MultiQiCleanup(_In_ MULTI_QI* multiQi) { if (multiQi->pItf) { multiQi->pItf->Release(); multiQi->pItf = nullptr; } } } /// @endcond //! A type that calls CoRevertToSelf on destruction (or reset()). using unique_coreverttoself_call = unique_call; //! Calls CoImpersonateClient and fail-fasts if it fails; returns an RAII object that reverts WI_NODISCARD inline unique_coreverttoself_call CoImpersonateClient_failfast() { FAIL_FAST_IF_FAILED(::CoImpersonateClient()); return unique_coreverttoself_call(); } typedef unique_struct unique_multi_qi; #endif // __WIL__COMBASEAPI_H_ #if defined(__WIL__COMBASEAPI_H_) && defined(WIL_ENABLE_EXCEPTIONS) && !defined(__WIL__COMBASEAPI_H_EXCEPTIONAL) #define __WIL__COMBASEAPI_H_EXCEPTIONAL WI_NODISCARD inline unique_coreverttoself_call CoImpersonateClient() { THROW_IF_FAILED(::CoImpersonateClient()); return unique_coreverttoself_call(); } #endif #if defined(__WIL__COMBASEAPI_H_) && !defined(__WIL__COMBASEAPI_H__STL) && defined(WIL_RESOURCE_STL) && (NTDDI_VERSION >= NTDDI_WIN8) #define __WIL__COMBASEAPI_H__STL typedef shared_any shared_mta_usage_cookie; typedef weak_any weak_mta_usage_cookie; #endif // __WIL__COMBASEAPI_H__STL #if defined(_COMBASEAPI_H_) && !defined(__WIL__COMBASEAPI_H_APP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) && !defined(WIL_KERNEL_MODE) #define __WIL__COMBASEAPI_H_APP //! A type that calls CoUninitialize on destruction (or reset()). using unique_couninitialize_call = unique_call; //! Calls CoInitializeEx and fail-fasts if it fails; returns an RAII object that reverts WI_NODISCARD inline unique_couninitialize_call CoInitializeEx_failfast(DWORD coinitFlags = 0 /*COINIT_MULTITHREADED*/) { FAIL_FAST_IF_FAILED(::CoInitializeEx(nullptr, coinitFlags)); return unique_couninitialize_call(); } #endif // __WIL__COMBASEAPI_H_APP #if defined(__WIL__COMBASEAPI_H_APP) && defined(WIL_ENABLE_EXCEPTIONS) && !defined(__WIL__COMBASEAPI_H_APPEXCEPTIONAL) #define __WIL__COMBASEAPI_H_APPEXCEPTIONAL WI_NODISCARD inline unique_couninitialize_call CoInitializeEx(DWORD coinitFlags = 0 /*COINIT_MULTITHREADED*/) { THROW_IF_FAILED(::CoInitializeEx(nullptr, coinitFlags)); return unique_couninitialize_call(); } #endif #if defined(__ROAPI_H_) && !defined(__WIL__ROAPI_H_APP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) && (NTDDI_VERSION >= NTDDI_WIN8) #define __WIL__ROAPI_H_APP typedef unique_any unique_ro_registration_cookie; //! A type that calls RoUninitialize on destruction (or reset()). //! Use as a replacement for Windows::Foundation::Uninitialize. using unique_rouninitialize_call = unique_call; //! Calls RoInitialize and fail-fasts if it fails; returns an RAII object that reverts //! Use as a replacement for Windows::Foundation::Initialize WI_NODISCARD inline unique_rouninitialize_call RoInitialize_failfast(RO_INIT_TYPE initType = RO_INIT_MULTITHREADED) { FAIL_FAST_IF_FAILED(::RoInitialize(initType)); return unique_rouninitialize_call(); } #endif // __WIL__ROAPI_H_APP #if defined(__WIL__ROAPI_H_APP) && defined(WIL_ENABLE_EXCEPTIONS) && !defined(__WIL__ROAPI_H_APPEXCEPTIONAL) #define __WIL__ROAPI_H_APPEXCEPTIONAL //! Calls RoInitialize and throws an exception if it fails; returns an RAII object that reverts //! Use as a replacement for Windows::Foundation::Initialize WI_NODISCARD inline unique_rouninitialize_call RoInitialize(RO_INIT_TYPE initType = RO_INIT_MULTITHREADED) { THROW_IF_FAILED(::RoInitialize(initType)); return unique_rouninitialize_call(); } #endif #if defined(__WINSTRING_H_) && !defined(__WIL__WINSTRING_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) #define __WIL__WINSTRING_H_ typedef unique_any unique_hstring; template<> inline unique_hstring make_unique_string_nothrow( _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCWSTR source, size_t length) WI_NOEXCEPT { WI_ASSERT(source != nullptr); // the HSTRING version of this function does not suport this case if (length == static_cast(-1)) { length = wcslen(source); } unique_hstring result; ::WindowsCreateString(source, static_cast(length), &result); return result; } typedef unique_any unique_hstring_buffer; /** Promotes an hstring_buffer to an HSTRING. When an HSTRING_BUFFER object is promoted to a real string it must not be passed to WindowsDeleteString. The caller owns the HSTRING afterwards. ~~~ HRESULT Type::MakePath(_Out_ HSTRING* path) { wchar_t* bufferStorage = nullptr; wil::unique_hstring_buffer theBuffer; RETURN_IF_FAILED(::WindowsPreallocateStringBuffer(65, &bufferStorage, &theBuffer)); RETURN_IF_FAILED(::PathCchCombine(bufferStorage, 65, m_foo, m_bar)); RETURN_IF_FAILED(wil::make_hstring_from_buffer_nothrow(wistd::move(theBuffer), path))); return S_OK; } ~~~ */ inline HRESULT make_hstring_from_buffer_nothrow(unique_hstring_buffer&& source, _Out_ HSTRING* promoted) { HRESULT hr = ::WindowsPromoteStringBuffer(source.get(), promoted); if (SUCCEEDED(hr)) { source.release(); } return hr; } //! A fail-fast variant of `make_hstring_from_buffer_nothrow` inline unique_hstring make_hstring_from_buffer_failfast(unique_hstring_buffer&& source) { unique_hstring result; FAIL_FAST_IF_FAILED(make_hstring_from_buffer_nothrow(wistd::move(source), &result)); return result; } #if defined WIL_ENABLE_EXCEPTIONS /** Promotes an hstring_buffer to an HSTRING. When an HSTRING_BUFFER object is promoted to a real string it must not be passed to WindowsDeleteString. The caller owns the HSTRING afterwards. ~~~ wil::unique_hstring Type::Make() { wchar_t* bufferStorage = nullptr; wil::unique_hstring_buffer theBuffer; THROW_IF_FAILED(::WindowsPreallocateStringBuffer(65, &bufferStorage, &theBuffer)); THROW_IF_FAILED(::PathCchCombine(bufferStorage, 65, m_foo, m_bar)); return wil::make_hstring_from_buffer(wistd::move(theBuffer)); } ~~~ */ inline unique_hstring make_hstring_from_buffer(unique_hstring_buffer&& source) { unique_hstring result; THROW_IF_FAILED(make_hstring_from_buffer_nothrow(wistd::move(source), &result)); return result; } #endif /// @cond namespace details { template<> struct string_maker { string_maker() = default; string_maker(const string_maker&) = delete; void operator=(const string_maker&) = delete; string_maker& operator=(string_maker&& source) WI_NOEXCEPT { m_value = wistd::move(source.m_value); m_bufferHandle = wistd::move(source.m_bufferHandle); m_charBuffer = wistd::exchange(source.m_charBuffer, nullptr); return *this; } HRESULT make( _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) _When_((source != nullptr) && length == static_cast(-1), _In_z_) const wchar_t* source, size_t length) { if (source) { RETURN_IF_FAILED(WindowsCreateString(source, static_cast(length), &m_value)); } else { // Need to set it to the empty string to support the empty string case. m_value.reset(); RETURN_IF_FAILED(WindowsPreallocateStringBuffer(static_cast(length), &m_charBuffer, &m_bufferHandle)); } return S_OK; } wchar_t* buffer() { WI_ASSERT(m_charBuffer != nullptr); return m_charBuffer; } const wchar_t* buffer() const { return m_charBuffer; } unique_hstring release() { m_charBuffer = nullptr; if (m_bufferHandle) { return make_hstring_from_buffer_failfast(wistd::move(m_bufferHandle)); } return wistd::move(m_value); } static PCWSTR get(const wil::unique_hstring& value) { return WindowsGetStringRawBuffer(value.get(), nullptr); } private: unique_hstring m_value; unique_hstring_buffer m_bufferHandle; wchar_t* m_charBuffer = nullptr; }; } /// @endcond // str_raw_ptr is an overloaded function that retrieves a const pointer to the first character in a string's buffer. // This is the overload for HSTRING. Other overloads available above. inline PCWSTR str_raw_ptr(HSTRING str) { return WindowsGetStringRawBuffer(str, nullptr); } inline PCWSTR str_raw_ptr(const unique_hstring& str) { return str_raw_ptr(str.get()); } #endif // __WIL__WINSTRING_H_ #if defined(__WIL__WINSTRING_H_) && !defined(__WIL__WINSTRING_H_STL) && defined(WIL_RESOURCE_STL) #define __WIL__WINSTRING_H_STL typedef shared_any shared_hstring; typedef shared_any shared_hstring_buffer; typedef weak_any weak_hstring; typedef weak_any weak_hstring_buffer; #endif // __WIL__WINSTRING_H_STL #if defined(_WINREG_) && !defined(__WIL_WINREG_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(WIL_KERNEL_MODE) #define __WIL_WINREG_ typedef unique_any unique_hkey; #endif // __WIL_WINREG_ #if defined(__WIL_WINREG_) && !defined(__WIL_WINREG_STL) && defined(WIL_RESOURCE_STL) #define __WIL_WINREG_STL typedef shared_any shared_hkey; typedef weak_any weak_hkey; #endif // __WIL_WINREG_STL #if defined(__propidl_h__) && !defined(_WIL__propidl_h__) && !defined(WIL_KERNEL_MODE) #define _WIL__propidl_h__ using unique_prop_variant = wil::unique_struct; #endif // _WIL__propidl_h__ #if defined(_OLEAUTO_H_) && !defined(__WIL_OLEAUTO_H_) && !defined(WIL_KERNEL_MODE) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) #define __WIL_OLEAUTO_H_ using unique_variant = wil::unique_struct; typedef unique_any unique_bstr; inline wil::unique_bstr make_bstr_nothrow(PCWSTR source) WI_NOEXCEPT { return wil::unique_bstr(::SysAllocString(source)); } inline wil::unique_bstr make_bstr_failfast(PCWSTR source) WI_NOEXCEPT { return wil::unique_bstr(FAIL_FAST_IF_NULL_ALLOC(::SysAllocString(source))); } #ifdef WIL_ENABLE_EXCEPTIONS inline wil::unique_bstr make_bstr(PCWSTR source) { wil::unique_bstr result(make_bstr_nothrow(source)); THROW_IF_NULL_ALLOC(result); return result; } #endif // WIL_ENABLE_EXCEPTIONS #endif // __WIL_OLEAUTO_H_ #if defined(__WIL_OLEAUTO_H_) && !defined(__WIL_OLEAUTO_H_STL) && defined(WIL_RESOURCE_STL) #define __WIL_OLEAUTO_H_STL typedef shared_any shared_bstr; typedef weak_any weak_bstr; #endif // __WIL_OLEAUTO_H_STL #if (defined(_WININET_) || defined(_DUBINET_)) && !defined(__WIL_WININET_) #define __WIL_WININET_ typedef unique_any unique_hinternet; #endif // __WIL_WININET_ #if defined(__WIL_WININET_) && !defined(__WIL_WININET_STL) && defined(WIL_RESOURCE_STL) #define __WIL_WININET_STL typedef shared_any shared_hinternet; typedef weak_any weak_hinternet; #endif // __WIL_WININET_STL #if defined(_WINHTTPX_) && !defined(__WIL_WINHTTP_) #define __WIL_WINHTTP_ typedef unique_any unique_winhttp_hinternet; #endif // __WIL_WINHTTP_ #if defined(__WIL_WINHTTP_) && !defined(__WIL_WINHTTP_STL) && defined(WIL_RESOURCE_STL) #define __WIL_WINHTTP_STL typedef shared_any shared_winhttp_hinternet; typedef weak_any weak_winhttp_hinternet; #endif // __WIL_WINHTTP_STL #if defined(_WINSOCKAPI_) && !defined(__WIL_WINSOCKAPI_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #define __WIL_WINSOCKAPI_ typedef unique_any unique_socket; #endif // __WIL_WINSOCKAPI_ #if defined(__WIL_WINSOCKAPI_) && !defined(__WIL_WINSOCKAPI_STL) && defined(WIL_RESOURCE_STL) #define __WIL_WINSOCKAPI_STL typedef shared_any shared_socket; typedef weak_any weak_socket; #endif // __WIL_WINSOCKAPI_STL #if defined(_WINGDI_) && !defined(__WIL_WINGDI_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(NOGDI) && !defined(WIL_KERNEL_MODE) #define __WIL_WINGDI_ struct window_dc { HDC dc; HWND hwnd; window_dc(HDC dc_, HWND hwnd_ = nullptr) WI_NOEXCEPT { dc = dc_; hwnd = hwnd_; } operator HDC() const WI_NOEXCEPT { return dc; } static void close(window_dc wdc) WI_NOEXCEPT { ::ReleaseDC(wdc.hwnd, wdc.dc); } }; typedef unique_any unique_hdc_window; struct paint_dc { HWND hwnd; PAINTSTRUCT ps; paint_dc(HDC hdc = nullptr) { ::ZeroMemory(this, sizeof(*this)); ps.hdc = hdc; } operator HDC() const WI_NOEXCEPT { return ps.hdc; } static void close(paint_dc pdc) WI_NOEXCEPT { ::EndPaint(pdc.hwnd, &pdc.ps); } }; typedef unique_any unique_hdc_paint; struct select_result { HGDIOBJ hgdi; HDC hdc; select_result(HGDIOBJ hgdi_, HDC hdc_ = nullptr) WI_NOEXCEPT { hgdi = hgdi_; hdc = hdc_; } operator HGDIOBJ() const WI_NOEXCEPT { return hgdi; } static void close(select_result sr) WI_NOEXCEPT { ::SelectObject(sr.hdc, sr.hgdi); } }; typedef unique_any unique_select_object; inline unique_hdc_window GetDC(HWND hwnd) WI_NOEXCEPT { return unique_hdc_window(window_dc(::GetDC(hwnd), hwnd)); } inline unique_hdc_window GetWindowDC(HWND hwnd) WI_NOEXCEPT { return unique_hdc_window(window_dc(::GetWindowDC(hwnd), hwnd)); } inline unique_hdc_paint BeginPaint(HWND hwnd, _Out_opt_ PPAINTSTRUCT pPaintStruct = nullptr) WI_NOEXCEPT { paint_dc pdc; pdc.hwnd = hwnd; HDC hdc = ::BeginPaint(hwnd, &pdc.ps); assign_to_opt_param(pPaintStruct, pdc.ps); return (hdc == nullptr) ? unique_hdc_paint() : unique_hdc_paint(pdc); } inline unique_select_object SelectObject(HDC hdc, HGDIOBJ gdiobj) WI_NOEXCEPT { return unique_select_object(select_result(::SelectObject(hdc, gdiobj), hdc)); } typedef unique_any unique_hgdiobj; typedef unique_any unique_hpen; typedef unique_any unique_hbrush; typedef unique_any unique_hfont; typedef unique_any unique_hbitmap; typedef unique_any unique_hrgn; typedef unique_any unique_hpalette; typedef unique_any unique_hdc; typedef unique_any unique_hicon; #if !defined(NOMENUS) typedef unique_any unique_hmenu; #endif // !defined(NOMENUS) #endif // __WIL_WINGDI_ #if defined(__WIL_WINGDI_) && !defined(__WIL_WINGDI_STL) && defined(WIL_RESOURCE_STL) #define __WIL_WINGDI_STL typedef shared_any shared_hgdiobj; typedef shared_any shared_hpen; typedef shared_any shared_hbrush; typedef shared_any shared_hfont; typedef shared_any shared_hbitmap; typedef shared_any shared_hrgn; typedef shared_any shared_hpalette; typedef shared_any shared_hdc; typedef shared_any shared_hicon; #if !defined(NOMENUS) typedef shared_any shared_hmenu; #endif // !defined(NOMENUS) typedef weak_any weak_hgdiobj; typedef weak_any weak_hpen; typedef weak_any weak_hbrush; typedef weak_any weak_hfont; typedef weak_any weak_hbitmap; typedef weak_any weak_hrgn; typedef weak_any weak_hpalette; typedef weak_any weak_hdc; typedef weak_any weak_hicon; #if !defined(NOMENUS) typedef weak_any weak_hmenu; #endif // !defined(NOMENUS) #endif // __WIL_WINGDI_STL #if defined(_INC_WTSAPI) && !defined(__WIL_WTSAPI) #define __WIL_WTSAPI template using unique_wtsmem_ptr = wistd::unique_ptr>; #endif // __WIL_WTSAPI #if defined(_WINSCARD_H_) && !defined(__WIL_WINSCARD_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #define __WIL_WINSCARD_H_ typedef unique_any unique_scardctx; #endif // __WIL_WINSCARD_H_ #if defined(__WIL_WINSCARD_H_) && !defined(__WIL_WINSCARD_H_STL) && defined(WIL_RESOURCE_STL) #define __WIL_WINSCARD_H_STL typedef shared_any shared_scardctx; typedef weak_any weak_scardctx; #endif // __WIL_WINSCARD_H_STL #if defined(__WINCRYPT_H__) && !defined(__WIL__WINCRYPT_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #define __WIL__WINCRYPT_H__ /// @cond namespace details { inline void __stdcall CertCloseStoreNoParam(_Pre_opt_valid_ _Frees_ptr_opt_ HCERTSTORE hCertStore) WI_NOEXCEPT { ::CertCloseStore(hCertStore, 0); } inline void __stdcall CryptReleaseContextNoParam(_Pre_opt_valid_ _Frees_ptr_opt_ HCRYPTPROV hCryptCtx) WI_NOEXCEPT { ::CryptReleaseContext(hCryptCtx, 0); } } /// @endcond typedef unique_any unique_cert_context; typedef unique_any unique_cert_chain_context; typedef unique_any unique_hcertstore; typedef unique_any unique_hcryptprov; typedef unique_any unique_hcryptkey; typedef unique_any unique_hcrypthash; #endif // __WIL__WINCRYPT_H__ #if defined(__WIL__WINCRYPT_H__) && !defined(__WIL__WINCRYPT_H__STL) && defined(WIL_RESOURCE_STL) #define __WIL__WINCRYPT_H__STL typedef shared_any shared_cert_context; typedef shared_any shared_cert_chain_context; typedef shared_any shared_hcertstore; typedef shared_any shared_hcryptprov; typedef shared_any shared_hcryptkey; typedef shared_any shared_hcrypthash; typedef weak_any weak_cert_context; typedef weak_any weak_cert_chain_context; typedef weak_any weak_hcertstore; typedef weak_any weak_hcryptprov; typedef weak_any weak_hcryptkey; typedef weak_any weak_hcrypthash; #endif // __WIL__WINCRYPT_H__STL #if defined(__NCRYPT_H__) && !defined(__WIL_NCRYPT_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #define __WIL_NCRYPT_H__ using ncrypt_deleter = function_deleter; template using unique_ncrypt_ptr = wistd::unique_ptr; typedef unique_any unique_ncrypt_prov; typedef unique_any unique_ncrypt_key; typedef unique_any unique_ncrypt_secret; #endif // __WIL_NCRYPT_H__ #if defined(__WIL_NCRYPT_H__) && !defined(__WIL_NCRYPT_H_STL) && defined(WIL_RESOURCE_STL) #define __WIL_NCRYPT_H_STL typedef shared_any shared_ncrypt_prov; typedef shared_any shared_ncrypt_key; typedef shared_any shared_ncrypt_secret; typedef weak_any weak_ncrypt_prov; typedef weak_any weak_ncrypt_key; typedef weak_any weak_ncrypt_secret; #endif // __WIL_NCRYPT_H_STL #if defined(__BCRYPT_H__) && !defined(__WIL_BCRYPT_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #define __WIL_BCRYPT_H__ /// @cond namespace details { inline void __stdcall BCryptCloseAlgorithmProviderNoFlags(_Pre_opt_valid_ _Frees_ptr_opt_ BCRYPT_ALG_HANDLE hAlgorithm) WI_NOEXCEPT { if (hAlgorithm) { ::BCryptCloseAlgorithmProvider(hAlgorithm, 0); } } } /// @endcond using bcrypt_deleter = function_deleter; template using unique_bcrypt_ptr = wistd::unique_ptr; typedef unique_any unique_bcrypt_algorithm; typedef unique_any unique_bcrypt_hash; typedef unique_any unique_bcrypt_key; typedef unique_any unique_bcrypt_secret; #endif // __WIL_BCRYPT_H__ #if defined(__WIL_BCRYPT_H__) && !defined(__WIL_BCRYPT_H_STL) && defined(WIL_RESOURCE_STL) #define __WIL_BCRYPT_H_STL typedef shared_any shared_bcrypt_algorithm; typedef shared_any shared_bcrypt_hash; typedef shared_any shared_bcrypt_key; typedef shared_any shared_bcrypt_secret; typedef weak_any weak_bcrypt_algorithm; typedef weak_any weak_bcrypt_hash; typedef weak_any weak_bcrypt_key; typedef weak_any weak_bcrypt_secret; #endif // __WIL_BCRYPT_H_STL #if defined(__RPCNDR_H__) && !defined(__WIL__RPCNDR_H__) && !defined(WIL_KERNEL_MODE) #define __WIL__RPCNDR_H__ //! Function deleter for use with pointers allocated by MIDL_user_allocate using midl_deleter = function_deleter; //! Unique-ptr holding a type allocated by MIDL_user_alloc or returned from an RPC invocation template using unique_midl_ptr = wistd::unique_ptr; //! Unique-ptr for strings allocated by MIDL_user_alloc using unique_midl_string = unique_midl_ptr; #ifndef WIL_NO_ANSI_STRINGS using unique_midl_ansistring = unique_midl_ptr; #endif namespace details { struct midl_allocator { static _Ret_opt_bytecap_(size) void* allocate(size_t size) WI_NOEXCEPT { return ::MIDL_user_allocate(size); } }; // Specialization to support construction of unique_midl_string instances template<> struct string_allocator : midl_allocator {}; #ifndef WIL_NO_ANSI_STRINGS template<> struct string_allocator : midl_allocator {}; #endif } #endif // __WIL__RPCNDR_H__ #if defined(_OBJBASE_H_) && !defined(__WIL_OBJBASE_H_) && !defined(WIL_KERNEL_MODE) #define __WIL_OBJBASE_H_ using cotaskmem_deleter = function_deleter; template using unique_cotaskmem_ptr = wistd::unique_ptr; template using unique_cotaskmem_array_ptr = unique_array_ptr; /** Provides `std::make_unique()` semantics for resources allocated with `CoTaskMemAlloc()` in a context that may not throw upon allocation failure. Use `wil::make_unique_cotaskmem_nothrow()` for resources returned from APIs that must satisfy a memory allocation contract that requires the use of `CoTaskMemAlloc()` / `CoTaskMemFree()`. Use `wil::make_unique_nothrow()` when `CoTaskMemAlloc()` is not required. Allocations are initialized with placement new and will call constructors (if present), but this does not guarantee initialization. Note that `wil::make_unique_cotaskmem_nothrow()` is not marked WI_NOEXCEPT as it may be used to create an exception-based class that may throw in its constructor. ~~~ auto foo = wil::make_unique_cotaskmem_nothrow(); if (foo) { // initialize allocated Foo object as appropriate } ~~~ */ template inline typename wistd::enable_if::value, unique_cotaskmem_ptr>::type make_unique_cotaskmem_nothrow(Args&&... args) { static_assert(wistd::is_trivially_destructible::value, "T has a destructor that won't be run when used with this function; use make_unique instead"); unique_cotaskmem_ptr sp(static_cast(::CoTaskMemAlloc(sizeof(T)))); if (sp) { // use placement new to initialize memory from the previous allocation new (sp.get()) T(wistd::forward(args)...); } return sp; } /** Provides `std::make_unique()` semantics for array resources allocated with `CoTaskMemAlloc()` in a context that may not throw upon allocation failure. See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. ~~~ const size_t size = 42; auto foos = wil::make_unique_cotaskmem_nothrow(size); if (foos) { for (auto& elem : wil::make_range(foos.get(), size)) { // initialize allocated Foo objects as appropriate } } ~~~ */ template inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_cotaskmem_ptr>::type make_unique_cotaskmem_nothrow(size_t size) { typedef typename wistd::remove_extent::type E; static_assert(wistd::is_trivially_destructible::value, "E has a destructor that won't be run when used with this function; use make_unique instead"); FAIL_FAST_IF((__WI_SIZE_MAX / sizeof(E)) < size); size_t allocSize = sizeof(E) * size; unique_cotaskmem_ptr sp(static_cast(::CoTaskMemAlloc(allocSize))); if (sp) { // use placement new to initialize memory from the previous allocation; // note that array placement new cannot be used as the standard allows for operator new[] // to consume overhead in the allocation for internal bookkeeping for (auto& elem : make_range(static_cast(sp.get()), size)) { new (&elem) E(); } } return sp; } /** Provides `std::make_unique()` semantics for resources allocated with `CoTaskMemAlloc()` in a context that must fail fast upon allocation failure. See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. ~~~ auto foo = wil::make_unique_cotaskmem_failfast(); // initialize allocated Foo object as appropriate ~~~ */ template inline typename wistd::enable_if::value, unique_cotaskmem_ptr>::type make_unique_cotaskmem_failfast(Args&&... args) { unique_cotaskmem_ptr result(make_unique_cotaskmem_nothrow(wistd::forward(args)...)); FAIL_FAST_IF_NULL_ALLOC(result); return result; } /** Provides `std::make_unique()` semantics for array resources allocated with `CoTaskMemAlloc()` in a context that must fail fast upon allocation failure. See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. ~~~ const size_t size = 42; auto foos = wil::make_unique_cotaskmem_failfast(size); for (auto& elem : wil::make_range(foos.get(), size)) { // initialize allocated Foo objects as appropriate } ~~~ */ template inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_cotaskmem_ptr>::type make_unique_cotaskmem_failfast(size_t size) { unique_cotaskmem_ptr result(make_unique_cotaskmem_nothrow(size)); FAIL_FAST_IF_NULL_ALLOC(result); return result; } #ifdef WIL_ENABLE_EXCEPTIONS /** Provides `std::make_unique()` semantics for resources allocated with `CoTaskMemAlloc()`. See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. ~~~ auto foo = wil::make_unique_cotaskmem(); // initialize allocated Foo object as appropriate ~~~ */ template inline typename wistd::enable_if::value, unique_cotaskmem_ptr>::type make_unique_cotaskmem(Args&&... args) { unique_cotaskmem_ptr result(make_unique_cotaskmem_nothrow(wistd::forward(args)...)); THROW_IF_NULL_ALLOC(result); return result; } /** Provides `std::make_unique()` semantics for array resources allocated with `CoTaskMemAlloc()`. See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. ~~~ const size_t size = 42; auto foos = wil::make_unique_cotaskmem(size); for (auto& elem : wil::make_range(foos.get(), size)) { // initialize allocated Foo objects as appropriate } ~~~ */ template inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_cotaskmem_ptr>::type make_unique_cotaskmem(size_t size) { unique_cotaskmem_ptr result(make_unique_cotaskmem_nothrow(size)); THROW_IF_NULL_ALLOC(result); return result; } #endif // WIL_ENABLE_EXCEPTIONS typedef unique_any unique_cotaskmem; typedef unique_any unique_cotaskmem_string; #ifndef WIL_NO_ANSI_STRINGS typedef unique_any unique_cotaskmem_ansistring; #endif // WIL_NO_ANSI_STRINGS /// @cond namespace details { struct cotaskmem_allocator { static _Ret_opt_bytecap_(size) void* allocate(size_t size) WI_NOEXCEPT { return ::CoTaskMemAlloc(size); } }; template<> struct string_allocator : cotaskmem_allocator {}; #ifndef WIL_NO_ANSI_STRINGS template<> struct string_allocator : cotaskmem_allocator {}; #endif // WIL_NO_ANSI_STRINGS } /// @endcond inline auto make_cotaskmem_string_nothrow( _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCWSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT { return make_unique_string_nothrow(source, length); } inline auto make_cotaskmem_string_failfast( _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCWSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT { return make_unique_string_failfast(source, length); } #ifdef WIL_ENABLE_EXCEPTIONS inline auto make_cotaskmem_string( _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCWSTR source, size_t length = static_cast(-1)) { return make_unique_string(source, length); } #endif // WIL_ENABLE_EXCEPTIONS #endif // __WIL_OBJBASE_H_ #if defined(__WIL_OBJBASE_H_) && !defined(__WIL_OBJBASE_H_STL) && defined(WIL_RESOURCE_STL) #define __WIL_OBJBASE_H_STL typedef shared_any shared_cotaskmem; typedef weak_any weak_cotaskmem; typedef shared_any shared_cotaskmem_string; typedef weak_any weak_cotaskmem_string; #endif // __WIL_OBJBASE_H_STL #if defined(__WIL_OBJBASE_H_) && defined(__WIL_WINBASE_) && !defined(__WIL_OBJBASE_AND_WINBASE_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #define __WIL_OBJBASE_AND_WINBASE_H_ struct cotaskmem_secure_deleter { template void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const { if (p) { IMalloc* malloc; if (SUCCEEDED(::CoGetMalloc(1, &malloc))) { size_t const size = malloc->GetSize(p); if (size != static_cast(-1)) { ::SecureZeroMemory(p, size); } malloc->Release(); } ::CoTaskMemFree(p); } } }; template using unique_cotaskmem_secure_ptr = wistd::unique_ptr; /** Provides `std::make_unique()` semantics for secure resources allocated with `CoTaskMemAlloc()` in a context that may not throw upon allocation failure. See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. ~~~ auto foo = wil::make_unique_cotaskmem_secure_nothrow(); if (foo) { // initialize allocated Foo object as appropriate } ~~~ */ template inline typename wistd::enable_if::value, unique_cotaskmem_secure_ptr>::type make_unique_cotaskmem_secure_nothrow(Args&&... args) { return unique_cotaskmem_secure_ptr(make_unique_cotaskmem_nothrow(wistd::forward(args)...).release()); } /** Provides `std::make_unique()` semantics for secure array resources allocated with `CoTaskMemAlloc()` in a context that may not throw upon allocation failure. See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. ~~~ const size_t size = 42; auto foos = wil::make_unique_cotaskmem_secure_nothrow(size); if (foos) { for (auto& elem : wil::make_range(foos.get(), size)) { // initialize allocated Foo objects as appropriate } } ~~~ */ template inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_cotaskmem_secure_ptr>::type make_unique_cotaskmem_secure_nothrow(size_t size) { return unique_cotaskmem_secure_ptr(make_unique_cotaskmem_nothrow(size).release()); } /** Provides `std::make_unique()` semantics for secure resources allocated with `CoTaskMemAlloc()` in a context that must fail fast upon allocation failure. See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. ~~~ auto foo = wil::make_unique_cotaskmem_secure_failfast(); // initialize allocated Foo object as appropriate ~~~ */ template inline typename wistd::enable_if::value, unique_cotaskmem_secure_ptr>::type make_unique_cotaskmem_secure_failfast(Args&&... args) { unique_cotaskmem_secure_ptr result(make_unique_cotaskmem_secure_nothrow(wistd::forward(args)...)); FAIL_FAST_IF_NULL_ALLOC(result); return result; } /** Provides `std::make_unique()` semantics for secure array resources allocated with `CoTaskMemAlloc()` in a context that must fail fast upon allocation failure. See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. ~~~ const size_t size = 42; auto foos = wil::make_unique_cotaskmem_secure_failfast(size); for (auto& elem : wil::make_range(foos.get(), size)) { // initialize allocated Foo objects as appropriate } ~~~ */ template inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_cotaskmem_secure_ptr>::type make_unique_cotaskmem_secure_failfast(size_t size) { unique_cotaskmem_secure_ptr result(make_unique_cotaskmem_secure_nothrow(size)); FAIL_FAST_IF_NULL_ALLOC(result); return result; } #ifdef WIL_ENABLE_EXCEPTIONS /** Provides `std::make_unique()` semantics for secure resources allocated with `CoTaskMemAlloc()`. See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. ~~~ auto foo = wil::make_unique_cotaskmem_secure(); // initialize allocated Foo object as appropriate ~~~ */ template inline typename wistd::enable_if::value, unique_cotaskmem_secure_ptr>::type make_unique_cotaskmem_secure(Args&&... args) { unique_cotaskmem_secure_ptr result(make_unique_cotaskmem_secure_nothrow(wistd::forward(args)...)); THROW_IF_NULL_ALLOC(result); return result; } /** Provides `std::make_unique()` semantics for secure array resources allocated with `CoTaskMemAlloc()`. See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. ~~~ const size_t size = 42; auto foos = wil::make_unique_cotaskmem_secure(size); for (auto& elem : wil::make_range(foos.get(), size)) { // initialize allocated Foo objects as appropriate } ~~~ */ template inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_cotaskmem_secure_ptr>::type make_unique_cotaskmem_secure(size_t size) { unique_cotaskmem_secure_ptr result(make_unique_cotaskmem_secure_nothrow(size)); THROW_IF_NULL_ALLOC(result); return result; } #endif // WIL_ENABLE_EXCEPTIONS typedef unique_cotaskmem_secure_ptr unique_cotaskmem_string_secure; /** Copies a given string into secure memory allocated with `CoTaskMemAlloc()` in a context that may not throw upon allocation failure. See the overload of `wil::make_cotaskmem_string_nothrow()` with supplied length for more details. ~~~ auto str = wil::make_cotaskmem_string_secure_nothrow(L"a string"); if (str) { std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" } ~~~ */ inline unique_cotaskmem_string_secure make_cotaskmem_string_secure_nothrow(_In_ PCWSTR source) WI_NOEXCEPT { return unique_cotaskmem_string_secure(make_cotaskmem_string_nothrow(source).release()); } /** Copies a given string into secure memory allocated with `CoTaskMemAlloc()` in a context that must fail fast upon allocation failure. See the overload of `wil::make_cotaskmem_string_nothrow()` with supplied length for more details. ~~~ auto str = wil::make_cotaskmem_string_secure_failfast(L"a string"); std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" ~~~ */ inline unique_cotaskmem_string_secure make_cotaskmem_string_secure_failfast(_In_ PCWSTR source) WI_NOEXCEPT { unique_cotaskmem_string_secure result(make_cotaskmem_string_secure_nothrow(source)); FAIL_FAST_IF_NULL_ALLOC(result); return result; } #ifdef WIL_ENABLE_EXCEPTIONS /** Copies a given string into secure memory allocated with `CoTaskMemAlloc()`. See the overload of `wil::make_cotaskmem_string_nothrow()` with supplied length for more details. ~~~ auto str = wil::make_cotaskmem_string_secure(L"a string"); std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" ~~~ */ inline unique_cotaskmem_string_secure make_cotaskmem_string_secure(_In_ PCWSTR source) { unique_cotaskmem_string_secure result(make_cotaskmem_string_secure_nothrow(source)); THROW_IF_NULL_ALLOC(result); return result; } #endif #endif // __WIL_OBJBASE_AND_WINBASE_H_ #if defined(_OLE2_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(__WIL_OLE2_H_) && !defined(WIL_KERNEL_MODE) #define __WIL_OLE2_H_ typedef unique_struct unique_stg_medium; struct unique_hglobal_locked : public unique_any { unique_hglobal_locked() = delete; explicit unique_hglobal_locked(HGLOBAL global) : unique_any(global) { // GlobalLock returns a pointer to the associated global memory block and that's what callers care about. m_globalMemory = GlobalLock(global); if (!m_globalMemory) { release(); } } explicit unique_hglobal_locked(unique_hglobal& global) : unique_hglobal_locked(global.get()) { } explicit unique_hglobal_locked(STGMEDIUM& medium) : unique_hglobal_locked(medium.hGlobal) { } pointer get() const { return m_globalMemory; } private: pointer m_globalMemory; }; //! A type that calls OleUninitialize on destruction (or reset()). //! Use as a replacement for Windows::Foundation::Uninitialize. using unique_oleuninitialize_call = unique_call; //! Calls RoInitialize and fail-fasts if it fails; returns an RAII object that reverts //! Use as a replacement for Windows::Foundation::Initialize _Check_return_ inline unique_oleuninitialize_call OleInitialize_failfast() { FAIL_FAST_IF_FAILED(::OleInitialize(nullptr)); return unique_oleuninitialize_call(); } #endif // __WIL_OLE2_H_ #if defined(__WIL_OLE2_H_) && defined(WIL_ENABLE_EXCEPTIONS) && !defined(__WIL_OLE2_H_EXCEPTIONAL) #define __WIL_OLE2_H_EXCEPTIONAL //! Calls RoInitialize and throws an exception if it fails; returns an RAII object that reverts //! Use as a replacement for Windows::Foundation::Initialize _Check_return_ inline unique_oleuninitialize_call OleInitialize() { THROW_IF_FAILED(::OleInitialize(nullptr)); return unique_oleuninitialize_call(); } #endif #if defined(_INC_COMMCTRL) && !defined(__WIL_INC_COMMCTRL) && !defined(WIL_KERNEL_MODE) #define __WIL_INC_COMMCTRL typedef unique_any unique_himagelist; #endif // __WIL_INC_COMMCTRL #if defined(__WIL_INC_COMMCTRL) && !defined(__WIL_INC_COMMCTRL_STL) && defined(WIL_RESOURCE_STL) #define __WIL_INC_COMMCTRL_STL typedef shared_any shared_himagelist; typedef weak_any weak_himagelist; #endif // __WIL_INC_COMMCTRL_STL #if defined(_UXTHEME_H_) && !defined(__WIL_INC_UXTHEME) && !defined(WIL_KERNEL_MODE) #define __WIL_INC_UXTHEME typedef unique_any unique_htheme; #endif // __WIL_INC_UXTHEME #if defined(_WINSVC_) && !defined(__WIL_HANDLE_H_WINSVC) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(WIL_KERNEL_MODE) #define __WIL_HANDLE_H_WINSVC typedef unique_any unique_schandle; #endif // __WIL_HANDLE_H_WINSVC #if defined(__WIL_HANDLE_H_WINSVC) && !defined(__WIL_HANDLE_H_WINSVC_STL) && defined(WIL_RESOURCE_STL) #define __WIL_HANDLE_H_WINSVC_STL typedef shared_any shared_schandle; typedef weak_any weak_schandle; #endif // __WIL_HANDLE_H_WINSVC_STL #if defined(_INC_STDIO) && !defined(__WIL_INC_STDIO) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(WIL_KERNEL_MODE) #define __WIL_INC_STDIO typedef unique_any unique_pipe; typedef unique_any unique_file; #endif // __WIL_INC_STDIO #if defined(__WIL_INC_STDIO) && !defined(__WIL__INC_STDIO_STL) && defined(WIL_RESOURCE_STL) #define __WIL__INC_STDIO_STL typedef shared_any shared_pipe; typedef weak_any weak_pipe; typedef shared_any shared_file; typedef weak_any weak_file; #endif // __WIL__INC_STDIO_STL #if defined(_NTLSA_) && !defined(__WIL_NTLSA_) && !defined(WIL_KERNEL_MODE) #define __WIL_NTLSA_ typedef unique_any unique_hlsa; using lsa_freemem_deleter = function_deleter; template using unique_lsamem_ptr = wistd::unique_ptr; #endif // _NTLSA_ #if defined(_NTLSA_) && !defined(__WIL_NTLSA_STL) && defined(WIL_RESOURCE_STL) #define __WIL_NTLSA_STL typedef shared_any shared_hlsa; typedef weak_any weak_hlsa; #endif // _NTLSA_ #if defined(_LSALOOKUP_) && !defined(__WIL_LSALOOKUP_) #define __WIL_LSALOOKUP_ typedef unique_any unique_hlsalookup; using lsalookup_freemem_deleter = function_deleter; template using unique_lsalookupmem_ptr = wistd::unique_ptr; #endif // _LSALOOKUP_ #if defined(_LSALOOKUP_) && !defined(__WIL_LSALOOKUP_STL) && defined(WIL_RESOURCE_STL) #define __WIL_LSALOOKUP_STL typedef shared_any shared_hlsalookup; typedef weak_any weak_hlsalookup; #endif // _LSALOOKUP_ #if defined(_NTLSA_IFS_) && !defined(__WIL_HANDLE_H_NTLSA_IFS_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #define __WIL_HANDLE_H_NTLSA_IFS_ using lsa_deleter = function_deleter; template using unique_lsa_ptr = wistd::unique_ptr; #endif // __WIL_HANDLE_H_NTLSA_IFS_ #if defined(__WERAPI_H__) && !defined(__WIL_WERAPI_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #define __WIL_WERAPI_H__ typedef unique_any unique_wer_report; #endif #if defined(__MIDLES_H__) && !defined(__WIL_MIDLES_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #define __WIL_MIDLES_H__ typedef unique_any unique_rpc_pickle; #endif #if defined(__WIL_MIDLES_H__) && !defined(__WIL_MIDLES_H_STL) && defined(WIL_RESOURCE_STL) #define __WIL_MIDLES_H_STL typedef shared_any shared_rpc_pickle; typedef weak_any weak_rpc_pickle; #endif #if defined(__RPCDCE_H__) && !defined(__WIL_RPCDCE_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #define __WIL_RPCDCE_H__ /// @cond namespace details { inline void __stdcall WpRpcBindingFree(_Pre_opt_valid_ _Frees_ptr_opt_ RPC_BINDING_HANDLE binding) { ::RpcBindingFree(&binding); } inline void __stdcall WpRpcBindingVectorFree(_Pre_opt_valid_ _Frees_ptr_opt_ RPC_BINDING_VECTOR* bindingVector) { ::RpcBindingVectorFree(&bindingVector); } inline void __stdcall WpRpcStringFree(_Pre_opt_valid_ _Frees_ptr_opt_ RPC_WSTR wstr) { ::RpcStringFreeW(&wstr); } } /// @endcond typedef unique_any unique_rpc_binding; typedef unique_any unique_rpc_binding_vector; typedef unique_any unique_rpc_wstr; #endif #if defined(__WIL_RPCDCE_H__) && !defined(__WIL_RPCDCE_H_STL) && defined(WIL_RESOURCE_STL) #define __WIL_RPCDCE_H_STL typedef shared_any shared_rpc_binding; typedef weak_any weak_rpc_binding; typedef shared_any shared_rpc_binding_vector; typedef weak_any weak_rpc_binding_vector; typedef shared_any shared_rpc_wstr; typedef weak_any weak_rpc_wstr; #endif #if defined(_WCMAPI_H) && !defined(__WIL_WCMAPI_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #define __WIL_WCMAPI_H_ using wcm_deleter = function_deleter; template using unique_wcm_ptr = wistd::unique_ptr; #endif #if defined(_NETIOAPI_H_) && defined(_WS2IPDEF_) && defined(MIB_INVALID_TEREDO_PORT_NUMBER) && !defined(__WIL_NETIOAPI_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #define __WIL_NETIOAPI_H_ typedef unique_any unique_mib_iftable; #endif #if defined(__WIL_NETIOAPI_H_) && !defined(__WIL_NETIOAPI_H_STL) && defined(WIL_RESOURCE_STL) #define __WIL_NETIOAPI_H_STL typedef shared_any shared_mib_iftable; typedef weak_any weak_mib_iftable; #endif #if defined(_WLAN_WLANAPI_H) && !defined(__WIL_WLAN_WLANAPI_H) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #define __WIL_WLAN_WLANAPI_H using wlan_deleter = function_deleter; template using unique_wlan_ptr = wistd::unique_ptr < T, wlan_deleter >; /// @cond namespace details { inline void __stdcall CloseWlanHandle(_Frees_ptr_ HANDLE hClientHandle) { ::WlanCloseHandle(hClientHandle, nullptr); } } /// @endcond typedef unique_any unique_wlan_handle; #endif #if defined(__WIL_WLAN_WLANAPI_H) && !defined(__WIL_WLAN_WLANAPI_H_STL) && defined(WIL_RESOURCE_STL) #define __WIL_WLAN_WLANAPI_H_STL typedef shared_any shared_wlan_handle; typedef weak_any weak_wlan_handle; #endif #if defined(_HPOWERNOTIFY_DEF_) && !defined(__WIL_HPOWERNOTIFY_DEF_H_) && !defined(WIL_KERNEL_MODE) #define __WIL_HPOWERNOTIFY_DEF_H_ typedef unique_any unique_hpowernotify; #endif #if defined(__WIL_WINBASE_DESKTOP) && defined(SID_DEFINED) && !defined(__WIL_PSID_DEF_H_) #define __WIL_PSID_DEF_H_ typedef unique_any unique_any_psid; #if defined(_OBJBASE_H_) typedef unique_any unique_cotaskmem_psid; #endif #endif #if defined(_PROCESSTHREADSAPI_H_) && !defined(__WIL_PROCESSTHREADSAPI_H_DESK_SYS) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && !defined(WIL_KERNEL_MODE) #define __WIL_PROCESSTHREADSAPI_H_DESK_SYS /// @cond namespace details { inline void __stdcall CloseProcessInformation(_In_ PROCESS_INFORMATION* p) { if (p->hProcess) { CloseHandle(p->hProcess); } if (p->hThread) { CloseHandle(p->hThread); } } } /// @endcond /** Manages the outbound parameter containing handles returned by `CreateProcess()` and related methods. ~~~ unique_process_information process; CreateProcessW(..., CREATE_SUSPENDED, ..., &process); THROW_IF_WIN32_BOOL_FALSE(ResumeThread(process.hThread)); THROW_LAST_ERROR_IF(WaitForSingleObject(process.hProcess, INFINITE) != WAIT_OBJECT_0); ~~~ */ using unique_process_information = unique_struct; #endif #if defined(_PROCESSENV_) && !defined(__WIL__PROCESSENV_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) #define __WIL__PROCESSENV_ /** Manages lifecycle of an environment-strings block ~~~ wil::unique_environstrings_ptr env { ::GetEnvironmentStringsW() }; const wchar_t *nextVar = env.get(); while (nextVar && *nextVar) { // consume 'nextVar' nextVar += wcslen(nextVar) + 1; } ~~~ */ using unique_environstrings_ptr = wistd::unique_ptr>; #ifndef WIL_NO_ANSI_STRINGS //! ANSI equivalent to unique_environstrings_ptr; using unique_environansistrings_ptr = wistd::unique_ptr>; #endif #endif #if defined(_APPMODEL_H_) && !defined(__WIL_APPMODEL_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #define __WIL_APPMODEL_H_ typedef unique_any unique_package_info_reference; #endif // __WIL_APPMODEL_H_ #if defined(__WIL_APPMODEL_H_) && !defined(__WIL_APPMODEL_H_STL) && defined(WIL_RESOURCE_STL) #define __WIL_APPMODEL_H_STL typedef shared_any shared_package_info_reference; typedef weak_any weak_package_info_reference; #endif // __WIL_APPMODEL_H_STL #if defined(WDFAPI) && !defined(__WIL_WDFAPI) #define __WIL_WDFAPI namespace details { template using wdf_object_resource_policy = resource_policy; } template using unique_wdf_any = unique_any_t>>; using unique_wdf_object = unique_wdf_any; using unique_wdf_timer = unique_wdf_any; using unique_wdf_work_item = unique_wdf_any; using unique_wdf_memory = unique_wdf_any; using unique_wdf_dma_enabler = unique_wdf_any; using unique_wdf_dma_transaction = unique_wdf_any; using unique_wdf_common_buffer = unique_wdf_any; using unique_wdf_key = unique_wdf_any; using unique_wdf_string = unique_wdf_any; using unique_wdf_collection = unique_wdf_any; using wdf_wait_lock_release_scope_exit = unique_any< WDFWAITLOCK, decltype(&::WdfWaitLockRelease), ::WdfWaitLockRelease, details::pointer_access_none>; inline WI_NODISCARD _IRQL_requires_max_(PASSIVE_LEVEL) _Acquires_lock_(lock) wdf_wait_lock_release_scope_exit acquire_wdf_wait_lock(WDFWAITLOCK lock) WI_NOEXCEPT { ::WdfWaitLockAcquire(lock, nullptr); return wdf_wait_lock_release_scope_exit(lock); } inline WI_NODISCARD _IRQL_requires_max_(APC_LEVEL) _When_(return, _Acquires_lock_(lock)) wdf_wait_lock_release_scope_exit try_acquire_wdf_wait_lock(WDFWAITLOCK lock) WI_NOEXCEPT { LONGLONG timeout = 0; NTSTATUS status = ::WdfWaitLockAcquire(lock, &timeout); if (status == STATUS_SUCCESS) { return wdf_wait_lock_release_scope_exit(lock); } else { return wdf_wait_lock_release_scope_exit(); } } using wdf_spin_lock_release_scope_exit = unique_any< WDFSPINLOCK, decltype(&::WdfSpinLockRelease), ::WdfSpinLockRelease, details::pointer_access_none>; inline WI_NODISCARD _IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_raises_(DISPATCH_LEVEL) _Acquires_lock_(lock) wdf_spin_lock_release_scope_exit acquire_wdf_spin_lock(WDFSPINLOCK lock) WI_NOEXCEPT { ::WdfSpinLockAcquire(lock); return wdf_spin_lock_release_scope_exit(lock); } namespace details { template using unique_wdf_lock_storage = unique_storage>; class unique_wdf_spin_lock_storage : public unique_wdf_lock_storage { using wdf_lock_storage_t = unique_wdf_lock_storage; public: using pointer = wdf_lock_storage_t::pointer; // Forward all base class constructors, but have it be explicit. template explicit unique_wdf_spin_lock_storage(args_t&& ... args) WI_NOEXCEPT : wdf_lock_storage_t(wistd::forward(args)...) {} NTSTATUS create(_In_opt_ WDF_OBJECT_ATTRIBUTES* attributes = WDF_NO_OBJECT_ATTRIBUTES) { return ::WdfSpinLockCreate(attributes, out_param(*this)); } WI_NODISCARD _IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_raises_(DISPATCH_LEVEL) wdf_spin_lock_release_scope_exit acquire() WI_NOEXCEPT { return wil::acquire_wdf_spin_lock(wdf_lock_storage_t::get()); } }; class unique_wdf_wait_lock_storage : public unique_wdf_lock_storage { using wdf_lock_storage_t = unique_wdf_lock_storage; public: using pointer = wdf_lock_storage_t::pointer; // Forward all base class constructors, but have it be explicit. template explicit unique_wdf_wait_lock_storage(args_t&& ... args) WI_NOEXCEPT : wdf_lock_storage_t(wistd::forward(args)...) {} NTSTATUS create(_In_opt_ WDF_OBJECT_ATTRIBUTES* attributes = WDF_NO_OBJECT_ATTRIBUTES) { return ::WdfWaitLockCreate(attributes, out_param(*this)); } WI_NODISCARD _IRQL_requires_max_(PASSIVE_LEVEL) wdf_wait_lock_release_scope_exit acquire() WI_NOEXCEPT { return wil::acquire_wdf_wait_lock(wdf_lock_storage_t::get()); } WI_NODISCARD _IRQL_requires_max_(APC_LEVEL) wdf_wait_lock_release_scope_exit try_acquire() WI_NOEXCEPT { return wil::try_acquire_wdf_wait_lock(wdf_lock_storage_t::get()); } }; } using unique_wdf_wait_lock = unique_any_t; using unique_wdf_spin_lock = unique_any_t; template struct wdf_object_reference { TWDFOBJECT wdfObject = WDF_NO_HANDLE; PVOID tag = nullptr; wdf_object_reference() WI_NOEXCEPT = default; wdf_object_reference(TWDFOBJECT wdfObject, PVOID tag = nullptr) WI_NOEXCEPT : wdfObject(wdfObject), tag(tag) { } operator TWDFOBJECT() const WI_NOEXCEPT { return wdfObject; } static void close(const wdf_object_reference& wdfObjectReference) WI_NOEXCEPT { // We don't use WdfObjectDereferenceActual because there is no way to provide the // correct __LINE__ and __FILE__, but if you use RAII all the way, you shouldn't have to // worry about where it was released, only where it was acquired. WdfObjectDereferenceWithTag(wdfObjectReference.wdfObject, wdfObjectReference.tag); } }; template using unique_wdf_object_reference = unique_any::close), &wdf_object_reference::close, details::pointer_access_noaddress, wdf_object_reference>; // Increment the ref-count on a WDF object a unique_wdf_object_reference for it. Use // WI_WdfObjectReferenceIncrement to automatically use the call-site source location. Use this // function only if the call-site source location is obtained from elsewhere (i.e., plumbed // through other abstractions). template inline WI_NODISCARD unique_wdf_object_reference wdf_object_reference_increment( TWDFOBJECT wdfObject, PVOID tag, LONG lineNumber, PCSTR fileName) WI_NOEXCEPT { // Parameter is incorrectly marked as non-const, so the const-cast is required. ::WdfObjectReferenceActual(wdfObject, tag, lineNumber, const_cast(fileName)); return unique_wdf_object_reference{ wdf_object_reference{ wdfObject, tag } }; } // A macro so that we can capture __LINE__ and __FILE__. #define WI_WdfObjectReferenceIncrement(wdfObject, tag) \ wil::wdf_object_reference_increment(wdfObject, tag, __LINE__, __FILE__) #endif #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && \ defined(_CFGMGR32_H_) && \ (WINVER >= _WIN32_WINNT_WIN8) && \ !defined(__WIL_CFGMGR32_H_) #define __WIL_CFGMGR32_H_ typedef unique_any unique_hcmnotification; #endif #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && \ defined(_SWDEVICE_H_) && \ (WINVER >= _WIN32_WINNT_WIN8) && \ !defined(__WIL_SWDEVICE_H_) #define __WIL_SWDEVICE_H_ typedef unique_any unique_hswdevice; #endif #if defined(WIL_KERNEL_MODE) && (defined(_WDMDDK_) || defined(_NTDDK_)) && !defined(__WIL_RESOURCE_WDM) #define __WIL_RESOURCE_WDM namespace details { struct kspin_lock_saved_irql { PKSPIN_LOCK spinLock = nullptr; KIRQL savedIrql = PASSIVE_LEVEL; kspin_lock_saved_irql() = default; kspin_lock_saved_irql(PKSPIN_LOCK /* spinLock */) { // This constructor exists simply to allow conversion of the pointer type to // pointer_storage type when constructing an invalid instance. The spinLock pointer // is expected to be nullptr. } // Exists to satisfy the interconvertibility requirement for pointer_storage and // pointer. explicit operator PKSPIN_LOCK() const { return spinLock; } _IRQL_requires_(DISPATCH_LEVEL) static void Release(_In_ _IRQL_restores_ const kspin_lock_saved_irql& spinLockSavedIrql) { KeReleaseSpinLock(spinLockSavedIrql.spinLock, spinLockSavedIrql.savedIrql); } }; // On some architectures KeReleaseSpinLockFromDpcLevel is a macro, and we need a thunk // function we can take the address of. inline _IRQL_requires_min_(DISPATCH_LEVEL) void __stdcall ReleaseSpinLockFromDpcLevel(_Inout_ PKSPIN_LOCK spinLock) WI_NOEXCEPT { KeReleaseSpinLockFromDpcLevel(spinLock); } } using kspin_lock_guard = unique_any; using kspin_lock_at_dpc_guard = unique_any; inline WI_NODISCARD _IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_saves_ _IRQL_raises_(DISPATCH_LEVEL) kspin_lock_guard acquire_kspin_lock(_In_ PKSPIN_LOCK spinLock) { details::kspin_lock_saved_irql spinLockSavedIrql; KeAcquireSpinLock(spinLock, &spinLockSavedIrql.savedIrql); spinLockSavedIrql.spinLock = spinLock; return kspin_lock_guard(spinLockSavedIrql); } inline WI_NODISCARD _IRQL_requires_min_(DISPATCH_LEVEL) kspin_lock_at_dpc_guard acquire_kspin_lock_at_dpc(_In_ PKSPIN_LOCK spinLock) { KeAcquireSpinLockAtDpcLevel(spinLock); return kspin_lock_at_dpc_guard(spinLock); } class kernel_spin_lock { public: kernel_spin_lock() WI_NOEXCEPT { ::KeInitializeSpinLock(&m_kSpinLock); } ~kernel_spin_lock() = default; // Cannot change memory location. kernel_spin_lock(const kernel_spin_lock&) = delete; kernel_spin_lock& operator=(const kernel_spin_lock&) = delete; kernel_spin_lock(kernel_spin_lock&&) = delete; kernel_spin_lock& operator=(kernel_spin_lock&&) = delete; WI_NODISCARD _IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_saves_ _IRQL_raises_(DISPATCH_LEVEL) kspin_lock_guard acquire() WI_NOEXCEPT { return acquire_kspin_lock(&m_kSpinLock); } WI_NODISCARD _IRQL_requires_min_(DISPATCH_LEVEL) kspin_lock_at_dpc_guard acquire_at_dpc() WI_NOEXCEPT { return acquire_kspin_lock_at_dpc(&m_kSpinLock); } private: KSPIN_LOCK m_kSpinLock; }; namespace details { template class kernel_event_t { public: explicit kernel_event_t(bool isSignaled = false) WI_NOEXCEPT { ::KeInitializeEvent(&m_kernelEvent, static_cast(eventType), isSignaled ? TRUE : FALSE); } // Cannot change memory location. kernel_event_t(const kernel_event_t&) = delete; kernel_event_t(kernel_event_t&&) = delete; kernel_event_t& operator=(const kernel_event_t&) = delete; kernel_event_t& operator=(kernel_event_t&&) = delete; // Get the underlying KEVENT structure for more advanced usages like // KeWaitForMultipleObjects or KeWaitForSingleObject with non-default parameters. PRKEVENT get() WI_NOEXCEPT { return &m_kernelEvent; } void clear() WI_NOEXCEPT { // The most common use-case is to clear the event with no interest in its previous // value. Hence, that is the functionality we provide by default. If the previous // value is required, one may .get() the underlying event object and call // ::KeResetEvent(). ::KeClearEvent(&m_kernelEvent); } // Returns the previous state of the event. bool set(KPRIORITY increment = IO_NO_INCREMENT) WI_NOEXCEPT { return ::KeSetEvent(&m_kernelEvent, increment, FALSE) ? true : false; } // Checks if the event is currently signaled. Does not change the state of the event. bool is_signaled() const WI_NOEXCEPT { return ::KeReadStateEvent(const_cast(&m_kernelEvent)) ? true : false; } // Return true if the wait was satisfied. Time is specified in 100ns units, relative // (negative) or absolute (positive). For more details, see the documentation of // KeWaitForSingleObject. bool wait(LONGLONG waitTime) WI_NOEXCEPT { LARGE_INTEGER duration; duration.QuadPart = waitTime; return wait_for_single_object(&duration); } // Waits indefinitely for the event to be signaled. void wait() WI_NOEXCEPT { wait_for_single_object(nullptr); } private: bool wait_for_single_object(_In_opt_ LARGE_INTEGER* waitDuration) WI_NOEXCEPT { auto status = ::KeWaitForSingleObject(&m_kernelEvent, Executive, KernelMode, FALSE, waitDuration); // We specified Executive and non-alertable, which means some of the return values are // not possible. WI_ASSERT((status == STATUS_SUCCESS) || (status == STATUS_TIMEOUT)); return (status == STATUS_SUCCESS); } KEVENT m_kernelEvent; }; } using kernel_event_auto_reset = details::kernel_event_t; using kernel_event_manual_reset = details::kernel_event_t; using kernel_event = kernel_event_auto_reset; // For parity with the default for other WIL event types. namespace details { // Define a templated type for pool functions in order to satisfy overload resolution below template struct pool_helpers { static inline _IRQL_requires_max_(DISPATCH_LEVEL) void __stdcall FreePoolWithTag(pointer value) WI_NOEXCEPT { if (value) { ExFreePoolWithTag(value, tag); } } }; } template using unique_tagged_pool_ptr = unique_any::FreePoolWithTag), &details::pool_helpers::FreePoolWithTag>; // For use with IRPs that need to be IoFreeIrp'ed when done, typically allocated using IoAllocateIrp. using unique_allocated_irp = wil::unique_any; using unique_io_workitem = wil::unique_any; #endif // __WIL_RESOURCE_WDM #if defined(WIL_KERNEL_MODE) && (defined(_WDMDDK_) || defined(_ZWAPI_)) && !defined(__WIL_RESOURCE_ZWAPI) #define __WIL_RESOURCE_ZWAPI using unique_kernel_handle = wil::unique_any; #endif // __WIL_RESOURCE_ZWAPI } // namespace wil #pragma warning(pop)