2024-06-10 06:09:51 +00:00
//*********************************************************
//
// 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.
//
//*********************************************************
//! @file
//! WIL Resource Wrappers (RAII): Provides a family of smart pointer patterns and resource wrappers to enable customers to
//! consistently use RAII in all code.
# 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
/// @cond
// 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
2024-12-05 06:06:53 +00:00
# define __WI_SIZE_MAX 0xffffffffffffffffULL // UINT64_MAX
# else /* _WIN64 */
# define __WI_SIZE_MAX 0xffffffffUL // UINT32_MAX
# endif /* _WIN64 */
2024-06-10 06:09:51 +00:00
/// @endcond
// Forward declaration
/// @cond
namespace Microsoft
{
namespace WRL
{
template < typename T >
class ComPtr ;
}
} // namespace Microsoft
/// @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
//! inadvertently 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 = false ;
DWORD m_error = 0 ;
public :
last_error_context ( ) WI_NOEXCEPT : last_error_context ( : : GetLastError ( ) )
{
}
explicit last_error_context ( DWORD error ) WI_NOEXCEPT : m_error ( error )
{
}
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 ;
}
WI_NODISCARD auto value ( ) const WI_NOEXCEPT
{
return m_error ;
}
# else
public :
void release ( ) WI_NOEXCEPT
{
}
# endif // WIL_KERNEL_MODE
} ;
/// @cond
namespace details
{
typedef wistd : : integral_constant < size_t , 0 > pointer_access_all ; // get(), release(), addressof(), and '&' are available
typedef wistd : : integral_constant < size_t , 1 > pointer_access_noaddress ; // get() and release() are available
typedef wistd : : integral_constant < size_t , 2 > pointer_access_none ; // the raw pointer is not available
template < bool is_fn_ptr , typename close_fn_t , close_fn_t close_fn , typename pointer_storage_t >
struct close_invoke_helper
{
__forceinline static void close ( pointer_storage_t value ) WI_NOEXCEPT
{
wistd : : invoke ( close_fn , value ) ;
}
inline static void close_reset ( pointer_storage_t value ) WI_NOEXCEPT
{
auto preserveError = last_error_context ( ) ;
wistd : : invoke ( close_fn , value ) ;
}
} ;
template < typename close_fn_t , close_fn_t close_fn , typename pointer_storage_t >
struct close_invoke_helper < true , close_fn_t , close_fn , pointer_storage_t >
{
__forceinline static void close ( pointer_storage_t value ) WI_NOEXCEPT
{
close_fn ( value ) ;
}
inline static void close_reset ( pointer_storage_t value ) WI_NOEXCEPT
{
auto preserveError = last_error_context ( ) ;
close_fn ( value ) ;
}
} ;
template < typename close_fn_t , close_fn_t close_fn , typename pointer_storage_t >
using close_invoker =
close_invoke_helper < wistd : : is_pointer_v < close_fn_t > ? wistd : : is_function_v < wistd : : remove_pointer_t < close_fn_t > > : false , close_fn_t , close_fn , pointer_storage_t > ;
template <
typename pointer_t , // The handle type
typename close_fn_t , // The handle close function type
close_fn_t close_fn , // * and function pointer
typename pointer_access_t = pointer_access_all , // all, noaddress or none to control pointer method access
typename pointer_storage_t = pointer_t , // The type used to store the handle (usually the same as the handle itself)
typename invalid_t = pointer_t , // The invalid handle value type
invalid_t invalid = invalid_t { } , // * and its value (default ZERO value)
typename pointer_invalid_t = wistd : : nullptr_t > // nullptr_t if the invalid handle value is compatible with nullptr, otherwise pointer
struct resource_policy : close_invoker < close_fn_t , close_fn , pointer_storage_t >
{
typedef pointer_storage_t pointer_storage ;
typedef pointer_t pointer ;
typedef pointer_invalid_t pointer_invalid ;
typedef pointer_access_t pointer_access ;
__forceinline static pointer_storage invalid_value ( )
{
return ( pointer ) invalid ;
}
__forceinline static bool is_valid ( pointer_storage value ) WI_NOEXCEPT
{
return ( static_cast < pointer > ( value ) ! = ( pointer ) invalid ) ;
}
} ;
// 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 < typename Policy >
class unique_storage
{
protected :
typedef Policy policy ;
typedef typename policy : : pointer_storage pointer_storage ;
typedef typename policy : : pointer pointer ;
typedef unique_storage < policy > base_storage ;
public :
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 ) ;
}
}
WI_NODISCARD 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 < typename policy : : pointer_invalid , wistd : : nullptr_t > : : value ,
" reset(nullptr): valid only for handle types using nullptr as the invalid value " ) ;
reset ( ) ;
}
WI_NODISCARD pointer get ( ) const WI_NOEXCEPT
{
return static_cast < pointer > ( m_ptr ) ;
}
pointer_storage release ( ) WI_NOEXCEPT
{
static_assert (
! wistd : : is_same < typename policy : : pointer_access , pointer_access_none > : : 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 < typename policy : : pointer_access , pointer_access_all > : : value ,
" addressof(): the address of the raw handle is not available for this resource class " ) ;
return & m_ptr ;
}
protected :
void replace ( unique_storage & & other ) WI_NOEXCEPT
{
reset ( other . m_ptr ) ;
other . m_ptr = policy : : invalid_value ( ) ;
}
private :
pointer_storage m_ptr ;
} ;
// Determines if it is safe to deallocate a resource without destructing the object
template < typename T >
struct needs_destruction
{
template < typename U >
static auto invoke ( int ) - > wistd : : bool_constant < sizeof ( U ) > = 0 > ; // Always true, but SFINAE's if incomplete type
template < typename U >
static auto invoke ( float ) - > wistd : : false_type ;
// A type needs destruction if:
// 1. It is a complete type,
// 2. It can be destructed, and
// 3. It's not trivially destructible
// Note that we need the "complete type" check because some places use an undefined struct as a type-safe
// resource type (e.g. 'typedef struct tagSERIALIZEDPROPSTORAGE SERIALIZEDPROPSTORAGE')
static constexpr const bool value = wistd : : conjunction_v <
decltype ( invoke < wistd : : remove_extent_t < T > > ( 0 ) ) ,
wistd : : is_destructible < wistd : : remove_extent_t < T > > ,
wistd : : negation < wistd : : is_trivially_destructible < wistd : : remove_extent_t < T > > > > ;
} ;
template < typename T >
constexpr bool needs_destruction_v = needs_destruction < T > : : value ;
// A pass-through type that statically asserts that the specified type does not need destruction. Useful when
// specifying template arguments for various unique_* types where the destructor won't run
template < typename T >
struct ensure_trivially_destructible
{
// NOTE: Temporary opt-out for existing code that uses these types incorrectly
# ifndef WIL_DISABLE_UNIQUE_PTR_DESTRUCTOR_CHECKS
// If this static_assert fires, it means you've used a type that is not trivially destructible as a template
// argument to a wil::unique* type that will not invoke that object's destructor
static_assert ( ! needs_destruction_v < T > , " Resource type has a non-trivial destructor, but is used in a context where its destructor will not be run " ) ;
# endif
using type = T ;
} ;
template < typename T >
using ensure_trivially_destructible_t = typename ensure_trivially_destructible < T > : : type ;
} // namespace 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 < typename storage_t >
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 < typename arg1 , typename . . . args_t >
explicit unique_any_t ( arg1 & & first , args_t & & . . . args )
__WI_NOEXCEPT_ ( ( wistd : : is_nothrow_constructible_v < storage_t , arg1 , args_t . . . > ) ) :
storage_t ( wistd : : forward < arg1 > ( first ) , wistd : : forward < args_t > ( args ) . . . )
{
static_assert (
wistd : : is_same < typename policy : : pointer_access , details : : pointer_access_none > : : value | |
wistd : : is_same < typename policy : : pointer_access , details : : pointer_access_all > : : value | |
wistd : : is_same < typename policy : : pointer_access , details : : pointer_access_noaddress > : : 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 < typename policy : : pointer_invalid , wistd : : nullptr_t > : : 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 < typename storage_t : : base_storage & > ( other ) ) ) ;
}
return ( * this ) ;
}
unique_any_t & operator = ( wistd : : nullptr_t ) WI_NOEXCEPT
{
static_assert (
wistd : : is_same < typename policy : : pointer_invalid , wistd : : nullptr_t > : : 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 ) ;
}
WI_NODISCARD explicit operator bool ( ) const WI_NOEXCEPT
{
return storage_t : : is_valid ( ) ;
}
//!
//! ~~~
//! BOOL OpenOrCreateWaffle(PCWSTR name, HWAFFLE* handle);
//! wil::unique_any<HWAFFLE, decltype(&::CloseWaffle), ::CloseWaffle> waffle;
//! RETURN_IF_WIN32_BOOL_FALSE(OpenOrCreateWaffle(L"tasty.yum", waffle.put()));
//! ~~~
pointer_storage * put ( ) WI_NOEXCEPT
{
static_assert (
wistd : : is_same < typename policy : : pointer_access , details : : pointer_access_all > : : value ,
" operator & is not available for this handle " ) ;
storage_t : : reset ( ) ;
return storage_t : : addressof ( ) ;
}
pointer_storage * operator & ( ) WI_NOEXCEPT
{
return put ( ) ;
}
WI_NODISCARD pointer get ( ) const WI_NOEXCEPT
{
static_assert (
! wistd : : is_same < typename policy : : pointer_access , details : : pointer_access_none > : : 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 < typename policy >
void swap ( unique_any_t < policy > & left , unique_any_t < policy > & right ) WI_NOEXCEPT
{
left . swap ( right ) ;
}
template < typename policy >
bool operator = = ( const unique_any_t < policy > & left , const unique_any_t < policy > & right ) WI_NOEXCEPT
{
return ( left . get ( ) = = right . get ( ) ) ;
}
template < typename policy >
bool operator = = ( const unique_any_t < policy > & left , wistd : : nullptr_t ) WI_NOEXCEPT
{
static_assert (
wistd : : is_same < typename unique_any_t < policy > : : policy : : pointer_invalid , wistd : : nullptr_t > : : value ,
" the resource class does not use nullptr as an invalid value " ) ;
return ! left ;
}
template < typename policy >
bool operator = = ( wistd : : nullptr_t , const unique_any_t < policy > & right ) WI_NOEXCEPT
{
static_assert (
wistd : : is_same < typename unique_any_t < policy > : : policy : : pointer_invalid , wistd : : nullptr_t > : : value ,
" the resource class does not use nullptr as an invalid value " ) ;
return ! right ;
}
template < typename policy >
bool operator ! = ( const unique_any_t < policy > & left , const unique_any_t < policy > & right ) WI_NOEXCEPT
{
return ( ! ( left . get ( ) = = right . get ( ) ) ) ;
}
template < typename policy >
bool operator ! = ( const unique_any_t < policy > & left , wistd : : nullptr_t ) WI_NOEXCEPT
{
static_assert (
wistd : : is_same < typename unique_any_t < policy > : : policy : : pointer_invalid , wistd : : nullptr_t > : : value ,
" the resource class does not use nullptr as an invalid value " ) ;
return ! ! left ;
}
template < typename policy >
bool operator ! = ( wistd : : nullptr_t , const unique_any_t < policy > & right ) WI_NOEXCEPT
{
static_assert (
wistd : : is_same < typename unique_any_t < policy > : : policy : : pointer_invalid , wistd : : nullptr_t > : : value ,
" the resource class does not use nullptr as an invalid value " ) ;
return ! ! right ;
}
template < typename policy >
bool operator < ( const unique_any_t < policy > & left , const unique_any_t < policy > & right ) WI_NOEXCEPT
{
return ( left . get ( ) < right . get ( ) ) ;
}
template < typename policy >
bool operator > = ( const unique_any_t < policy > & left , const unique_any_t < policy > & right ) WI_NOEXCEPT
{
return ( ! ( left < right ) ) ;
}
template < typename policy >
bool operator > ( const unique_any_t < policy > & left , const unique_any_t < policy > & right ) WI_NOEXCEPT
{
return ( right < left ) ;
}
template < typename policy >
bool operator < = ( const unique_any_t < policy > & left , const unique_any_t < policy > & 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 <
typename pointer , // The handle type
typename close_fn_t , // The handle close function type
close_fn_t close_fn , // * and function pointer
typename pointer_access = details : : pointer_access_all , // all, noaddress or none to control pointer method access
typename pointer_storage = pointer , // The type used to store the handle (usually the same as the handle itself)
typename invalid_t = pointer , // The invalid handle value type
invalid_t invalid = invalid_t { } , // * and its value (default ZERO value)
typename pointer_invalid = wistd : : nullptr_t > // nullptr_t if the invalid handle value is compatible with nullptr, otherwise pointer
using unique_any =
unique_any_t < details : : unique_storage < details : : resource_policy < pointer , close_fn_t , close_fn , pointer_access , pointer_storage , invalid_t , invalid , pointer_invalid > > > ;
/// @cond
namespace details
{
template < typename TLambda >
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 < decltype ( lambda ( ) ) , void > : : value , " scope_exit lambdas must not have a return value " ) ;
static_assert (
! wistd : : is_lvalue_reference < TLambda > : : value & & ! wistd : : is_rvalue_reference < TLambda > : : 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
WI_NODISCARD explicit operator bool ( ) const WI_NOEXCEPT
{
return m_call ;
}
protected :
TLambda m_lambda ;
bool m_call = true ;
} ;
# ifdef WIL_ENABLE_EXCEPTIONS
template < typename TLambda >
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 < decltype ( lambda ( ) ) , void > : : value , " scope_exit lambdas must return 'void' " ) ;
static_assert (
! wistd : : is_lvalue_reference < TLambda > : : value & & ! wistd : : is_rvalue_reference < TLambda > : : 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 < FailureType : : Log > ( __R_DIAGNOSTICS ( m_info ) , m_address ) ;
}
}
}
// Returns true if the scope_exit lambda is still going to be executed
WI_NODISCARD 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
} // namespace details
/// @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 < typename TLambda >
WI_NODISCARD inline auto scope_exit ( TLambda & & lambda ) WI_NOEXCEPT
{
return details : : lambda_call < TLambda > ( wistd : : forward < TLambda > ( 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 < typename TLambda >
WI_NODISCARD inline __declspec ( noinline ) auto scope_exit_log ( const DiagnosticsInfo & diagnostics , TLambda & & lambda ) WI_NOEXCEPT
{
return details : : lambda_call_log < TLambda > ( _ReturnAddress ( ) , diagnostics , wistd : : forward < TLambda > ( lambda ) ) ;
}
# endif
// Forward declaration...
template < typename T , typename err_policy >
class com_ptr_t ;
//! Type traits class that identifies the inner type of any smart pointer.
template < typename Ptr >
struct smart_pointer_details
{
typedef typename Ptr : : pointer pointer ;
} ;
/// @cond
template < typename T >
struct smart_pointer_details < Microsoft : : WRL : : ComPtr < T > >
{
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 < typename TSmartPointer >
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 < typename T , typename err >
WI_NODISCARD T * detach_from_smart_pointer ( wil : : com_ptr_t < T , err > & smartPtr )
{
return smartPtr . detach ( ) ;
}
// Generically detaches a raw pointer from any smart pointer
template < typename T >
WI_NODISCARD T * detach_from_smart_pointer ( Microsoft : : WRL : : ComPtr < T > & smartPtr )
{
return smartPtr . Detach ( ) ;
}
template < typename T , typename err >
class com_ptr_t ; // forward
namespace details
{
// The first two attach_to_smart_pointer() overloads are ambiguous when passed a com_ptr_t.
2024-12-05 06:06:53 +00:00
// To solve that use this functions return type to eliminate the reset form for com_ptr_t.
2024-06-10 06:09:51 +00:00
template < typename T , typename err >
wistd : : false_type use_reset ( wil : : com_ptr_t < T , err > * )
{
return wistd : : false_type ( ) ;
}
template < typename T >
wistd : : true_type use_reset ( T * )
{
return wistd : : true_type ( ) ;
}
} // namespace details
/// @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 < typename TSmartPointer , typename EnableResetForm = wistd : : enable_if_t < decltype ( details : : use_reset ( static_cast < TSmartPointer * > ( 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 < typename T , typename err >
void attach_to_smart_pointer ( wil : : com_ptr_t < T , err > & smartPtr , T * rawPtr )
{
smartPtr . attach ( rawPtr ) ;
}
// Generically attach a raw pointer to a compatible smart pointer.
template < typename T >
void attach_to_smart_pointer ( Microsoft : : WRL : : ComPtr < T > & 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 < typename T , typename TSmartPointer >
inline void detach_to_opt_param ( _Out_opt_ T * outParam , TSmartPointer & & smartPtr )
{
if ( outParam )
{
* outParam = detach_from_smart_pointer ( smartPtr ) ;
}
}
/// @cond
namespace details
{
template < typename T >
struct out_param_t
{
typedef typename wil : : smart_pointer_details < T > : : 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 ) WI_NOEXCEPT : 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 < typename Tcast , typename T >
struct out_param_ptr_t
{
typedef typename wil : : smart_pointer_details < T > : : 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 ) WI_NOEXCEPT : wrapper ( other . wrapper ) , pRaw ( other . pRaw )
{
WI_ASSERT ( other . replace ) ;
other . replace = false ;
}
operator Tcast ( )
{
WI_ASSERT ( replace ) ;
return reinterpret_cast < Tcast > ( & 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 ;
} ;
} // namespace 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 < typename T >
details : : out_param_t < T > out_param ( T & p )
{
return details : : out_param_t < 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 requires , necessitating a cast .
Example : ` wil : : out_param_ptr < PSECURITY_DESCRIPTOR * > ( securityDescriptor ) ` */
template < typename Tcast , typename T >
details : : out_param_ptr_t < Tcast , T > out_param_ptr ( T & p )
{
return details : : out_param_ptr_t < Tcast , 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 ) . Submit pull
requests to [ GitHub ] ( https : //github.com/microsoft/wil/). 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 < PROPVARIANT , decltype ( & : : PropVariantClear ) , : : PropVariantClear > unique_prop_variant_default_init ;
unique_prop_variant_default_init propvariant ;
SomeFunction ( & propvariant ) ;
~ ~ ~
Defined using a custom initializer
~ ~ ~
typedef wil : : unique_struct < PROPVARIANT , decltype ( & : : PropVariantClear ) , : : PropVariantClear , decltype ( & : : PropVariantInit ) ,
: : PropVariantInit > unique_prop_variant ;
unique_prop_variant propvariant ;
SomeFunction ( & propvariant ) ;
~ ~ ~
*/
template < typename struct_t , typename close_fn_t , close_fn_t close_fn , typename init_fn_t = wistd : : nullptr_t , init_fn_t init_fn = wistd : : nullptr_t ( ) >
class unique_struct : public struct_t
{
using closer = details : : close_invoker < close_fn_t , close_fn , 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
{
closer : : close ( 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
{
closer : : close_reset ( 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
{
closer : : close ( 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 < init_fn_t , wistd : : nullptr_t > : : 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 < typename T >
void operator ( ) ( _Pre_opt_valid_ _Frees_ptr_opt_ T ) const
{
static_assert (
! details : : needs_destruction_v < T > ,
" Resource type has a non-trivial destructor, but is used in a context where its destructor will not be run " ) ;
}
} ;
/** 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
2024-12-05 06:06:53 +00:00
freed . The intended use for this RAII type would be to capture out params from API like IPropertyValue : : GetStringArray . This class
2024-06-10 06:09:51 +00:00
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 pull requests
to [ GitHub ] ( https : //github.com/microsoft/wil/). 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 < NOTMYTYPE , : : CoTaskMemFree , not_my_deleter > myArray ;
GetSomeArray ( myArray . size_address ( ) , & myArray ) ;
~ ~ ~ */
template < typename ValueType , typename ArrayDeleter , typename ElementDeleter = empty_deleter >
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 ;
}
WI_NODISCARD iterator begin ( ) WI_NOEXCEPT
{
return ( iterator ( m_ptr ) ) ;
}
WI_NODISCARD const_iterator begin ( ) const WI_NOEXCEPT
{
return ( const_iterator ( m_ptr ) ) ;
}
WI_NODISCARD iterator end ( ) WI_NOEXCEPT
{
return ( iterator ( m_ptr + m_size ) ) ;
}
WI_NODISCARD const_iterator end ( ) const WI_NOEXCEPT
{
return ( const_iterator ( m_ptr + m_size ) ) ;
}
WI_NODISCARD const_iterator cbegin ( ) const WI_NOEXCEPT
{
return ( begin ( ) ) ;
}
WI_NODISCARD const_iterator cend ( ) const WI_NOEXCEPT
{
return ( end ( ) ) ;
}
WI_NODISCARD size_type size ( ) const WI_NOEXCEPT
{
return ( m_size ) ;
}
WI_NODISCARD bool empty ( ) const WI_NOEXCEPT
{
return ( size ( ) = = size_type { } ) ;
}
WI_NODISCARD reference operator [ ] ( size_type position )
{
WI_ASSERT ( position < m_size ) ;
_Analysis_assume_ ( position < m_size ) ;
return ( m_ptr [ position ] ) ;
}
WI_NODISCARD const_reference operator [ ] ( size_type position ) const
{
WI_ASSERT ( position < m_size ) ;
_Analysis_assume_ ( position < m_size ) ;
return ( m_ptr [ position ] ) ;
}
WI_NODISCARD reference front ( )
{
WI_ASSERT ( ! empty ( ) ) ;
return ( m_ptr [ 0 ] ) ;
}
WI_NODISCARD const_reference front ( ) const
{
WI_ASSERT ( ! empty ( ) ) ;
return ( m_ptr [ 0 ] ) ;
}
WI_NODISCARD reference back ( )
{
WI_ASSERT ( ! empty ( ) ) ;
return ( m_ptr [ m_size - 1 ] ) ;
}
WI_NODISCARD const_reference back ( ) const
{
WI_ASSERT ( ! empty ( ) ) ;
return ( m_ptr [ m_size - 1 ] ) ;
}
WI_NODISCARD ValueType * data ( ) WI_NOEXCEPT
{
return ( m_ptr ) ;
}
WI_NODISCARD const ValueType * data ( ) const WI_NOEXCEPT
{
return ( m_ptr ) ;
}
WI_NODISCARD pointer get ( ) const WI_NOEXCEPT
{
return m_ptr ;
}
WI_NODISCARD 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 < typename TSize >
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 ) WI_NOEXCEPT : 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_type > ( size ) ;
}
}
size_address_ptr ( size_address_ptr const & other ) = delete ;
size_address_ptr & operator = ( size_address_ptr const & other ) = delete ;
} ;
template < typename T >
size_address_ptr < T > size_address ( ) WI_NOEXCEPT
{
return size_address_ptr < T > ( * this ) ;
}
private :
pointer m_ptr = nullptr ;
size_type m_size { } ;
void reset_array ( const empty_deleter & )
{
}
template < typename T >
void reset_array ( const T & deleter )
{
for ( auto & element : make_range ( m_ptr , m_size ) )
{
deleter ( element ) ;
}
}
} ;
// forward declaration
template < typename T , typename err_policy >
class com_ptr_t ;
/// @cond
namespace details
{
template < typename UniqueAnyType >
struct unique_any_array_deleter
{
template < typename T >
void operator ( ) ( _Pre_opt_valid_ _Frees_ptr_opt_ T * p ) const
{
UniqueAnyType : : policy : : close_reset ( p ) ;
}
} ;
template < typename close_fn_t , close_fn_t close_fn >
struct unique_struct_array_deleter
{
template < typename T >
void operator ( ) ( _Pre_opt_valid_ _Frees_ptr_opt_ T & p ) const
{
close_invoker < close_fn_t , close_fn , T * > : : close ( & p ) ;
}
} ;
struct com_unknown_deleter
{
template < typename T >
void operator ( ) ( _Pre_opt_valid_ _Frees_ptr_opt_ T * p ) const
{
if ( p )
{
p - > Release ( ) ;
}
}
} ;
template < class T >
struct element_traits
{
typedef empty_deleter deleter ;
typedef T type ;
} ;
template < typename storage_t >
struct element_traits < unique_any_t < storage_t > >
{
typedef unique_any_array_deleter < unique_any_t < storage_t > > deleter ;
typedef typename unique_any_t < storage_t > : : pointer type ;
} ;
template < typename T , typename err_policy >
struct element_traits < com_ptr_t < T , err_policy > >
{
typedef com_unknown_deleter deleter ;
typedef T * type ;
} ;
template < typename struct_t , typename close_fn_t , close_fn_t close_fn , typename init_fn_t , init_fn_t init_fn >
struct element_traits < unique_struct < struct_t , close_fn_t , close_fn , init_fn_t , init_fn > >
{
typedef unique_struct_array_deleter < close_fn_t , close_fn > deleter ;
typedef struct_t type ;
} ;
} // namespace details
/// @endcond
template < typename T , typename ArrayDeleter >
using unique_array_ptr =
unique_any_array_ptr < typename details : : element_traits < T > : : type , ArrayDeleter , typename details : : element_traits < T > : : 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 .
@ code
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 < typename T >
using unique_mydll_ptr = wistd : : unique_ptr < T , wil : : function_deleter < decltype ( & MyDllFreeMemory ) , MyDllFreeMemory > > ;
HRESULT Test ( )
{
unique_mydll_ptr < WCHAR [ ] > dllString ;
unique_mydll_ptr < MYSTRUCT > 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 ;
}
@ endcode
*/
template < typename Q , Q TDeleter >
struct function_deleter
{
template < typename T >
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 < IMyInterface , DWORD , decltype ( MyInterfaceCloseFunction ) , MyInterfaceCloseFunction , 0xFFFFFFFF > ;
~ ~ ~ */
template < typename interface_t , typename token_t , typename close_fn_t , close_fn_t close_fn , token_t invalid_token = token_t ( ) >
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
WI_NODISCARD 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
WI_NODISCARD 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 < IClosable , decltype ( CloseIClosable ) , CloseIClosable > ;
~ ~ ~ */
template < typename interface_t , typename close_fn_t , close_fn_t close_fn >
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 )
{
details : : close_invoker < close_fn_t , close_fn , interface_t * > : : close ( 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
WI_NODISCARD 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 < decltype ( CoUninitializeFunction ) , CoUninitializeFunction > ;
~ ~ ~ */
template < typename close_fn_t , close_fn_t close_fn , bool default_value = true >
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 )
{
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
WI_NODISCARD 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 < typename T >
PCWSTR str_raw_ptr ( const unique_any_t < T > & ua )
{
return str_raw_ptr ( ua . get ( ) ) ;
}
# if !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE)
/// @cond
namespace details
{
// Forward declaration
template < typename string_type >
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 < typename string_type >
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 < string_type > 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 < typename string_type , typename . . . Strings >
HRESULT str_build_nothrow ( string_type & result , Strings . . . strings )
{
PCWSTR localStrings [ ] = { strings . . . } ;
return str_build_nothrow ( result , localStrings , sizeof . . . ( Strings ) ) ;
}
} // namespace details
/// @endcond
// 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 < typename string_type , typename . . . strings >
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 < string_type > : : get ( buffer ) , str_raw_ptr ( str ) . . . ) ;
}
# endif // !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE)
# ifdef WIL_ENABLE_EXCEPTIONS
// Concatenate any number of strings together and store it in an automatically allocated string.
template < typename string_type , typename . . . arguments >
string_type str_concat ( arguments & & . . . args )
{
string_type result { } ;
THROW_IF_FAILED ( str_concat_nothrow ( result , wistd : : forward < arguments > ( args ) . . . ) ) ;
return result ;
}
# endif // WIL_ENABLE_EXCEPTIONS
// Concatenate any number of strings together and store it in an automatically allocated string.
template < typename string_type , typename . . . arguments >
string_type str_concat_failfast ( arguments & & . . . args )
{
string_type result { } ;
FAIL_FAST_IF_FAILED ( str_concat_nothrow ( result , wistd : : forward < arguments > ( args ) . . . ) ) ;
return result ;
}
# if !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE)
/// @cond
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 < typename string_type >
HRESULT str_vprintf_nothrow ( string_type & result , _Printf_format_string_ PCWSTR pszFormat , va_list & argsVL )
{
size_t lengthRequiredWithoutNull = _vscwprintf ( pszFormat , argsVL ) ;
string_maker < string_type > 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 ;
}
} // namespace details
/// @endcond
// Wraps StringCchPrintFExW and stores it in an automatically allocated string. Takes a buffer followed by the same format
// arguments that StringCchPrintfExW takes.
template < typename string_type >
HRESULT str_printf_nothrow ( string_type & result , _Printf_format_string_ PCWSTR pszFormat , . . . )
{
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 < typename string_type >
string_type str_printf ( _Printf_format_string_ PCWSTR pszFormat , . . . )
{
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 < typename string_type >
string_type str_printf_failfast ( _Printf_format_string_ PCWSTR pszFormat , . . . )
{
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 ;
}
# endif // !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE)
} // namespace wil
# endif // __WIL_RESOURCE
// Hash deferral function for unique_any_t
# if ((defined(_UNORDERED_SET_) || defined(_UNORDERED_MAP_)) && !defined(__WIL_RESOURCE_UNIQUE_HASH)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_RESOURCE_UNIQUE_HASH
/// @endcond
namespace std
{
template < typename storage_t >
struct hash < wil : : unique_any_t < storage_t > >
{
WI_NODISCARD size_t operator ( ) ( wil : : unique_any_t < storage_t > const & val ) const
{
return ( hash < typename wil : : unique_any_t < storage_t > : : pointer > ( ) ( val . get ( ) ) ) ;
}
} ;
} // namespace std
# endif
// shared_any and weak_any implementation using <memory> STL header
# if (defined(_MEMORY_) && defined(WIL_ENABLE_EXCEPTIONS) && !defined(WIL_RESOURCE_STL) && !defined(RESOURCE_SUPPRESS_STL)) || \
defined ( WIL_DOXYGEN )
/// @cond
# define WIL_RESOURCE_STL
/// @endcond
namespace wil
{
template < typename storage_t >
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 < typename UniqueT >
class shared_storage
{
protected :
typedef UniqueT unique_t ;
typedef typename unique_t : : policy policy ;
typedef typename policy : : pointer_storage pointer_storage ;
typedef typename policy : : pointer pointer ;
typedef shared_storage < unique_t > base_storage ;
public :
shared_storage ( ) = default ;
explicit shared_storage ( pointer_storage ptr )
{
if ( policy : : is_valid ( ptr ) )
{
m_ptr = std : : make_shared < unique_t > ( 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 < unique_t > ( 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 < unique_t > const & ptr ) : m_ptr ( ptr )
{
}
WI_NODISCARD 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 > ( 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 < unique_t > ( wistd : : move ( other ) ) ;
}
void reset ( wistd : : nullptr_t ) WI_NOEXCEPT
{
static_assert (
wistd : : is_same < typename policy : : pointer_invalid , wistd : : nullptr_t > : : value ,
" reset(nullptr): valid only for handle types using nullptr as the invalid value " ) ;
reset ( ) ;
}
template <
typename allow_t = typename policy : : pointer_access ,
typename wistd : : enable_if < ! wistd : : is_same < allow_t , details : : pointer_access_none > : : value , int > : : type = 0 >
WI_NODISCARD pointer get ( ) const WI_NOEXCEPT
{
return ( m_ptr ? m_ptr - > get ( ) : policy : : invalid_value ( ) ) ;
}
template <
typename allow_t = typename policy : : pointer_access ,
typename wistd : : enable_if < wistd : : is_same < allow_t , details : : pointer_access_all > : : value , int > : : type = 0 >
pointer_storage * addressof ( )
{
if ( ! m_ptr )
{
m_ptr = std : : make_shared < unique_t > ( ) ;
}
return m_ptr - > addressof ( ) ;
}
WI_NODISCARD long int use_count ( ) const WI_NOEXCEPT
{
return m_ptr . use_count ( ) ;
}
protected :
void replace ( shared_storage & & other ) WI_NOEXCEPT
{
m_ptr = wistd : : move ( other . m_ptr ) ;
}
private :
template < typename storage_t >
friend class : : wil : : weak_any ;
std : : shared_ptr < unique_t > m_ptr ;
} ;
} // namespace details
/// @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 < typename storage_t >
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 < typename . . . args_t >
explicit shared_any_t ( args_t & & . . . args ) __WI_NOEXCEPT_ ( ( wistd : : is_nothrow_constructible_v < storage_t , args_t . . . > ) ) :
storage_t ( wistd : : forward < args_t > ( args ) . . . )
{
}
shared_any_t ( wistd : : nullptr_t ) WI_NOEXCEPT
{
static_assert (
wistd : : is_same < typename policy : : pointer_invalid , wistd : : nullptr_t > : : 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 < typename storage_t : : base_storage & > ( 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 < typename policy : : pointer_invalid , wistd : : nullptr_t > : : 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 ) ;
}
WI_NODISCARD explicit operator bool ( ) const WI_NOEXCEPT
{
return storage_t : : is_valid ( ) ;
}
pointer_storage * put ( )
{
static_assert (
wistd : : is_same < typename policy : : pointer_access , details : : pointer_access_all > : : value ,
" operator & is not available for this handle " ) ;
storage_t : : reset ( ) ;
return storage_t : : addressof ( ) ;
}
pointer_storage * operator & ( )
{
return put ( ) ;
}
WI_NODISCARD pointer get ( ) const WI_NOEXCEPT
{
static_assert (
! wistd : : is_same < typename policy : : pointer_access , details : : pointer_access_none > : : 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 < typename unique_t >
void swap ( shared_any_t < unique_t > & left , shared_any_t < unique_t > & right ) WI_NOEXCEPT
{
left . swap ( right ) ;
}
template < typename unique_t >
bool operator = = ( const shared_any_t < unique_t > & left , const shared_any_t < unique_t > & right ) WI_NOEXCEPT
{
return ( left . get ( ) = = right . get ( ) ) ;
}
template < typename unique_t >
bool operator = = ( const shared_any_t < unique_t > & left , wistd : : nullptr_t ) WI_NOEXCEPT
{
static_assert (
wistd : : is_same < typename shared_any_t < unique_t > : : policy : : pointer_invalid , wistd : : nullptr_t > : : value ,
" the resource class does not use nullptr as an invalid value " ) ;
return ! left ;
}
template < typename unique_t >
bool operator = = ( wistd : : nullptr_t , const shared_any_t < unique_t > & right ) WI_NOEXCEPT
{
static_assert (
wistd : : is_same < typename shared_any_t < unique_t > : : policy : : pointer_invalid , wistd : : nullptr_t > : : value ,
" the resource class does not use nullptr as an invalid value " ) ;
return ! right ;
}
template < typename unique_t >
bool operator ! = ( const shared_any_t < unique_t > & left , const shared_any_t < unique_t > & right ) WI_NOEXCEPT
{
return ( ! ( left . get ( ) = = right . get ( ) ) ) ;
}
template < typename unique_t >
bool operator ! = ( const shared_any_t < unique_t > & left , wistd : : nullptr_t ) WI_NOEXCEPT
{
static_assert (
wistd : : is_same < typename shared_any_t < unique_t > : : policy : : pointer_invalid , wistd : : nullptr_t > : : value ,
" the resource class does not use nullptr as an invalid value " ) ;
return ! ! left ;
}
template < typename unique_t >
bool operator ! = ( wistd : : nullptr_t , const shared_any_t < unique_t > & right ) WI_NOEXCEPT
{
static_assert (
wistd : : is_same < typename shared_any_t < unique_t > : : policy : : pointer_invalid , wistd : : nullptr_t > : : value ,
" the resource class does not use nullptr as an invalid value " ) ;
return ! ! right ;
}
template < typename unique_t >
bool operator < ( const shared_any_t < unique_t > & left , const shared_any_t < unique_t > & right ) WI_NOEXCEPT
{
return ( left . get ( ) < right . get ( ) ) ;
}
template < typename unique_t >
bool operator > = ( const shared_any_t < unique_t > & left , const shared_any_t < unique_t > & right ) WI_NOEXCEPT
{
return ( ! ( left < right ) ) ;
}
template < typename unique_t >
bool operator > ( const shared_any_t < unique_t > & left , const shared_any_t < unique_t > & right ) WI_NOEXCEPT
{
return ( right < left ) ;
}
template < typename unique_t >
bool operator < = ( const shared_any_t < unique_t > & left , const shared_any_t < unique_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 < typename SharedT >
class weak_any
{
public :
typedef SharedT 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 ) ;
}
WI_NODISCARD bool expired ( ) const WI_NOEXCEPT
{
return m_weakPtr . expired ( ) ;
}
WI_NODISCARD shared_t lock ( ) const WI_NOEXCEPT
{
return shared_t ( m_weakPtr . lock ( ) ) ;
}
private :
std : : weak_ptr < typename shared_t : : unique_t > m_weakPtr ;
} ;
template < typename shared_t >
void swap ( weak_any < shared_t > & left , weak_any < shared_t > & right ) WI_NOEXCEPT
{
left . swap ( right ) ;
}
template < typename unique_t >
using shared_any = shared_any_t < details : : shared_storage < unique_t > > ;
} // namespace wil
# endif
# if (defined(WIL_RESOURCE_STL) && (defined(_UNORDERED_SET_) || defined(_UNORDERED_MAP_)) && !defined(__WIL_RESOURCE_SHARED_HASH)) || \
defined ( WIL_DOXYGEN )
/// @cond
# define __WIL_RESOURCE_SHARED_HASH
/// @endcond
namespace std
{
template < typename storage_t >
struct hash < wil : : shared_any_t < storage_t > >
{
WI_NODISCARD size_t operator ( ) ( wil : : shared_any_t < storage_t > const & val ) const
{
return ( hash < typename wil : : shared_any_t < storage_t > : : pointer > ( ) ( val . get ( ) ) ) ;
}
} ;
} // namespace std
# endif
namespace wil
{
# if (defined(__NOTHROW_T_DEFINED) && !defined(__WIL__NOTHROW_T_DEFINED)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL__NOTHROW_T_DEFINED
/// @endcond
/** 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 < Foo > ( fooConstructorParam1 , fooConstructorParam2 ) ;
if ( foo )
{
foo - > Bar ( ) ;
}
~ ~ ~
*/
template < class _Ty , class . . . _Types >
inline typename wistd : : enable_if < ! wistd : : is_array < _Ty > : : 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 < Foo [ ] > ( 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 < class _Ty >
inline typename wistd : : enable_if < wistd : : is_array < _Ty > : : 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 < class _Ty , class . . . _Types >
typename wistd : : enable_if < wistd : : extent < _Ty > : : 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 < Foo > ( fooConstructorParam1 , fooConstructorParam2 ) ;
foo - > Bar ( ) ;
~ ~ ~
*/
template < class _Ty , class . . . _Types >
inline typename wistd : : enable_if < ! wistd : : is_array < _Ty > : : 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 < Foo [ ] > ( size ) ; // the default constructor will be called on each Foo object
for ( auto & elem : wil : : make_range ( foos . get ( ) , size ) )
{
elem . Bar ( ) ;
}
~ ~ ~
*/
template < class _Ty >
inline typename wistd : : enable_if < wistd : : is_array < _Ty > : : 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 < class _Ty , class . . . _Types >
typename wistd : : enable_if < wistd : : extent < _Ty > : : 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)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_WINBASE_
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 < PendingCallbackCancellationBehavior cancellationBehavior >
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 < PendingCallbackCancellationBehavior : : NoWait >
{
static void Destroy ( _In_ PTP_WAIT threadPoolWait ) WI_NOEXCEPT
{
: : CloseThreadpoolWait ( threadPoolWait ) ;
}
} ;
template < PendingCallbackCancellationBehavior cancellationBehavior >
struct DestroyThreadPoolWork
{
static void Destroy ( _In_ PTP_WORK threadpoolWork ) WI_NOEXCEPT
{
: : WaitForThreadpoolWorkCallbacks ( threadpoolWork , ( cancellationBehavior = = PendingCallbackCancellationBehavior : : Cancel ) ) ;
: : CloseThreadpoolWork ( threadpoolWork ) ;
}
} ;
template < >
struct DestroyThreadPoolWork < PendingCallbackCancellationBehavior : : NoWait >
{
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_ 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 < typename threadpool_t , PendingCallbackCancellationBehavior cancellationBehavior >
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 < typename threadpool_t >
struct DestroyThreadPoolTimer < threadpool_t , PendingCallbackCancellationBehavior : : NoWait >
{
static void Destroy ( _In_ PTP_TIMER threadpoolTimer ) WI_NOEXCEPT
{
threadpool_t : : CloseThreadpoolTimer ( threadpoolTimer ) ;
}
} ;
template < PendingCallbackCancellationBehavior cancellationBehavior >
struct DestroyThreadPoolIo
{
static void Destroy ( _In_ PTP_IO threadpoolIo ) WI_NOEXCEPT
{
: : WaitForThreadpoolIoCallbacks ( threadpoolIo , ( cancellationBehavior = = PendingCallbackCancellationBehavior : : Cancel ) ) ;
: : CloseThreadpoolIo ( threadpoolIo ) ;
}
} ;
template < >
struct DestroyThreadPoolIo < PendingCallbackCancellationBehavior : : NoWait >
{
static void Destroy ( _In_ PTP_IO threadpoolIo ) WI_NOEXCEPT
{
: : CloseThreadpoolIo ( threadpoolIo ) ;
}
} ;
template < typename close_fn_t , close_fn_t close_fn >
struct handle_invalid_resource_policy
: resource_policy < HANDLE , close_fn_t , close_fn , details : : pointer_access_all , HANDLE , INT_PTR , - 1 , HANDLE >
{
__forceinline static bool is_valid ( HANDLE ptr ) WI_NOEXCEPT
{
return ( ( ptr ! = INVALID_HANDLE_VALUE ) & & ( ptr ! = nullptr ) ) ;
}
} ;
template < typename close_fn_t , close_fn_t close_fn >
struct handle_null_resource_policy : resource_policy < HANDLE , close_fn_t , close_fn >
{
__forceinline static bool is_valid ( HANDLE ptr ) WI_NOEXCEPT
{
return ( ( ptr ! = nullptr ) & & ( ptr ! = INVALID_HANDLE_VALUE ) ) ;
}
} ;
template < typename close_fn_t , close_fn_t close_fn >
struct handle_null_only_resource_policy : resource_policy < HANDLE , close_fn_t , close_fn >
{
__forceinline static bool is_valid ( HANDLE ptr ) WI_NOEXCEPT
{
return ( ptr ! = nullptr ) ;
}
} ;
typedef resource_policy < HANDLE , decltype ( & details : : CloseHandle ) , details : : CloseHandle , details : : pointer_access_all > handle_resource_policy ;
} // namespace details
/// @endcond
template < typename close_fn_t , close_fn_t close_fn >
using unique_any_handle_invalid =
unique_any_t < details : : unique_storage < details : : handle_invalid_resource_policy < close_fn_t , close_fn > > > ;
template < typename close_fn_t , close_fn_t close_fn >
using unique_any_handle_null = unique_any_t < details : : unique_storage < details : : handle_null_resource_policy < close_fn_t , close_fn > > > ;
template < typename close_fn_t , close_fn_t close_fn >
using unique_any_handle_null_only =
unique_any_t < details : : unique_storage < details : : handle_null_only_resource_policy < close_fn_t , close_fn > > > ;
typedef unique_any_handle_invalid < decltype ( & : : CloseHandle ) , : : CloseHandle > unique_hfile ;
typedef unique_any_handle_null < decltype ( & : : CloseHandle ) , : : CloseHandle > unique_handle ;
typedef unique_any_handle_invalid < decltype ( & : : FindClose ) , : : FindClose > unique_hfind ;
typedef unique_any < HMODULE , decltype ( & : : FreeLibrary ) , : : FreeLibrary > unique_hmodule ;
typedef unique_any_handle_null_only < decltype ( & : : CloseHandle ) , : : CloseHandle > unique_process_handle ;
typedef unique_struct < TOKEN_LINKED_TOKEN , decltype ( & details : : CloseTokenLinkedToken ) , details : : CloseTokenLinkedToken > unique_token_linked_token ;
# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
typedef unique_any < PSID , decltype ( & : : FreeSid ) , : : FreeSid > unique_sid ;
typedef unique_any_handle_null_only < decltype ( & : : DeleteBoundaryDescriptor ) , : : DeleteBoundaryDescriptor > unique_boundary_descriptor ;
/// @cond
namespace details
{
template < ULONG flags >
inline void __stdcall ClosePrivateNamespaceHelper ( HANDLE h ) WI_NOEXCEPT
{
: : ClosePrivateNamespace ( h , flags ) ;
}
} // namespace details
/// @endcond
template < ULONG flags = 0 >
using unique_private_namespace =
unique_any_handle_null_only < void ( __stdcall * ) ( HANDLE ) WI_PFN_NOEXCEPT , & details : : ClosePrivateNamespaceHelper < flags > > ;
using unique_private_namespace_close = unique_private_namespace < > ;
using unique_private_namespace_destroy = unique_private_namespace < PRIVATE_NAMESPACE_FLAG_DESTROY > ;
# endif
using unique_tool_help_snapshot = unique_hfile ;
typedef unique_any < PTP_WAIT , void ( * ) ( PTP_WAIT ) , details : : DestroyThreadPoolWait < details : : PendingCallbackCancellationBehavior : : Cancel > : : Destroy > unique_threadpool_wait ;
typedef unique_any < PTP_WAIT , void ( * ) ( PTP_WAIT ) , details : : DestroyThreadPoolWait < details : : PendingCallbackCancellationBehavior : : Wait > : : Destroy > unique_threadpool_wait_nocancel ;
typedef unique_any < PTP_WAIT , void ( * ) ( PTP_WAIT ) , details : : DestroyThreadPoolWait < details : : PendingCallbackCancellationBehavior : : NoWait > : : Destroy > unique_threadpool_wait_nowait ;
typedef unique_any < PTP_WORK , void ( * ) ( PTP_WORK ) , details : : DestroyThreadPoolWork < details : : PendingCallbackCancellationBehavior : : Cancel > : : Destroy > unique_threadpool_work ;
typedef unique_any < PTP_WORK , void ( * ) ( PTP_WORK ) , details : : DestroyThreadPoolWork < details : : PendingCallbackCancellationBehavior : : Wait > : : Destroy > unique_threadpool_work_nocancel ;
typedef unique_any < PTP_WORK , void ( * ) ( PTP_WORK ) , details : : DestroyThreadPoolWork < details : : PendingCallbackCancellationBehavior : : NoWait > : : Destroy > unique_threadpool_work_nowait ;
typedef unique_any < PTP_TIMER , void ( * ) ( PTP_TIMER ) , details : : DestroyThreadPoolTimer < details : : SystemThreadPoolMethods , details : : PendingCallbackCancellationBehavior : : Cancel > : : Destroy >
unique_threadpool_timer ;
typedef unique_any < PTP_TIMER , void ( * ) ( PTP_TIMER ) , details : : DestroyThreadPoolTimer < details : : SystemThreadPoolMethods , details : : PendingCallbackCancellationBehavior : : Wait > : : Destroy >
unique_threadpool_timer_nocancel ;
typedef unique_any < PTP_TIMER , void ( * ) ( PTP_TIMER ) , details : : DestroyThreadPoolTimer < details : : SystemThreadPoolMethods , details : : PendingCallbackCancellationBehavior : : NoWait > : : Destroy >
unique_threadpool_timer_nowait ;
typedef unique_any < PTP_IO , void ( * ) ( PTP_IO ) , details : : DestroyThreadPoolIo < details : : PendingCallbackCancellationBehavior : : Cancel > : : Destroy > unique_threadpool_io ;
typedef unique_any < PTP_IO , void ( * ) ( PTP_IO ) , details : : DestroyThreadPoolIo < details : : PendingCallbackCancellationBehavior : : Wait > : : Destroy > unique_threadpool_io_nocancel ;
typedef unique_any < PTP_IO , void ( * ) ( PTP_IO ) , details : : DestroyThreadPoolIo < details : : PendingCallbackCancellationBehavior : : NoWait > : : Destroy > unique_threadpool_io_nowait ;
# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
typedef unique_any_handle_invalid < decltype ( & : : FindCloseChangeNotification ) , : : FindCloseChangeNotification > unique_hfind_change ;
# endif
typedef unique_any < HANDLE , decltype ( & details : : SetEvent ) , details : : SetEvent , details : : pointer_access_noaddress > event_set_scope_exit ;
typedef unique_any < HANDLE , decltype ( & details : : ResetEvent ) , details : : ResetEvent , details : : pointer_access_noaddress > 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 , BOOL bAlertable = FALSE ) WI_NOEXCEPT
{
DWORD status = : : WaitForSingleObjectEx ( hEvent , dwMilliseconds , bAlertable ) ;
__FAIL_FAST_ASSERT__ ( ( status = = WAIT_TIMEOUT ) | | ( status = = WAIT_OBJECT_0 ) | | ( bAlertable & & ( status = = WAIT_IO_COMPLETION ) ) ) ;
return ( status = = WAIT_OBJECT_0 ) ;
}
enum class EventOptions
{
None = 0x0 ,
ManualReset = 0x1 ,
Signaled = 0x2
} ;
DEFINE_ENUM_FLAG_OPERATORS ( EventOptions ) ;
template < typename storage_t , typename err_policy = err_exception_policy >
class event_t : public storage_t
{
public :
// forward all base class constructors...
template < typename . . . args_t >
explicit event_t ( args_t & & . . . args ) WI_NOEXCEPT : storage_t ( wistd : : forward < args_t > ( 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 < void , result > : : 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
WI_NODISCARD 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 , BOOL bAlertable = FALSE ) const WI_NOEXCEPT
{
return wil : : handle_wait ( storage_t : : get ( ) , dwMilliseconds , bAlertable ) ;
}
// 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 securityAttributes = nullptr , _Out_opt_ bool * alreadyExists = nullptr )
{
auto handle = : : CreateEventExW (
securityAttributes ,
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 ( alreadyExists , false ) ;
return false ;
}
assign_to_opt_param ( alreadyExists , ( : : 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 securityAttributes = nullptr ,
_Out_opt_ bool * alreadyExists = nullptr )
{
return err_policy : : LastErrorIfFalse ( try_create ( options , name , securityAttributes , alreadyExists ) ) ;
}
// 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 < event_t < details : : unique_storage < details : : handle_resource_policy > , err_returncode_policy > > unique_event_nothrow ;
typedef unique_any_t < event_t < details : : unique_storage < details : : handle_resource_policy > , err_failfast_policy > > unique_event_failfast ;
# ifdef WIL_ENABLE_EXCEPTIONS
typedef unique_any_t < event_t < details : : unique_storage < details : : handle_resource_policy > , err_exception_policy > > unique_event ;
# endif
2024-12-05 06:06:53 +00:00
# ifndef WIL_NO_SLIM_EVENT
2024-06-10 06:09:51 +00:00
# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && \
( ( _WIN32_WINNT > = _WIN32_WINNT_WIN8 ) | | ( __WIL_RESOURCE_ENABLE_QUIRKS & & ( _WIN32_WINNT > = _WIN32_WINNT_WIN7 ) ) )
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 < wil : : slim_event > CreateSharedEvent ( bool startSignaled )
{
return std : : make_shared < wil : : slim_event > ( startSignaled ) ;
}
~ ~ ~ ~ */
template < SlimEventType Type >
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.
WI_NODISCARD bool is_signaled ( ) const WI_NOEXCEPT
{
return ! ! ReadAcquire ( & m_isSignaled ) ;
}
2024-12-05 06:06:53 +00:00
bool wait ( DWORD timeoutMilliseconds ) WI_NOEXCEPT
2024-06-10 06:09:51 +00:00
{
2024-12-05 06:06:53 +00:00
if ( timeoutMilliseconds = = 0 )
2024-06-10 06:09:51 +00:00
{
return TryAcquireEvent ( ) ;
}
2024-12-05 06:06:53 +00:00
else if ( timeoutMilliseconds = = INFINITE )
2024-06-10 06:09:51 +00:00
{
return wait ( ) ;
}
UINT64 startTime { } ;
QueryUnbiasedInterruptTime ( & startTime ) ;
UINT64 elapsedTimeMilliseconds = 0 ;
while ( ! TryAcquireEvent ( ) )
{
2024-12-05 06:06:53 +00:00
if ( elapsedTimeMilliseconds > = timeoutMilliseconds )
2024-06-10 06:09:51 +00:00
{
return false ;
}
2024-12-05 06:06:53 +00:00
DWORD newTimeout = static_cast < DWORD > ( timeoutMilliseconds - elapsedTimeMilliseconds ) ;
2024-06-10 06:09:51 +00:00
if ( ! WaitForSignal ( newTimeout ) )
{
return false ;
}
UINT64 currTime ;
QueryUnbiasedInterruptTime ( & currTime ) ;
elapsedTimeMilliseconds = ( currTime - startTime ) / static_cast < UINT64 > ( 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 ( ) ;
}
}
2024-12-05 06:06:53 +00:00
bool WaitForSignal ( DWORD timeoutMilliseconds ) WI_NOEXCEPT
2024-06-10 06:09:51 +00:00
{
LONG falseValue = FALSE ;
2024-12-05 06:06:53 +00:00
BOOL waitResult = WaitOnAddress ( & m_isSignaled , & falseValue , sizeof ( m_isSignaled ) , timeoutMilliseconds ) ;
2024-06-10 06:09:51 +00:00
__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 < SlimEventType : : AutoReset > ;
/** An event object that once signaled remains that way forever, unless `ResetEvent()` is called. */
using slim_event_manual_reset = slim_event_t < SlimEventType : : ManualReset > ;
/** An alias for `wil::slim_event_auto_reset`. */
using slim_event = slim_event_auto_reset ;
# endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
2024-12-05 06:06:53 +00:00
# endif // WIL_NO_SLIM_EVENT
2024-06-10 06:09:51 +00:00
typedef unique_any < HANDLE , decltype ( & details : : ReleaseMutex ) , details : : ReleaseMutex , details : : pointer_access_none > 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 < typename storage_t , typename err_policy = err_exception_policy >
class mutex_t : public storage_t
{
public :
// forward all base class constructors...
template < typename . . . args_t >
explicit mutex_t ( args_t & & . . . args ) WI_NOEXCEPT : storage_t ( wistd : : forward < args_t > ( 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 < void , result > : : 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 mutexAttributes = nullptr ,
_Out_opt_ bool * alreadyExists = nullptr )
{
auto handle = : : CreateMutexExW ( mutexAttributes , name , dwFlags , desiredAccess ) ;
if ( handle = = nullptr )
{
assign_to_opt_param ( alreadyExists , false ) ;
return false ;
}
assign_to_opt_param ( alreadyExists , ( : : GetLastError ( ) = = ERROR_ALREADY_EXISTS ) ) ;
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 mutexAttributes = nullptr ,
_Out_opt_ bool * alreadyExists = nullptr )
{
return err_policy : : LastErrorIfFalse ( try_create ( name , dwFlags , desiredAccess , mutexAttributes , alreadyExists ) ) ;
}
// 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 < mutex_t < details : : unique_storage < details : : handle_resource_policy > , err_returncode_policy > > unique_mutex_nothrow ;
typedef unique_any_t < mutex_t < details : : unique_storage < details : : handle_resource_policy > , err_failfast_policy > > unique_mutex_failfast ;
# ifdef WIL_ENABLE_EXCEPTIONS
typedef unique_any_t < mutex_t < details : : unique_storage < details : : handle_resource_policy > , err_exception_policy > > unique_mutex ;
# endif
typedef unique_any < HANDLE , decltype ( & details : : ReleaseSemaphore ) , details : : ReleaseSemaphore , details : : pointer_access_none > 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 < typename storage_t , typename err_policy = err_exception_policy >
class semaphore_t : public storage_t
{
public :
// forward all base class constructors...
template < typename . . . args_t >
explicit semaphore_t ( args_t & & . . . args ) WI_NOEXCEPT : storage_t ( wistd : : forward < args_t > ( 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 < void , result > : : 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 ,
_Out_opt_ bool * alreadyExists = nullptr )
{
auto handle = : : CreateSemaphoreExW ( pSemaphoreAttributes , lInitialCount , lMaximumCount , name , 0 , desiredAccess ) ;
if ( handle = = nullptr )
{
assign_to_opt_param ( alreadyExists , false ) ;
return false ;
}
assign_to_opt_param ( alreadyExists , ( : : GetLastError ( ) = = ERROR_ALREADY_EXISTS ) ) ;
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 ,
_Out_opt_ bool * alreadyExists = nullptr )
{
return err_policy : : LastErrorIfFalse (
try_create ( lInitialCount , lMaximumCount , name , desiredAccess , pSemaphoreAttributes , alreadyExists ) ) ;
}
// 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 < semaphore_t < details : : unique_storage < details : : handle_resource_policy > , err_returncode_policy > > unique_semaphore_nothrow ;
typedef unique_any_t < semaphore_t < details : : unique_storage < details : : handle_resource_policy > , err_failfast_policy > > unique_semaphore_failfast ;
# ifdef WIL_ENABLE_EXCEPTIONS
typedef unique_any_t < semaphore_t < details : : unique_storage < details : : handle_resource_policy > , err_exception_policy > > unique_semaphore ;
# endif
typedef unique_any < SRWLOCK * , decltype ( & : : ReleaseSRWLockExclusive ) , : : ReleaseSRWLockExclusive , details : : pointer_access_noaddress > rwlock_release_exclusive_scope_exit ;
typedef unique_any < SRWLOCK * , decltype ( & : : ReleaseSRWLockShared ) , : : ReleaseSRWLockShared , details : : pointer_access_noaddress > 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 < CRITICAL_SECTION * , decltype ( & : : LeaveCriticalSection ) , : : LeaveCriticalSection , details : : pointer_access_noaddress > 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 < typename string_class >
struct string_allocator
{
static void * allocate ( size_t /*size*/ ) WI_NOEXCEPT
{
static_assert (
! wistd : : is_same < string_class , string_class > : : value ,
" This type did not provide a string_allocator, add a specialization of string_allocator to support your type. " ) ;
return nullptr ;
}
} ;
} // namespace details
/// @endcond
// This string helper does not support the ansi wil string helpers
template < typename string_type >
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 < wil : : unique_cotaskmem_string > ( 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 < unique_hlocal_string > ( 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 < typename string_type >
string_type make_unique_string_nothrow (
_When_ ( ( source ! = nullptr ) & & length ! = static_cast < size_t > ( - 1 ) , _In_reads_ ( length ) )
_When_ ( ( source ! = nullptr ) & & length = = static_cast < size_t > ( - 1 ) , _In_z_ ) const wchar_t * source ,
size_t length = static_cast < size_t > ( - 1 ) ) WI_NOEXCEPT
{
// guard against invalid parameters (null source with -1 length)
FAIL_FAST_IF ( ! source & & ( length = = static_cast < size_t > ( - 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 < size_t > ( - 1 ) )
{
length = lengthToCopy ;
}
const size_t allocatedBytes = ( length + 1 ) * sizeof ( * source ) ;
auto result = static_cast < PWSTR > ( details : : string_allocator < string_type > : : 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 < typename string_type >
string_type make_unique_ansistring_nothrow (
_When_ ( ( source ! = nullptr ) & & length ! = static_cast < size_t > ( - 1 ) , _In_reads_ ( length ) )
_When_ ( ( source ! = nullptr ) & & length = = static_cast < size_t > ( - 1 ) , _In_z_ ) PCSTR source ,
size_t length = static_cast < size_t > ( - 1 ) ) WI_NOEXCEPT
{
if ( length = = static_cast < size_t > ( - 1 ) )
{
// guard against invalid parameters (null source with -1 length)
FAIL_FAST_IF ( ! source ) ;
length = strlen ( source ) ;
}
const size_t cb = ( length + 1 ) * sizeof ( * source ) ;
auto result = static_cast < PSTR > ( details : : string_allocator < string_type > : : 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 < typename string_type >
string_type make_unique_string_failfast (
_When_ ( ( source ! = nullptr ) & & length ! = static_cast < size_t > ( - 1 ) , _In_reads_ ( length ) )
_When_ ( ( source ! = nullptr ) & & length = = static_cast < size_t > ( - 1 ) , _In_z_ ) PCWSTR source ,
size_t length = static_cast < size_t > ( - 1 ) ) WI_NOEXCEPT
{
auto result ( make_unique_string_nothrow < string_type > ( source , length ) ) ;
FAIL_FAST_IF_NULL_ALLOC ( result ) ;
return result ;
}
# ifndef WIL_NO_ANSI_STRINGS
template < typename string_type >
string_type make_unique_ansistring_failfast (
_When_ ( ( source ! = nullptr ) & & length ! = static_cast < size_t > ( - 1 ) , _In_reads_ ( length ) )
_When_ ( ( source ! = nullptr ) & & length = = static_cast < size_t > ( - 1 ) , _In_z_ ) PCSTR source ,
size_t length = static_cast < size_t > ( - 1 ) ) WI_NOEXCEPT
{
auto result ( make_unique_ansistring_nothrow < string_type > ( 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 < typename string_type >
string_type make_unique_string (
_When_ ( ( source ! = nullptr ) & & length ! = static_cast < size_t > ( - 1 ) , _In_reads_ ( length ) )
_When_ ( ( source ! = nullptr ) & & length = = static_cast < size_t > ( - 1 ) , _In_z_ ) PCWSTR source ,
size_t length = static_cast < size_t > ( - 1 ) )
{
auto result ( make_unique_string_nothrow < string_type > ( source , length ) ) ;
THROW_IF_NULL_ALLOC ( result ) ;
return result ;
}
# ifndef WIL_NO_ANSI_STRINGS
template < typename string_type >
string_type make_unique_ansistring (
_When_ ( ( source ! = nullptr ) & & length ! = static_cast < size_t > ( - 1 ) , _In_reads_ ( length ) )
_When_ ( ( source ! = nullptr ) & & length = = static_cast < size_t > ( - 1 ) , _In_z_ ) PCSTR source ,
size_t length = static_cast < size_t > ( - 1 ) )
{
auto result ( make_unique_ansistring_nothrow < string_type > ( 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 < typename string_type >
struct string_maker
{
HRESULT make (
_When_ ( ( source ! = nullptr ) & & length ! = static_cast < size_t > ( - 1 ) , _In_reads_ ( length ) )
_When_ ( ( source ! = nullptr ) & & length = = static_cast < size_t > ( - 1 ) , _In_z_ ) const wchar_t * source ,
size_t length )
{
m_value = make_unique_string_nothrow < string_type > ( source , length ) ;
return m_value ? S_OK : E_OUTOFMEMORY ;
}
wchar_t * buffer ( )
{
WI_ASSERT ( m_value . get ( ) ) ;
return m_value . get ( ) ;
}
// By default, assume string_type is a null-terminated string and therefore does not require trimming.
HRESULT trim_at_existing_null ( size_t /* length */ )
{
return S_OK ;
}
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_ ;
}
WI_NODISCARD operator void * ( ) const WI_NOEXCEPT
{
return pointer ;
}
static void Close ( SecureZeroData data ) WI_NOEXCEPT
{
: : SecureZeroMemory ( data . pointer , data . sizeBytes ) ;
}
} ;
} // namespace details
/// @endcond
typedef unique_any < void * , decltype ( & details : : SecureZeroData : : Close ) , details : : SecureZeroData : : Close , details : : pointer_access_all , details : : SecureZeroData > 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 < void * > ( 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 ) ;
}
} // namespace details
/// @endcond
struct process_heap_deleter
{
template < typename T >
void operator ( ) ( _Pre_valid_ _Frees_ptr_ T * p ) const
{
details : : FreeProcessHeap ( p ) ;
}
} ;
struct virtualalloc_deleter
{
template < typename T >
void operator ( ) ( _Pre_valid_ _Frees_ptr_ T * p ) const
{
: : VirtualFree ( p , 0 , MEM_RELEASE ) ;
}
} ;
struct mapview_deleter
{
template < typename T >
void operator ( ) ( _Pre_valid_ _Frees_ptr_ T * p ) const
{
: : UnmapViewOfFile ( p ) ;
}
} ;
template < typename T = void >
using unique_process_heap_ptr = wistd : : unique_ptr < details : : ensure_trivially_destructible_t < T > , process_heap_deleter > ;
typedef unique_any < PWSTR , decltype ( & details : : FreeProcessHeap ) , details : : FreeProcessHeap > unique_process_heap_string ;
/// @cond
namespace details
{
template < >
struct string_allocator < unique_process_heap_string >
{
static _Ret_opt_bytecap_ ( size ) void * allocate ( size_t size ) WI_NOEXCEPT
{
return : : HeapAlloc ( : : GetProcessHeap ( ) , HEAP_ZERO_MEMORY , size ) ;
}
} ;
} // namespace details
/// @endcond
/** Manages a typed pointer allocated with VirtualAlloc
A specialization of wistd : : unique_ptr < > that frees via VirtualFree ( p , 0 , MEM_RELEASE ) .
*/
template < typename T = void >
using unique_virtualalloc_ptr = wistd : : unique_ptr < details : : ensure_trivially_destructible_t < T > , virtualalloc_deleter > ;
/** Manages a typed pointer allocated with MapViewOfFile
A specialization of wistd : : unique_ptr < > that frees via UnmapViewOfFile ( p ) .
*/
template < typename T = void >
using unique_mapview_ptr = wistd : : unique_ptr < details : : ensure_trivially_destructible_t < T > , mapview_deleter > ;
# endif // __WIL_WINBASE_
# if (defined(__WIL_WINBASE_) && defined(__NOTHROW_T_DEFINED) && !defined(__WIL_WINBASE_NOTHROW_T_DEFINED)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_WINBASE_NOTHROW_T_DEFINED
/// @endcond
// unique_event_watcher, unique_event_watcher_nothrow, unique_event_watcher_failfast
//
// Clients must include <new> or <new.h> 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 < void ( ) > & & callback ) :
m_callback ( wistd : : move ( callback ) ) , m_event ( wistd : : move ( eventHandle ) )
{
}
wistd : : function < void ( ) > 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 * , decltype ( & delete_event_watcher_state ) , delete_event_watcher_state , details : : pointer_access_none > event_watcher_state_resource_policy ;
} // namespace details
/// @endcond
template < typename storage_t , typename err_policy = err_exception_policy >
class event_watcher_t : public storage_t
{
public :
// forward all base class constructors...
template < typename . . . args_t >
explicit event_watcher_t ( args_t & & . . . args ) WI_NOEXCEPT : storage_t ( wistd : : forward < args_t > ( args ) . . . )
{
}
// HRESULT or void error handling...
typedef typename err_policy : : result result ;
// Exception-based constructors
template < typename from_err_policy >
event_watcher_t (
unique_any_t < event_t < details : : unique_storage < details : : handle_resource_policy > , from_err_policy > > & & eventHandle ,
wistd : : function < void ( ) > & & callback )
{
static_assert ( wistd : : is_same < void , result > : : 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 < void ( ) > & & callback )
{
static_assert ( wistd : : is_same < void , result > : : value , " this constructor requires exceptions or fail fast; use the create method " ) ;
create ( eventHandle , wistd : : move ( callback ) ) ;
}
event_watcher_t ( wistd : : function < void ( ) > & & callback )
{
static_assert ( wistd : : is_same < void , result > : : value , " this constructor requires exceptions or fail fast; use the create method " ) ;
create ( wistd : : move ( callback ) ) ;
}
template < typename event_err_policy >
result create (
unique_any_t < event_t < details : : unique_storage < details : : handle_resource_policy > , event_err_policy > > & & eventHandle ,
wistd : : function < void ( ) > & & 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 < void ( ) > & & 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 < void ( ) > & & 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.
WI_NODISCARD 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 < details : : event_watcher_state * > ( 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 < void ( ) > & & callback )
{
__FAIL_FAST_ASSERT__ ( rawHandleOwnershipTaken ! = nullptr ) ; // invalid parameter
unique_event_nothrow eventHandle ( rawHandleOwnershipTaken ) ;
wistd : : unique_ptr < details : : event_watcher_state > 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 < event_watcher_t < details : : unique_storage < details : : event_watcher_state_resource_policy > , err_returncode_policy > > unique_event_watcher_nothrow ;
typedef unique_any_t < event_watcher_t < details : : unique_storage < details : : event_watcher_state_resource_policy > , err_failfast_policy > > unique_event_watcher_failfast ;
template < typename err_policy >
unique_event_watcher_nothrow make_event_watcher_nothrow (
unique_any_t < event_t < details : : unique_storage < details : : handle_resource_policy > , err_policy > > & & eventHandle ,
wistd : : function < void ( ) > & & 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 < void ( ) > & & 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 < void ( ) > & & callback ) WI_NOEXCEPT
{
unique_event_watcher_nothrow watcher ;
watcher . create ( wistd : : move ( callback ) ) ;
return watcher ; // caller must test for success using if (watcher)
}
template < typename err_policy >
unique_event_watcher_failfast make_event_watcher_failfast (
unique_any_t < event_t < details : : unique_storage < details : : handle_resource_policy > , err_policy > > & & eventHandle ,
wistd : : function < void ( ) > & & 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 < void ( ) > & & callback )
{
return unique_event_watcher_failfast ( eventHandle , wistd : : move ( callback ) ) ;
}
inline unique_event_watcher_failfast make_event_watcher_failfast ( wistd : : function < void ( ) > & & callback )
{
return unique_event_watcher_failfast ( wistd : : move ( callback ) ) ;
}
# ifdef WIL_ENABLE_EXCEPTIONS
typedef unique_any_t < event_watcher_t < details : : unique_storage < details : : event_watcher_state_resource_policy > , err_exception_policy > > unique_event_watcher ;
template < typename err_policy >
unique_event_watcher make_event_watcher (
unique_any_t < event_t < details : : unique_storage < details : : handle_resource_policy > , err_policy > > & & eventHandle ,
wistd : : function < void ( ) > & & callback )
{
return unique_event_watcher ( wistd : : move ( eventHandle ) , wistd : : move ( callback ) ) ;
}
inline unique_event_watcher make_event_watcher ( _In_ HANDLE eventHandle , wistd : : function < void ( ) > & & callback )
{
return unique_event_watcher ( eventHandle , wistd : : move ( callback ) ) ;
}
inline unique_event_watcher make_event_watcher ( wistd : : function < void ( ) > & & 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)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_WINBASE_STL
/// @endcond
typedef shared_any_t < event_t < details : : shared_storage < unique_event > > > shared_event ;
typedef shared_any_t < mutex_t < details : : shared_storage < unique_mutex > > > shared_mutex ;
typedef shared_any_t < semaphore_t < details : : shared_storage < unique_semaphore > > > shared_semaphore ;
typedef shared_any < unique_hfile > shared_hfile ;
typedef shared_any < unique_handle > shared_handle ;
typedef shared_any < unique_hfind > shared_hfind ;
typedef shared_any < unique_hmodule > shared_hmodule ;
# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
typedef shared_any < unique_threadpool_wait > shared_threadpool_wait ;
typedef shared_any < unique_threadpool_wait_nocancel > shared_threadpool_wait_nocancel ;
typedef shared_any < unique_threadpool_work > shared_threadpool_work ;
typedef shared_any < unique_threadpool_work_nocancel > shared_threadpool_work_nocancel ;
typedef shared_any < unique_hfind_change > shared_hfind_change ;
# endif
typedef weak_any < shared_event > weak_event ;
typedef weak_any < shared_mutex > weak_mutex ;
typedef weak_any < shared_semaphore > weak_semaphore ;
typedef weak_any < shared_hfile > weak_hfile ;
typedef weak_any < shared_handle > weak_handle ;
typedef weak_any < shared_hfind > weak_hfind ;
typedef weak_any < shared_hmodule > weak_hmodule ;
# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
typedef weak_any < shared_threadpool_wait > weak_threadpool_wait ;
typedef weak_any < shared_threadpool_wait_nocancel > weak_threadpool_wait_nocancel ;
typedef weak_any < shared_threadpool_work > weak_threadpool_work ;
typedef weak_any < shared_threadpool_work_nocancel > weak_threadpool_work_nocancel ;
typedef weak_any < shared_hfind_change > 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)) || \
defined ( WIL_DOXYGEN )
/// @cond
# define __WIL_WINBASE_NOTHROW_T_DEFINED_STL
/// @endcond
typedef shared_any_t < event_watcher_t < details : : shared_storage < unique_event_watcher > > > shared_event_watcher ;
typedef weak_any < shared_event_watcher > weak_event_watcher ;
# endif // __WIL_WINBASE_NOTHROW_T_DEFINED_STL
# if (defined(__WIL_WINBASE_) && !defined(__WIL_WINBASE_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || \
defined ( WIL_DOXYGEN )
/// @cond
# define __WIL_WINBASE_DESKTOP
namespace details
{
inline void __stdcall DestroyPrivateObjectSecurity ( _Pre_opt_valid_ _Frees_ptr_opt_ PSECURITY_DESCRIPTOR pObjectDescriptor ) WI_NOEXCEPT
{
: : DestroyPrivateObjectSecurity ( & pObjectDescriptor ) ;
}
} // namespace details
/// @endcond
using hlocal_deleter = function_deleter < decltype ( & : : LocalFree ) , LocalFree > ;
template < typename T = void >
using unique_hlocal_ptr = wistd : : unique_ptr < details : : ensure_trivially_destructible_t < T > , hlocal_deleter > ;
template < typename T >
using unique_hlocal_array_ptr = wil : : unique_array_ptr < T , wil : : hlocal_deleter > ;
/** 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 .
@ code
auto foo = wil : : make_unique_hlocal_nothrow < Foo > ( ) ;
if ( foo )
{
// initialize allocated Foo object as appropriate
}
@ endcode
*/
template < typename T , typename . . . Args >
inline typename wistd : : enable_if < ! wistd : : is_array < T > : : value , unique_hlocal_ptr < T > > : : type make_unique_hlocal_nothrow ( Args & & . . . args )
{
unique_hlocal_ptr < T > sp ( static_cast < T * > ( : : LocalAlloc ( LMEM_FIXED , sizeof ( T ) ) ) ) ;
if ( sp )
{
// use placement new to initialize memory from the previous allocation
new ( sp . get ( ) ) T ( wistd : : forward < Args > ( 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 .
@ code
const size_t size = 42 ;
auto foos = wil : : make_unique_hlocal_nothrow < Foo [ ] > ( size ) ;
if ( foos )
{
for ( auto & elem : wil : : make_range ( foos . get ( ) , size ) )
{
// initialize allocated Foo objects as appropriate
}
}
@ endcode
*/
template < typename T >
inline typename wistd : : enable_if < wistd : : is_array < T > : : value & & wistd : : extent < T > : : value = = 0 , unique_hlocal_ptr < T > > : : type make_unique_hlocal_nothrow (
size_t size )
{
typedef typename wistd : : remove_extent < T > : : type E ;
FAIL_FAST_IF ( ( __WI_SIZE_MAX / sizeof ( E ) ) < size ) ;
size_t allocSize = sizeof ( E ) * size ;
unique_hlocal_ptr < T > sp ( static_cast < E * > ( : : 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 < E * > ( 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 .
@ code
auto foo = wil : : make_unique_hlocal_failfast < Foo > ( ) ;
// initialize allocated Foo object as appropriate
@ endcode
*/
template < typename T , typename . . . Args >
inline typename wistd : : enable_if < ! wistd : : is_array < T > : : value , unique_hlocal_ptr < T > > : : type make_unique_hlocal_failfast ( Args & & . . . args )
{
unique_hlocal_ptr < T > result ( make_unique_hlocal_nothrow < T > ( wistd : : forward < Args > ( 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 .
@ code
const size_t size = 42 ;
auto foos = wil : : make_unique_hlocal_failfast < Foo [ ] > ( size ) ;
for ( auto & elem : wil : : make_range ( foos . get ( ) , size ) )
{
// initialize allocated Foo objects as appropriate
}
@ endcode
*/
template < typename T >
inline typename wistd : : enable_if < wistd : : is_array < T > : : value & & wistd : : extent < T > : : value = = 0 , unique_hlocal_ptr < T > > : : type make_unique_hlocal_failfast (
size_t size )
{
unique_hlocal_ptr < T > result ( make_unique_hlocal_nothrow < T > ( 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 .
@ code
auto foo = wil : : make_unique_hlocal < Foo > ( ) ;
// initialize allocated Foo object as appropriate
@ endcode
*/
template < typename T , typename . . . Args >
inline typename wistd : : enable_if < ! wistd : : is_array < T > : : value , unique_hlocal_ptr < T > > : : type make_unique_hlocal ( Args & & . . . args )
{
unique_hlocal_ptr < T > result ( make_unique_hlocal_nothrow < T > ( wistd : : forward < Args > ( 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 .
@ code
const size_t size = 42 ;
auto foos = wil : : make_unique_hlocal < Foo [ ] > ( size ) ;
for ( auto & elem : wil : : make_range ( foos . get ( ) , size ) )
{
// initialize allocated Foo objects as appropriate
}
@ endcode
*/
template < typename T >
inline typename wistd : : enable_if < wistd : : is_array < T > : : value & & wistd : : extent < T > : : value = = 0 , unique_hlocal_ptr < T > > : : type make_unique_hlocal ( size_t size )
{
unique_hlocal_ptr < T > result ( make_unique_hlocal_nothrow < T > ( size ) ) ;
THROW_IF_NULL_ALLOC ( result ) ;
return result ;
}
# endif // WIL_ENABLE_EXCEPTIONS
typedef unique_any < HLOCAL , decltype ( & : : LocalFree ) , : : LocalFree > unique_hlocal ;
typedef unique_any < PWSTR , decltype ( & : : LocalFree ) , : : LocalFree > unique_hlocal_string ;
# ifndef WIL_NO_ANSI_STRINGS
typedef unique_any < PSTR , decltype ( & : : LocalFree ) , : : LocalFree > 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 < unique_hlocal_string > : localalloc_allocator
{
} ;
# ifndef WIL_NO_ANSI_STRINGS
template < >
struct string_allocator < unique_hlocal_ansistring > : localalloc_allocator
{
} ;
# endif // WIL_NO_ANSI_STRINGS
} // namespace details
/// @endcond
inline auto make_hlocal_string_nothrow (
_When_ ( ( source ! = nullptr ) & & length ! = static_cast < size_t > ( - 1 ) , _In_reads_ ( length ) )
_When_ ( ( source ! = nullptr ) & & length = = static_cast < size_t > ( - 1 ) , _In_z_ ) PCWSTR source ,
size_t length = static_cast < size_t > ( - 1 ) ) WI_NOEXCEPT
{
return make_unique_string_nothrow < unique_hlocal_string > ( source , length ) ;
}
inline auto make_hlocal_string_failfast (
_When_ ( ( source ! = nullptr ) & & length ! = static_cast < size_t > ( - 1 ) , _In_reads_ ( length ) )
_When_ ( ( source ! = nullptr ) & & length = = static_cast < size_t > ( - 1 ) , _In_z_ ) PCWSTR source ,
size_t length = static_cast < size_t > ( - 1 ) ) WI_NOEXCEPT
{
return make_unique_string_failfast < unique_hlocal_string > ( source , length ) ;
}
# ifndef WIL_NO_ANSI_STRINGS
inline auto make_hlocal_ansistring_nothrow (
_When_ ( ( source ! = nullptr ) & & length ! = static_cast < size_t > ( - 1 ) , _In_reads_ ( length ) )
_When_ ( ( source ! = nullptr ) & & length = = static_cast < size_t > ( - 1 ) , _In_z_ ) PCSTR source ,
size_t length = static_cast < size_t > ( - 1 ) ) WI_NOEXCEPT
{
return make_unique_ansistring_nothrow < unique_hlocal_ansistring > ( source , length ) ;
}
inline auto make_hlocal_ansistring_failfast (
_When_ ( ( source ! = nullptr ) & & length ! = static_cast < size_t > ( - 1 ) , _In_reads_ ( length ) )
_When_ ( ( source ! = nullptr ) & & length = = static_cast < size_t > ( - 1 ) , _In_z_ ) PCSTR source ,
size_t length = static_cast < size_t > ( - 1 ) ) WI_NOEXCEPT
{
return make_unique_ansistring_failfast < unique_hlocal_ansistring > ( source , length ) ;
}
# endif
# ifdef WIL_ENABLE_EXCEPTIONS
inline auto make_hlocal_string (
_When_ ( ( source ! = nullptr ) & & length ! = static_cast < size_t > ( - 1 ) , _In_reads_ ( length ) )
_When_ ( ( source ! = nullptr ) & & length = = static_cast < size_t > ( - 1 ) , _In_z_ ) PCWSTR source ,
size_t length = static_cast < size_t > ( - 1 ) )
{
return make_unique_string < unique_hlocal_string > ( source , length ) ;
}
# ifndef WIL_NO_ANSI_STRINGS
inline auto make_hlocal_ansistring (
_When_ ( ( source ! = nullptr ) & & length ! = static_cast < size_t > ( - 1 ) , _In_reads_ ( length ) )
_When_ ( ( source ! = nullptr ) & & length = = static_cast < size_t > ( - 1 ) , _In_z_ ) PCSTR source ,
size_t length = static_cast < size_t > ( - 1 ) )
{
return make_unique_ansistring < unique_hlocal_ansistring > ( source , length ) ;
}
# endif // WIL_NO_ANSI_STRINGS
# endif // WIL_ENABLE_EXCEPTIONS
struct hlocal_secure_deleter
{
template < typename T >
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 < typename T = void >
using unique_hlocal_secure_ptr = wistd : : unique_ptr < details : : ensure_trivially_destructible_t < T > , hlocal_secure_deleter > ;
/** 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 .
@ code
auto foo = wil : : make_unique_hlocal_secure_nothrow < Foo > ( ) ;
if ( foo )
{
// initialize allocated Foo object as appropriate
}
@ endcode
*/
template < typename T , typename . . . Args >
inline typename wistd : : enable_if < ! wistd : : is_array < T > : : value , unique_hlocal_secure_ptr < T > > : : type make_unique_hlocal_secure_nothrow ( Args & & . . . args )
{
return unique_hlocal_secure_ptr < T > ( make_unique_hlocal_nothrow < T > ( wistd : : forward < Args > ( 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 .
@ code
const size_t size = 42 ;
auto foos = wil : : make_unique_hlocal_secure_nothrow < Foo [ ] > ( size ) ;
if ( foos )
{
for ( auto & elem : wil : : make_range ( foos . get ( ) , size ) )
{
// initialize allocated Foo objects as appropriate
}
}
@ endcode
*/
template < typename T >
inline typename wistd : : enable_if < wistd : : is_array < T > : : value & & wistd : : extent < T > : : value = = 0 , unique_hlocal_secure_ptr < T > > : : type make_unique_hlocal_secure_nothrow (
size_t size )
{
return unique_hlocal_secure_ptr < T > ( make_unique_hlocal_nothrow < T > ( 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 .
@ code
auto foo = wil : : make_unique_hlocal_secure_failfast < Foo > ( ) ;
// initialize allocated Foo object as appropriate
@ endcode
*/
template < typename T , typename . . . Args >
inline typename wistd : : enable_if < ! wistd : : is_array < T > : : value , unique_hlocal_secure_ptr < T > > : : type make_unique_hlocal_secure_failfast ( Args & & . . . args )
{
unique_hlocal_secure_ptr < T > result ( make_unique_hlocal_secure_nothrow < T > ( wistd : : forward < Args > ( 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 .
@ code
const size_t size = 42 ;
auto foos = wil : : make_unique_hlocal_secure_failfast < Foo [ ] > ( size ) ;
for ( auto & elem : wil : : make_range ( foos . get ( ) , size ) )
{
// initialize allocated Foo objects as appropriate
}
@ endcode
*/
template < typename T >
inline typename wistd : : enable_if < wistd : : is_array < T > : : value & & wistd : : extent < T > : : value = = 0 , unique_hlocal_secure_ptr < T > > : : type make_unique_hlocal_secure_failfast (
size_t size )
{
unique_hlocal_secure_ptr < T > result ( make_unique_hlocal_secure_nothrow < T > ( 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 .
@ code
auto foo = wil : : make_unique_hlocal_secure < Foo > ( ) ;
// initialize allocated Foo object as appropriate
@ endcode
*/
template < typename T , typename . . . Args >
inline typename wistd : : enable_if < ! wistd : : is_array < T > : : value , unique_hlocal_secure_ptr < T > > : : type make_unique_hlocal_secure ( Args & & . . . args )
{
unique_hlocal_secure_ptr < T > result ( make_unique_hlocal_secure_nothrow < T > ( wistd : : forward < Args > ( 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 .
@ code
const size_t size = 42 ;
auto foos = wil : : make_unique_hlocal_secure < Foo [ ] > ( size ) ;
for ( auto & elem : wil : : make_range ( foos . get ( ) , size ) )
{
// initialize allocated Foo objects as appropriate
}
@ endcode
*/
template < typename T >
inline typename wistd : : enable_if < wistd : : is_array < T > : : value & & wistd : : extent < T > : : value = = 0 , unique_hlocal_secure_ptr < T > > : : type make_unique_hlocal_secure (
size_t size )
{
unique_hlocal_secure_ptr < T > result ( make_unique_hlocal_secure_nothrow < T > ( size ) ) ;
THROW_IF_NULL_ALLOC ( result ) ;
return result ;
}
# endif // WIL_ENABLE_EXCEPTIONS
typedef unique_hlocal_secure_ptr < wchar_t [ ] > 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 < decltype ( & : : GlobalFree ) , : : GlobalFree > ;
template < typename T = void >
using unique_hglobal_ptr = wistd : : unique_ptr < details : : ensure_trivially_destructible_t < T > , hglobal_deleter > ;
typedef unique_any < HGLOBAL , decltype ( & : : GlobalFree ) , : : GlobalFree > unique_hglobal ;
typedef unique_any < PWSTR , decltype ( & : : GlobalFree ) , : : GlobalFree > unique_hglobal_string ;
# ifndef WIL_NO_ANSI_STRINGS
typedef unique_any < PSTR , decltype ( & : : GlobalFree ) , : : GlobalFree > unique_hglobal_ansistring ;
# endif // WIL_NO_ANSI_STRINGS
/// @cond
namespace details
{
template < >
struct string_allocator < unique_hglobal_string >
{
static _Ret_opt_bytecap_ ( size ) void * allocate ( size_t size ) WI_NOEXCEPT
{
return : : GlobalAlloc ( GPTR , size ) ;
}
} ;
} // namespace details
/// @endcond
inline auto make_process_heap_string_nothrow (
_When_ ( ( source ! = nullptr ) & & length ! = static_cast < size_t > ( - 1 ) , _In_reads_ ( length ) )
_When_ ( ( source ! = nullptr ) & & length = = static_cast < size_t > ( - 1 ) , _In_z_ ) PCWSTR source ,
size_t length = static_cast < size_t > ( - 1 ) ) WI_NOEXCEPT
{
return make_unique_string_nothrow < unique_process_heap_string > ( source , length ) ;
}
inline auto make_process_heap_string_failfast (
_When_ ( ( source ! = nullptr ) & & length ! = static_cast < size_t > ( - 1 ) , _In_reads_ ( length ) )
_When_ ( ( source ! = nullptr ) & & length = = static_cast < size_t > ( - 1 ) , _In_z_ ) PCWSTR source ,
size_t length = static_cast < size_t > ( - 1 ) ) WI_NOEXCEPT
{
return make_unique_string_failfast < unique_process_heap_string > ( source , length ) ;
}
# ifdef WIL_ENABLE_EXCEPTIONS
inline auto make_process_heap_string (
_When_ ( ( source ! = nullptr ) & & length ! = static_cast < size_t > ( - 1 ) , _In_reads_ ( length ) )
_When_ ( ( source ! = nullptr ) & & length = = static_cast < size_t > ( - 1 ) , _In_z_ ) PCWSTR source ,
size_t length = static_cast < size_t > ( - 1 ) )
{
return make_unique_string < unique_process_heap_string > ( source , length ) ;
}
# endif // WIL_ENABLE_EXCEPTIONS
typedef unique_any_handle_null < decltype ( & : : HeapDestroy ) , : : HeapDestroy > unique_hheap ;
typedef unique_any < DWORD , decltype ( & : : TlsFree ) , : : TlsFree , details : : pointer_access_all , DWORD , DWORD , TLS_OUT_OF_INDEXES , DWORD > unique_tls ;
typedef unique_any < PSECURITY_DESCRIPTOR , decltype ( & : : LocalFree ) , : : LocalFree > unique_hlocal_security_descriptor ;
typedef unique_any < PSECURITY_DESCRIPTOR , decltype ( & details : : DestroyPrivateObjectSecurity ) , details : : DestroyPrivateObjectSecurity > unique_private_security_descriptor ;
# if (defined(_WINUSER_) && !defined(__WIL__WINUSER_)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL__WINUSER_
/// @endcond
typedef unique_any < HACCEL , decltype ( & : : DestroyAcceleratorTable ) , : : DestroyAcceleratorTable > unique_haccel ;
typedef unique_any < HCURSOR , decltype ( & : : DestroyCursor ) , : : DestroyCursor > unique_hcursor ;
typedef unique_any < HWND , decltype ( & : : DestroyWindow ) , : : DestroyWindow > unique_hwnd ;
# if !defined(NOUSER) && !defined(NOWH)
typedef unique_any < HHOOK , decltype ( & : : UnhookWindowsHookEx ) , : : UnhookWindowsHookEx > unique_hhook ;
# endif
# if !defined(NOWINABLE)
typedef unique_any < HWINEVENTHOOK , decltype ( & : : UnhookWinEvent ) , : : UnhookWinEvent > unique_hwineventhook ;
# endif
# if !defined(NOCLIPBOARD)
using unique_close_clipboard_call = unique_call < decltype ( : : CloseClipboard ) , & : : CloseClipboard > ;
inline unique_close_clipboard_call open_clipboard ( HWND hwnd )
{
return unique_close_clipboard_call { OpenClipboard ( hwnd ) ! = FALSE } ;
}
# endif
# endif // __WIL__WINUSER_
# if !defined(NOGDI) && !defined(NODESKTOP)
typedef unique_any < HDESK , decltype ( & : : CloseDesktop ) , : : CloseDesktop > unique_hdesk ;
typedef unique_any < HWINSTA , decltype ( & : : CloseWindowStation ) , : : CloseWindowStation > unique_hwinsta ;
# endif // !defined(NOGDI) && !defined(NODESKTOP)
# endif
# if (defined(__WIL_WINBASE_DESKTOP) && !defined(__WIL_WINBASE_DESKTOP_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_WINBASE_DESKTOP_STL
/// @endcond
typedef shared_any < unique_hheap > shared_hheap ;
typedef shared_any < unique_hlocal > shared_hlocal ;
typedef shared_any < unique_tls > shared_tls ;
typedef shared_any < unique_hlocal_security_descriptor > shared_hlocal_security_descriptor ;
typedef shared_any < unique_private_security_descriptor > shared_private_security_descriptor ;
typedef shared_any < unique_haccel > shared_haccel ;
typedef shared_any < unique_hcursor > shared_hcursor ;
# if !defined(NOGDI) && !defined(NODESKTOP)
typedef shared_any < unique_hdesk > shared_hdesk ;
typedef shared_any < unique_hwinsta > shared_hwinsta ;
# endif // !defined(NOGDI) && !defined(NODESKTOP)
typedef shared_any < unique_hwnd > shared_hwnd ;
# if !defined(NOUSER) && !defined(NOWH)
typedef shared_any < unique_hhook > shared_hhook ;
# endif
# if !defined(NOWINABLE)
typedef shared_any < unique_hwineventhook > shared_hwineventhook ;
# endif
typedef weak_any < shared_hheap > weak_hheap ;
typedef weak_any < shared_hlocal > weak_hlocal ;
typedef weak_any < shared_tls > weak_tls ;
typedef weak_any < shared_hlocal_security_descriptor > weak_hlocal_security_descriptor ;
typedef weak_any < shared_private_security_descriptor > weak_private_security_descriptor ;
typedef weak_any < shared_haccel > weak_haccel ;
typedef weak_any < shared_hcursor > weak_hcursor ;
# if !defined(NOGDI) && !defined(NODESKTOP)
typedef weak_any < shared_hdesk > weak_hdesk ;
typedef weak_any < shared_hwinsta > weak_hwinsta ;
# endif // !defined(NOGDI) && !defined(NODESKTOP)
typedef weak_any < shared_hwnd > weak_hwnd ;
# if !defined(NOUSER) && !defined(NOWH)
typedef weak_any < shared_hhook > weak_hhook ;
# endif
# if !defined(NOWINABLE)
typedef weak_any < shared_hwineventhook > 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)) || \
defined ( WIL_DOXYGEN )
/// @cond
# define __WIL__COMBASEAPI_H_
/// @endcond
# if (NTDDI_VERSION >= NTDDI_WIN8)
typedef unique_any < CO_MTA_USAGE_COOKIE , decltype ( & : : CoDecrementMTAUsage ) , : : CoDecrementMTAUsage > unique_mta_usage_cookie ;
# endif
typedef unique_any < DWORD , decltype ( & : : CoRevokeClassObject ) , : : CoRevokeClassObject > 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 ;
}
}
} // namespace details
/// @endcond
//! A type that calls CoRevertToSelf on destruction (or reset()).
using unique_coreverttoself_call = unique_call < decltype ( & : : CoRevertToSelf ) , : : CoRevertToSelf > ;
//! 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 ( ) ;
}
# ifdef WIL_ENABLE_EXCEPTIONS
WI_NODISCARD inline unique_coreverttoself_call CoImpersonateClient ( )
{
THROW_IF_FAILED ( : : CoImpersonateClient ( ) ) ;
return unique_coreverttoself_call ( ) ;
}
# endif
typedef unique_struct < MULTI_QI , decltype ( & details : : MultiQiCleanup ) , details : : MultiQiCleanup > unique_multi_qi ;
# endif // __WIL__COMBASEAPI_H_
# if (defined(__WIL__COMBASEAPI_H_) && !defined(__WIL__COMBASEAPI_H__STL) && defined(WIL_RESOURCE_STL) && (NTDDI_VERSION >= NTDDI_WIN8)) || \
defined ( WIL_DOXYGEN )
/// @cond
# define __WIL__COMBASEAPI_H__STL
/// @endcond
typedef shared_any < unique_mta_usage_cookie > shared_mta_usage_cookie ;
typedef weak_any < shared_mta_usage_cookie > 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)) || \
defined ( WIL_DOXYGEN )
/// @cond
# define __WIL__COMBASEAPI_H_APP
/// @endcond
//! A type that calls CoUninitialize on destruction (or reset()).
using unique_couninitialize_call = unique_call < decltype ( & : : CoUninitialize ) , : : CoUninitialize > ;
//! 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 { } ;
}
# ifdef WIL_ENABLE_EXCEPTIONS
WI_NODISCARD inline unique_couninitialize_call CoInitializeEx ( DWORD coinitFlags = 0 /*COINIT_MULTITHREADED*/ )
{
THROW_IF_FAILED ( : : CoInitializeEx ( nullptr , coinitFlags ) ) ;
return { } ;
}
# endif
# endif // __WIL__COMBASEAPI_H_APP
# if (defined(__ROAPI_H_) && !defined(__WIL__ROAPI_H_APP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) && (NTDDI_VERSION >= NTDDI_WIN8)) || \
defined ( WIL_DOXYGEN )
/// @cond
# define __WIL__ROAPI_H_APP
/// @endcond
typedef unique_any < RO_REGISTRATION_COOKIE , decltype ( & : : RoRevokeActivationFactories ) , : : RoRevokeActivationFactories > 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 < decltype ( & : : RoUninitialize ) , : : RoUninitialize > ;
//! 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 ( ) ;
}
# ifdef WIL_ENABLE_EXCEPTIONS
//! 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
# endif // __WIL__ROAPI_H_APP
# if (defined(__WINSTRING_H_) && !defined(__WIL__WINSTRING_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)) || \
defined ( WIL_DOXYGEN )
/// @cond
# define __WIL__WINSTRING_H_
/// @endcond
typedef unique_any < HSTRING , decltype ( & : : WindowsDeleteString ) , : : WindowsDeleteString > unique_hstring ;
template < >
inline unique_hstring make_unique_string_nothrow < unique_hstring > (
_When_ ( ( source ! = nullptr ) & & length ! = static_cast < size_t > ( - 1 ) , _In_reads_ ( length ) )
_When_ ( ( source ! = nullptr ) & & length = = static_cast < size_t > ( - 1 ) , _In_z_ ) PCWSTR source ,
size_t length ) WI_NOEXCEPT
{
2024-12-05 06:06:53 +00:00
WI_ASSERT ( source ! = nullptr ) ; // the HSTRING version of this function does not support this case
2024-06-10 06:09:51 +00:00
if ( length = = static_cast < size_t > ( - 1 ) )
{
length = wcslen ( source ) ;
}
unique_hstring result ;
: : WindowsCreateString ( source , static_cast < UINT32 > ( length ) , & result ) ;
return result ;
}
typedef unique_any < HSTRING_BUFFER , decltype ( & : : WindowsDeleteStringBuffer ) , : : WindowsDeleteStringBuffer > 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 < unique_hstring >
{
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 < size_t > ( - 1 ) , _In_reads_ ( length ) )
_When_ ( ( source ! = nullptr ) & & length = = static_cast < size_t > ( - 1 ) , _In_z_ ) const wchar_t * source ,
size_t length )
{
if ( source )
{
RETURN_IF_FAILED ( WindowsCreateString ( source , static_cast < UINT32 > ( length ) , & m_value ) ) ;
m_charBuffer = nullptr ;
m_bufferHandle . reset ( ) ; // do this after WindowsCreateString so we can trim_at_existing_null() from our own buffer
}
else
{
// Need to set it to the empty string to support the empty string case.
m_value . reset ( ) ;
RETURN_IF_FAILED ( WindowsPreallocateStringBuffer ( static_cast < UINT32 > ( length ) , & m_charBuffer , & m_bufferHandle ) ) ;
}
return S_OK ;
}
WI_NODISCARD wchar_t * buffer ( )
{
WI_ASSERT ( m_charBuffer ! = nullptr ) ;
return m_charBuffer ;
}
WI_NODISCARD const wchar_t * buffer ( ) const
{
return m_charBuffer ;
}
HRESULT trim_at_existing_null ( size_t length )
{
return make ( buffer ( ) , length ) ;
}
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 ;
} ;
} // namespace details
/// @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)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL__WINSTRING_H_STL
/// @endcond
typedef shared_any < unique_hstring > shared_hstring ;
typedef shared_any < unique_hstring_buffer > shared_hstring_buffer ;
typedef weak_any < shared_hstring > weak_hstring ;
typedef weak_any < shared_hstring_buffer > weak_hstring_buffer ;
# endif // __WIL__WINSTRING_H_STL
# if (defined(_WINREG_) && !defined(__WIL_WINREG_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(WIL_KERNEL_MODE)) || \
defined ( WIL_DOXYGEN )
/// @cond
# define __WIL_WINREG_
/// @endcond
typedef unique_any < HKEY , decltype ( & : : RegCloseKey ) , : : RegCloseKey > unique_hkey ;
# endif // __WIL_WINREG_
# if (defined(__WIL_WINREG_) && !defined(__WIL_WINREG_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_WINREG_STL
/// @endcond
typedef shared_any < unique_hkey > shared_hkey ;
typedef weak_any < shared_hkey > weak_hkey ;
# endif // __WIL_WINREG_STL
# if (defined(__propidl_h__) && !defined(_WIL__propidl_h__) && !defined(WIL_KERNEL_MODE)) || defined(WIL_DOXYGEN)
/// @cond
# define _WIL__propidl_h__
/// @endcond
// if language extensions (/Za) disabled, PropVariantInit will not exist, PROPVARIANT has forward declaration only
# if defined(_MSC_EXTENSIONS)
using unique_prop_variant =
wil : : unique_struct < PROPVARIANT , decltype ( & : : PropVariantClear ) , : : PropVariantClear , decltype ( & : : PropVariantInit ) , : : PropVariantInit > ;
# endif
# 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)) || \
defined ( WIL_DOXYGEN )
/// @cond
# define __WIL_OLEAUTO_H_
/// @endcond
using unique_variant = wil : : unique_struct < VARIANT , decltype ( & : : VariantClear ) , : : VariantClear , decltype ( & : : VariantInit ) , : : VariantInit > ;
typedef unique_any < BSTR , decltype ( & : : SysFreeString ) , : : SysFreeString > 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
inline wil : : unique_variant make_variant_bstr_nothrow ( PCWSTR source ) WI_NOEXCEPT
{
wil : : unique_variant result { } ;
V_UNION ( result . addressof ( ) , bstrVal ) = : : SysAllocString ( source ) ;
if ( V_UNION ( result . addressof ( ) , bstrVal ) ! = nullptr )
{
V_VT ( result . addressof ( ) ) = VT_BSTR ;
}
return result ;
}
inline wil : : unique_variant make_variant_bstr_failfast ( PCWSTR source ) WI_NOEXCEPT
{
auto result { make_variant_bstr_nothrow ( source ) } ;
FAIL_FAST_HR_IF ( E_OUTOFMEMORY , V_VT ( result . addressof ( ) ) = = VT_EMPTY ) ;
return result ;
}
# ifdef WIL_ENABLE_EXCEPTIONS
inline wil : : unique_variant make_variant_bstr ( PCWSTR source )
{
auto result { make_variant_bstr_nothrow ( source ) } ;
THROW_HR_IF ( E_OUTOFMEMORY , V_VT ( result . addressof ( ) ) = = VT_EMPTY ) ;
return result ;
}
# endif // WIL_ENABLE_EXCEPTIONS
# endif // __WIL_OLEAUTO_H_
# if (defined(__WIL_OLEAUTO_H_) && !defined(__WIL_OLEAUTO_H_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_OLEAUTO_H_STL
/// @endcond
typedef shared_any < unique_bstr > shared_bstr ;
typedef weak_any < shared_bstr > weak_bstr ;
# endif // __WIL_OLEAUTO_H_STL
# if ((defined(_WININET_) || defined(_DUBINET_)) && !defined(__WIL_WININET_)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_WININET_
/// @endcond
typedef unique_any < HINTERNET , decltype ( & : : InternetCloseHandle ) , : : InternetCloseHandle > unique_hinternet ;
# endif // __WIL_WININET_
# if (defined(__WIL_WININET_) && !defined(__WIL_WININET_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_WININET_STL
/// @endcond
typedef shared_any < unique_hinternet > shared_hinternet ;
typedef weak_any < shared_hinternet > weak_hinternet ;
# endif // __WIL_WININET_STL
# if (defined(_WINHTTPX_) && !defined(__WIL_WINHTTP_)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_WINHTTP_
/// @endcond
typedef unique_any < HINTERNET , decltype ( & : : WinHttpCloseHandle ) , : : WinHttpCloseHandle > unique_winhttp_hinternet ;
# endif // __WIL_WINHTTP_
# if (defined(__WIL_WINHTTP_) && !defined(__WIL_WINHTTP_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_WINHTTP_STL
/// @endcond
typedef shared_any < unique_winhttp_hinternet > shared_winhttp_hinternet ;
typedef weak_any < shared_winhttp_hinternet > weak_winhttp_hinternet ;
# endif // __WIL_WINHTTP_STL
# if (defined(_WINSOCKAPI_) && !defined(__WIL_WINSOCKAPI_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_WINSOCKAPI_
/// @endcond
typedef unique_any < SOCKET , int ( WINAPI * ) ( SOCKET ) , : : closesocket , details : : pointer_access_all , SOCKET , SOCKET , INVALID_SOCKET , SOCKET > unique_socket ;
# endif // __WIL_WINSOCKAPI_
# if (defined(__WIL_WINSOCKAPI_) && !defined(__WIL_WINSOCKAPI_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_WINSOCKAPI_STL
/// @endcond
typedef shared_any < unique_socket > shared_socket ;
typedef weak_any < shared_socket > weak_socket ;
# endif // __WIL_WINSOCKAPI_STL
# if (defined(_WINGDI_) && !defined(__WIL_WINGDI_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(NOGDI) && !defined(WIL_KERNEL_MODE)) || \
defined ( WIL_DOXYGEN )
/// @cond
# define __WIL_WINGDI_
/// @endcond
struct window_dc
{
HDC dc ;
HWND hwnd ;
window_dc ( HDC dc_ , HWND hwnd_ = nullptr ) WI_NOEXCEPT
{
dc = dc_ ;
hwnd = hwnd_ ;
}
WI_NODISCARD operator HDC ( ) const WI_NOEXCEPT
{
return dc ;
}
static void close ( window_dc wdc ) WI_NOEXCEPT
{
: : ReleaseDC ( wdc . hwnd , wdc . dc ) ;
}
} ;
typedef unique_any < HDC , decltype ( & window_dc : : close ) , window_dc : : close , details : : pointer_access_all , window_dc > unique_hdc_window ;
struct paint_dc
{
HWND hwnd ;
PAINTSTRUCT ps ;
paint_dc ( HDC hdc = nullptr )
{
: : ZeroMemory ( this , sizeof ( * this ) ) ;
ps . hdc = hdc ;
}
WI_NODISCARD operator HDC ( ) const WI_NOEXCEPT
{
return ps . hdc ;
}
static void close ( paint_dc pdc ) WI_NOEXCEPT
{
: : EndPaint ( pdc . hwnd , & pdc . ps ) ;
}
} ;
typedef unique_any < HDC , decltype ( & paint_dc : : close ) , paint_dc : : close , details : : pointer_access_all , paint_dc > unique_hdc_paint ;
struct select_result
{
HGDIOBJ hgdi ;
HDC hdc ;
select_result ( HGDIOBJ hgdi_ , HDC hdc_ = nullptr ) WI_NOEXCEPT
{
hgdi = hgdi_ ;
hdc = hdc_ ;
}
WI_NODISCARD operator HGDIOBJ ( ) const WI_NOEXCEPT
{
return hgdi ;
}
static void close ( select_result sr ) WI_NOEXCEPT
{
: : SelectObject ( sr . hdc , sr . hgdi ) ;
}
} ;
typedef unique_any < HGDIOBJ , decltype ( & select_result : : close ) , select_result : : close , details : : pointer_access_all , select_result > 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 < HGDIOBJ , decltype ( & : : DeleteObject ) , : : DeleteObject > unique_hgdiobj ;
typedef unique_any < HPEN , decltype ( & : : DeleteObject ) , : : DeleteObject > unique_hpen ;
typedef unique_any < HBRUSH , decltype ( & : : DeleteObject ) , : : DeleteObject > unique_hbrush ;
typedef unique_any < HFONT , decltype ( & : : DeleteObject ) , : : DeleteObject > unique_hfont ;
typedef unique_any < HBITMAP , decltype ( & : : DeleteObject ) , : : DeleteObject > unique_hbitmap ;
typedef unique_any < HRGN , decltype ( & : : DeleteObject ) , : : DeleteObject > unique_hrgn ;
typedef unique_any < HPALETTE , decltype ( & : : DeleteObject ) , : : DeleteObject > unique_hpalette ;
typedef unique_any < HDC , decltype ( & : : DeleteDC ) , : : DeleteDC > unique_hdc ;
typedef unique_any < HICON , decltype ( & : : DestroyIcon ) , : : DestroyIcon > unique_hicon ;
# if !defined(NOMENUS)
typedef unique_any < HMENU , decltype ( & : : DestroyMenu ) , : : DestroyMenu > unique_hmenu ;
# endif // !defined(NOMENUS)
# endif // __WIL_WINGDI_
# if (defined(__WIL_WINGDI_) && !defined(__WIL_WINGDI_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_WINGDI_STL
/// @endcond
typedef shared_any < unique_hgdiobj > shared_hgdiobj ;
typedef shared_any < unique_hpen > shared_hpen ;
typedef shared_any < unique_hbrush > shared_hbrush ;
typedef shared_any < unique_hfont > shared_hfont ;
typedef shared_any < unique_hbitmap > shared_hbitmap ;
typedef shared_any < unique_hrgn > shared_hrgn ;
typedef shared_any < unique_hpalette > shared_hpalette ;
typedef shared_any < unique_hdc > shared_hdc ;
typedef shared_any < unique_hicon > shared_hicon ;
# if !defined(NOMENUS)
typedef shared_any < unique_hmenu > shared_hmenu ;
# endif // !defined(NOMENUS)
typedef weak_any < shared_hgdiobj > weak_hgdiobj ;
typedef weak_any < shared_hpen > weak_hpen ;
typedef weak_any < shared_hbrush > weak_hbrush ;
typedef weak_any < shared_hfont > weak_hfont ;
typedef weak_any < shared_hbitmap > weak_hbitmap ;
typedef weak_any < shared_hrgn > weak_hrgn ;
typedef weak_any < shared_hpalette > weak_hpalette ;
typedef weak_any < shared_hdc > weak_hdc ;
typedef weak_any < shared_hicon > weak_hicon ;
# if !defined(NOMENUS)
typedef weak_any < shared_hmenu > weak_hmenu ;
# endif // !defined(NOMENUS)
# endif // __WIL_WINGDI_STL
# if (defined(_INC_WTSAPI) && !defined(__WIL_WTSAPI)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_WTSAPI
/// @endcond
template < typename T >
using unique_wtsmem_ptr =
wistd : : unique_ptr < details : : ensure_trivially_destructible_t < T > , function_deleter < decltype ( & WTSFreeMemory ) , WTSFreeMemory > > ;
# endif // __WIL_WTSAPI
# if (defined(_INC_WTSAPI) && !defined(__WIL_WTSAPI_WTSVIRTUALCHANNELCLOSE)) || defined(WIL_DOXYGEN)
# define __WIL_WTSAPI_WTSVIRTUALCHANNELCLOSE
typedef unique_any_handle_null < decltype ( & : : WTSVirtualChannelClose ) , : : WTSVirtualChannelClose > unique_channel_handle ;
# endif // __WIL_WTSAPI_WTSVIRTUALCHANNELCLOSE
# if (defined(_WINSCARD_H_) && !defined(__WIL_WINSCARD_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_WINSCARD_H_
/// @endcond
typedef unique_any < SCARDCONTEXT , decltype ( & : : SCardReleaseContext ) , : : SCardReleaseContext > unique_scardctx ;
# endif // __WIL_WINSCARD_H_
# if (defined(__WIL_WINSCARD_H_) && !defined(__WIL_WINSCARD_H_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_WINSCARD_H_STL
/// @endcond
typedef shared_any < unique_scardctx > shared_scardctx ;
typedef weak_any < shared_scardctx > weak_scardctx ;
# endif // __WIL_WINSCARD_H_STL
# if (defined(__WINCRYPT_H__) && !defined(__WIL__WINCRYPT_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || \
defined ( WIL_DOXYGEN )
/// @cond
# define __WIL__WINCRYPT_H__
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 ) ;
}
} // namespace details
/// @endcond
struct cert_context_t
: details : : unique_storage < details : : resource_policy < PCCERT_CONTEXT , decltype ( & : : CertFreeCertificateContext ) , : : CertFreeCertificateContext > >
{
// forward all base class constructors...
template < typename . . . args_t >
explicit cert_context_t ( args_t & & . . . args ) WI_NOEXCEPT : unique_storage ( wistd : : forward < args_t > ( args ) . . . )
{
}
/** A wrapper around CertEnumCertificatesInStore.
2024-12-05 06:06:53 +00:00
CertEnumCertificatesInStore takes ownership of its second parameter in an unclear fashion ,
2024-06-10 06:09:51 +00:00
making it error - prone to use in combination with unique_cert_context . This wrapper helps
manage the resource correctly while ensuring the GetLastError state set by CertEnumCertificatesInStore .
is not lost . See MSDN for more information on ` CertEnumCertificatesInStore ` .
~ ~ ~ ~
void MyMethod ( HCERTSTORE certStore )
{
wil : : unique_cert_context enumCert ;
while ( enumCert . CertEnumCertificatesInStore ( certStore ) )
{
UseTheCertToDoTheThing ( enumCert ) ;
}
}
~ ~ ~ ~
@ param certStore A handle of a certificate store .
@ return ' true ' if a certificate was enumerated by this call , false otherwise .
*/
bool CertEnumCertificatesInStore ( HCERTSTORE certStore ) WI_NOEXCEPT
{
reset ( : : CertEnumCertificatesInStore ( certStore , release ( ) ) ) ;
return is_valid ( ) ;
}
} ;
// Warning - ::CertEnumCertificatesInStore takes ownership of its parameter. Prefer the
// .CertEnumCertificatesInStore method of the unique_cert_context or else use .release
// when calling ::CertEnumCertificatesInStore directly.
typedef unique_any_t < cert_context_t > unique_cert_context ;
typedef unique_any < PCCERT_CHAIN_CONTEXT , decltype ( & : : CertFreeCertificateChain ) , : : CertFreeCertificateChain > unique_cert_chain_context ;
typedef unique_any < HCERTSTORE , decltype ( & details : : CertCloseStoreNoParam ) , details : : CertCloseStoreNoParam > unique_hcertstore ;
typedef unique_any < HCRYPTPROV , decltype ( & details : : CryptReleaseContextNoParam ) , details : : CryptReleaseContextNoParam > unique_hcryptprov ;
typedef unique_any < HCRYPTKEY , decltype ( & : : CryptDestroyKey ) , : : CryptDestroyKey > unique_hcryptkey ;
typedef unique_any < HCRYPTHASH , decltype ( & : : CryptDestroyHash ) , : : CryptDestroyHash > unique_hcrypthash ;
typedef unique_any < HCRYPTMSG , decltype ( & : : CryptMsgClose ) , : : CryptMsgClose > unique_hcryptmsg ;
# endif // __WIL__WINCRYPT_H__
# if (defined(__WIL__WINCRYPT_H__) && !defined(__WIL__WINCRYPT_H__STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL__WINCRYPT_H__STL
/// @endcond
typedef shared_any < unique_cert_context > shared_cert_context ;
typedef shared_any < unique_cert_chain_context > shared_cert_chain_context ;
typedef shared_any < unique_hcertstore > shared_hcertstore ;
typedef shared_any < unique_hcryptprov > shared_hcryptprov ;
typedef shared_any < unique_hcryptkey > shared_hcryptkey ;
typedef shared_any < unique_hcrypthash > shared_hcrypthash ;
typedef shared_any < unique_hcryptmsg > shared_hcryptmsg ;
typedef weak_any < shared_cert_context > weak_cert_context ;
typedef weak_any < shared_cert_chain_context > weak_cert_chain_context ;
typedef weak_any < shared_hcertstore > weak_hcertstore ;
typedef weak_any < shared_hcryptprov > weak_hcryptprov ;
typedef weak_any < shared_hcryptkey > weak_hcryptkey ;
typedef weak_any < shared_hcrypthash > weak_hcrypthash ;
typedef weak_any < shared_hcryptmsg > weak_hcryptmsg ;
# endif // __WIL__WINCRYPT_H__STL
# if (defined(__NCRYPT_H__) && !defined(__WIL_NCRYPT_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_NCRYPT_H__
/// @endcond
using ncrypt_deleter = function_deleter < decltype ( & : : NCryptFreeBuffer ) , NCryptFreeBuffer > ;
template < typename T >
using unique_ncrypt_ptr = wistd : : unique_ptr < details : : ensure_trivially_destructible_t < T > , ncrypt_deleter > ;
typedef unique_any < NCRYPT_PROV_HANDLE , decltype ( & : : NCryptFreeObject ) , : : NCryptFreeObject > unique_ncrypt_prov ;
typedef unique_any < NCRYPT_KEY_HANDLE , decltype ( & : : NCryptFreeObject ) , : : NCryptFreeObject > unique_ncrypt_key ;
typedef unique_any < NCRYPT_SECRET_HANDLE , decltype ( & : : NCryptFreeObject ) , : : NCryptFreeObject > unique_ncrypt_secret ;
# endif // __WIL_NCRYPT_H__
# if (defined(__WIL_NCRYPT_H__) && !defined(__WIL_NCRYPT_H_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_NCRYPT_H_STL
/// @endcond
typedef shared_any < unique_ncrypt_prov > shared_ncrypt_prov ;
typedef shared_any < unique_ncrypt_key > shared_ncrypt_key ;
typedef shared_any < unique_ncrypt_secret > shared_ncrypt_secret ;
typedef weak_any < shared_ncrypt_prov > weak_ncrypt_prov ;
typedef weak_any < shared_ncrypt_key > weak_ncrypt_key ;
typedef weak_any < shared_ncrypt_secret > weak_ncrypt_secret ;
# endif // __WIL_NCRYPT_H_STL
# if (defined(__BCRYPT_H__) && !defined(__WIL_BCRYPT_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_BCRYPT_H__
namespace details
{
inline void __stdcall BCryptCloseAlgorithmProviderNoFlags ( _Pre_opt_valid_ _Frees_ptr_opt_ BCRYPT_ALG_HANDLE hAlgorithm ) WI_NOEXCEPT
{
if ( hAlgorithm )
{
: : BCryptCloseAlgorithmProvider ( hAlgorithm , 0 ) ;
}
}
} // namespace details
/// @endcond
using bcrypt_deleter = function_deleter < decltype ( & : : BCryptFreeBuffer ) , BCryptFreeBuffer > ;
template < typename T >
using unique_bcrypt_ptr = wistd : : unique_ptr < details : : ensure_trivially_destructible_t < T > , bcrypt_deleter > ;
typedef unique_any < BCRYPT_ALG_HANDLE , decltype ( & details : : BCryptCloseAlgorithmProviderNoFlags ) , details : : BCryptCloseAlgorithmProviderNoFlags > unique_bcrypt_algorithm ;
typedef unique_any < BCRYPT_HASH_HANDLE , decltype ( & : : BCryptDestroyHash ) , : : BCryptDestroyHash > unique_bcrypt_hash ;
typedef unique_any < BCRYPT_KEY_HANDLE , decltype ( & : : BCryptDestroyKey ) , : : BCryptDestroyKey > unique_bcrypt_key ;
typedef unique_any < BCRYPT_SECRET_HANDLE , decltype ( & : : BCryptDestroySecret ) , : : BCryptDestroySecret > unique_bcrypt_secret ;
# endif // __WIL_BCRYPT_H__
# if (defined(__WIL_BCRYPT_H__) && !defined(__WIL_BCRYPT_H_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_BCRYPT_H_STL
/// @endcond
typedef shared_any < unique_bcrypt_algorithm > shared_bcrypt_algorithm ;
typedef shared_any < unique_bcrypt_hash > shared_bcrypt_hash ;
typedef shared_any < unique_bcrypt_key > shared_bcrypt_key ;
typedef shared_any < unique_bcrypt_secret > shared_bcrypt_secret ;
typedef weak_any < shared_bcrypt_algorithm > weak_bcrypt_algorithm ;
typedef weak_any < shared_bcrypt_hash > weak_bcrypt_hash ;
typedef weak_any < unique_bcrypt_key > weak_bcrypt_key ;
typedef weak_any < shared_bcrypt_secret > weak_bcrypt_secret ;
# endif // __WIL_BCRYPT_H_STL
# if (defined(__RPCNDR_H__) && !defined(__WIL__RPCNDR_H__) && !defined(WIL_KERNEL_MODE)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL__RPCNDR_H__
/// @endcond
//! Function deleter for use with pointers allocated by MIDL_user_allocate
using midl_deleter = function_deleter < decltype ( & : : MIDL_user_free ) , MIDL_user_free > ;
//! Unique-ptr holding a type allocated by MIDL_user_alloc or returned from an RPC invocation
template < typename T = void >
using unique_midl_ptr = wistd : : unique_ptr < details : : ensure_trivially_destructible_t < T > , midl_deleter > ;
//! Unique-ptr for strings allocated by MIDL_user_alloc
using unique_midl_string = unique_midl_ptr < wchar_t > ;
# ifndef WIL_NO_ANSI_STRINGS
using unique_midl_ansistring = unique_midl_ptr < char > ;
# endif
/// @cond
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 < unique_midl_string > : midl_allocator
{
} ;
# ifndef WIL_NO_ANSI_STRINGS
template < >
struct string_allocator < unique_midl_ansistring > : midl_allocator
{
} ;
# endif
} // namespace details
/// @endcond
# endif // __WIL__RPCNDR_H__
# if (defined(_OBJBASE_H_) && !defined(__WIL_OBJBASE_H_) && !defined(WIL_KERNEL_MODE)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_OBJBASE_H_
/// @endcond
using cotaskmem_deleter = function_deleter < decltype ( & : : CoTaskMemFree ) , : : CoTaskMemFree > ;
template < typename T = void >
using unique_cotaskmem_ptr = wistd : : unique_ptr < details : : ensure_trivially_destructible_t < T > , cotaskmem_deleter > ;
template < typename T >
using unique_cotaskmem_array_ptr = unique_array_ptr < T , cotaskmem_deleter > ;
/** 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 .
@ code
auto foo = wil : : make_unique_cotaskmem_nothrow < Foo > ( ) ;
if ( foo )
{
// initialize allocated Foo object as appropriate
}
@ endcode
*/
template < typename T , typename . . . Args >
inline typename wistd : : enable_if < ! wistd : : is_array < T > : : value , unique_cotaskmem_ptr < T > > : : type make_unique_cotaskmem_nothrow ( Args & & . . . args )
{
unique_cotaskmem_ptr < T > sp ( static_cast < T * > ( : : CoTaskMemAlloc ( sizeof ( T ) ) ) ) ;
if ( sp )
{
// use placement new to initialize memory from the previous allocation
new ( sp . get ( ) ) T ( wistd : : forward < Args > ( 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 .
@ code
const size_t size = 42 ;
auto foos = wil : : make_unique_cotaskmem_nothrow < Foo [ ] > ( size ) ;
if ( foos )
{
for ( auto & elem : wil : : make_range ( foos . get ( ) , size ) )
{
// initialize allocated Foo objects as appropriate
}
}
@ endcode
*/
template < typename T >
inline typename wistd : : enable_if < wistd : : is_array < T > : : value & & wistd : : extent < T > : : value = = 0 , unique_cotaskmem_ptr < T > > : : type make_unique_cotaskmem_nothrow (
size_t size )
{
typedef typename wistd : : remove_extent < T > : : type E ;
FAIL_FAST_IF ( ( __WI_SIZE_MAX / sizeof ( E ) ) < size ) ;
size_t allocSize = sizeof ( E ) * size ;
unique_cotaskmem_ptr < T > sp ( static_cast < E * > ( : : 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 < E * > ( 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 .
@ code
auto foo = wil : : make_unique_cotaskmem_failfast < Foo > ( ) ;
// initialize allocated Foo object as appropriate
@ endcode
*/
template < typename T , typename . . . Args >
inline typename wistd : : enable_if < ! wistd : : is_array < T > : : value , unique_cotaskmem_ptr < T > > : : type make_unique_cotaskmem_failfast ( Args & & . . . args )
{
unique_cotaskmem_ptr < T > result ( make_unique_cotaskmem_nothrow < T > ( wistd : : forward < Args > ( 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 .
@ code
const size_t size = 42 ;
auto foos = wil : : make_unique_cotaskmem_failfast < Foo [ ] > ( size ) ;
for ( auto & elem : wil : : make_range ( foos . get ( ) , size ) )
{
// initialize allocated Foo objects as appropriate
}
@ endcode
*/
template < typename T >
inline typename wistd : : enable_if < wistd : : is_array < T > : : value & & wistd : : extent < T > : : value = = 0 , unique_cotaskmem_ptr < T > > : : type make_unique_cotaskmem_failfast (
size_t size )
{
unique_cotaskmem_ptr < T > result ( make_unique_cotaskmem_nothrow < T > ( 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 .
@ code
auto foo = wil : : make_unique_cotaskmem < Foo > ( ) ;
// initialize allocated Foo object as appropriate
@ endcode
*/
template < typename T , typename . . . Args >
inline typename wistd : : enable_if < ! wistd : : is_array < T > : : value , unique_cotaskmem_ptr < T > > : : type make_unique_cotaskmem ( Args & & . . . args )
{
unique_cotaskmem_ptr < T > result ( make_unique_cotaskmem_nothrow < T > ( wistd : : forward < Args > ( 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 .
@ code
const size_t size = 42 ;
auto foos = wil : : make_unique_cotaskmem < Foo [ ] > ( size ) ;
for ( auto & elem : wil : : make_range ( foos . get ( ) , size ) )
{
// initialize allocated Foo objects as appropriate
}
@ endcode
*/
template < typename T >
inline typename wistd : : enable_if < wistd : : is_array < T > : : value & & wistd : : extent < T > : : value = = 0 , unique_cotaskmem_ptr < T > > : : type make_unique_cotaskmem ( size_t size )
{
unique_cotaskmem_ptr < T > result ( make_unique_cotaskmem_nothrow < T > ( size ) ) ;
THROW_IF_NULL_ALLOC ( result ) ;
return result ;
}
# endif // WIL_ENABLE_EXCEPTIONS
typedef unique_any < void * , decltype ( & : : CoTaskMemFree ) , : : CoTaskMemFree > unique_cotaskmem ;
typedef unique_any < PWSTR , decltype ( & : : CoTaskMemFree ) , : : CoTaskMemFree > unique_cotaskmem_string ;
# ifndef WIL_NO_ANSI_STRINGS
typedef unique_any < PSTR , decltype ( & : : CoTaskMemFree ) , : : CoTaskMemFree > 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 < unique_cotaskmem_string > : cotaskmem_allocator
{
} ;
# ifndef WIL_NO_ANSI_STRINGS
template < >
struct string_allocator < unique_cotaskmem_ansistring > : cotaskmem_allocator
{
} ;
# endif // WIL_NO_ANSI_STRINGS
} // namespace details
/// @endcond
inline auto make_cotaskmem_string_nothrow (
_When_ ( ( source ! = nullptr ) & & length ! = static_cast < size_t > ( - 1 ) , _In_reads_ ( length ) )
_When_ ( ( source ! = nullptr ) & & length = = static_cast < size_t > ( - 1 ) , _In_z_ ) PCWSTR source ,
size_t length = static_cast < size_t > ( - 1 ) ) WI_NOEXCEPT
{
return make_unique_string_nothrow < unique_cotaskmem_string > ( source , length ) ;
}
inline auto make_cotaskmem_string_failfast (
_When_ ( ( source ! = nullptr ) & & length ! = static_cast < size_t > ( - 1 ) , _In_reads_ ( length ) )
_When_ ( ( source ! = nullptr ) & & length = = static_cast < size_t > ( - 1 ) , _In_z_ ) PCWSTR source ,
size_t length = static_cast < size_t > ( - 1 ) ) WI_NOEXCEPT
{
return make_unique_string_failfast < unique_cotaskmem_string > ( source , length ) ;
}
# ifdef WIL_ENABLE_EXCEPTIONS
inline auto make_cotaskmem_string (
_When_ ( ( source ! = nullptr ) & & length ! = static_cast < size_t > ( - 1 ) , _In_reads_ ( length ) )
_When_ ( ( source ! = nullptr ) & & length = = static_cast < size_t > ( - 1 ) , _In_z_ ) PCWSTR source ,
size_t length = static_cast < size_t > ( - 1 ) )
{
return make_unique_string < unique_cotaskmem_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)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_OBJBASE_H_STL
/// @endcond
typedef shared_any < unique_cotaskmem > shared_cotaskmem ;
typedef weak_any < shared_cotaskmem > weak_cotaskmem ;
typedef shared_any < unique_cotaskmem_string > shared_cotaskmem_string ;
typedef weak_any < shared_cotaskmem_string > 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)) || \
defined ( WIL_DOXYGEN )
/// @cond
# define __WIL_OBJBASE_AND_WINBASE_H_
/// @endcond
struct cotaskmem_secure_deleter
{
template < typename T >
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 < size_t > ( - 1 ) )
{
: : SecureZeroMemory ( p , size ) ;
}
malloc - > Release ( ) ;
}
: : CoTaskMemFree ( p ) ;
}
}
} ;
template < typename T = void >
using unique_cotaskmem_secure_ptr = wistd : : unique_ptr < details : : ensure_trivially_destructible_t < T > , cotaskmem_secure_deleter > ;
/** 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 .
@ code
auto foo = wil : : make_unique_cotaskmem_secure_nothrow < Foo > ( ) ;
if ( foo )
{
// initialize allocated Foo object as appropriate
}
@ endcode
*/
template < typename T , typename . . . Args >
inline typename wistd : : enable_if < ! wistd : : is_array < T > : : value , unique_cotaskmem_secure_ptr < T > > : : type make_unique_cotaskmem_secure_nothrow (
Args & & . . . args )
{
return unique_cotaskmem_secure_ptr < T > ( make_unique_cotaskmem_nothrow < T > ( wistd : : forward < Args > ( 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 .
@ code
const size_t size = 42 ;
auto foos = wil : : make_unique_cotaskmem_secure_nothrow < Foo [ ] > ( size ) ;
if ( foos )
{
for ( auto & elem : wil : : make_range ( foos . get ( ) , size ) )
{
// initialize allocated Foo objects as appropriate
}
}
@ endcode
*/
template < typename T >
inline typename wistd : : enable_if < wistd : : is_array < T > : : value & & wistd : : extent < T > : : value = = 0 , unique_cotaskmem_secure_ptr < T > > : : type make_unique_cotaskmem_secure_nothrow (
size_t size )
{
return unique_cotaskmem_secure_ptr < T > ( make_unique_cotaskmem_nothrow < T > ( 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 .
@ code
auto foo = wil : : make_unique_cotaskmem_secure_failfast < Foo > ( ) ;
// initialize allocated Foo object as appropriate
@ endcode
*/
template < typename T , typename . . . Args >
inline typename wistd : : enable_if < ! wistd : : is_array < T > : : value , unique_cotaskmem_secure_ptr < T > > : : type make_unique_cotaskmem_secure_failfast (
Args & & . . . args )
{
unique_cotaskmem_secure_ptr < T > result ( make_unique_cotaskmem_secure_nothrow < T > ( wistd : : forward < Args > ( 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 .
@ code
const size_t size = 42 ;
auto foos = wil : : make_unique_cotaskmem_secure_failfast < Foo [ ] > ( size ) ;
for ( auto & elem : wil : : make_range ( foos . get ( ) , size ) )
{
// initialize allocated Foo objects as appropriate
}
@ endcode
*/
template < typename T >
inline typename wistd : : enable_if < wistd : : is_array < T > : : value & & wistd : : extent < T > : : value = = 0 , unique_cotaskmem_secure_ptr < T > > : : type make_unique_cotaskmem_secure_failfast (
size_t size )
{
unique_cotaskmem_secure_ptr < T > result ( make_unique_cotaskmem_secure_nothrow < T > ( 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 .
@ code
auto foo = wil : : make_unique_cotaskmem_secure < Foo > ( ) ;
// initialize allocated Foo object as appropriate
@ endcode
*/
template < typename T , typename . . . Args >
inline typename wistd : : enable_if < ! wistd : : is_array < T > : : value , unique_cotaskmem_secure_ptr < T > > : : type make_unique_cotaskmem_secure ( Args & & . . . args )
{
unique_cotaskmem_secure_ptr < T > result ( make_unique_cotaskmem_secure_nothrow < T > ( wistd : : forward < Args > ( 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 .
@ code
const size_t size = 42 ;
auto foos = wil : : make_unique_cotaskmem_secure < Foo [ ] > ( size ) ;
for ( auto & elem : wil : : make_range ( foos . get ( ) , size ) )
{
// initialize allocated Foo objects as appropriate
}
@ endcode
*/
template < typename T >
inline typename wistd : : enable_if < wistd : : is_array < T > : : value & & wistd : : extent < T > : : value = = 0 , unique_cotaskmem_secure_ptr < T > > : : type make_unique_cotaskmem_secure (
size_t size )
{
unique_cotaskmem_secure_ptr < T > result ( make_unique_cotaskmem_secure_nothrow < T > ( size ) ) ;
THROW_IF_NULL_ALLOC ( result ) ;
return result ;
}
# endif // WIL_ENABLE_EXCEPTIONS
typedef unique_cotaskmem_secure_ptr < wchar_t [ ] > 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)) || \
defined ( WIL_DOXYGEN )
/// @cond
# define __WIL_OLE2_H_
/// @endcond
typedef unique_struct < STGMEDIUM , decltype ( & : : ReleaseStgMedium ) , : : ReleaseStgMedium > unique_stg_medium ;
struct unique_hglobal_locked : public unique_any < void * , decltype ( & : : GlobalUnlock ) , : : GlobalUnlock >
{
unique_hglobal_locked ( ) = delete ;
explicit unique_hglobal_locked ( HGLOBAL global ) : unique_any < void * , decltype ( & : : GlobalUnlock ) , : : GlobalUnlock > ( 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 ( STGMEDIUM & medium ) : unique_hglobal_locked ( medium . hGlobal )
{
}
WI_NODISCARD 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 < decltype ( & : : OleUninitialize ) , : : OleUninitialize > ;
//! 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 ( ) ;
}
# ifdef WIL_ENABLE_EXCEPTIONS
//! 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
# endif // __WIL_OLE2_H_
# if (defined(_INC_COMMCTRL) && !defined(__WIL_INC_COMMCTRL) && !defined(WIL_KERNEL_MODE)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_INC_COMMCTRL
/// @endcond
typedef unique_any < HIMAGELIST , decltype ( & : : ImageList_Destroy ) , : : ImageList_Destroy > unique_himagelist ;
# endif // __WIL_INC_COMMCTRL
# if (defined(__WIL_INC_COMMCTRL) && !defined(__WIL_INC_COMMCTRL_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_INC_COMMCTRL_STL
/// @endcond
typedef shared_any < unique_himagelist > shared_himagelist ;
typedef weak_any < shared_himagelist > weak_himagelist ;
# endif // __WIL_INC_COMMCTRL_STL
# if (defined(_UXTHEME_H_) && !defined(__WIL_INC_UXTHEME) && !defined(WIL_KERNEL_MODE)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_INC_UXTHEME
/// @endcond
typedef unique_any < HTHEME , decltype ( & : : CloseThemeData ) , : : CloseThemeData > unique_htheme ;
# endif // __WIL_INC_UXTHEME
# pragma warning(push)
# pragma warning(disable : 4995)
# if (defined(_INC_USERENV) && !defined(__WIL_INC_USERENV) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && !defined(WIL_KERNEL_MODE)) || \
defined ( WIL_DOXYGEN )
/// @cond
# define __WIL_INC_USERENV
/// @endcond
typedef unique_any < void * , decltype ( & : : DestroyEnvironmentBlock ) , : : DestroyEnvironmentBlock > unique_environment_block ;
# endif // __WIL_INC_USERENV
# pragma warning(pop)
# if (defined(__WINEVT_H__) && !defined(__WIL_INC_EVT_HANDLE) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_EVENTLOGSERVICE) && !defined(WIL_KERNEL_MODE)) || \
defined ( WIL_DOXYGEN )
/// @cond
# define __WIL_INC_EVT_HANDLE
/// @endcond
typedef unique_any < EVT_HANDLE , decltype ( & : : EvtClose ) , : : EvtClose > unique_evt_handle ;
# endif // __WIL_INC_EVT_HANDLE
# if (defined(_WINSVC_) && !defined(__WIL_HANDLE_H_WINSVC) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(WIL_KERNEL_MODE)) || \
defined ( WIL_DOXYGEN )
/// @cond
# define __WIL_HANDLE_H_WINSVC
/// @endcond
typedef unique_any < SC_HANDLE , decltype ( & : : CloseServiceHandle ) , : : CloseServiceHandle > unique_schandle ;
# endif // __WIL_HANDLE_H_WINSVC
# if (defined(__WIL_HANDLE_H_WINSVC) && !defined(__WIL_HANDLE_H_WINSVC_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_HANDLE_H_WINSVC_STL
/// @endcond
typedef shared_any < unique_schandle > shared_schandle ;
typedef weak_any < shared_schandle > 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)) || \
defined ( WIL_DOXYGEN )
/// @cond
# define __WIL_INC_STDIO
/// @endcond
typedef unique_any < FILE * , decltype ( & : : _pclose ) , : : _pclose > unique_pipe ;
typedef unique_any < FILE * , decltype ( & : : fclose ) , : : fclose > unique_file ;
# endif // __WIL_INC_STDIO
# if (defined(__WIL_INC_STDIO) && !defined(__WIL__INC_STDIO_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL__INC_STDIO_STL
/// @endcond
typedef shared_any < unique_pipe > shared_pipe ;
typedef weak_any < shared_pipe > weak_pipe ;
typedef shared_any < unique_file > shared_file ;
typedef weak_any < unique_file > weak_file ;
# endif // __WIL__INC_STDIO_STL
# if (defined(_INC_LOCALE) && !defined(__WIL_INC_LOCALE) && !defined(WIL_KERNEL_MODE)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_INC_LOCALE
/// @endcond
typedef unique_any < _locale_t , decltype ( & : : _free_locale ) , : : _free_locale > unique_locale ;
# endif // __WIL_INC_LOCALE
# if (defined(__WIL_INC_LOCALE) && !defined(__WIL__INC_LOCALE_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL__INC_LOCALE_STL
/// @endcond
typedef shared_any < unique_locale > shared_locale ;
typedef weak_any < unique_locale > weak_locale ;
# endif // __WIL__INC_LOCALE_STL
# if (defined(_NTLSA_) && !defined(__WIL_NTLSA_) && !defined(WIL_KERNEL_MODE)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_NTLSA_
/// @endcond
typedef unique_any < LSA_HANDLE , decltype ( & : : LsaClose ) , : : LsaClose > unique_hlsa ;
using lsa_freemem_deleter = function_deleter < decltype ( & : : LsaFreeMemory ) , LsaFreeMemory > ;
template < typename T >
using unique_lsamem_ptr = wistd : : unique_ptr < details : : ensure_trivially_destructible_t < T > , lsa_freemem_deleter > ;
# endif // _NTLSA_
# if (defined(_NTLSA_) && !defined(__WIL_NTLSA_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_NTLSA_STL
/// @endcond
typedef shared_any < unique_hlsa > shared_hlsa ;
typedef weak_any < shared_hlsa > weak_hlsa ;
# endif // _NTLSA_
# if (defined(_LSALOOKUP_) && !defined(__WIL_LSALOOKUP_)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_LSALOOKUP_
/// @endcond
typedef unique_any < LSA_HANDLE , decltype ( & : : LsaLookupClose ) , : : LsaLookupClose > unique_hlsalookup ;
using lsalookup_freemem_deleter = function_deleter < decltype ( & : : LsaLookupFreeMemory ) , LsaLookupFreeMemory > ;
template < typename T >
using unique_lsalookupmem_ptr = wistd : : unique_ptr < details : : ensure_trivially_destructible_t < T > , lsalookup_freemem_deleter > ;
# endif // _LSALOOKUP_
# if (defined(_LSALOOKUP_) && !defined(__WIL_LSALOOKUP_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_LSALOOKUP_STL
/// @endcond
typedef shared_any < unique_hlsalookup > shared_hlsalookup ;
typedef weak_any < shared_hlsalookup > weak_hlsalookup ;
# endif // _LSALOOKUP_
# if (defined(_NTLSA_IFS_) && !defined(__WIL_HANDLE_H_NTLSA_IFS_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || \
defined ( WIL_DOXYGEN )
/// @cond
# define __WIL_HANDLE_H_NTLSA_IFS_
/// @endcond
using lsa_deleter = function_deleter < decltype ( & : : LsaFreeReturnBuffer ) , LsaFreeReturnBuffer > ;
template < typename T >
using unique_lsa_ptr = wistd : : unique_ptr < details : : ensure_trivially_destructible_t < T > , lsa_deleter > ;
# endif // __WIL_HANDLE_H_NTLSA_IFS_
# if (defined(__WERAPI_H__) && !defined(__WIL_WERAPI_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_WERAPI_H__
/// @endcond
typedef unique_any < HREPORT , decltype ( & WerReportCloseHandle ) , WerReportCloseHandle > unique_wer_report ;
# endif
# if (defined(__MIDLES_H__) && !defined(__WIL_MIDLES_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_MIDLES_H__
/// @endcond
typedef unique_any < handle_t , decltype ( & : : MesHandleFree ) , : : MesHandleFree > unique_rpc_pickle ;
# endif
# if (defined(__WIL_MIDLES_H__) && !defined(__WIL_MIDLES_H_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_MIDLES_H_STL
/// @endcond
typedef shared_any < unique_rpc_pickle > shared_rpc_pickle ;
typedef weak_any < shared_rpc_pickle > weak_rpc_pickle ;
# endif
# if (defined(__RPCDCE_H__) && !defined(__WIL_RPCDCE_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_RPCDCE_H__
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 ) ;
}
} // namespace details
/// @endcond
typedef unique_any < RPC_BINDING_HANDLE , decltype ( & details : : WpRpcBindingFree ) , details : : WpRpcBindingFree > unique_rpc_binding ;
typedef unique_any < RPC_BINDING_VECTOR * , decltype ( & details : : WpRpcBindingVectorFree ) , details : : WpRpcBindingVectorFree > unique_rpc_binding_vector ;
typedef unique_any < RPC_WSTR , decltype ( & details : : WpRpcStringFree ) , details : : WpRpcStringFree > unique_rpc_wstr ;
# endif
# if (defined(__WIL_RPCDCE_H__) && !defined(__WIL_RPCDCE_H_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_RPCDCE_H_STL
/// @endcond
typedef shared_any < unique_rpc_binding > shared_rpc_binding ;
typedef weak_any < shared_rpc_binding > weak_rpc_binding ;
typedef shared_any < unique_rpc_binding_vector > shared_rpc_binding_vector ;
typedef weak_any < shared_rpc_binding_vector > weak_rpc_binding_vector ;
typedef shared_any < unique_rpc_wstr > shared_rpc_wstr ;
typedef weak_any < unique_rpc_wstr > weak_rpc_wstr ;
# endif
# if (defined(_WCMAPI_H) && !defined(__WIL_WCMAPI_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_WCMAPI_H_
/// @endcond
using wcm_deleter = function_deleter < decltype ( & : : WcmFreeMemory ) , WcmFreeMemory > ;
template < typename T >
using unique_wcm_ptr = wistd : : unique_ptr < details : : ensure_trivially_destructible_t < T > , wcm_deleter > ;
# endif
# if (defined(_NETIOAPI_H_) && defined(_WS2IPDEF_) && defined(MIB_INVALID_TEREDO_PORT_NUMBER) && !defined(__WIL_NETIOAPI_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || \
defined ( WIL_DOXYGEN )
/// @cond
# define __WIL_NETIOAPI_H_
/// @endcond
typedef unique_any < PMIB_IF_TABLE2 , decltype ( & : : FreeMibTable ) , : : FreeMibTable > unique_mib_iftable ;
# endif
# if (defined(__WIL_NETIOAPI_H_) && !defined(__WIL_NETIOAPI_H_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_NETIOAPI_H_STL
/// @endcond
typedef shared_any < unique_mib_iftable > shared_mib_iftable ;
typedef weak_any < shared_mib_iftable > weak_mib_iftable ;
# endif
# if (defined(_WLAN_WLANAPI_H) && !defined(__WIL_WLAN_WLANAPI_H) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || \
defined ( WIL_DOXYGEN )
/// @cond
# define __WIL_WLAN_WLANAPI_H
/// @endcond
using wlan_deleter = function_deleter < decltype ( & : : WlanFreeMemory ) , : : WlanFreeMemory > ;
template < typename T >
using unique_wlan_ptr = wistd : : unique_ptr < details : : ensure_trivially_destructible_t < T > , wlan_deleter > ;
/// @cond
namespace details
{
inline void __stdcall CloseWlanHandle ( _In_ HANDLE hClientHandle )
{
: : WlanCloseHandle ( hClientHandle , nullptr ) ;
}
} // namespace details
/// @endcond
typedef unique_any < HANDLE , decltype ( & details : : CloseWlanHandle ) , details : : CloseWlanHandle , details : : pointer_access_all , HANDLE , INT_PTR , - 1 > unique_wlan_handle ;
# endif
# if (defined(__WIL_WLAN_WLANAPI_H) && !defined(__WIL_WLAN_WLANAPI_H_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_WLAN_WLANAPI_H_STL
/// @endcond
typedef shared_any < unique_wlan_handle > shared_wlan_handle ;
typedef weak_any < shared_wlan_handle > weak_wlan_handle ;
# endif
# if (defined(_HPOWERNOTIFY_DEF_) && !defined(__WIL_HPOWERNOTIFY_DEF_H_) && !defined(WIL_KERNEL_MODE)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_HPOWERNOTIFY_DEF_H_
/// @endcond
typedef unique_any < HPOWERNOTIFY , decltype ( & : : UnregisterPowerSettingNotification ) , : : UnregisterPowerSettingNotification > unique_hpowernotify ;
# endif
# if (defined(__WIL_WINBASE_DESKTOP) && defined(SID_DEFINED) && !defined(__WIL_PSID_DEF_H_)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_PSID_DEF_H_
/// @endcond
typedef unique_any < PSID , decltype ( & details : : FreeProcessHeap ) , details : : FreeProcessHeap > unique_process_heap_psid ;
typedef unique_any < PSID , decltype ( & : : LocalFree ) , : : LocalFree > unique_any_psid ;
# if defined(_OBJBASE_H_) || defined(WIL_DOXYGEN)
typedef unique_any < PSID , decltype ( & : : CoTaskMemFree ) , : : CoTaskMemFree > 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)) || \
defined ( WIL_DOXYGEN )
/// @cond
# define __WIL_PROCESSTHREADSAPI_H_DESK_SYS
namespace details
{
inline void __stdcall CloseProcessInformation ( _In_ PROCESS_INFORMATION * p )
{
if ( p - > hProcess )
{
CloseHandle ( p - > hProcess ) ;
}
if ( p - > hThread )
{
CloseHandle ( p - > hThread ) ;
}
}
} // namespace details
/// @endcond
/** Manages the outbound parameter containing handles returned by `CreateProcess()` and related methods.
~ ~ ~
unique_process_information process ;
CreateProcessW ( . . . , CREATE_SUSPENDED , . . . , & process ) ;
THROW_LAST_ERROR_IF ( ResumeThread ( process . hThread ) = = - 1 ) ;
THROW_LAST_ERROR_IF ( WaitForSingleObject ( process . hProcess , INFINITE ) ! = WAIT_OBJECT_0 ) ;
~ ~ ~
*/
using unique_process_information =
unique_struct < PROCESS_INFORMATION , decltype ( & details : : CloseProcessInformation ) , details : : CloseProcessInformation > ;
# endif
# if (defined(_PROCESSENV_) && !defined(__WIL__PROCESSENV_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)) || \
defined ( WIL_DOXYGEN )
/// @cond
# define __WIL__PROCESSENV_
/// @endcond
/** Manages lifecycle of an environment-strings block.
@ code
wil : : unique_environstrings_ptr env { : : GetEnvironmentStringsW ( ) } ;
const wchar_t * nextVar = env . get ( ) ;
while ( nextVar & & * nextVar )
{
// consume 'nextVar'
nextVar + = wcslen ( nextVar ) + 1 ;
}
@ endcode
*/
using unique_environstrings_ptr =
wistd : : unique_ptr < wchar_t , function_deleter < decltype ( & : : FreeEnvironmentStringsW ) , FreeEnvironmentStringsW > > ;
# ifndef WIL_NO_ANSI_STRINGS
//! ANSI equivalent to unique_environstrings_ptr;
using unique_environansistrings_ptr =
wistd : : unique_ptr < char , function_deleter < decltype ( & : : FreeEnvironmentStringsA ) , FreeEnvironmentStringsA > > ;
# endif
# endif
# if (defined(_APPMODEL_H_) && !defined(__WIL_APPMODEL_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_APPMODEL_H_
/// @endcond
typedef unique_any < PACKAGE_INFO_REFERENCE , decltype ( & : : ClosePackageInfo ) , : : ClosePackageInfo > unique_package_info_reference ;
# if NTDDI_VERSION >= NTDDI_WIN10_CO
typedef unique_any < PACKAGEDEPENDENCY_CONTEXT , decltype ( & : : RemovePackageDependency ) , : : RemovePackageDependency > unique_package_dependency_context ;
# endif // NTDDI_VERSION >= NTDDI_WIN10_CO
# endif // __WIL_APPMODEL_H_
# if (defined(__WIL_APPMODEL_H_) && !defined(__WIL_APPMODEL_H_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_APPMODEL_H_STL
/// @endcond
typedef shared_any < unique_package_info_reference > shared_package_info_reference ;
typedef weak_any < shared_package_info_reference > weak_package_info_reference ;
# if NTDDI_VERSION >= NTDDI_WIN10_CO
typedef shared_any < unique_package_dependency_context > shared_package_dependency_context ;
typedef weak_any < shared_package_dependency_context > weak_package_dependency_context ;
# endif // NTDDI_VERSION >= NTDDI_WIN10_CO
# endif // __WIL_APPMODEL_H_STL
# if (defined(MSIXDYNAMICDEPENDENCY_H) && !defined(__WIL_MSIXDYNAMICDEPENDENCY_H)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_MSIXDYNAMICDEPENDENCY_H
/// @endcond
typedef unique_any < MDD_PACKAGEDEPENDENCY_CONTEXT , decltype ( & : : MddRemovePackageDependency ) , : : MddRemovePackageDependency > unique_mdd_package_dependency_context ;
# endif // __WIL_MSIXDYNAMICDEPENDENCY_H
# if (defined(MSIXDYNAMICDEPENDENCY_H) && !defined(__WIL_MSIXDYNAMICDEPENDENCY_H_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_MSIXDYNAMICDEPENDENCY_H_STL
/// @endcond
typedef shared_any < unique_mdd_package_dependency_context > shared_mdd_package_dependency_context ;
typedef weak_any < shared_mdd_package_dependency_context > weak_mdd_package_dependency_context ;
# endif // __WIL_MSIXDYNAMICDEPENDENCY_H_STL
# if (defined(_APISETLIBLOADER_) && !defined(__WIL_APISETLIBLOADER_)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_APISETLIBLOADER_
/// @endcond
# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
typedef unique_any < DLL_DIRECTORY_COOKIE , decltype ( & : : RemoveDllDirectory ) , : : RemoveDllDirectory > unique_dll_directory_cookie ;
# endif
# endif // __WIL_APISETLIBLOADER_
# if (defined(_APISETLIBLOADER_) && !defined(__WIL_APISETLIBLOADER_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_APISETLIBLOADER_STL
/// @endcond
# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
typedef shared_any < unique_dll_directory_cookie > shared_dll_directory_cookie ;
typedef weak_any < shared_dll_directory_cookie > weak_dll_directory_cookie ;
# endif
# endif // __WIL_APISETLIBLOADER_STL
# if (defined(WDFAPI) && !defined(__WIL_WDFAPI)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_WDFAPI
namespace details
{
template < typename TWDFOBJECT >
using wdf_object_resource_policy = resource_policy < TWDFOBJECT , decltype ( & : : WdfObjectDelete ) , & : : WdfObjectDelete > ;
}
/// @endcond
template < typename TWDFOBJECT >
using unique_wdf_any = unique_any_t < details : : unique_storage < details : : wdf_object_resource_policy < TWDFOBJECT > > > ;
using unique_wdf_object = unique_wdf_any < WDFOBJECT > ;
using unique_wdf_queue = unique_wdf_any < WDFQUEUE > ;
using unique_wdf_timer = unique_wdf_any < WDFTIMER > ;
using unique_wdf_work_item = unique_wdf_any < WDFWORKITEM > ;
using unique_wdf_memory = unique_wdf_any < WDFMEMORY > ;
using unique_wdf_dma_enabler = unique_wdf_any < WDFDMAENABLER > ;
using unique_wdf_dma_transaction = unique_wdf_any < WDFDMATRANSACTION > ;
using unique_wdf_common_buffer = unique_wdf_any < WDFCOMMONBUFFER > ;
using unique_wdf_key = unique_wdf_any < WDFKEY > ;
using unique_wdf_string = unique_wdf_any < WDFSTRING > ;
using unique_wdf_collection = unique_wdf_any < WDFCOLLECTION > ;
using wdf_wait_lock_release_scope_exit =
unique_any < WDFWAITLOCK , decltype ( & : : WdfWaitLockRelease ) , : : WdfWaitLockRelease , details : : pointer_access_none > ;
# if defined(WIL_KERNEL_MODE)
using unique_wdf_device_init = unique_any < WDFDEVICE_INIT * , decltype ( & : : WdfDeviceInitFree ) , : : WdfDeviceInitFree > ;
# endif
2024-12-05 06:06:53 +00:00
WI_NODISCARD inline _IRQL_requires_max_ ( PASSIVE_LEVEL )
2024-06-10 06:09:51 +00:00
_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 ) ;
}
2024-12-05 06:06:53 +00:00
WI_NODISCARD inline _IRQL_requires_max_ ( APC_LEVEL )
2024-06-10 06:09:51 +00:00
_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 > ;
2024-12-05 06:06:53 +00:00
WI_NODISCARD inline _IRQL_requires_max_ ( DISPATCH_LEVEL )
2024-06-10 06:09:51 +00:00
_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 ) ;
}
/// @cond
namespace details
{
template < typename TWDFLOCK >
using unique_wdf_lock_storage = unique_storage < wdf_object_resource_policy < TWDFLOCK > > ;
class unique_wdf_spin_lock_storage : public unique_wdf_lock_storage < WDFSPINLOCK >
{
using wdf_lock_storage_t = unique_wdf_lock_storage < WDFSPINLOCK > ;
public :
using pointer = wdf_lock_storage_t : : pointer ;
// Forward all base class constructors, but have it be explicit.
template < typename . . . args_t >
explicit unique_wdf_spin_lock_storage ( args_t & & . . . args ) WI_NOEXCEPT : wdf_lock_storage_t ( wistd : : forward < args_t > ( 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 < WDFWAITLOCK >
{
using wdf_lock_storage_t = unique_wdf_lock_storage < WDFWAITLOCK > ;
public :
using pointer = wdf_lock_storage_t : : pointer ;
// Forward all base class constructors, but have it be explicit.
template < typename . . . args_t >
explicit unique_wdf_wait_lock_storage ( args_t & & . . . args ) WI_NOEXCEPT : wdf_lock_storage_t ( wistd : : forward < args_t > ( 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 ( ) ) ;
}
} ;
} // namespace details
/// @endcond
using unique_wdf_wait_lock = unique_any_t < details : : unique_wdf_wait_lock_storage > ;
using unique_wdf_spin_lock = unique_any_t < details : : unique_wdf_spin_lock_storage > ;
//! unique_wdf_object_reference is a RAII type for managing WDF object references acquired using
//! the WdfObjectReference* family of APIs. The behavior of this class is exactly identical to
//! wil::unique_any but a few methods have some WDF-object-reference-specific enhancements.
//!
//! * The constructor takes not only a WDFOBJECT-compatible type or a wil::unique_wdf_any, but
//! optionally also a tag with which the reference was acquired.
//! * A get_tag() method is provided to retrieve the tag.
//! * reset() is similar to the constructor in that it also optionally takes a tag.
//! * release() optionally takes an out-param that returns the tag.
//!
//! These subtle differences make it impossible to reuse the wil::unique_any_t template for its implementation.
template < typename wdf_object_t >
class unique_wdf_object_reference
{
public :
unique_wdf_object_reference ( ) WI_NOEXCEPT = default ;
//! Wrap a WDF object reference that has already been acquired into this RAII type. If you
//! want to acquire a new reference instead, use WI_WdfObjectReferenceIncrement.
explicit unique_wdf_object_reference ( wdf_object_t wdfObject , void * tag = nullptr ) WI_NOEXCEPT : m_wdfObject ( wdfObject ) , m_tag ( tag )
{
}
//! This is similar to the constructor that takes a raw WDF handle but is enlightened to
//! take a const-ref to a wil::unique_wdf_any<> instead, obviating the need to call .get()
//! on it. As with the other constructor, the expectation is that the raw reference has
//! already been acquired and ownership is being transferred into this RAII object.
explicit unique_wdf_object_reference ( const wil : : unique_wdf_any < wdf_object_t > & wdfObject , void * tag = nullptr ) WI_NOEXCEPT
: unique_wdf_object_reference ( wdfObject . get ( ) , tag )
{
}
unique_wdf_object_reference ( const unique_wdf_object_reference & ) = delete ;
unique_wdf_object_reference & operator = ( const unique_wdf_object_reference & ) = delete ;
unique_wdf_object_reference ( unique_wdf_object_reference & & other ) : m_wdfObject ( other . m_wdfObject ) , m_tag ( other . m_tag )
{
other . m_wdfObject = WDF_NO_HANDLE ;
other . m_tag = nullptr ;
}
unique_wdf_object_reference & operator = ( unique_wdf_object_reference & & other )
{
if ( this ! = wistd : : addressof ( other ) )
{
reset ( other . m_wdfObject , other . m_tag ) ;
other . m_wdfObject = WDF_NO_HANDLE ;
other . m_tag = nullptr ;
}
return * this ;
}
~ unique_wdf_object_reference ( ) WI_NOEXCEPT
{
reset ( ) ;
}
WI_NODISCARD explicit operator bool ( ) const WI_NOEXCEPT
{
return m_wdfObject ! = WDF_NO_HANDLE ;
}
WI_NODISCARD wdf_object_t get ( ) const WI_NOEXCEPT
{
return m_wdfObject ;
}
WI_NODISCARD void * get_tag ( ) const WI_NOEXCEPT
{
return m_tag ;
}
//! Replaces the current instance (releasing it if it exists) with a new WDF object
//! reference that has already been acquired by the caller.
void reset ( wdf_object_t wdfObject = WDF_NO_HANDLE , void * tag = nullptr ) WI_NOEXCEPT
{
if ( m_wdfObject ! = WDF_NO_HANDLE )
{
// 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 ( m_wdfObject , m_tag ) ;
}
m_wdfObject = wdfObject ;
m_tag = tag ;
}
void reset ( const wil : : unique_wdf_any < wdf_object_t > & wdfObject , void * tag = nullptr ) WI_NOEXCEPT
{
reset ( wdfObject . get ( ) , tag ) ;
}
wdf_object_t release ( _Outptr_opt_ void * * tag = nullptr ) WI_NOEXCEPT
{
const auto wdfObject = m_wdfObject ;
wil : : assign_to_opt_param ( tag , m_tag ) ;
m_wdfObject = WDF_NO_HANDLE ;
m_tag = nullptr ;
return wdfObject ;
}
void swap ( unique_wdf_object_reference & other ) WI_NOEXCEPT
{
wistd : : swap_wil ( m_wdfObject , other . m_wdfObject ) ;
wistd : : swap_wil ( m_tag , other . m_tag ) ;
}
//! Drops the current reference if any, and returns a pointer to a WDF handle which can
//! receive a newly referenced WDF handle. The tag is assumed to be nullptr. If a different
//! tag needs to be used, a temporary variable will need to be used to receive the WDF
//! handle and a unique_wdf_object_reference will need to be constructed with it.
//!
//! The quintessential use-case for this method is WdfIoQueueFindRequest.
wdf_object_t * put ( ) WI_NOEXCEPT
{
reset ( ) ;
return & m_wdfObject ;
}
wdf_object_t * operator & ( ) WI_NOEXCEPT
{
return put ( ) ;
}
private :
wdf_object_t m_wdfObject = WDF_NO_HANDLE ;
void * m_tag = nullptr ;
} ;
// Increment the ref-count on a WDF object and return 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 < typename wdf_object_t >
2024-12-05 06:06:53 +00:00
WI_NODISCARD inline unique_wdf_object_reference < wdf_object_t > wdf_object_reference_increment (
2024-06-10 06:09:51 +00:00
wdf_object_t 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 < char * > ( fileName ) ) ;
return unique_wdf_object_reference < wdf_object_t > { wdfObject , tag } ;
}
template < typename wdf_object_t >
2024-12-05 06:06:53 +00:00
WI_NODISCARD inline unique_wdf_object_reference < wdf_object_t > wdf_object_reference_increment (
2024-06-10 06:09:51 +00:00
const wil : : unique_wdf_any < wdf_object_t > & wdfObject , PVOID tag , LONG lineNumber , PCSTR fileName ) WI_NOEXCEPT
{
return wdf_object_reference_increment ( wdfObject . get ( ) , tag , lineNumber , fileName ) ;
}
// A macro so that we can capture __LINE__ and __FILE__.
# define WI_WdfObjectReferenceIncrement(wdfObject, tag) wil::wdf_object_reference_increment(wdfObject, tag, __LINE__, __FILE__)
//! wdf_request_completer is a unique_any-like RAII class for managing completion of a
//! WDFREQUEST. On destruction or explicit reset() it completes the WDFREQUEST with parameters
//! (status, information, priority boost) previously set using methods on this class.
//!
//! This class does not use the unique_any_t template primarily because the release() and put()
//! methods need to return a WDFREQUEST/WDFREQUEST*, as opposed to the internal storage type.
class wdf_request_completer
{
public :
explicit wdf_request_completer ( WDFREQUEST wdfRequest = WDF_NO_HANDLE ) WI_NOEXCEPT : m_wdfRequest ( wdfRequest )
{
}
wdf_request_completer ( const wdf_request_completer & ) = delete ;
wdf_request_completer & operator = ( const wdf_request_completer & ) = delete ;
wdf_request_completer ( wdf_request_completer & & other ) WI_NOEXCEPT : m_wdfRequest ( other . m_wdfRequest ) ,
m_status ( other . m_status ) ,
m_information ( other . m_information ) ,
# if defined(WIL_KERNEL_MODE)
m_priorityBoost ( other . m_priorityBoost ) ,
# endif
m_completionFlags ( other . m_completionFlags )
{
clear_state ( other ) ;
}
wdf_request_completer & operator = ( wdf_request_completer & & other ) WI_NOEXCEPT
{
if ( this ! = wistd : : addressof ( other ) )
{
reset ( ) ;
m_wdfRequest = other . m_wdfRequest ;
m_status = other . m_status ;
m_information = other . m_information ;
# if defined(WIL_KERNEL_MODE)
m_priorityBoost = other . m_priorityBoost ;
# endif
m_completionFlags = other . m_completionFlags ;
clear_state ( other ) ;
}
return * this ;
}
~ wdf_request_completer ( ) WI_NOEXCEPT
{
reset ( ) ;
}
WI_NODISCARD WDFREQUEST get ( ) const WI_NOEXCEPT
{
return m_wdfRequest ;
}
//! Set the NTSTATUS value with with the WDFREQUEST will be completed when the RAII object
//! goes out of scope or .reset() is called explicitly. Calling this method does *not*
//! complete the request right away. No effect if this object currently does not have
//! ownership of a WDFREQUEST. The expected usage pattern is that set_status() is called
//! only after ownership of a WDFREQUEST is transferred to this object.
void set_status ( NTSTATUS status ) WI_NOEXCEPT
{
// The contract is that this method has no effect if we currently do not have a
// m_wdfRequest. But that is enforced by discarding all state when a WDFREQUEST is
// attached, not by explicitly checking for that condition here.
m_status = status ;
}
//! Set the IO_STATUS_BLOCK.Information value with which the WDFREQUEST will be completed.
//! Note that the Information value is not stored directly in the WDFREQUEST using
//! WdfRequestSetInformation. It is only used at the time of completion. No effect if this
//! object currently does not have ownership of a WDFREQUEST. The expected usage pattern is
//! that set_information() is called only after ownership of a WDFREQUEST is transferred to
//! this object.
void set_information ( ULONG_PTR information ) WI_NOEXCEPT
{
// The contract is that this method has no effect if we currently do not have a
// m_wdfRequest. But that is enforced by discarding all state when a WDFREQUEST is
// attached, not by explicitly checking for that condition here.
m_completionFlags . informationSet = 1 ;
m_information = information ;
}
# if defined(WIL_KERNEL_MODE)
//! Set the priority boost with which the WDFREQUEST will be completed. If this method is
//! called, the WDFREQUEST will eventually be completed with
//! WdfRequestCompleteWithPriorityBoost. No effect if this object currently does not have
//! ownership of a WDFREQUEST. The expected usage pattern is that set_priority_boost() is
//! called only after ownership of a WDFREQUEST is transferred to this object.
void set_priority_boost ( CCHAR priorityBoost ) WI_NOEXCEPT
{
// The contract is that this method has no effect if we currently do not have a
// m_wdfRequest. But that is enforced by discarding all state when a WDFREQUEST is
// attached, not by explicitly checking for that condition here.
m_completionFlags . priorityBoostSet = 1 ;
m_priorityBoost = priorityBoost ;
}
# endif
WI_NODISCARD explicit operator bool ( ) const WI_NOEXCEPT
{
return m_wdfRequest ! = WDF_NO_HANDLE ;
}
WDFREQUEST * put ( ) WI_NOEXCEPT
{
reset ( ) ;
return & m_wdfRequest ;
}
WDFREQUEST * operator & ( ) WI_NOEXCEPT
{
return put ( ) ;
}
//! Relinquishes completion responsibility for the WDFREQUEST. Note that any state
//! (information, priority boost, status) set on this object is lost. This design choice was
//! made because it is atypical to set an information or priority boost value upfront; they
//! are typically set at the point where the request is going to be completed. Hence a
//! use-case wherein release() is called will typically not have set an information or
//! priority boost.
WDFREQUEST release ( ) WI_NOEXCEPT
{
const auto wdfRequest = m_wdfRequest ;
clear_state ( * this ) ;
return wdfRequest ;
}
void swap ( wdf_request_completer & other ) WI_NOEXCEPT
{
wistd : : swap_wil ( m_wdfRequest , other . m_wdfRequest ) ;
wistd : : swap_wil ( m_information , other . m_information ) ;
wistd : : swap_wil ( m_status , other . m_status ) ;
# if defined(WIL_KERNEL_MODE)
wistd : : swap_wil ( m_priorityBoost , other . m_priorityBoost ) ;
# endif
wistd : : swap_wil ( m_completionFlags , other . m_completionFlags ) ;
}
void reset ( WDFREQUEST newWdfRequest = WDF_NO_HANDLE )
{
if ( m_wdfRequest ! = WDF_NO_HANDLE )
{
// We try to match the usage patterns that the driver would have typically used in the
// various scenarios. For instance, if the driver has set the information field, we'll
// call WdfRequestCompleteWithInformation instead of calling WdfRequestSetInformation
// followed by WdfRequestComplete.
# if defined(WIL_KERNEL_MODE)
if ( m_completionFlags . priorityBoostSet )
{
if ( m_completionFlags . informationSet )
{
WdfRequestSetInformation ( m_wdfRequest , m_information ) ;
}
WdfRequestCompleteWithPriorityBoost ( m_wdfRequest , m_status , m_priorityBoost ) ;
}
else
# endif
if ( m_completionFlags . informationSet )
{
WdfRequestCompleteWithInformation ( m_wdfRequest , m_status , m_information ) ;
}
else
{
WdfRequestComplete ( m_wdfRequest , m_status ) ;
}
}
// We call clear_state unconditionally just in case some parameters (status,
// information, etc.) were set prior to attaching a WDFREQUEST to this object. Those
// parameters are not considered relevant to the WDFREQUEST being attached to this
// object now.
clear_state ( * this , newWdfRequest ) ;
}
private :
static void clear_state ( wdf_request_completer & completer , WDFREQUEST newWdfRequest = WDF_NO_HANDLE ) WI_NOEXCEPT
{
completer . m_wdfRequest = newWdfRequest ;
completer . m_status = STATUS_UNSUCCESSFUL ;
completer . m_information = 0 ;
# if defined(WIL_KERNEL_MODE)
completer . m_priorityBoost = 0 ;
# endif
completer . m_completionFlags = { } ;
}
// Members are ordered in decreasing size to minimize padding.
WDFREQUEST m_wdfRequest = WDF_NO_HANDLE ;
// This will not be used unless m_completionFlags.informationSet is set.
ULONG_PTR m_information = 0 ;
// There is no reasonably default NTSTATUS value. Callers are expected to explicitly set a
// status value at the point where it is decided that the request needs to be completed.
NTSTATUS m_status = STATUS_UNSUCCESSFUL ;
// UMDF does not support WdfRequestCompleteWithPriorityBoost.
# if defined(WIL_KERNEL_MODE)
// This will not be used unless m_completionFlags.priorityBoostSet is set.
CCHAR m_priorityBoost = 0 ;
# endif
struct
{
UINT8 informationSet : 1 ;
# if defined(WIL_KERNEL_MODE)
UINT8 priorityBoostSet : 1 ;
# endif
} m_completionFlags = { } ;
} ;
# endif
# if (WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && defined(_CFGMGR32_H_) && (WINVER >= _WIN32_WINNT_WIN8) && !defined(__WIL_CFGMGR32_H_)) || \
defined ( WIL_DOXYGEN )
/// @cond
# define __WIL_CFGMGR32_H_
/// @endcond
typedef unique_any < HCMNOTIFICATION , decltype ( & : : CM_Unregister_Notification ) , : : CM_Unregister_Notification > unique_hcmnotification ;
# endif
# if (WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && defined(_SWDEVICE_H_) && (WINVER >= _WIN32_WINNT_WIN8) && !defined(__WIL_SWDEVICE_H_)) || \
defined ( WIL_DOXYGEN )
/// @cond
# define __WIL_SWDEVICE_H_
/// @endcond
typedef unique_any < HSWDEVICE , decltype ( & : : SwDeviceClose ) , : : SwDeviceClose > unique_hswdevice ;
# endif
# if defined(WIL_KERNEL_MODE) && (defined(_WDMDDK_) || defined(_NTDDK_)) && !defined(__WIL_RESOURCE_WDM)
# define __WIL_RESOURCE_WDM
/// @cond
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.
WI_NODISCARD 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 ) ;
}
} // namespace details
/// @endcond
using kspin_lock_guard =
unique_any < PKSPIN_LOCK , decltype ( details : : kspin_lock_saved_irql : : Release ) , & details : : kspin_lock_saved_irql : : Release , details : : pointer_access_none , details : : kspin_lock_saved_irql > ;
using kspin_lock_at_dpc_guard =
unique_any < PKSPIN_LOCK , decltype ( details : : ReleaseSpinLockFromDpcLevel ) , & details : : ReleaseSpinLockFromDpcLevel , details : : pointer_access_none > ;
WI_NODISCARD
inline _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 ) ;
}
WI_NODISCARD
inline _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 ;
} ;
/// @cond
namespace details
{
template < EVENT_TYPE eventType >
class kernel_event_t
{
public :
explicit kernel_event_t ( bool isSignaled = false ) WI_NOEXCEPT
{
: : KeInitializeEvent ( & m_kernelEvent , static_cast < EVENT_TYPE > ( 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.
WI_NODISCARD bool is_signaled ( ) const WI_NOEXCEPT
{
return : : KeReadStateEvent ( const_cast < PRKEVENT > ( & 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 ;
} ;
} // namespace details
/// @endcond
using kernel_event_auto_reset = details : : kernel_event_t < SynchronizationEvent > ;
using kernel_event_manual_reset = details : : kernel_event_t < NotificationEvent > ;
using kernel_event = kernel_event_auto_reset ; // For parity with the default for other WIL event types.
/**
RAII class and lock - guards for a kernel FAST_MUTEX .
*/
using fast_mutex_guard = unique_any < FAST_MUTEX * , decltype ( : : ExReleaseFastMutex ) , & : : ExReleaseFastMutex , details : : pointer_access_none > ;
WI_NODISCARD
inline _IRQL_requires_max_ ( APC_LEVEL )
fast_mutex_guard acquire_fast_mutex ( FAST_MUTEX * fastMutex ) WI_NOEXCEPT
{
: : ExAcquireFastMutex ( fastMutex ) ;
return fast_mutex_guard ( fastMutex ) ;
}
WI_NODISCARD
inline _IRQL_requires_max_ ( APC_LEVEL )
fast_mutex_guard try_acquire_fast_mutex ( FAST_MUTEX * fastMutex ) WI_NOEXCEPT
{
if ( : : ExTryToAcquireFastMutex ( fastMutex ) )
{
return fast_mutex_guard ( fastMutex ) ;
}
else
{
return fast_mutex_guard ( ) ;
}
}
class fast_mutex
{
public :
fast_mutex ( ) WI_NOEXCEPT
{
: : ExInitializeFastMutex ( & m_fastMutex ) ;
}
~ fast_mutex ( ) WI_NOEXCEPT = default ;
// Cannot change memory location.
fast_mutex ( const fast_mutex & ) = delete ;
fast_mutex & operator = ( const fast_mutex & ) = delete ;
fast_mutex ( fast_mutex & & ) = delete ;
fast_mutex & operator = ( fast_mutex & & ) = delete ;
// Calls ExAcquireFastMutex. Returned wil::unique_any object calls ExReleaseFastMutex on
// destruction.
WI_NODISCARD
_IRQL_requires_max_ ( APC_LEVEL )
fast_mutex_guard acquire ( ) WI_NOEXCEPT
{
return acquire_fast_mutex ( & m_fastMutex ) ;
}
// Calls ExTryToAcquireFastMutex. Returned wil::unique_any may be empty. If non-empty, it
// calls ExReleaseFastMutex on destruction.
WI_NODISCARD
_IRQL_requires_max_ ( APC_LEVEL )
fast_mutex_guard try_acquire ( ) WI_NOEXCEPT
{
return try_acquire_fast_mutex ( & m_fastMutex ) ;
}
private :
FAST_MUTEX m_fastMutex ;
} ;
/// @cond
namespace details
{
_IRQL_requires_max_ ( APC_LEVEL )
inline void release_fast_mutex_with_critical_region ( FAST_MUTEX * fastMutex ) WI_NOEXCEPT
{
: : ExReleaseFastMutexUnsafe ( fastMutex ) ;
: : KeLeaveCriticalRegion ( ) ;
}
} // namespace details
/// @endcond
using fast_mutex_with_critical_region_guard =
unique_any < FAST_MUTEX * , decltype ( details : : release_fast_mutex_with_critical_region ) , & details : : release_fast_mutex_with_critical_region , details : : pointer_access_none > ;
WI_NODISCARD
inline _IRQL_requires_max_ ( APC_LEVEL )
fast_mutex_with_critical_region_guard acquire_fast_mutex_with_critical_region ( FAST_MUTEX * fastMutex ) WI_NOEXCEPT
{
: : KeEnterCriticalRegion ( ) ;
: : ExAcquireFastMutexUnsafe ( fastMutex ) ;
return fast_mutex_with_critical_region_guard ( fastMutex ) ;
}
// A FAST_MUTEX lock class that calls KeEnterCriticalRegion and then ExAcquireFastMutexUnsafe.
// Returned wil::unique_any lock-guard calls ExReleaseFastMutexUnsafe and KeLeaveCriticalRegion
// on destruction. This is useful if calling code wants to stay at PASSIVE_LEVEL.
class fast_mutex_with_critical_region
{
public :
fast_mutex_with_critical_region ( ) WI_NOEXCEPT
{
: : ExInitializeFastMutex ( & m_fastMutex ) ;
}
~ fast_mutex_with_critical_region ( ) WI_NOEXCEPT = default ;
// Cannot change memory location.
fast_mutex_with_critical_region ( const fast_mutex_with_critical_region & ) = delete ;
fast_mutex_with_critical_region & operator = ( const fast_mutex_with_critical_region & ) = delete ;
fast_mutex_with_critical_region ( fast_mutex_with_critical_region & & ) = delete ;
fast_mutex_with_critical_region & operator = ( fast_mutex_with_critical_region & & ) = delete ;
WI_NODISCARD
_IRQL_requires_max_ ( APC_LEVEL )
fast_mutex_with_critical_region_guard acquire ( ) WI_NOEXCEPT
{
return acquire_fast_mutex_with_critical_region ( & m_fastMutex ) ;
}
private :
FAST_MUTEX m_fastMutex ;
} ;
//! A type that calls KeLeaveCriticalRegion on destruction (or reset()).
using unique_leave_critical_region_call = unique_call < decltype ( & : : KeLeaveCriticalRegion ) , : : KeLeaveCriticalRegion > ;
//! Disables user APCs and normal kernel APCs; returns an RAII object that reverts
WI_NODISCARD inline unique_leave_critical_region_call enter_critical_region ( )
{
KeEnterCriticalRegion ( ) ;
return { } ;
}
//! A type that calls KeLeaveGuardedRegion on destruction (or reset()).
using unique_leave_guarded_region_call = unique_call < decltype ( & : : KeLeaveGuardedRegion ) , : : KeLeaveGuardedRegion > ;
//! Disables all APCs; returns an RAII object that reverts
WI_NODISCARD inline unique_leave_guarded_region_call enter_guarded_region ( )
{
KeEnterGuardedRegion ( ) ;
return { } ;
}
//! WDM version of EX_PUSH_LOCK is available starting with Windows 10 1809
# if (NTDDI_VERSION >= NTDDI_WIN10_RS5)
/// @cond
namespace details
{
_IRQL_requires_max_ ( APC_LEVEL )
inline void release_push_lock_exclusive ( EX_PUSH_LOCK * pushLock ) WI_NOEXCEPT
{
: : ExReleasePushLockExclusive ( pushLock ) ;
: : KeLeaveCriticalRegion ( ) ;
}
_IRQL_requires_max_ ( APC_LEVEL )
inline void release_push_lock_shared ( EX_PUSH_LOCK * pushLock ) WI_NOEXCEPT
{
: : ExReleasePushLockShared ( pushLock ) ;
: : KeLeaveCriticalRegion ( ) ;
}
} // namespace details
/// @endcond
using push_lock_exclusive_guard =
unique_any < EX_PUSH_LOCK * , decltype ( & details : : release_push_lock_exclusive ) , & details : : release_push_lock_exclusive , details : : pointer_access_noaddress > ;
using push_lock_shared_guard =
unique_any < EX_PUSH_LOCK * , decltype ( & details : : release_push_lock_shared ) , & details : : release_push_lock_shared , details : : pointer_access_noaddress > ;
WI_NODISCARD
inline _IRQL_requires_max_ ( APC_LEVEL )
push_lock_exclusive_guard acquire_push_lock_exclusive ( EX_PUSH_LOCK * pushLock ) WI_NOEXCEPT
{
: : KeEnterCriticalRegion ( ) ;
: : ExAcquirePushLockExclusive ( pushLock ) ;
return push_lock_exclusive_guard ( pushLock ) ;
}
WI_NODISCARD
inline _IRQL_requires_max_ ( APC_LEVEL )
push_lock_shared_guard acquire_push_lock_shared ( EX_PUSH_LOCK * pushLock ) WI_NOEXCEPT
{
: : KeEnterCriticalRegion ( ) ;
: : ExAcquirePushLockShared ( pushLock ) ;
return push_lock_shared_guard ( pushLock ) ;
}
class push_lock
{
public :
push_lock ( ) WI_NOEXCEPT
{
: : ExInitializePushLock ( & m_pushLock ) ;
}
~ push_lock ( ) WI_NOEXCEPT = default ;
// Cannot change memory location.
push_lock ( const push_lock & ) = delete ;
push_lock & operator = ( const push_lock & ) = delete ;
push_lock ( push_lock & & ) = delete ;
push_lock & operator = ( push_lock & & ) = delete ;
WI_NODISCARD
_IRQL_requires_max_ ( APC_LEVEL )
push_lock_exclusive_guard acquire_exclusive ( ) WI_NOEXCEPT
{
return acquire_push_lock_exclusive ( & m_pushLock ) ;
}
WI_NODISCARD
_IRQL_requires_max_ ( APC_LEVEL )
push_lock_shared_guard acquire_shared ( ) WI_NOEXCEPT
{
return acquire_push_lock_shared ( & m_pushLock ) ;
}
private :
EX_PUSH_LOCK m_pushLock ;
} ;
# endif
/// @cond
namespace details
{
// Define a templated type for pool functions in order to satisfy overload resolution below
template < typename pointer , ULONG tag >
struct pool_helpers
{
static inline _IRQL_requires_max_ ( DISPATCH_LEVEL )
void __stdcall FreePoolWithTag ( pointer value ) WI_NOEXCEPT
{
if ( value )
{
ExFreePoolWithTag ( value , tag ) ;
}
}
} ;
} // namespace details
/// @endcond
template < typename pointer , ULONG tag = 0 >
using unique_tagged_pool_ptr =
unique_any < pointer , decltype ( details : : pool_helpers < pointer , tag > : : FreePoolWithTag ) , & details : : pool_helpers < pointer , tag > : : FreePoolWithTag > ;
// For use with IRPs that need to be IoFreeIrp'ed when done, typically allocated using IoAllocateIrp.
using unique_allocated_irp = wil : : unique_any < PIRP , decltype ( & : : IoFreeIrp ) , : : IoFreeIrp , details : : pointer_access_noaddress > ;
using unique_io_workitem =
wil : : unique_any < PIO_WORKITEM , decltype ( & : : IoFreeWorkItem ) , : : IoFreeWorkItem , details : : pointer_access_noaddress > ;
# 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 < HANDLE , decltype ( & : : ZwClose ) , : : ZwClose > ;
# endif // __WIL_RESOURCE_ZWAPI
# if (defined(WINTRUST_H) && defined(SOFTPUB_H) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(__WIL_WINTRUST)) || \
defined ( WIL_DOXYGEN )
/// @cond
# define __WIL_WINTRUST
namespace details
{
inline void __stdcall CloseWintrustData ( _Inout_ WINTRUST_DATA * wtData ) WI_NOEXCEPT
{
GUID guidV2 = WINTRUST_ACTION_GENERIC_VERIFY_V2 ;
wtData - > dwStateAction = WTD_STATEACTION_CLOSE ;
WinVerifyTrust ( static_cast < HWND > ( INVALID_HANDLE_VALUE ) , & guidV2 , wtData ) ;
}
} // namespace details
/// @endcond
typedef wil : : unique_struct < WINTRUST_DATA , decltype ( & details : : CloseWintrustData ) , details : : CloseWintrustData > unique_wintrust_data ;
# endif // __WIL_WINTRUST
# if (defined(MSCAT_H) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(__WIL_MSCAT)) || defined(WIL_DOXYGEN)
/// @cond
# define __WIL_MSCAT
namespace details
{
inline void __stdcall CryptCATAdminReleaseContextNoFlags ( _Pre_opt_valid_ _Frees_ptr_opt_ HCATADMIN handle ) WI_NOEXCEPT
{
CryptCATAdminReleaseContext ( handle , 0 ) ;
}
} // namespace details
/// @endcond
typedef wil : : unique_any < HCATADMIN , decltype ( & details : : CryptCATAdminReleaseContextNoFlags ) , details : : CryptCATAdminReleaseContextNoFlags > unique_hcatadmin ;
# if defined(WIL_RESOURCE_STL)
typedef shared_any < unique_hcatadmin > shared_hcatadmin ;
struct hcatinfo_deleter
{
hcatinfo_deleter ( wil : : shared_hcatadmin handle ) WI_NOEXCEPT : m_hCatAdmin ( wistd : : move ( handle ) )
{
}
void operator ( ) ( _Pre_opt_valid_ _Frees_ptr_opt_ HCATINFO handle ) const WI_NOEXCEPT
{
CryptCATAdminReleaseCatalogContext ( m_hCatAdmin . get ( ) , handle , 0 ) ;
}
wil : : shared_hcatadmin m_hCatAdmin ;
} ;
// This stores HCATINFO, i.e. HANDLE (void *)
typedef wistd : : unique_ptr < void , hcatinfo_deleter > unique_hcatinfo ;
/// @cond
namespace details
{
class crypt_catalog_enumerator
{
wil : : unique_hcatinfo m_hCatInfo ;
const BYTE * m_hash ;
DWORD m_hashLen ;
bool m_initialized = false ;
struct ref
{
explicit ref ( crypt_catalog_enumerator & r ) WI_NOEXCEPT : m_r ( r )
{
}
WI_NODISCARD operator HCATINFO ( ) const WI_NOEXCEPT
{
return m_r . current ( ) ;
}
wil : : unique_hcatinfo move_from_unique_hcatinfo ( ) WI_NOEXCEPT
{
wil : : unique_hcatinfo info ( wistd : : move ( m_r . m_hCatInfo ) ) ;
return info ;
}
WI_NODISCARD bool operator = = ( wistd : : nullptr_t ) const WI_NOEXCEPT
{
return m_r . m_hCatInfo = = nullptr ;
}
WI_NODISCARD bool operator ! = ( wistd : : nullptr_t ) const WI_NOEXCEPT
{
return ! ( * this = = nullptr ) ;
}
private :
crypt_catalog_enumerator & m_r ;
} ;
struct iterator
{
# if defined(_XUTILITY_) || defined(WIL_DOXYGEN)
// muse be input_iterator_tag as use of one instance invalidates the other.
typedef : : std : : input_iterator_tag iterator_category ;
# endif
explicit iterator ( crypt_catalog_enumerator * r ) WI_NOEXCEPT : m_r ( r )
{
}
iterator ( const iterator & ) = default ;
iterator ( iterator & & ) = default ;
iterator & operator = ( const iterator & ) = default ;
iterator & operator = ( iterator & & ) = default ;
WI_NODISCARD bool operator = = ( const iterator & rhs ) const WI_NOEXCEPT
{
if ( rhs . m_r = = m_r )
{
return true ;
}
return ( * this = = nullptr ) & & ( rhs = = nullptr ) ;
}
WI_NODISCARD bool operator ! = ( const iterator & rhs ) const WI_NOEXCEPT
{
return ! ( rhs = = * this ) ;
}
WI_NODISCARD bool operator = = ( wistd : : nullptr_t ) const WI_NOEXCEPT
{
return nullptr = = m_r | | nullptr = = m_r - > current ( ) ;
}
WI_NODISCARD bool operator ! = ( wistd : : nullptr_t ) const WI_NOEXCEPT
{
return ! ( * this = = nullptr ) ;
}
iterator & operator + + ( ) WI_NOEXCEPT
{
if ( m_r ! = nullptr )
{
m_r - > next ( ) ;
}
return * this ;
}
WI_NODISCARD ref operator * ( ) const WI_NOEXCEPT
{
return ref ( * m_r ) ;
}
private :
crypt_catalog_enumerator * m_r ;
} ;
shared_hcatadmin & hcatadmin ( ) WI_NOEXCEPT
{
return m_hCatInfo . get_deleter ( ) . m_hCatAdmin ;
}
bool move_next ( ) WI_NOEXCEPT
{
HCATINFO prevCatInfo = m_hCatInfo . release ( ) ;
m_hCatInfo . reset ( : : CryptCATAdminEnumCatalogFromHash ( hcatadmin ( ) . get ( ) , const_cast < BYTE * > ( m_hash ) , m_hashLen , 0 , & prevCatInfo ) ) ;
return ! ! m_hCatInfo ;
}
HCATINFO next ( ) WI_NOEXCEPT
{
if ( m_initialized & & m_hCatInfo )
{
move_next ( ) ;
}
return current ( ) ;
}
HCATINFO init ( ) WI_NOEXCEPT
{
if ( ! m_initialized )
{
m_initialized = true ;
move_next ( ) ;
}
return current ( ) ;
}
HCATINFO current ( ) WI_NOEXCEPT
{
return m_hCatInfo . get ( ) ;
}
public :
crypt_catalog_enumerator ( wil : : shared_hcatadmin & hCatAdmin , const BYTE * hash , DWORD hashLen ) WI_NOEXCEPT
: m_hCatInfo ( nullptr , hCatAdmin ) ,
m_hash ( hash ) ,
m_hashLen ( hashLen )
// , m_initialized(false) // redundant
{
}
WI_NODISCARD iterator begin ( ) WI_NOEXCEPT
{
init ( ) ;
return iterator ( this ) ;
}
WI_NODISCARD iterator end ( ) const WI_NOEXCEPT
{
return iterator ( nullptr ) ;
}
crypt_catalog_enumerator ( crypt_catalog_enumerator & & ) = default ;
crypt_catalog_enumerator & operator = ( crypt_catalog_enumerator & & ) = default ;
crypt_catalog_enumerator ( const crypt_catalog_enumerator & ) = delete ;
crypt_catalog_enumerator & operator = ( const crypt_catalog_enumerator & ) = delete ;
} ;
} // namespace details
/// @endcond
/** Use to enumerate catalogs containing a hash with a range-based for.
This avoids handling a raw resource to call CryptCATAdminEnumCatalogFromHash correctly .
Example :
` for ( auto & & cat : wil : : make_catalog_enumerator ( hCatAdmin , hash , hashLen ) )
{ CryptCATCatalogInfoFromContext ( cat , & catInfo , 0 ) ; } ` */
inline details : : crypt_catalog_enumerator make_crypt_catalog_enumerator (
wil : : shared_hcatadmin & hCatAdmin , _In_count_ ( hashLen ) const BYTE * hash , DWORD hashLen ) WI_NOEXCEPT
{
return details : : crypt_catalog_enumerator ( hCatAdmin , hash , hashLen ) ;
}
template < size_t Size >
details : : crypt_catalog_enumerator make_crypt_catalog_enumerator ( wil : : shared_hcatadmin & hCatAdmin , const BYTE ( & hash ) [ Size ] ) WI_NOEXCEPT
{
static_assert ( Size < = static_cast < size_t > ( 0xffffffffUL ) , " Array size truncated " ) ;
return details : : crypt_catalog_enumerator ( hCatAdmin , hash , static_cast < DWORD > ( Size ) ) ;
}
# endif // WI_RESOURCE_STL
# endif // __WIL_MSCAT
# if !defined(__WIL_RESOURCE_LOCK_ENFORCEMENT)
/// @cond
# define __WIL_RESOURCE_LOCK_ENFORCEMENT
/// @endcond
/// @cond
namespace details
{
// Only those lock types specialized by lock_proof_traits will allow either a write_lock_required or
// read_lock_required to be constructed. The allows_exclusive value indicates if the type represents an exclusive,
2024-12-05 06:06:53 +00:00
// write-safe lock acquisition, or a shared, read-only lock acquisition.
2024-06-10 06:09:51 +00:00
template < typename T >
struct lock_proof_traits
{
} ;
// Base for specializing lock_proof_traits where the lock type is shared
struct shared_lock_proof
{
static constexpr bool allows_shared = true ;
} ;
// Base for specializing lock_proof_traits where the lock type is exclusive (super-set of shared_lock_proof)
struct exclusive_lock_proof : shared_lock_proof
{
static constexpr bool allows_exclusive = true ;
} ;
} // namespace details
/// @endcond
/**
Functions that need an exclusive lock use can use write_lock_required as a parameter to enforce lock
safety at compile time . Similarly , read_lock_required may stand as a parameter where shared ownership
of a lock is required . These are empty structs that will never be used , other than passing them on to
another function that requires them .
These types are implicitly convertible from various lock holding types , enabling callers to provide them as
proof of the lock that they hold .
2024-12-05 06:06:53 +00:00
The following example is intentionally contrived to demonstrate multiple use cases :
2024-06-10 06:09:51 +00:00
- Methods that require only shared / read access
- Methods that require only exclusive write access
- Methods that pass their proof - of - lock to a helper
~ ~ ~
class RemoteControl
{
public :
void VolumeUp ( ) ;
int GetVolume ( ) ;
private :
int GetCurrentVolume ( wil : : read_lock_required ) ;
void AdjustVolume ( int delta , wil : : write_lock_required ) ;
void SetNewVolume ( int newVolume , wil : : write_lock_required ) ;
int m_currentVolume = 0 ;
wil : : srwlock m_lock ;
} ;
void RemoteControl : : VolumeUp ( )
{
auto writeLock = m_lock . lock_exclusive ( ) ;
AdjustVolume ( 1 , writeLock ) ;
}
int RemoteControl : : GetVolume ( )
{
auto readLock = m_lock . lock_shared ( ) ;
return GetCurrentVolume ( readLock ) ;
}
int RemoteControl : : GetCurrentVolume ( wil : : read_lock_required )
{
return m_currentVolume ;
}
void AdjustVolume ( int delta , wil : : write_lock_required lockProof )
{
const auto currentVolume = GetCurrentVolume ( lockProof ) ;
SetNewVolume ( currentVolume + delta , lockProof ) ;
}
void RemoteControl : : SetNewVolume ( int newVolume , wil : : write_lock_required )
{
m_currentVolume = newVolume ;
}
~ ~ ~
In this design it is impossible to not meet the " lock must be held " precondition and the function parameter types
help you understand which one .
Cases not handled :
- Functions that need the lock held , but fail to specify this fact by requiring a lock required parameter need
to be found via code inspection .
- Recursively taking a lock , when it is already held , is not avoided in this pattern
- Readers will learn to be suspicious of acquiring a lock in functions with lock required parameters .
- Designs with multiple locks , that must be careful to take them in the same order every time , are not helped
by this pattern .
- Locking the wrong object
- Use of a std : : lock type that has not actually be secured yet ( such as by std : : try_to_lock or std : : defer_lock )
- or use of a lock type that had been acquired but has since been released , reset , or otherwise unlocked
These utility types are not fool - proof against all lock misuse , anti - patterns , or other complex yet valid
scenarios . However on the net , their usage in typical cases can assist in creating clearer , self - documenting
code that catches the common issues of forgetting to hold a lock or forgetting whether a lock is required to
call another method safely .
*/
struct write_lock_required
{
/**
Construct a new write_lock_required object for use as proof that an exclusive lock has been acquired .
*/
template < typename TLockProof >
write_lock_required ( const TLockProof & , wistd : : enable_if_t < details : : lock_proof_traits < TLockProof > : : allows_exclusive , int > = 0 )
{
}
write_lock_required ( ) = delete ; // No default construction
} ;
/**
Stands as proof that a shared lock has been acquired . See write_lock_required for more information .
*/
struct read_lock_required
{
/**
Construct a new read_lock_required object for use as proof that a shared lock has been acquired .
*/
template < typename TLockProof >
read_lock_required ( const TLockProof & , wistd : : enable_if_t < details : : lock_proof_traits < TLockProof > : : allows_shared , int > = 0 )
{
}
/**
Uses a prior write_lock_required object to construct a read_lock_required object as proof that at shared lock
has been acquired . ( Exclusive locks held are presumed to suffice for proof of a read lock )
*/
read_lock_required ( const write_lock_required & )
{
}
read_lock_required ( ) = delete ; // No default construction
} ;
# endif // __WIL_RESOURCE_LOCK_ENFORCEMENT
# if defined(__WIL_WINBASE_) && !defined(__WIL__RESOURCE_LOCKPROOF_WINBASE) && defined(__WIL_RESOURCE_LOCK_ENFORCEMENT)
# define __WIL__RESOURCE_LOCKPROOF_WINBASE
/// @cond
namespace details
{
// Specializations for srwlock
template < >
struct lock_proof_traits < rwlock_release_shared_scope_exit > : shared_lock_proof
{
} ;
template < >
struct lock_proof_traits < rwlock_release_exclusive_scope_exit > : exclusive_lock_proof
{
} ;
// Specialization for critical_section
template < >
struct lock_proof_traits < cs_leave_scope_exit > : exclusive_lock_proof
{
} ;
} // namespace details
/// @endcond
# endif //__WIL__RESOURCE_LOCKPROOF_WINBASE
# if defined(_MUTEX_) && !defined(__WIL__RESOURCE_LOCKPROOF_MUTEX) && defined(__WIL_RESOURCE_LOCK_ENFORCEMENT)
# define __WIL__RESOURCE_LOCKPROOF_MUTEX
/// @cond
namespace details
{
template < typename TMutex >
struct lock_proof_traits < std : : unique_lock < TMutex > > : exclusive_lock_proof
{
} ;
template < typename TMutex >
struct lock_proof_traits < std : : lock_guard < TMutex > > : exclusive_lock_proof
{
} ;
} // namespace details
/// @endcond
# endif //__WIL__RESOURCE_LOCKPROOF_MUTEX
# if defined(_SHARED_MUTEX_) && !defined(__WIL__RESOURCE_LOCKPROOF_SHAREDMUTEX) && defined(__WIL_RESOURCE_LOCK_ENFORCEMENT)
# define __WIL__RESOURCE_LOCKPROOF_SHAREDMUTEX
/// @cond
namespace details
{
template < typename TMutex >
struct lock_proof_traits < std : : shared_lock < TMutex > > : shared_lock_proof
{
} ;
} // namespace details
/// @endcond
# endif //__WIL__RESOURCE_LOCKPROOF_SHAREDMUTEX
} // namespace wil
# pragma warning(pop)