1 //*********************************************************
2 //
3 //    Copyright (c) Microsoft. All rights reserved.
4 //    This code is licensed under the MIT License.
5 //    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
6 //    ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
7 //    TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
8 //    PARTICULAR PURPOSE AND NONINFRINGEMENT.
9 //
10 //*********************************************************
11 
12 #include "result_macros.h"
13 #include "wistd_functional.h"
14 #include "wistd_memory.h"
15 
16 #pragma warning(push)
17 #pragma warning(disable:26135 26110)    // Missing locking annotation, Caller failing to hold lock
18 #pragma warning(disable:4714)           // __forceinline not honored
19 
20 #ifndef __WIL_RESOURCE
21 #define __WIL_RESOURCE
22 
23 // stdint.h and intsafe.h have conflicting definitions, so it's not safe to include either to pick up our dependencies,
24 // so the definitions we need are copied below
25 #ifdef _WIN64
26 #define __WI_SIZE_MAX   0xffffffffffffffffui64 // UINT64_MAX
27 #else /* _WIN64 */
28 #define __WI_SIZE_MAX   0xffffffffui32 // UINT32_MAX
29 #endif /* _WIN64 */
30 
31 // Forward declaration
32 /// @cond
33 namespace Microsoft
34 {
35     namespace WRL
36     {
37         template <typename T>
38         class ComPtr;
39     }
40 }
41 /// @endcond
42 
43 namespace wil
44 {
45     //! This type copies the current value of GetLastError at construction and resets the last error
46     //! to that value when it is destroyed.
47     //!
48     //! This is useful in library code that runs during a value's destructor. If the library code could
49     //! inadvertantly change the value of GetLastError (by calling a Win32 API or similar), it should
50     //! instantiate a value of this type before calling the library function in order to preserve the
51     //! GetLastError value the user would expect.
52     //!
53     //! This construct exists to hide kernel mode/user mode differences in wil library code.
54     //!
55     //! Example usage:
56     //!
57     //!     if (!CreateFile(...))
58     //!     {
59     //!         auto lastError = wil::last_error_context();
60     //!         WriteFile(g_hlog, logdata);
61     //!     }
62     //!
63     class last_error_context
64     {
65 #ifndef WIL_KERNEL_MODE
66         bool m_dismissed;
67         DWORD m_error;
68     public:
last_error_context()69         last_error_context() WI_NOEXCEPT :
70             m_dismissed(false),
71             m_error(::GetLastError())
72         {
73         }
74 
last_error_context(last_error_context && other)75         last_error_context(last_error_context&& other) WI_NOEXCEPT
76         {
77             operator=(wistd::move(other));
78         }
79 
80         last_error_context & operator=(last_error_context&& other) WI_NOEXCEPT
81         {
82             m_dismissed = wistd::exchange(other.m_dismissed, true);
83             m_error = other.m_error;
84 
85             return *this;
86         }
87 
~last_error_context()88         ~last_error_context() WI_NOEXCEPT
89         {
90             if (!m_dismissed)
91             {
92                 ::SetLastError(m_error);
93             }
94         }
95 
96         //! last_error_context doesn't own a concrete resource, so therefore
97         //! it just disarms its destructor and returns void.
release()98         void release() WI_NOEXCEPT
99         {
100             WI_ASSERT(!m_dismissed);
101             m_dismissed = true;
102         }
103 #else
104     public:
105         void release() WI_NOEXCEPT { }
106 #endif // WIL_KERNEL_MODE
107     };
108 
109     /// @cond
110     namespace details
111     {
112         typedef wistd::integral_constant<size_t, 0> pointer_access_all;             // get(), release(), addressof(), and '&' are available
113         typedef wistd::integral_constant<size_t, 1> pointer_access_noaddress;       // get() and release() are available
114         typedef wistd::integral_constant<size_t, 2> pointer_access_none;            // the raw pointer is not available
115 
116         template <typename pointer,                                           // The handle type
117             typename close_fn_t,                                              // The handle close function type
118             close_fn_t close_fn,                                              //      * and function pointer
119             typename pointer_access = pointer_access_all,                     // all, noaddress or none to control pointer method access
120             typename pointer_storage = pointer,                               // The type used to store the handle (usually the same as the handle itself)
121             typename invalid_t = pointer,                                     // The invalid handle value type
122             invalid_t invalid = invalid_t(),                                  //      * and its value (default ZERO value)
123             typename pointer_invalid = wistd::nullptr_t>                      // nullptr_t if the invalid handle value is compatible with nullptr, otherwise pointer
124             struct resource_policy
125         {
126             typedef pointer_storage pointer_storage;
127             typedef pointer pointer;
128             typedef pointer_invalid pointer_invalid;
129             typedef pointer_access pointer_access;
invalid_valueresource_policy130             __forceinline static pointer_storage invalid_value() WI_NOEXCEPT { return (pointer)invalid; }
is_validresource_policy131             __forceinline static bool is_valid(pointer_storage value) WI_NOEXCEPT { return (static_cast<pointer>(value) != (pointer)invalid); }
closeresource_policy132             __forceinline static void close(pointer_storage value) WI_NOEXCEPT { wistd::invoke(close_fn, value); }
133 
close_resetresource_policy134             inline static void close_reset(pointer_storage value) WI_NOEXCEPT
135             {
136                 auto preserveError = last_error_context();
137                 wistd::invoke(close_fn, value);
138             }
139         };
140 
141 
142         // This class provides the pointer storage behind the implementation of unique_any_t utilizing the given
143         // resource_policy.  It is separate from unique_any_t to allow a type-specific specialization class to plug
144         // into the inheritance chain between unique_any_t and unique_storage.  This allows classes like unique_event
145         // to be a unique_any formed class, but also expose methods like SetEvent directly.
146 
147         template <typename policy>
148         class unique_storage
149         {
150         protected:
151             typedef policy policy;
152             typedef typename policy::pointer_storage pointer_storage;
153             typedef typename policy::pointer pointer;
154             typedef unique_storage<policy> base_storage;
155 
unique_storage()156             unique_storage() WI_NOEXCEPT :
157             m_ptr(policy::invalid_value())
158             {
159             }
160 
unique_storage(pointer_storage ptr)161             explicit unique_storage(pointer_storage ptr) WI_NOEXCEPT :
162                 m_ptr(ptr)
163             {
164             }
165 
unique_storage(unique_storage && other)166             unique_storage(unique_storage &&other) WI_NOEXCEPT :
167                 m_ptr(wistd::move(other.m_ptr))
168             {
169                 other.m_ptr = policy::invalid_value();
170             }
171 
~unique_storage()172             ~unique_storage() WI_NOEXCEPT
173             {
174                 if (policy::is_valid(m_ptr))
175                 {
176                     policy::close(m_ptr);
177                 }
178             }
179 
replace(unique_storage && other)180             void replace(unique_storage &&other) WI_NOEXCEPT
181             {
182                 reset(other.m_ptr);
183                 other.m_ptr = policy::invalid_value();
184             }
185 
186         public:
is_valid()187             bool is_valid() const WI_NOEXCEPT
188             {
189                 return policy::is_valid(m_ptr);
190             }
191 
192             void reset(pointer_storage ptr = policy::invalid_value()) WI_NOEXCEPT
193             {
194                 if (policy::is_valid(m_ptr))
195                 {
196                     policy::close_reset(m_ptr);
197                 }
198                 m_ptr = ptr;
199             }
200 
reset(wistd::nullptr_t)201             void reset(wistd::nullptr_t) WI_NOEXCEPT
202             {
203                 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");
204                 reset();
205             }
206 
get()207             pointer get() const WI_NOEXCEPT
208             {
209                 return static_cast<pointer>(m_ptr);
210             }
211 
release()212             pointer_storage release() WI_NOEXCEPT
213             {
214                 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");
215                 auto ptr = m_ptr;
216                 m_ptr = policy::invalid_value();
217                 return ptr;
218             }
219 
addressof()220             pointer_storage *addressof() WI_NOEXCEPT
221             {
222                 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");
223                 return &m_ptr;
224             }
225 
226         private:
227             pointer_storage m_ptr;
228         };
229     } // details
230       /// @endcond
231 
232 
233       // This class when paired with unique_storage and an optional type-specific specialization class implements
234       // the same interface as STL's unique_ptr<> for resource handle types.  It is a non-copyable, yet movable class
235       // supporting attach (reset), detach (release), retrieval (get()).
236 
237     template <typename storage_t>
238     class unique_any_t : public storage_t
239     {
240     public:
241         typedef typename storage_t::policy policy;
242         typedef typename policy::pointer_storage pointer_storage;
243         typedef typename policy::pointer pointer;
244 
245         unique_any_t(unique_any_t const &) = delete;
246         unique_any_t& operator=(unique_any_t const &) = delete;
247 
248         // Note that the default constructor really shouldn't be needed (taken care of by the forwarding constructor below), but
249         // the forwarding constructor causes an internal compiler error when the class is used in a C++ array.  Defining the default
250         // constructor independent of the forwarding constructor removes the compiler limitation.
251         unique_any_t() = default;
252 
253         // forwarding constructor: forwards all 'explicit' and multi-arg constructors to the base class
254         template <typename arg1, typename... args_t>
unique_any_t(arg1 && first,args_t &&...args)255         explicit unique_any_t(arg1 && first, args_t&&... args) :  // should not be WI_NOEXCEPT (may forward to a throwing constructor)
256             storage_t(wistd::forward<arg1>(first), wistd::forward<args_t>(args)...)
257         {
258             static_assert(wistd::is_same<typename policy::pointer_access, details::pointer_access_none>::value ||
259                 wistd::is_same<typename policy::pointer_access, details::pointer_access_all>::value ||
260                 wistd::is_same<typename policy::pointer_access, details::pointer_access_noaddress>::value, "pointer_access policy must be a known pointer_access* integral type");
261         }
262 
unique_any_t(wistd::nullptr_t)263         unique_any_t(wistd::nullptr_t) WI_NOEXCEPT
264         {
265             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");
266         }
267 
unique_any_t(unique_any_t && other)268         unique_any_t(unique_any_t &&other) WI_NOEXCEPT :
269         storage_t(wistd::move(other))
270         {
271         }
272 
273         unique_any_t& operator=(unique_any_t &&other) WI_NOEXCEPT
274         {
275             if (this != wistd::addressof(other))
276             {
277                 // cast to base_storage to 'skip' calling the (optional) specialization class that provides handle-specific functionality
278                 storage_t::replace(wistd::move(static_cast<typename storage_t::base_storage &>(other)));
279             }
280             return (*this);
281         }
282 
283         unique_any_t& operator=(wistd::nullptr_t) WI_NOEXCEPT
284         {
285             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");
286             storage_t::reset();
287             return (*this);
288         }
289 
swap(unique_any_t & other)290         void swap(unique_any_t &other) WI_NOEXCEPT
291         {
292             unique_any_t self(wistd::move(*this));
293             operator=(wistd::move(other));
294             other = wistd::move(self);
295         }
296 
297         explicit operator bool() const WI_NOEXCEPT
298         {
299             return storage_t::is_valid();
300         }
301 
302         //! ~~~~
303         //! BOOL OpenOrCreateWaffle(PCWSTR name, HWAFFLE* handle);
304         //! wil::unique_any<HWAFFLE, decltype(&::CloseWaffle), ::CloseWaffle> waffle;
305         //! RETURN_IF_WIN32_BOOL_FALSE(OpenOrCreateWaffle(L"tasty.yum", waffle.put()));
306         //! ~~~~
put()307         pointer_storage *put() WI_NOEXCEPT
308         {
309             static_assert(wistd::is_same<typename policy::pointer_access, details::pointer_access_all>::value, "operator & is not available for this handle");
310             storage_t::reset();
311             return storage_t::addressof();
312         }
313 
314         pointer_storage *operator&() WI_NOEXCEPT
315         {
316             return put();
317         }
318 
get()319         pointer get() const WI_NOEXCEPT
320         {
321             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");
322             return storage_t::get();
323         }
324 
325         // The following functions are publicly exposed by their inclusion in the unique_storage base class
326 
327         // explicit unique_any_t(pointer_storage ptr) WI_NOEXCEPT
328         // void reset(pointer_storage ptr = policy::invalid_value()) WI_NOEXCEPT
329         // void reset(wistd::nullptr_t) WI_NOEXCEPT
330         // pointer_storage release() WI_NOEXCEPT                                        // not exposed for some resource types
331         // pointer_storage *addressof() WI_NOEXCEPT                                     // not exposed for some resource types
332     };
333 
334     template <typename policy>
swap(unique_any_t<policy> & left,unique_any_t<policy> & right)335     void swap(unique_any_t<policy>& left, unique_any_t<policy>& right) WI_NOEXCEPT
336     {
337         left.swap(right);
338     }
339 
340     template <typename policy>
341     bool operator==(const unique_any_t<policy>& left, const unique_any_t<policy>& right) WI_NOEXCEPT
342     {
343         return (left.get() == right.get());
344     }
345 
346     template <typename policy>
347     bool operator==(const unique_any_t<policy>& left, wistd::nullptr_t) WI_NOEXCEPT
348     {
349         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");
350         return !left;
351     }
352 
353     template <typename policy>
354     bool operator==(wistd::nullptr_t, const unique_any_t<policy>& right) WI_NOEXCEPT
355     {
356         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");
357         return !right;
358     }
359 
360     template <typename policy>
361     bool operator!=(const unique_any_t<policy>& left, const unique_any_t<policy>& right) WI_NOEXCEPT
362     {
363         return (!(left.get() == right.get()));
364     }
365 
366     template <typename policy>
367     bool operator!=(const unique_any_t<policy>& left, wistd::nullptr_t) WI_NOEXCEPT
368     {
369         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");
370         return !!left;
371     }
372 
373     template <typename policy>
374     bool operator!=(wistd::nullptr_t, const unique_any_t<policy>& right) WI_NOEXCEPT
375     {
376         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");
377         return !!right;
378     }
379 
380     template <typename policy>
381     bool operator<(const unique_any_t<policy>& left, const unique_any_t<policy>& right) WI_NOEXCEPT
382     {
383         return (left.get() < right.get());
384     }
385 
386     template <typename policy>
387     bool operator>=(const unique_any_t<policy>& left, const unique_any_t<policy>& right) WI_NOEXCEPT
388     {
389         return (!(left < right));
390     }
391 
392     template <typename policy>
393     bool operator>(const unique_any_t<policy>& left, const unique_any_t<policy>& right) WI_NOEXCEPT
394     {
395         return (right < left);
396     }
397 
398     template <typename policy>
399     bool operator<=(const unique_any_t<policy>& left, const unique_any_t<policy>& right) WI_NOEXCEPT
400     {
401         return (!(right < left));
402     }
403 
404     // unique_any provides a template alias for easily building a unique_any_t from a unique_storage class with the given
405     // template parameters for resource_policy.
406 
407     template <typename pointer,                                   // The handle type
408         typename close_fn_t,                                      // The handle close function type
409         close_fn_t close_fn,                                      //      * and function pointer
410         typename pointer_access = details::pointer_access_all,    // all, noaddress or none to control pointer method access
411         typename pointer_storage = pointer,                       // The type used to store the handle (usually the same as the handle itself)
412         typename invalid_t = pointer,                             // The invalid handle value type
413         invalid_t invalid = invalid_t(),                          //      * and its value (default ZERO value)
414         typename pointer_invalid = wistd::nullptr_t>              // nullptr_t if the invalid handle value is compatible with nullptr, otherwise pointer
415         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>>>;
416 
417     /// @cond
418     namespace details
419     {
420         template <typename TLambda>
421         class lambda_call
422         {
423         public:
424             lambda_call(const lambda_call&) = delete;
425             lambda_call& operator=(const lambda_call&) = delete;
426             lambda_call& operator=(lambda_call&& other) = delete;
427 
lambda_call(TLambda && lambda)428             explicit lambda_call(TLambda&& lambda) WI_NOEXCEPT : m_lambda(wistd::move(lambda))
429             {
430                 static_assert(wistd::is_same<decltype(lambda()), void>::value, "scope_exit lambdas must not have a return value");
431                 static_assert(!wistd::is_lvalue_reference<TLambda>::value && !wistd::is_rvalue_reference<TLambda>::value,
432                     "scope_exit should only be directly used with a lambda");
433             }
434 
lambda_call(lambda_call && other)435             lambda_call(lambda_call&& other) WI_NOEXCEPT : m_lambda(wistd::move(other.m_lambda)), m_call(other.m_call)
436             {
437                 other.m_call = false;
438             }
439 
~lambda_call()440             ~lambda_call() WI_NOEXCEPT
441             {
442                 reset();
443             }
444 
445             // Ensures the scope_exit lambda will not be called
release()446             void release() WI_NOEXCEPT
447             {
448                 m_call = false;
449             }
450 
451             // Executes the scope_exit lambda immediately if not yet run; ensures it will not run again
reset()452             void reset() WI_NOEXCEPT
453             {
454                 if (m_call)
455                 {
456                     m_call = false;
457                     m_lambda();
458                 }
459             }
460 
461             // Returns true if the scope_exit lambda is still going to be executed
462             explicit operator bool() const WI_NOEXCEPT
463             {
464                 return m_call;
465             }
466 
467         protected:
468             TLambda m_lambda;
469             bool m_call = true;
470         };
471 
472 #ifdef WIL_ENABLE_EXCEPTIONS
473         template <typename TLambda>
474         class lambda_call_log
475         {
476         public:
477             lambda_call_log(const lambda_call_log&) = delete;
478             lambda_call_log& operator=(const lambda_call_log&) = delete;
479             lambda_call_log& operator=(lambda_call_log&& other) = delete;
480 
lambda_call_log(void * address,const DiagnosticsInfo & info,TLambda && lambda)481             explicit lambda_call_log(void* address, const DiagnosticsInfo& info, TLambda&& lambda) WI_NOEXCEPT :
482             m_address(address), m_info(info), m_lambda(wistd::move(lambda))
483             {
484                 static_assert(wistd::is_same<decltype(lambda()), void>::value, "scope_exit lambdas must return 'void'");
485                 static_assert(!wistd::is_lvalue_reference<TLambda>::value && !wistd::is_rvalue_reference<TLambda>::value,
486                     "scope_exit should only be directly used with a lambda");
487             }
488 
lambda_call_log(lambda_call_log && other)489             lambda_call_log(lambda_call_log&& other) WI_NOEXCEPT :
490             m_address(other.m_address), m_info(other.m_info), m_lambda(wistd::move(other.m_lambda)), m_call(other.m_call)
491             {
492                 other.m_call = false;
493             }
494 
~lambda_call_log()495             ~lambda_call_log() WI_NOEXCEPT
496             {
497                 reset();
498             }
499 
500             // Ensures the scope_exit lambda will not be called
release()501             void release() WI_NOEXCEPT
502             {
503                 m_call = false;
504             }
505 
506             // Executes the scope_exit lambda immediately if not yet run; ensures it will not run again
reset()507             void reset() WI_NOEXCEPT
508             {
509                 if (m_call)
510                 {
511                     m_call = false;
512                     try
513                     {
514                         m_lambda();
515                     }
516                     catch (...)
517                     {
518                         ReportFailure_CaughtException<FailureType::Log>(__R_DIAGNOSTICS(m_info), m_address);
519                     }
520                 }
521             }
522 
523             // Returns true if the scope_exit lambda is still going to be executed
524             explicit operator bool() const WI_NOEXCEPT
525             {
526                 return m_call;
527             }
528 
529         private:
530             void* m_address;
531             DiagnosticsInfo m_info;
532             TLambda m_lambda;
533             bool m_call = true;
534         };
535 #endif  // WIL_ENABLE_EXCEPTIONS
536     }
537     /// @endcond
538 
539     /** Returns an object that executes the given lambda when destroyed.
540     Capture the object with 'auto'; use reset() to execute the lambda early or release() to avoid
541     execution.  Exceptions thrown in the lambda will fail-fast; use scope_exit_log to avoid. */
542     template <typename TLambda>
scope_exit(TLambda && lambda)543     WI_NODISCARD inline auto scope_exit(TLambda&& lambda) WI_NOEXCEPT
544     {
545         return details::lambda_call<TLambda>(wistd::forward<TLambda>(lambda));
546     }
547 
548 #ifdef WIL_ENABLE_EXCEPTIONS
549     /** Returns an object that executes the given lambda when destroyed; logs exceptions.
550     Capture the object with 'auto'; use reset() to execute the lambda early or release() to avoid
551     execution.  Exceptions thrown in the lambda will be caught and logged without being propagated. */
552     template <typename TLambda>
scope_exit_log(const DiagnosticsInfo & diagnostics,TLambda && lambda)553     WI_NODISCARD inline __declspec(noinline) auto scope_exit_log(const DiagnosticsInfo& diagnostics, TLambda&& lambda) WI_NOEXCEPT
554     {
555         return details::lambda_call_log<TLambda>(_ReturnAddress(), diagnostics, wistd::forward<TLambda>(lambda));
556     }
557 #endif
558 
559     // Forward declaration...
560     template <typename T, typename err_policy>
561     class com_ptr_t;
562 
563     //! Type traits class that identifies the inner type of any smart pointer.
564     template <typename Ptr>
565     struct smart_pointer_details
566     {
567         typedef typename Ptr::pointer pointer;
568     };
569 
570     /// @cond
571     template <typename T>
572     struct smart_pointer_details<Microsoft::WRL::ComPtr<T>>
573     {
574         typedef T* pointer;
575     };
576     /// @endcond
577 
578     /** Generically detaches a raw pointer from any smart pointer.
579     Caller takes ownership of the returned raw pointer; calls the correct release(), detach(),
580     or Detach() method based on the smart pointer type */
581     template <typename TSmartPointer>
582     WI_NODISCARD typename TSmartPointer::pointer detach_from_smart_pointer(TSmartPointer& smartPtr)
583     {
584         return smartPtr.release();
585     }
586 
587     /// @cond
588     // Generically detaches a raw pointer from any smart pointer
589     template <typename T, typename err>
590     WI_NODISCARD T* detach_from_smart_pointer(wil::com_ptr_t<T, err>& smartPtr)
591     {
592         return smartPtr.detach();
593     }
594 
595     // Generically detaches a raw pointer from any smart pointer
596     template <typename T>
597     WI_NODISCARD T* detach_from_smart_pointer(Microsoft::WRL::ComPtr<T>& smartPtr)
598     {
599         return smartPtr.Detach();
600     }
601 
602     template<typename T, typename err> class com_ptr_t; // forward
603     namespace details
604     {
605         // The first two attach_to_smart_pointer() overloads are ambiguous when passed a com_ptr_t.
606         // To solve that use this functions return type to elminate the reset form for com_ptr_t.
607         template <typename T, typename err> wistd::false_type use_reset(wil::com_ptr_t<T, err>*) { return wistd::false_type(); }
608         template <typename T> wistd::true_type use_reset(T*) { return wistd::true_type(); }
609     }
610     /// @endcond
611 
612     /** Generically attach a raw pointer to a compatible smart pointer.
613     Calls the correct reset(), attach(), or Attach() method based on samrt pointer type. */
614     template <typename TSmartPointer, typename EnableResetForm = wistd::enable_if_t<decltype(details::use_reset(static_cast<TSmartPointer*>(nullptr)))::value>>
615     void attach_to_smart_pointer(TSmartPointer& smartPtr, typename TSmartPointer::pointer rawPtr)
616     {
617         smartPtr.reset(rawPtr);
618     }
619 
620     /// @cond
621 
622     // Generically attach a raw pointer to a compatible smart pointer.
623     template <typename T, typename err>
624     void attach_to_smart_pointer(wil::com_ptr_t<T, err>& smartPtr, T* rawPtr)
625     {
626         smartPtr.attach(rawPtr);
627     }
628 
629     // Generically attach a raw pointer to a compatible smart pointer.
630     template <typename T>
631     void attach_to_smart_pointer(Microsoft::WRL::ComPtr<T>& smartPtr, T* rawPtr)
632     {
633         smartPtr.Attach(rawPtr);
634     }
635     /// @endcond
636 
637     //! @ingroup outparam
638     /** Detach a smart pointer resource to an optional output pointer parameter.
639     Avoids cluttering code with nullptr tests; works generically for any smart pointer */
640     template <typename T, typename TSmartPointer>
641     inline void detach_to_opt_param(_Out_opt_ T* outParam, TSmartPointer&& smartPtr)
642     {
643         if (outParam)
644         {
645             *outParam = detach_from_smart_pointer(smartPtr);
646         }
647     }
648 
649     /// @cond
650     namespace details
651     {
652         template <typename T>
653         struct out_param_t
654         {
655             typedef typename wil::smart_pointer_details<T>::pointer pointer;
656             T &wrapper;
657             pointer pRaw;
658             bool replace = true;
659 
660             out_param_t(_Inout_ T &output) :
661                 wrapper(output),
662                 pRaw(nullptr)
663             {
664             }
665 
666             out_param_t(out_param_t&& other) :
667                 wrapper(other.wrapper),
668                 pRaw(other.pRaw)
669             {
670                 WI_ASSERT(other.replace);
671                 other.replace = false;
672             }
673 
674             operator pointer*()
675             {
676                 WI_ASSERT(replace);
677                 return &pRaw;
678             }
679 
680             ~out_param_t()
681             {
682                 if (replace)
683                 {
684                     attach_to_smart_pointer(wrapper, pRaw);
685                 }
686             }
687 
688             out_param_t(out_param_t const &other) = delete;
689             out_param_t &operator=(out_param_t const &other) = delete;
690         };
691 
692         template <typename Tcast, typename T>
693         struct out_param_ptr_t
694         {
695             typedef typename wil::smart_pointer_details<T>::pointer pointer;
696             T &wrapper;
697             pointer pRaw;
698             bool replace = true;
699 
700             out_param_ptr_t(_Inout_ T &output) :
701                 wrapper(output),
702                 pRaw(nullptr)
703             {
704             }
705 
706             out_param_ptr_t(out_param_ptr_t&& other) :
707                 wrapper(other.wrapper),
708                 pRaw(other.pRaw)
709             {
710                 WI_ASSERT(other.replace);
711                 other.replace = false;
712             }
713 
714             operator Tcast()
715             {
716                 WI_ASSERT(replace);
717                 return reinterpret_cast<Tcast>(&pRaw);
718             }
719 
720             ~out_param_ptr_t()
721             {
722                 if (replace)
723                 {
724                     attach_to_smart_pointer(wrapper, pRaw);
725                 }
726             }
727 
728             out_param_ptr_t(out_param_ptr_t const &other) = delete;
729             out_param_ptr_t &operator=(out_param_ptr_t const &other) = delete;
730         };
731     } // details
732       /// @endcond
733 
734       /** Use to retrieve raw out parameter pointers into smart pointers that do not support the '&' operator.
735       This avoids multi-step handling of a raw resource to establish the smart pointer.
736       Example: `GetFoo(out_param(foo));` */
737     template <typename T>
738     details::out_param_t<T> out_param(T& p)
739     {
740         return details::out_param_t<T>(p);
741     }
742 
743     /** Use to retrieve raw out parameter pointers (with a required cast) into smart pointers that do not support the '&' operator.
744     Use only when the smart pointer's &handle is not equal to the output type a function requries, necessitating a cast.
745     Example: `wil::out_param_ptr<PSECURITY_DESCRIPTOR*>(securityDescriptor)` */
746     template <typename Tcast, typename T>
747     details::out_param_ptr_t<Tcast, T> out_param_ptr(T& p)
748     {
749         return details::out_param_ptr_t<Tcast, T>(p);
750     }
751 
752     /** Use unique_struct to define an RAII type for a trivial struct that references resources that must be cleaned up.
753     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
754     then ZeroMemory is used.
755     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.
756 
757     If the type you're wrapping is a system type, you can share the code by declaring it in this file (Resource.h). Send requests to wildisc.
758     Otherwise, if the type is local to your project, declare it locally.
759     @tparam struct_t The struct you want to manage
760     @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.
761     @tparam close_fn The function of type close_fn_t. This is called in the destructor and reset functions.
762     @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.
763     @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.
764 
765     Defined using the default zero memory initializer
766     ~~~
767     typedef wil::unique_struct<PROPVARIANT, decltype(&::PropVariantClear), ::PropVariantClear> unique_prop_variant_default_init;
768 
769     unique_prop_variant propvariant;
770     SomeFunction(&propvariant);
771     ~~~
772 
773     Defined using a custom initializer
774     ~~~
775     typedef wil::unique_struct<PROPVARIANT, decltype(&::PropVariantClear), ::PropVariantClear, decltype(&::PropVariantInit), ::PropVariantInit> unique_prop_variant;
776 
777     unique_prop_variant propvariant;
778     SomeFunction(&propvariant);
779     ~~~
780     */
781     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()>
782     class unique_struct : public struct_t
783     {
784     public:
785         //! Initializes the managed struct using the user-provided initialization function, or ZeroMemory if no function is specified
786         unique_struct()
787         {
788             call_init(use_default_init_fn());
789         }
790 
791         //! Takes ownership of the struct by doing a shallow copy. Must explicitly be type struct_t
792         explicit unique_struct(const struct_t& other) WI_NOEXCEPT :
793         struct_t(other)
794         {}
795 
796         //! Initializes the managed struct by taking the ownership of the other managed struct
797         //! Then resets the other managed struct by calling the custom close function
798         unique_struct(unique_struct&& other) WI_NOEXCEPT :
799         struct_t(other.release())
800         {}
801 
802         //! Resets this managed struct by calling the custom close function and takes ownership of the other managed struct
803         //! Then resets the other managed struct by calling the custom close function
804         unique_struct & operator=(unique_struct&& other) WI_NOEXCEPT
805         {
806             if (this != wistd::addressof(other))
807             {
808                 reset(other.release());
809             }
810             return *this;
811         }
812 
813         //! Calls the custom close function
814         ~unique_struct() WI_NOEXCEPT
815         {
816             wistd::invoke(close_fn, this);
817         }
818 
819         void reset(const unique_struct&) = delete;
820 
821         //! Resets this managed struct by calling the custom close function and begins management of the other struct
822         void reset(const struct_t& other) WI_NOEXCEPT
823         {
824             {
825                 auto preserveError = last_error_context();
826                 wistd::invoke(close_fn, this);
827             }
828             struct_t::operator=(other);
829         }
830 
831         //! Resets this managed struct by calling the custom close function
832         //! Then initializes this managed struct using the user-provided initialization function, or ZeroMemory if no function is specified
833         void reset() WI_NOEXCEPT
834         {
835             wistd::invoke(close_fn, this);
836             call_init(use_default_init_fn());
837         }
838 
839         void swap(struct_t&) = delete;
840 
841         //! Swaps the managed structs
842         void swap(unique_struct& other) WI_NOEXCEPT
843         {
844             struct_t self(*this);
845             struct_t::operator=(other);
846             *(other.addressof()) = self;
847         }
848 
849         //! Returns the managed struct
850         //! Then initializes this managed struct using the user-provided initialization function, or ZeroMemory if no function is specified
851         struct_t release() WI_NOEXCEPT
852         {
853             struct_t value(*this);
854             call_init(use_default_init_fn());
855             return value;
856         }
857 
858         //! Returns address of the managed struct
859         struct_t * addressof() WI_NOEXCEPT
860         {
861             return this;
862         }
863 
864         //! Resets this managed struct by calling the custom close function
865         //! Then initializes this managed struct using the user-provided initialization function, or ZeroMemory if no function is specified
866         //! Returns address of the managed struct
867         struct_t * reset_and_addressof() WI_NOEXCEPT
868         {
869             reset();
870             return this;
871         }
872 
873         unique_struct(const unique_struct&) = delete;
874         unique_struct& operator=(const unique_struct&) = delete;
875         unique_struct& operator=(const struct_t&) = delete;
876 
877     private:
878         typedef typename wistd::is_same<init_fn_t, wistd::nullptr_t>::type use_default_init_fn;
879 
880         void call_init(wistd::true_type)
881         {
882             RtlZeroMemory(this, sizeof(*this));
883         }
884 
885         void call_init(wistd::false_type)
886         {
887             init_fn(this);
888         }
889     };
890 
891     struct empty_deleter
892     {
893         template <typename T>
894         void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T) const
895         {
896         }
897     };
898 
899     /** unique_any_array_ptr is a RAII type for managing conformant arrays that need to be freed and have elements that may need to be freed.
900     The intented use for this RAII type would be to capture out params from API like IPropertyValue::GetStringArray.
901     This class also maintains the size of the array, so it can iterate over the members and deallocate them before it deallocates the base array pointer.
902 
903     If the type you're wrapping is a system type, you can share the code by declaring it in this file (Resource.h). Send requests to wildisc.
904     Otherwise, if the type is local to your project, declare it locally.
905 
906     @tparam ValueType: The type of array you want to manage.
907     @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.
908     @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.
909 
910     ~~~
911     void GetSomeArray(_Out_ size_t*, _Out_ NOTMYTYPE**);
912 
913     struct not_my_deleter
914     {
915     void operator()(NOTMYTYPE p) const
916     {
917     destroy(p);
918     }
919     };
920 
921     wil::unique_any_array_ptr<NOTMYTYPE, ::CoTaskMemFree, not_my_deleter> myArray;
922     GetSomeArray(myArray.size_address(), &myArray);
923     ~~~ */
924     template <typename ValueType, typename ArrayDeleter, typename ElementDeleter = empty_deleter>
925     class unique_any_array_ptr
926     {
927     public:
928         typedef ValueType value_type;
929         typedef size_t size_type;
930         typedef ptrdiff_t difference_type;
931         typedef ValueType *pointer;
932         typedef const ValueType *const_pointer;
933         typedef ValueType& reference;
934         typedef const ValueType& const_reference;
935 
936         typedef ValueType* iterator;
937         typedef const ValueType* const_iterator;
938 
939         unique_any_array_ptr() = default;
940         unique_any_array_ptr(const unique_any_array_ptr&) = delete;
941         unique_any_array_ptr& operator=(const unique_any_array_ptr&) = delete;
942 
943         unique_any_array_ptr(wistd::nullptr_t) WI_NOEXCEPT
944         {
945         }
946 
947         unique_any_array_ptr& operator=(wistd::nullptr_t) WI_NOEXCEPT
948         {
949             reset();
950             return *this;
951         }
952 
953         unique_any_array_ptr(pointer ptr, size_t size) WI_NOEXCEPT : m_ptr(ptr), m_size(size)
954         {
955         }
956 
957         unique_any_array_ptr(unique_any_array_ptr&& other) WI_NOEXCEPT : m_ptr(other.m_ptr), m_size(other.m_size)
958         {
959             other.m_ptr = nullptr;
960             other.m_size = size_type{};
961         }
962 
963         unique_any_array_ptr& operator=(unique_any_array_ptr&& other) WI_NOEXCEPT
964         {
965             if (this != wistd::addressof(other))
966             {
967                 reset();
968                 swap(other);
969             }
970             return *this;
971         }
972 
973         ~unique_any_array_ptr() WI_NOEXCEPT
974         {
975             reset();
976         }
977 
978         void swap(unique_any_array_ptr& other) WI_NOEXCEPT
979         {
980             auto ptr = m_ptr;
981             auto size = m_size;
982             m_ptr = other.m_ptr;
983             m_size = other.m_size;
984             other.m_ptr = ptr;
985             other.m_size = size;
986         }
987 
988         iterator begin() WI_NOEXCEPT
989         {
990             return (iterator(m_ptr));
991         }
992 
993         const_iterator begin() const WI_NOEXCEPT
994         {
995             return (const_iterator(m_ptr));
996         }
997 
998         iterator end() WI_NOEXCEPT
999         {
1000             return (iterator(m_ptr + m_size));
1001         }
1002 
1003         const_iterator end() const WI_NOEXCEPT
1004         {
1005             return (const_iterator(m_ptr + m_size));
1006         }
1007 
1008         const_iterator cbegin() const WI_NOEXCEPT
1009         {
1010             return (begin());
1011         }
1012 
1013         const_iterator cend() const WI_NOEXCEPT
1014         {
1015             return (end());
1016         }
1017 
1018         size_type size() const WI_NOEXCEPT
1019         {
1020             return (m_size);
1021         }
1022 
1023         bool empty() const WI_NOEXCEPT
1024         {
1025             return (size() == size_type{});
1026         }
1027 
1028         reference operator[](size_type position)
1029         {
1030             WI_ASSERT(position < m_size);
1031             _Analysis_assume_(position < m_size);
1032             return (m_ptr[position]);
1033         }
1034 
1035         const_reference operator[](size_type position) const
1036         {
1037             WI_ASSERT(position < m_size);
1038             _Analysis_assume_(position < m_size);
1039             return (m_ptr[position]);
1040         }
1041 
1042         reference front()
1043         {
1044             WI_ASSERT(!empty());
1045             return (m_ptr[0]);
1046         }
1047 
1048         const_reference front() const
1049         {
1050             WI_ASSERT(!empty());
1051             return (m_ptr[0]);
1052         }
1053 
1054         reference back()
1055         {
1056             WI_ASSERT(!empty());
1057             return (m_ptr[m_size - 1]);
1058         }
1059 
1060         const_reference back() const
1061         {
1062             WI_ASSERT(!empty());
1063             return (m_ptr[m_size - 1]);
1064         }
1065 
1066         ValueType* data() WI_NOEXCEPT
1067         {
1068             return (m_ptr);
1069         }
1070 
1071         const ValueType* data() const WI_NOEXCEPT
1072         {
1073             return (m_ptr);
1074         }
1075 
1076         pointer get() const WI_NOEXCEPT
1077         {
1078             return m_ptr;
1079         }
1080 
1081         explicit operator bool() const WI_NOEXCEPT
1082         {
1083             return (m_ptr != pointer());
1084         }
1085 
1086         pointer release() WI_NOEXCEPT
1087         {
1088             auto result = m_ptr;
1089             m_ptr = nullptr;
1090             m_size = size_type{};
1091             return result;
1092         }
1093 
1094         void reset() WI_NOEXCEPT
1095         {
1096             if (m_ptr)
1097             {
1098                 reset_array(ElementDeleter());
1099                 ArrayDeleter()(m_ptr);
1100                 m_ptr = nullptr;
1101                 m_size = size_type{};
1102             }
1103         }
1104 
1105         void reset(pointer ptr, size_t size) WI_NOEXCEPT
1106         {
1107             reset();
1108             m_ptr = ptr;
1109             m_size = size;
1110         }
1111 
1112         pointer* addressof() WI_NOEXCEPT
1113         {
1114             return &m_ptr;
1115         }
1116 
1117         pointer* put() WI_NOEXCEPT
1118         {
1119             reset();
1120             return addressof();
1121         }
1122 
1123         pointer* operator&() WI_NOEXCEPT
1124         {
1125             return put();
1126         }
1127 
1128         size_type* size_address() WI_NOEXCEPT
1129         {
1130             return &m_size;
1131         }
1132 
1133         template <typename TSize>
1134         struct size_address_ptr
1135         {
1136             unique_any_array_ptr& wrapper;
1137             TSize size{};
1138             bool replace = true;
1139 
1140             size_address_ptr(_Inout_ unique_any_array_ptr& output) :
1141                 wrapper(output)
1142             {
1143             }
1144 
1145             size_address_ptr(size_address_ptr&& other) :
1146                 wrapper(other.wrapper),
1147                 size(other.size)
1148             {
1149                 WI_ASSERT(other.replace);
1150                 other.replace = false;
1151             }
1152 
1153             operator TSize*()
1154             {
1155                 WI_ASSERT(replace);
1156                 return &size;
1157             }
1158 
1159             ~size_address_ptr()
1160             {
1161                 if (replace)
1162                 {
1163                     *wrapper.size_address() = static_cast<size_type>(size);
1164                 }
1165             }
1166 
1167             size_address_ptr(size_address_ptr const &other) = delete;
1168             size_address_ptr &operator=(size_address_ptr const &other) = delete;
1169         };
1170 
1171         template <typename T>
1172         size_address_ptr<T> size_address() WI_NOEXCEPT
1173         {
1174             return size_address_ptr<T>(*this);
1175         }
1176 
1177     private:
1178         pointer m_ptr = nullptr;
1179         size_type m_size{};
1180 
1181         void reset_array(const empty_deleter&)
1182         {
1183         }
1184 
1185         template <typename T>
1186         void reset_array(const T& deleter)
1187         {
1188             for (auto& element : make_range(m_ptr, m_size))
1189             {
1190                 deleter(element);
1191             }
1192         }
1193     };
1194 
1195     // forward declaration
1196     template <typename T, typename err_policy>
1197     class com_ptr_t;
1198 
1199     /// @cond
1200     namespace details
1201     {
1202         template <typename UniqueAnyType>
1203         struct unique_any_array_deleter
1204         {
1205             template <typename T>
1206             void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const
1207             {
1208                 UniqueAnyType::policy::close_reset(p);
1209             }
1210         };
1211 
1212         template <typename close_fn_t, close_fn_t close_fn>
1213         struct unique_struct_array_deleter
1214         {
1215             template <typename T>
1216             void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T& p) const
1217             {
1218                 wistd::invoke(close_fn, &p);
1219             }
1220         };
1221 
1222         struct com_unknown_deleter
1223         {
1224             template <typename T>
1225             void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const
1226             {
1227                 if (p)
1228                 {
1229                     p->Release();
1230                 }
1231             }
1232         };
1233 
1234         template <class T>
1235         struct element_traits
1236         {
1237             typedef empty_deleter deleter;
1238             typedef T type;
1239         };
1240 
1241         template <typename storage_t>
1242         struct element_traits<unique_any_t<storage_t>>
1243         {
1244             typedef unique_any_array_deleter<unique_any_t<storage_t>> deleter;
1245             typedef typename unique_any_t<storage_t>::pointer type;
1246         };
1247 
1248         template <typename T, typename err_policy>
1249         struct element_traits<com_ptr_t<T, err_policy>>
1250         {
1251             typedef com_unknown_deleter deleter;
1252             typedef T* type;
1253         };
1254 
1255         template <typename struct_t, typename close_fn_t, close_fn_t close_fn, typename init_fn_t, init_fn_t init_fn>
1256         struct element_traits<unique_struct<struct_t, close_fn_t, close_fn, init_fn_t, init_fn>>
1257         {
1258             typedef unique_struct_array_deleter<close_fn_t, close_fn> deleter;
1259             typedef struct_t type;
1260         };
1261     }
1262     /// @endcond
1263 
1264     template <typename T, typename ArrayDeleter>
1265     using unique_array_ptr = unique_any_array_ptr<typename details::element_traits<T>::type, ArrayDeleter, typename details::element_traits<T>::deleter>;
1266 
1267     /** Adapter for single-parameter 'free memory' for `wistd::unique_ptr`.
1268     This struct provides a standard wrapper for calling a platform function to deallocate memory held by a
1269     `wistd::unique_ptr`, making declaring them as easy as declaring wil::unique_any<>.
1270 
1271     Consider this adapter in preference to `wil::unique_any<>` when the returned type is really a pointer or an
1272     array of items; `wistd::unique_ptr<>` exposes `operator->()` and `operator[]` for array-typed things safely.
1273     ~~~~
1274     EXTERN_C VOID WINAPI MyDllFreeMemory(void* p);
1275     EXTERN_C HRESULT MyDllGetString(_Outptr_ PWSTR* pString);
1276     EXTERN_C HRESULT MyDllGetThing(_In_ PCWSTR pString, _Outptr_ PMYSTRUCT* ppThing);
1277     template<typename T>
1278     using unique_mydll_ptr = wistd::unique_ptr<T, wil::function_deleter<decltype(&MyDllFreeMemory), MyDllFreeMemory>>;
1279     HRESULT Test()
1280     {
1281     unique_mydll_ptr<WCHAR[]> dllString;
1282     unique_mydll_ptr<MYSTRUCT> thing;
1283     RETURN_IF_FAILED(MyDllGetString(wil::out_param(dllString)));
1284     RETURN_IF_FAILED(MyDllGetThing(dllString.get(), wil::out_param(thing)));
1285     if (thing->Member)
1286     {
1287     // ...
1288     }
1289     return S_OK;
1290     }
1291     ~~~~ */
1292     template<typename Q, Q TDeleter> struct function_deleter
1293     {
1294         template<typename T> void operator()(_Frees_ptr_opt_ T* toFree) const
1295         {
1296             TDeleter(toFree);
1297         }
1298     };
1299 
1300     /** Use unique_com_token to define an RAII type for a token-based resource that is managed by a COM interface.
1301     By comparison, unique_any_t has the requirement that the close function must be static. This works for functions
1302     such as CloseHandle(), but for any resource cleanup function that relies on a more complex interface,
1303     unique_com_token can be used.
1304 
1305     @tparam interface_t A COM interface pointer that will manage this resource type.
1306     @tparam token_t The token type that relates to the COM interface management functions.
1307     @tparam close_fn_t The type of the function that is called when the resource is destroyed.
1308     @tparam close_fn The function used to destroy the associated resource. This function should have the signature void(interface_t* source, token_t token).
1309     @tparam invalid_token Optional:An invalid token value. Defaults to default-constructed token_t().
1310 
1311     Example
1312     ~~~
1313     void __stdcall MyInterfaceCloseFunction(IMyInterface* source, DWORD token)
1314     {
1315     source->MyCloseFunction(token);
1316     }
1317     using unique_my_interface_token = wil::unique_com_token<IMyInterface, DWORD, decltype(MyInterfaceCloseFunction), MyInterfaceCloseFunction, 0xFFFFFFFF>;
1318     ~~~ */
1319     template <typename interface_t, typename token_t, typename close_fn_t, close_fn_t close_fn, token_t invalid_token = token_t()>
1320     class unique_com_token
1321     {
1322     public:
1323         unique_com_token() = default;
1324 
1325         unique_com_token(_In_opt_ interface_t* source, token_t token = invalid_token) WI_NOEXCEPT
1326         {
1327             reset(source, token);
1328         }
1329 
1330         unique_com_token(unique_com_token&& other) WI_NOEXCEPT : m_source(other.m_source), m_token(other.m_token)
1331         {
1332             other.m_source = nullptr;
1333             other.m_token = invalid_token;
1334         }
1335 
1336         unique_com_token& operator=(unique_com_token&& other) WI_NOEXCEPT
1337         {
1338             if (this != wistd::addressof(other))
1339             {
1340                 reset();
1341                 m_source = other.m_source;
1342                 m_token = other.m_token;
1343 
1344                 other.m_source = nullptr;
1345                 other.m_token = invalid_token;
1346             }
1347             return *this;
1348         }
1349 
1350         ~unique_com_token() WI_NOEXCEPT
1351         {
1352             reset();
1353         }
1354 
1355         //! Determine if the underlying source and token are valid
1356         explicit operator bool() const WI_NOEXCEPT
1357         {
1358             return (m_token != invalid_token) && m_source;
1359         }
1360 
1361         //! Associates a new source and releases the existing token if valid
1362         void associate(_In_opt_ interface_t* source) WI_NOEXCEPT
1363         {
1364             reset(source, invalid_token);
1365         }
1366 
1367         //! Assigns a new source and token
1368         void reset(_In_opt_ interface_t* source, token_t token) WI_NOEXCEPT
1369         {
1370             WI_ASSERT(source || (token == invalid_token));
1371 
1372             // Determine if we need to call the close function on our previous token.
1373             if (m_token != invalid_token)
1374             {
1375                 if ((m_source != source) || (m_token != token))
1376                 {
1377                     wistd::invoke(close_fn, m_source, m_token);
1378                 }
1379             }
1380 
1381             m_token = token;
1382 
1383             // Assign our new source and manage the reference counts
1384             if (m_source != source)
1385             {
1386                 auto oldSource = m_source;
1387                 m_source = source;
1388 
1389                 if (m_source)
1390                 {
1391                     m_source->AddRef();
1392                 }
1393 
1394                 if (oldSource)
1395                 {
1396                     oldSource->Release();
1397                 }
1398             }
1399         }
1400 
1401         //! Assigns a new token without modifying the source; associate must be called first
1402         void reset(token_t token) WI_NOEXCEPT
1403         {
1404             reset(m_source, token);
1405         }
1406 
1407         //! Closes the token and the releases the reference to the source
1408         void reset() WI_NOEXCEPT
1409         {
1410             reset(nullptr, invalid_token);
1411         }
1412 
1413         //! Exchanges values with another managed token
1414         void swap(unique_com_token& other) WI_NOEXCEPT
1415         {
1416             wistd::swap_wil(m_source, other.m_source);
1417             wistd::swap_wil(m_token, other.m_token);
1418         }
1419 
1420         //! Releases the held token to the caller without closing it and releases the reference to the source.
1421         //! Requires that the associated COM interface be kept alive externally or the released token may be invalidated
1422         token_t release() WI_NOEXCEPT
1423         {
1424             auto token = m_token;
1425             m_token = invalid_token;
1426             reset();
1427             return token;
1428         }
1429 
1430         //! Returns address of the managed token; associate must be called first
1431         token_t* addressof() WI_NOEXCEPT
1432         {
1433             WI_ASSERT(m_source);
1434             return &m_token;
1435         }
1436 
1437         //! Releases the held token and allows attaching a new token; associate must be called first
1438         token_t* put() WI_NOEXCEPT
1439         {
1440             reset(invalid_token);
1441             return addressof();
1442         }
1443 
1444         //! Releases the held token and allows attaching a new token; associate must be called first
1445         token_t* operator&() WI_NOEXCEPT
1446         {
1447             return put();
1448         }
1449 
1450         //! Retrieves the token
1451         token_t get() const WI_NOEXCEPT
1452         {
1453             return m_token;
1454         }
1455 
1456         unique_com_token(const unique_com_token&) = delete;
1457         unique_com_token& operator=(const unique_com_token&) = delete;
1458 
1459     private:
1460         interface_t* m_source = nullptr;
1461         token_t m_token = invalid_token;
1462     };
1463 
1464     /** Use unique_com_call to define an RAII type that demands a particular parameter-less method be called on a COM interface.
1465     This allows implementing an RAII type that can call a Close() method (think IClosable) or a SetSite(nullptr)
1466     method (think IObjectWithSite) or some other method when a basic interface call is required as part of the RAII contract.
1467     see wil::com_set_site in wil\com.h for the IObjectWithSite support.
1468 
1469     @tparam interface_t A COM interface pointer that provides context to make the call.
1470     @tparam close_fn_t The type of the function that is called to invoke the method.
1471     @tparam close_fn The function used to invoke the interface method.  This function should have the signature void(interface_t* source).
1472 
1473     Example
1474     ~~~
1475     void __stdcall CloseIClosable(IClosable* source)
1476     {
1477     source->Close();
1478     }
1479     using unique_closable_call = wil::unique_com_call<IClosable, decltype(CloseIClosable), CloseIClosable>;
1480     ~~~ */
1481     template <typename interface_t, typename close_fn_t, close_fn_t close_fn>
1482     class unique_com_call
1483     {
1484     public:
1485         unique_com_call() = default;
1486 
1487         explicit unique_com_call(_In_opt_ interface_t* ptr) WI_NOEXCEPT
1488         {
1489             reset(ptr);
1490         }
1491 
1492         unique_com_call(unique_com_call&& other) WI_NOEXCEPT
1493         {
1494             m_ptr = other.m_ptr;
1495             other.m_ptr = nullptr;
1496         }
1497 
1498         unique_com_call& operator=(unique_com_call&& other) WI_NOEXCEPT
1499         {
1500             if (this != wistd::addressof(other))
1501             {
1502                 reset();
1503                 m_ptr = other.m_ptr;
1504                 other.m_ptr = nullptr;
1505             }
1506             return *this;
1507         }
1508 
1509         ~unique_com_call() WI_NOEXCEPT
1510         {
1511             reset();
1512         }
1513 
1514         //! Assigns an interface to make a given call on
1515         void reset(_In_opt_ interface_t* ptr = nullptr) WI_NOEXCEPT
1516         {
1517             if (ptr != m_ptr)
1518             {
1519                 auto oldSource = m_ptr;
1520                 m_ptr = ptr;
1521                 if (m_ptr)
1522                 {
1523                     m_ptr->AddRef();
1524                 }
1525                 if (oldSource)
1526                 {
1527                     wistd::invoke(close_fn, oldSource);
1528                     oldSource->Release();
1529                 }
1530             }
1531         }
1532 
1533         //! Exchanges values with another class
1534         void swap(unique_com_call& other) WI_NOEXCEPT
1535         {
1536             wistd::swap_wil(m_ptr, other.m_ptr);
1537         }
1538 
1539         //! Cancel the interface call that this class was expected to make
1540         void release() WI_NOEXCEPT
1541         {
1542             auto ptr = m_ptr;
1543             m_ptr = nullptr;
1544             if (ptr)
1545             {
1546                 ptr->Release();
1547             }
1548         }
1549 
1550         //! Returns true if the call this class was expected to make is still outstanding
1551         explicit operator bool() const WI_NOEXCEPT
1552         {
1553             return (m_ptr != nullptr);
1554         }
1555 
1556         //! Returns address of the internal interface
1557         interface_t** addressof() WI_NOEXCEPT
1558         {
1559             return &m_ptr;
1560         }
1561 
1562         //! Releases the held interface (first performing the interface call if required)
1563         //! and allows attaching a new interface
1564         interface_t** put() WI_NOEXCEPT
1565         {
1566             reset();
1567             return addressof();
1568         }
1569 
1570         //! Releases the held interface (first performing the interface call if required)
1571         //! and allows attaching a new interface
1572         interface_t** operator&() WI_NOEXCEPT
1573         {
1574             return put();
1575         }
1576 
1577         unique_com_call(const unique_com_call&) = delete;
1578         unique_com_call& operator=(const unique_com_call&) = delete;
1579 
1580     private:
1581         interface_t* m_ptr = nullptr;
1582     };
1583 
1584 
1585     /** Use unique_call to define an RAII type that demands a particular parameter-less global function be called.
1586     This allows implementing a RAII types that can call methods like CoUninitialize.
1587 
1588     @tparam close_fn_t The type of the function that is called to invoke the call.
1589     @tparam close_fn The function used to invoke the call.  This function should have the signature void().
1590     @tparam default_value Determines whether the unique_call is active or inactive when default-constructed or reset.
1591 
1592     Example
1593     ~~~
1594     void __stdcall CoUninitializeFunction()
1595     {
1596     ::CoUninitialize();
1597     }
1598     using unique_couninitialize_call = wil::unique_call<decltype(CoUninitializeFunction), CoUninitializeFunction>;
1599     ~~~ */
1600     template <typename close_fn_t, close_fn_t close_fn, bool default_value = true>
1601     class unique_call
1602     {
1603     public:
1604         unique_call() = default;
1605 
1606         explicit unique_call(bool call) WI_NOEXCEPT : m_call(call)
1607         {
1608         }
1609 
1610         unique_call(unique_call&& other) WI_NOEXCEPT
1611         {
1612             m_call = other.m_call;
1613             other.m_call = false;
1614         }
1615 
1616         unique_call& operator=(unique_call&& other) WI_NOEXCEPT
1617         {
1618             if (this != wistd::addressof(other))
1619             {
1620                 reset();
1621                 m_call = other.m_call;
1622                 other.m_call = false;
1623             }
1624             return *this;
1625         }
1626 
1627         ~unique_call() WI_NOEXCEPT
1628         {
1629             reset();
1630         }
1631 
1632         //! Assigns a new ptr and token
1633         void reset() WI_NOEXCEPT
1634         {
1635             auto call = m_call;
1636             m_call = false;
1637             if (call)
1638             {
1639                 wistd::invoke(close_fn);
1640             }
1641         }
1642 
1643         //! Exchanges values with raii class
1644         void swap(unique_call& other) WI_NOEXCEPT
1645         {
1646             wistd::swap_wil(m_call, other.m_call);
1647         }
1648 
1649         //! Make the interface call that was expected of this class
1650         void activate() WI_NOEXCEPT
1651         {
1652             m_call = true;
1653         }
1654 
1655         //! Do not make the interface call that was expected of this class
1656         void release() WI_NOEXCEPT
1657         {
1658             m_call = false;
1659         }
1660 
1661         //! Returns true if the call that was expected is still outstanding
1662         explicit operator bool() const WI_NOEXCEPT
1663         {
1664             return m_call;
1665         }
1666 
1667         unique_call(const unique_call&) = delete;
1668         unique_call& operator=(const unique_call&) = delete;
1669 
1670     private:
1671         bool m_call = default_value;
1672     };
1673 
1674     // str_raw_ptr is an overloaded function that retrieves a const pointer to the first character in a string's buffer.
1675     // Overloads in this file support any string that is implicitly convertible to a PCWSTR, HSTRING, and any unique_any_t
1676     // that points to any other supported type (this covers unique_hstring, unique_cotaskmem_string, and similar).
1677     // An overload for std::wstring is available in stl.h.
1678     inline PCWSTR str_raw_ptr(PCWSTR str)
1679     {
1680         return str;
1681     }
1682 
1683     template <typename T>
1684     PCWSTR str_raw_ptr(const unique_any_t<T>& ua)
1685     {
1686         return str_raw_ptr(ua.get());
1687     }
1688 
1689     namespace details
1690     {
1691         // Forward declaration
1692         template<typename string_type> struct string_maker;
1693 
1694         // Concatenate any number of strings together and store it in an automatically allocated string.  If a string is present
1695         // in the input buffer, it is overwritten.
1696         template <typename string_type>
1697         HRESULT str_build_nothrow(string_type& result, _In_reads_(strCount) PCWSTR* strList, size_t strCount)
1698         {
1699             size_t lengthRequiredWithoutNull{};
1700             for (auto& string : make_range(strList, strCount))
1701             {
1702                 lengthRequiredWithoutNull += string ? wcslen(string) : 0;
1703             }
1704 
1705             details::string_maker<string_type> maker;
1706             RETURN_IF_FAILED(maker.make(nullptr, lengthRequiredWithoutNull));
1707 
1708             auto buffer = maker.buffer();
1709             auto bufferEnd = buffer + lengthRequiredWithoutNull + 1;
1710             for (auto& string : make_range(strList, strCount))
1711             {
1712                 if (string)
1713                 {
1714                     RETURN_IF_FAILED(StringCchCopyExW(buffer, (bufferEnd - buffer), string, &buffer, nullptr, STRSAFE_IGNORE_NULLS));
1715                 }
1716             }
1717 
1718             result = maker.release();
1719             return S_OK;
1720         }
1721 
1722         // NOTE: 'Strings' must all be PCWSTR, or convertible to PCWSTR, but C++ doesn't allow us to express that cleanly
1723         template <typename string_type, typename... Strings>
1724         HRESULT str_build_nothrow(string_type& result, Strings... strings)
1725         {
1726             PCWSTR localStrings[] = { strings... };
1727             return str_build_nothrow(result, localStrings, sizeof...(Strings));
1728         }
1729     }
1730 
1731     // Concatenate any number of strings together and store it in an automatically allocated string.  If a string is present
1732     // in the input buffer, the remaining strings are appended to it.
1733     template <typename string_type, typename... strings>
1734     HRESULT str_concat_nothrow(string_type& buffer, const strings&... str)
1735     {
1736         static_assert(sizeof...(str) > 0, "attempting to concatenate no strings");
1737         return details::str_build_nothrow(buffer, details::string_maker<string_type>::get(buffer), str_raw_ptr(str)...);
1738     }
1739 
1740 #ifdef WIL_ENABLE_EXCEPTIONS
1741     // Concatenate any number of strings together and store it in an automatically allocated string.
1742     template <typename string_type, typename... arguments>
1743     string_type str_concat(arguments&&... args)
1744     {
1745         string_type result;
1746         THROW_IF_FAILED(str_concat_nothrow(result, wistd::forward<arguments>(args)...));
1747         return result;
1748     }
1749 #endif // WIL_ENABLE_EXCEPTIONS
1750 
1751     // Concatenate any number of strings together and store it in an automatically allocated string.
1752     template <typename string_type, typename... arguments>
1753     string_type str_concat_failfast(arguments&&... args)
1754     {
1755         string_type result;
1756         FAIL_FAST_IF_FAILED(str_concat_nothrow(result, wistd::forward<arguments>(args)...));
1757         return result;
1758     }
1759 
1760     namespace details
1761     {
1762         // Wraps StringCchPrintFExW and stores it in an automatically allocated string.  Takes a buffer followed by the same format arguments
1763         // that StringCchPrintfExW takes.
1764         template <typename string_type>
1765         HRESULT str_vprintf_nothrow(string_type& result, _Printf_format_string_ PCWSTR pszFormat, va_list& argsVL)
1766         {
1767             size_t lengthRequiredWithoutNull = _vscwprintf(pszFormat, argsVL);
1768 
1769             string_maker<string_type> maker;
1770             RETURN_IF_FAILED(maker.make(nullptr, lengthRequiredWithoutNull));
1771 
1772             auto buffer = maker.buffer();
1773             RETURN_IF_FAILED(::StringCchVPrintfExW(buffer, lengthRequiredWithoutNull + 1, nullptr, nullptr, STRSAFE_NULL_ON_FAILURE, pszFormat, argsVL));
1774 
1775             result = maker.release();
1776             return S_OK;
1777         }
1778     }
1779 
1780     // Wraps StringCchPrintFExW and stores it in an automatically allocated string.  Takes a buffer followed by the same format arguments
1781     // that StringCchPrintfExW takes.
1782     template <typename string_type>
1783     HRESULT str_printf_nothrow(string_type& result, _Printf_format_string_ PCWSTR pszFormat, _In_ ...)
1784     {
1785         va_list argsVL;
1786         va_start(argsVL, pszFormat);
1787         auto hr = details::str_vprintf_nothrow(result, pszFormat, argsVL);
1788         va_end(argsVL);
1789         return hr;
1790     }
1791 
1792 #ifdef WIL_ENABLE_EXCEPTIONS
1793     // Wraps StringCchPrintFExW and stores it in an automatically allocated string.  Takes a buffer followed by the same format arguments
1794     // that StringCchPrintfExW takes.
1795     template <typename string_type>
1796     string_type str_printf(_Printf_format_string_ PCWSTR pszFormat, _In_ ...)
1797     {
1798         string_type result;
1799         va_list argsVL;
1800         va_start(argsVL, pszFormat);
1801         auto hr = details::str_vprintf_nothrow(result, pszFormat, argsVL);
1802         va_end(argsVL);
1803         THROW_IF_FAILED(hr);
1804         return result;
1805     }
1806 #endif // WIL_ENABLE_EXCEPTIONS
1807 
1808     // Wraps StringCchPrintFExW and stores it in an automatically allocated string.  Takes a buffer followed by the same format arguments
1809     // that StringCchPrintfExW takes.
1810     template <typename string_type>
1811     string_type str_printf_failfast(_Printf_format_string_ PCWSTR pszFormat, _In_ ...)
1812     {
1813         string_type result;
1814         va_list argsVL;
1815         va_start(argsVL, pszFormat);
1816         auto hr = details::str_vprintf_nothrow(result, pszFormat, argsVL);
1817         va_end(argsVL);
1818         FAIL_FAST_IF_FAILED(hr);
1819         return result;
1820     }
1821 
1822 } // namespace wil
1823 #endif // __WIL_RESOURCE
1824 
1825 
1826   // Hash deferral function for unique_any_t
1827 #if (defined(_UNORDERED_SET_) || defined(_UNORDERED_MAP_)) && !defined(__WIL_RESOURCE_UNIQUE_HASH)
1828 #define __WIL_RESOURCE_UNIQUE_HASH
1829 namespace std
1830 {
1831     template <typename storage_t>
1832     struct hash<wil::unique_any_t<storage_t>>
1833     {
1834         size_t operator()(wil::unique_any_t<storage_t> const &val) const
1835         {
1836             return (hash<typename wil::unique_any_t<storage_t>::pointer>()(val.get()));
1837         }
1838     };
1839 }
1840 #endif
1841 
1842 // shared_any and weak_any implementation using <memory> STL header
1843 #if defined(_MEMORY_) && defined(WIL_ENABLE_EXCEPTIONS) && !defined(WIL_RESOURCE_STL) && !defined(RESOURCE_SUPPRESS_STL)
1844 #define WIL_RESOURCE_STL
1845 namespace wil {
1846 
1847     template <typename storage_t>
1848     class weak_any;
1849 
1850     /// @cond
1851     namespace details
1852     {
1853         // This class provides the pointer storage behind the implementation of shared_any_t utilizing the given
1854         // resource_policy.  It is separate from shared_any_t to allow a type-specific specialization class to plug
1855         // into the inheritance chain between shared_any_t and shared_storage.  This allows classes like shared_event
1856         // to be a shared_any formed class, but also expose methods like SetEvent directly.
1857 
1858         template <typename unique_t>
1859         class shared_storage
1860         {
1861         protected:
1862             typedef unique_t unique_t;
1863             typedef typename unique_t::policy policy;
1864             typedef typename policy::pointer_storage pointer_storage;
1865             typedef typename policy::pointer pointer;
1866             typedef shared_storage<unique_t> base_storage;
1867 
1868             shared_storage() = default;
1869 
1870             explicit shared_storage(pointer_storage ptr)
1871             {
1872                 if (policy::is_valid(ptr))
1873                 {
1874                     m_ptr = std::make_shared<unique_t>(unique_t(ptr));      // unique_t on the stack to prevent leak on throw
1875                 }
1876             }
1877 
1878             shared_storage(unique_t &&other)
1879             {
1880                 if (other)
1881                 {
1882                     m_ptr = std::make_shared<unique_t>(wistd::move(other));
1883                 }
1884             }
1885 
1886             shared_storage(const shared_storage &other) WI_NOEXCEPT :
1887             m_ptr(other.m_ptr)
1888             {
1889             }
1890 
1891             shared_storage& operator=(const shared_storage &other) WI_NOEXCEPT
1892             {
1893                 m_ptr = other.m_ptr;
1894                 return *this;
1895             }
1896 
1897             shared_storage(shared_storage &&other) WI_NOEXCEPT :
1898             m_ptr(wistd::move(other.m_ptr))
1899             {
1900             }
1901 
1902             shared_storage(std::shared_ptr<unique_t> const &ptr) :
1903                 m_ptr(ptr)
1904             {
1905             }
1906 
1907             void replace(shared_storage &&other) WI_NOEXCEPT
1908             {
1909                 m_ptr = wistd::move(other.m_ptr);
1910             }
1911 
1912         public:
1913             bool is_valid() const WI_NOEXCEPT
1914             {
1915                 return (m_ptr && m_ptr->is_valid());
1916             }
1917 
1918             void reset(pointer_storage ptr = policy::invalid_value())
1919             {
1920                 if (policy::is_valid(ptr))
1921                 {
1922                     m_ptr = std::make_shared<unique_t>(unique_t(ptr));      // unique_t on the stack to prevent leak on throw
1923                 }
1924                 else
1925                 {
1926                     m_ptr = nullptr;
1927                 }
1928             }
1929 
1930             void reset(unique_t &&other)
1931             {
1932                 m_ptr = std::make_shared<unique_t>(wistd::move(other));
1933             }
1934 
1935             void reset(wistd::nullptr_t) WI_NOEXCEPT
1936             {
1937                 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");
1938                 reset();
1939             }
1940 
1941             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>
1942             pointer get() const WI_NOEXCEPT
1943             {
1944                 return (m_ptr ? m_ptr->get() : policy::invalid_value());
1945             }
1946 
1947             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>
1948             pointer_storage *addressof()
1949             {
1950                 if (!m_ptr)
1951                 {
1952                     m_ptr = std::make_shared<unique_t>();
1953                 }
1954                 return m_ptr->addressof();
1955             }
1956 
1957             long int use_count() const WI_NOEXCEPT
1958             {
1959                 return m_ptr.use_count();
1960             }
1961 
1962         private:
1963             template <typename storage_t>
1964             friend class ::wil::weak_any;
1965 
1966             std::shared_ptr<unique_t> m_ptr;
1967         };
1968     }
1969     /// @endcond
1970 
1971     // This class when paired with shared_storage and an optional type-specific specialization class implements
1972     // the same interface as STL's shared_ptr<> for resource handle types.  It is both copyable and movable, supporting
1973     // weak references and automatic closure of the handle upon release of the last shared_any.
1974 
1975     template <typename storage_t>
1976     class shared_any_t : public storage_t
1977     {
1978     public:
1979         typedef typename storage_t::policy policy;
1980         typedef typename policy::pointer_storage pointer_storage;
1981         typedef typename policy::pointer pointer;
1982         typedef typename storage_t::unique_t unique_t;
1983 
1984         // default and forwarding constructor: forwards default, all 'explicit' and multi-arg constructors to the base class
1985         template <typename... args_t>
1986         explicit shared_any_t(args_t&&... args) :  // should not be WI_NOEXCEPT (may forward to a throwing constructor)
1987             storage_t(wistd::forward<args_t>(args)...)
1988         {
1989         }
1990 
1991         shared_any_t(wistd::nullptr_t) WI_NOEXCEPT
1992         {
1993             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");
1994         }
1995 
1996         shared_any_t(shared_any_t &&other) WI_NOEXCEPT :
1997         storage_t(wistd::move(other))
1998         {
1999         }
2000 
2001         shared_any_t(const shared_any_t &other) WI_NOEXCEPT :
2002             storage_t(other)
2003         {
2004         }
2005 
2006         shared_any_t& operator=(shared_any_t &&other) WI_NOEXCEPT
2007         {
2008             if (this != wistd::addressof(other))
2009             {
2010                 storage_t::replace(wistd::move(static_cast<typename storage_t::base_storage &>(other)));
2011             }
2012             return (*this);
2013         }
2014 
2015         shared_any_t& operator=(const shared_any_t& other) WI_NOEXCEPT
2016         {
2017             storage_t::operator=(other);
2018             return (*this);
2019         }
2020 
2021         shared_any_t(unique_t &&other) :
2022             storage_t(wistd::move(other))
2023         {
2024         }
2025 
2026         shared_any_t& operator=(unique_t &&other)
2027         {
2028             storage_t::reset(wistd::move(other));
2029             return (*this);
2030         }
2031 
2032         shared_any_t& operator=(wistd::nullptr_t) WI_NOEXCEPT
2033         {
2034             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");
2035             storage_t::reset();
2036             return (*this);
2037         }
2038 
2039         void swap(shared_any_t &other) WI_NOEXCEPT
2040         {
2041             shared_any_t self(wistd::move(*this));
2042             operator=(wistd::move(other));
2043             other = wistd::move(self);
2044         }
2045 
2046         explicit operator bool() const WI_NOEXCEPT
2047         {
2048             return storage_t::is_valid();
2049         }
2050 
2051         pointer_storage *put()
2052         {
2053             static_assert(wistd::is_same<typename policy::pointer_access, details::pointer_access_all>::value, "operator & is not available for this handle");
2054             storage_t::reset();
2055             return storage_t::addressof();
2056         }
2057 
2058         pointer_storage *operator&()
2059         {
2060             return put();
2061         }
2062 
2063         pointer get() const WI_NOEXCEPT
2064         {
2065             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");
2066             return storage_t::get();
2067         }
2068 
2069         // The following functions are publicly exposed by their inclusion in the base class
2070 
2071         // void reset(pointer_storage ptr = policy::invalid_value()) WI_NOEXCEPT
2072         // void reset(wistd::nullptr_t) WI_NOEXCEPT
2073         // pointer_storage *addressof() WI_NOEXCEPT                                     // (note: not exposed for opaque resource types)
2074     };
2075 
2076     template <typename unique_t>
2077     void swap(shared_any_t<unique_t>& left, shared_any_t<unique_t>& right) WI_NOEXCEPT
2078     {
2079         left.swap(right);
2080     }
2081 
2082     template <typename unique_t>
2083     bool operator==(const shared_any_t<unique_t>& left, const shared_any_t<unique_t>& right) WI_NOEXCEPT
2084     {
2085         return (left.get() == right.get());
2086     }
2087 
2088     template <typename unique_t>
2089     bool operator==(const shared_any_t<unique_t>& left, wistd::nullptr_t) WI_NOEXCEPT
2090     {
2091         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");
2092         return !left;
2093     }
2094 
2095     template <typename unique_t>
2096     bool operator==(wistd::nullptr_t, const shared_any_t<unique_t>& right) WI_NOEXCEPT
2097     {
2098         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");
2099         return !right;
2100     }
2101 
2102     template <typename unique_t>
2103     bool operator!=(const shared_any_t<unique_t>& left, const shared_any_t<unique_t>& right) WI_NOEXCEPT
2104     {
2105         return (!(left.get() == right.get()));
2106     }
2107 
2108     template <typename unique_t>
2109     bool operator!=(const shared_any_t<unique_t>& left, wistd::nullptr_t) WI_NOEXCEPT
2110     {
2111         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");
2112         return !!left;
2113     }
2114 
2115     template <typename unique_t>
2116     bool operator!=(wistd::nullptr_t, const shared_any_t<unique_t>& right) WI_NOEXCEPT
2117     {
2118         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");
2119         return !!right;
2120     }
2121 
2122     template <typename unique_t>
2123     bool operator<(const shared_any_t<unique_t>& left, const shared_any_t<unique_t>& right) WI_NOEXCEPT
2124     {
2125         return (left.get() < right.get());
2126     }
2127 
2128     template <typename unique_t>
2129     bool operator>=(const shared_any_t<unique_t>& left, const shared_any_t<unique_t>& right) WI_NOEXCEPT
2130     {
2131         return (!(left < right));
2132     }
2133 
2134     template <typename unique_t>
2135     bool operator>(const shared_any_t<unique_t>& left, const shared_any_t<unique_t>& right) WI_NOEXCEPT
2136     {
2137         return (right < left);
2138     }
2139 
2140     template <typename unique_t>
2141     bool operator<=(const shared_any_t<unique_t>& left, const shared_any_t<unique_t>& right) WI_NOEXCEPT
2142     {
2143         return (!(right < left));
2144     }
2145 
2146 
2147     // This class provides weak_ptr<> support for shared_any<>, bringing the same weak reference counting and lock() acquire semantics
2148     // to shared_any.
2149 
2150     template <typename shared_t>
2151     class weak_any
2152     {
2153     public:
2154         typedef shared_t shared_t;
2155 
2156         weak_any() WI_NOEXCEPT
2157         {
2158         }
2159 
2160         weak_any(const shared_t &other) WI_NOEXCEPT :
2161             m_weakPtr(other.m_ptr)
2162         {
2163         }
2164 
2165         weak_any(const weak_any &other) WI_NOEXCEPT :
2166             m_weakPtr(other.m_weakPtr)
2167         {
2168         }
2169 
2170         weak_any& operator=(const weak_any &right) WI_NOEXCEPT
2171         {
2172             m_weakPtr = right.m_weakPtr;
2173             return (*this);
2174         }
2175 
2176         weak_any& operator=(const shared_t &right) WI_NOEXCEPT
2177         {
2178             m_weakPtr = right.m_ptr;
2179             return (*this);
2180         }
2181 
2182         void reset() WI_NOEXCEPT
2183         {
2184             m_weakPtr.reset();
2185         }
2186 
2187         void swap(weak_any &other) WI_NOEXCEPT
2188         {
2189             m_weakPtr.swap(other.m_weakPtr);
2190         }
2191 
2192         bool expired() const WI_NOEXCEPT
2193         {
2194             return m_weakPtr.expired();
2195         }
2196 
2197         shared_t lock() const WI_NOEXCEPT
2198         {
2199             return shared_t(m_weakPtr.lock());
2200         }
2201 
2202     private:
2203         std::weak_ptr<typename shared_t::unique_t> m_weakPtr;
2204     };
2205 
2206     template <typename shared_t>
2207     void swap(weak_any<shared_t>& left, weak_any<shared_t>& right) WI_NOEXCEPT
2208     {
2209         left.swap(right);
2210     }
2211 
2212     template <typename unique_t>
2213     using shared_any = shared_any_t<details::shared_storage<unique_t>>;
2214 
2215 } // namespace wil
2216 #endif
2217 
2218 
2219 #if defined(WIL_RESOURCE_STL) && (defined(_UNORDERED_SET_) || defined(_UNORDERED_MAP_)) && !defined(__WIL_RESOURCE_SHARED_HASH)
2220 #define __WIL_RESOURCE_SHARED_HASH
2221 namespace std
2222 {
2223     template <typename storage_t>
2224     struct hash<wil::shared_any_t<storage_t>>
2225     {
2226         size_t operator()(wil::shared_any_t<storage_t> const &val) const
2227         {
2228             return (hash<typename wil::shared_any_t<storage_t>::pointer>()(val.get()));
2229         }
2230     };
2231 }
2232 #endif
2233 
2234 
2235 namespace wil
2236 {
2237 
2238 #if defined(__NOTHROW_T_DEFINED) && !defined(__WIL__NOTHROW_T_DEFINED)
2239 #define __WIL__NOTHROW_T_DEFINED
2240     /** Provides `std::make_unique()` semantics for resources allocated in a context that may not throw upon allocation failure.
2241     `wil::make_unique_nothrow()` is identical to `std::make_unique()` except for the following:
2242     * It returns `wistd::unique_ptr`, rather than `std::unique_ptr`
2243     * It returns an empty (null) `wistd::unique_ptr` upon allocation failure, rather than throwing an exception
2244 
2245     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.
2246     ~~~
2247     auto foo = wil::make_unique_nothrow<Foo>(fooConstructorParam1, fooConstructorParam2);
2248     if (foo)
2249     {
2250     foo->Bar();
2251     }
2252     ~~~
2253     */
2254     template <class _Ty, class... _Types>
2255     inline typename wistd::enable_if<!wistd::is_array<_Ty>::value, wistd::unique_ptr<_Ty> >::type make_unique_nothrow(_Types&&... _Args)
2256     {
2257         return (wistd::unique_ptr<_Ty>(new(std::nothrow) _Ty(wistd::forward<_Types>(_Args)...)));
2258     }
2259 
2260     /** Provides `std::make_unique()` semantics for array resources allocated in a context that may not throw upon allocation failure.
2261     See the overload of `wil::make_unique_nothrow()` for non-array types for more details.
2262     ~~~
2263     const size_t size = 42;
2264     auto foos = wil::make_unique_nothrow<Foo[]>(size); // the default constructor will be called on each Foo object
2265     if (foos)
2266     {
2267     for (auto& elem : wil::make_range(foos.get(), size))
2268     {
2269     elem.Bar();
2270     }
2271     }
2272     ~~~
2273     */
2274     template <class _Ty>
2275     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)
2276     {
2277         typedef typename wistd::remove_extent<_Ty>::type _Elem;
2278         return (wistd::unique_ptr<_Ty>(new(std::nothrow) _Elem[_Size]()));
2279     }
2280 
2281     template <class _Ty, class... _Types>
2282     typename wistd::enable_if<wistd::extent<_Ty>::value != 0, void>::type make_unique_nothrow(_Types&&...) = delete;
2283 
2284 #if !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE)
2285     /** Provides `std::make_unique()` semantics for resources allocated in a context that must fail fast upon allocation failure.
2286     See the overload of `wil::make_unique_nothrow()` for non-array types for more details.
2287     ~~~
2288     auto foo = wil::make_unique_failfast<Foo>(fooConstructorParam1, fooConstructorParam2);
2289     foo->Bar();
2290     ~~~
2291     */
2292     template <class _Ty, class... _Types>
2293     inline typename wistd::enable_if<!wistd::is_array<_Ty>::value, wistd::unique_ptr<_Ty> >::type make_unique_failfast(_Types&&... _Args)
2294     {
2295 #pragma warning(suppress: 28193)    // temporary must be inspected (it is within the called function)
2296         return (wistd::unique_ptr<_Ty>(FAIL_FAST_IF_NULL_ALLOC(new(std::nothrow) _Ty(wistd::forward<_Types>(_Args)...))));
2297     }
2298 
2299     /** Provides `std::make_unique()` semantics for array resources allocated in a context that must fail fast upon allocation failure.
2300     See the overload of `wil::make_unique_nothrow()` for non-array types for more details.
2301     ~~~
2302     const size_t size = 42;
2303     auto foos = wil::make_unique_nothrow<Foo[]>(size); // the default constructor will be called on each Foo object
2304     for (auto& elem : wil::make_range(foos.get(), size))
2305     {
2306     elem.Bar();
2307     }
2308     ~~~
2309     */
2310     template <class _Ty>
2311     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)
2312     {
2313         typedef typename wistd::remove_extent<_Ty>::type _Elem;
2314 #pragma warning(suppress: 28193)    // temporary must be inspected (it is within the called function)
2315         return (wistd::unique_ptr<_Ty>(FAIL_FAST_IF_NULL_ALLOC(new(std::nothrow) _Elem[_Size]())));
2316     }
2317 
2318     template <class _Ty, class... _Types>
2319     typename wistd::enable_if<wistd::extent<_Ty>::value != 0, void>::type make_unique_failfast(_Types&&...) = delete;
2320 #endif // !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE)
2321 #endif // __WIL__NOTHROW_T_DEFINED
2322 
2323 #if defined(_WINBASE_) && !defined(__WIL_WINBASE_) && !defined(WIL_KERNEL_MODE)
2324 #define __WIL_WINBASE_
2325     /// @cond
2326     namespace details
2327     {
2328         inline void __stdcall SetEvent(HANDLE h) WI_NOEXCEPT
2329         {
2330             __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::SetEvent(h));
2331         }
2332 
2333         inline void __stdcall ResetEvent(HANDLE h) WI_NOEXCEPT
2334         {
2335             __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::ResetEvent(h));
2336         }
2337 
2338         inline void __stdcall CloseHandle(HANDLE h) WI_NOEXCEPT
2339         {
2340             __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::CloseHandle(h));
2341         }
2342 
2343         inline void __stdcall ReleaseSemaphore(_In_ HANDLE h) WI_NOEXCEPT
2344         {
2345             __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::ReleaseSemaphore(h, 1, nullptr));
2346         }
2347 
2348         inline void __stdcall ReleaseMutex(_In_ HANDLE h) WI_NOEXCEPT
2349         {
2350             __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::ReleaseMutex(h));
2351         }
2352 
2353         inline void __stdcall CloseTokenLinkedToken(_In_ TOKEN_LINKED_TOKEN* linkedToken) WI_NOEXCEPT
2354         {
2355             if (linkedToken->LinkedToken && (linkedToken->LinkedToken != INVALID_HANDLE_VALUE))
2356             {
2357                 __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::CloseHandle(linkedToken->LinkedToken));
2358             }
2359         }
2360 
2361         enum class PendingCallbackCancellationBehavior
2362         {
2363             Cancel,
2364             Wait,
2365             NoWait,
2366         };
2367 
2368         template <PendingCallbackCancellationBehavior cancellationBehavior>
2369         struct DestroyThreadPoolWait
2370         {
2371             static void Destroy(_In_ PTP_WAIT threadPoolWait) WI_NOEXCEPT
2372             {
2373                 ::SetThreadpoolWait(threadPoolWait, nullptr, nullptr);
2374                 ::WaitForThreadpoolWaitCallbacks(threadPoolWait, (cancellationBehavior == PendingCallbackCancellationBehavior::Cancel));
2375                 ::CloseThreadpoolWait(threadPoolWait);
2376             }
2377         };
2378 
2379         template <>
2380         struct DestroyThreadPoolWait<PendingCallbackCancellationBehavior::NoWait>
2381         {
2382             static void Destroy(_In_ PTP_WAIT threadPoolWait) WI_NOEXCEPT
2383             {
2384                 ::CloseThreadpoolWait(threadPoolWait);
2385             }
2386         };
2387 
2388         template <PendingCallbackCancellationBehavior cancellationBehavior>
2389         struct DestroyThreadPoolWork
2390         {
2391             static void Destroy(_In_ PTP_WORK threadpoolWork) WI_NOEXCEPT
2392             {
2393                 ::WaitForThreadpoolWorkCallbacks(threadpoolWork, (cancellationBehavior == PendingCallbackCancellationBehavior::Cancel));
2394                 ::CloseThreadpoolWork(threadpoolWork);
2395             }
2396         };
2397 
2398         template <>
2399         struct DestroyThreadPoolWork<PendingCallbackCancellationBehavior::NoWait>
2400         {
2401             static void Destroy(_In_ PTP_WORK threadpoolWork) WI_NOEXCEPT
2402             {
2403                 ::CloseThreadpoolWork(threadpoolWork);
2404             }
2405         };
2406 
2407         // Non-RTL implementation for threadpool_t parameter of DestroyThreadPoolTimer<>
2408         struct SystemThreadPoolMethods
2409         {
2410             static void WINAPI SetThreadpoolTimer(_Inout_ PTP_TIMER Timer, _In_opt_ PFILETIME DueTime, _In_ DWORD Period, _In_opt_ DWORD WindowLength) WI_NOEXCEPT
2411             {
2412                 ::SetThreadpoolTimer(Timer, DueTime, Period, WindowLength);
2413             }
2414             static void WaitForThreadpoolTimerCallbacks(_Inout_ PTP_TIMER Timer, _In_ BOOL CancelPendingCallbacks) WI_NOEXCEPT
2415             {
2416                 ::WaitForThreadpoolTimerCallbacks(Timer, CancelPendingCallbacks);
2417             }
2418             static void CloseThreadpoolTimer(_Inout_ PTP_TIMER Timer) WI_NOEXCEPT
2419             {
2420                 ::CloseThreadpoolTimer(Timer);
2421             }
2422         };
2423 
2424         // SetThreadpoolTimer(timer, nullptr, 0, 0) will cancel any pending callbacks,
2425         // then CloseThreadpoolTimer will asynchronusly close the timer if a callback is running.
2426         template <typename threadpool_t, PendingCallbackCancellationBehavior cancellationBehavior>
2427         struct DestroyThreadPoolTimer
2428         {
2429             static void Destroy(_In_ PTP_TIMER threadpoolTimer) WI_NOEXCEPT
2430             {
2431                 threadpool_t::SetThreadpoolTimer(threadpoolTimer, nullptr, 0, 0);
2432 #pragma warning(suppress:4127) // conditional expression is constant
2433                 if (cancellationBehavior != PendingCallbackCancellationBehavior::NoWait)
2434                 {
2435                     threadpool_t::WaitForThreadpoolTimerCallbacks(threadpoolTimer, (cancellationBehavior == PendingCallbackCancellationBehavior::Cancel));
2436                 }
2437                 threadpool_t::CloseThreadpoolTimer(threadpoolTimer);
2438             }
2439         };
2440 
2441         // PendingCallbackCancellationBehavior::NoWait explicitly does not block waiting for
2442         // callbacks when destructing.
2443         template <typename threadpool_t>
2444         struct DestroyThreadPoolTimer<threadpool_t, PendingCallbackCancellationBehavior::NoWait>
2445         {
2446             static void Destroy(_In_ PTP_TIMER threadpoolTimer) WI_NOEXCEPT
2447             {
2448                 threadpool_t::CloseThreadpoolTimer(threadpoolTimer);
2449             }
2450         };
2451 
2452         template <PendingCallbackCancellationBehavior cancellationBehavior>
2453         struct DestroyThreadPoolIo
2454         {
2455             static void Destroy(_In_ PTP_IO threadpoolIo) WI_NOEXCEPT
2456             {
2457                 ::WaitForThreadpoolIoCallbacks(threadpoolIo, (cancellationBehavior == PendingCallbackCancellationBehavior::Cancel));
2458                 ::CloseThreadpoolIo(threadpoolIo);
2459             }
2460         };
2461 
2462         template <>
2463         struct DestroyThreadPoolIo<PendingCallbackCancellationBehavior::NoWait>
2464         {
2465             static void Destroy(_In_ PTP_IO threadpoolIo) WI_NOEXCEPT
2466             {
2467                 ::CloseThreadpoolIo(threadpoolIo);
2468             }
2469         };
2470 
2471         template <typename close_fn_t, close_fn_t close_fn>
2472         struct handle_invalid_resource_policy : resource_policy<HANDLE, close_fn_t, close_fn, details::pointer_access_all, HANDLE, INT_PTR, -1, HANDLE>
2473         {
2474             __forceinline static bool is_valid(HANDLE ptr) WI_NOEXCEPT { return ((ptr != INVALID_HANDLE_VALUE) && (ptr != nullptr)); }
2475         };
2476 
2477         template <typename close_fn_t, close_fn_t close_fn>
2478         struct handle_null_resource_policy : resource_policy<HANDLE, close_fn_t, close_fn>
2479         {
2480             __forceinline static bool is_valid(HANDLE ptr) WI_NOEXCEPT { return ((ptr != nullptr) && (ptr != INVALID_HANDLE_VALUE)); }
2481         };
2482 
2483         template <typename close_fn_t, close_fn_t close_fn>
2484         struct handle_null_only_resource_policy : resource_policy<HANDLE, close_fn_t, close_fn>
2485         {
2486             __forceinline static bool is_valid(HANDLE ptr) WI_NOEXCEPT { return (ptr != nullptr); }
2487         };
2488 
2489         typedef resource_policy<HANDLE, decltype(&details::CloseHandle), details::CloseHandle, details::pointer_access_all> handle_resource_policy;
2490     }
2491     /// @endcond
2492 
2493     template <typename close_fn_t, close_fn_t close_fn>
2494     using unique_any_handle_invalid = unique_any_t<details::unique_storage<details::handle_invalid_resource_policy<close_fn_t, close_fn>>>;
2495 
2496     template <typename close_fn_t, close_fn_t close_fn>
2497     using unique_any_handle_null = unique_any_t<details::unique_storage<details::handle_null_resource_policy<close_fn_t, close_fn>>>;
2498 
2499     template <typename close_fn_t, close_fn_t close_fn>
2500     using unique_any_handle_null_only = unique_any_t<details::unique_storage<details::handle_null_only_resource_policy<close_fn_t, close_fn>>>;
2501 
2502     typedef unique_any_handle_invalid<decltype(&::CloseHandle), ::CloseHandle> unique_hfile;
2503     typedef unique_any_handle_null<decltype(&::CloseHandle), ::CloseHandle> unique_handle;
2504     typedef unique_any_handle_invalid<decltype(&::FindClose), ::FindClose> unique_hfind;
2505     typedef unique_any<HMODULE, decltype(&::FreeLibrary), ::FreeLibrary> unique_hmodule;
2506     typedef unique_any_handle_null_only<decltype(&::CloseHandle), ::CloseHandle> unique_process_handle;
2507 
2508     typedef unique_struct<TOKEN_LINKED_TOKEN, decltype(&details::CloseTokenLinkedToken), details::CloseTokenLinkedToken> unique_token_linked_token;
2509 
2510 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
2511     typedef unique_any<PSID, decltype(&::FreeSid), ::FreeSid> unique_sid;
2512 #endif
2513 
2514     using unique_tool_help_snapshot = unique_hfile;
2515 
2516     typedef unique_any<PTP_WAIT, void(*)(PTP_WAIT), details::DestroyThreadPoolWait<details::PendingCallbackCancellationBehavior::Cancel>::Destroy> unique_threadpool_wait;
2517     typedef unique_any<PTP_WAIT, void(*)(PTP_WAIT), details::DestroyThreadPoolWait<details::PendingCallbackCancellationBehavior::Wait>::Destroy> unique_threadpool_wait_nocancel;
2518     typedef unique_any<PTP_WAIT, void(*)(PTP_WAIT), details::DestroyThreadPoolWait<details::PendingCallbackCancellationBehavior::NoWait>::Destroy> unique_threadpool_wait_nowait;
2519     typedef unique_any<PTP_WORK, void(*)(PTP_WORK), details::DestroyThreadPoolWork<details::PendingCallbackCancellationBehavior::Cancel>::Destroy> unique_threadpool_work;
2520     typedef unique_any<PTP_WORK, void(*)(PTP_WORK), details::DestroyThreadPoolWork<details::PendingCallbackCancellationBehavior::Wait>::Destroy> unique_threadpool_work_nocancel;
2521     typedef unique_any<PTP_WORK, void(*)(PTP_WORK), details::DestroyThreadPoolWork<details::PendingCallbackCancellationBehavior::NoWait>::Destroy> unique_threadpool_work_nowait;
2522     typedef unique_any<PTP_TIMER, void(*)(PTP_TIMER), details::DestroyThreadPoolTimer<details::SystemThreadPoolMethods, details::PendingCallbackCancellationBehavior::Cancel>::Destroy> unique_threadpool_timer;
2523     typedef unique_any<PTP_TIMER, void(*)(PTP_TIMER), details::DestroyThreadPoolTimer<details::SystemThreadPoolMethods, details::PendingCallbackCancellationBehavior::Wait>::Destroy> unique_threadpool_timer_nocancel;
2524     typedef unique_any<PTP_TIMER, void(*)(PTP_TIMER), details::DestroyThreadPoolTimer<details::SystemThreadPoolMethods, details::PendingCallbackCancellationBehavior::NoWait>::Destroy> unique_threadpool_timer_nowait;
2525     typedef unique_any<PTP_IO, void(*)(PTP_IO), details::DestroyThreadPoolIo<details::PendingCallbackCancellationBehavior::Cancel>::Destroy> unique_threadpool_io;
2526     typedef unique_any<PTP_IO, void(*)(PTP_IO), details::DestroyThreadPoolIo<details::PendingCallbackCancellationBehavior::Wait>::Destroy> unique_threadpool_io_nocancel;
2527     typedef unique_any<PTP_IO, void(*)(PTP_IO), details::DestroyThreadPoolIo<details::PendingCallbackCancellationBehavior::NoWait>::Destroy> unique_threadpool_io_nowait;
2528 
2529 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
2530     typedef unique_any_handle_invalid<decltype(&::FindCloseChangeNotification), ::FindCloseChangeNotification> unique_hfind_change;
2531 #endif
2532 
2533     typedef unique_any<HANDLE, decltype(&details::SetEvent), details::SetEvent, details::pointer_access_noaddress> event_set_scope_exit;
2534     typedef unique_any<HANDLE, decltype(&details::ResetEvent), details::ResetEvent, details::pointer_access_noaddress> event_reset_scope_exit;
2535 
2536     // Guarantees a SetEvent on the given event handle when the returned object goes out of scope
2537     // Note: call SetEvent early with the reset() method on the returned object or abort the call with the release() method
2538     WI_NODISCARD inline event_set_scope_exit SetEvent_scope_exit(HANDLE hEvent) WI_NOEXCEPT
2539     {
2540         __FAIL_FAST_ASSERT__(hEvent != nullptr);
2541         return event_set_scope_exit(hEvent);
2542     }
2543 
2544     // Guarantees a ResetEvent on the given event handle when the returned object goes out of scope
2545     // Note: call ResetEvent early with the reset() method on the returned object or abort the call with the release() method
2546     WI_NODISCARD inline event_reset_scope_exit ResetEvent_scope_exit(HANDLE hEvent) WI_NOEXCEPT
2547     {
2548         __FAIL_FAST_ASSERT__(hEvent != nullptr);
2549         return event_reset_scope_exit(hEvent);
2550     }
2551 
2552     // Checks to see if the given *manual reset* event is currently signaled.  The event must not be an auto-reset event.
2553     // Use when the event will only be set once (cancellation-style) or will only be reset by the polling thread
2554     inline bool event_is_signaled(HANDLE hEvent) WI_NOEXCEPT
2555     {
2556         auto status = ::WaitForSingleObjectEx(hEvent, 0, FALSE);
2557         // Fast fail will trip for wait failures, auto-reset events, or when the event is being both Set and Reset
2558         // from a thread other than the polling thread (use event_wait directly for those cases).
2559         __FAIL_FAST_ASSERT__((status == WAIT_TIMEOUT) || ((status == WAIT_OBJECT_0) && (WAIT_OBJECT_0 == ::WaitForSingleObjectEx(hEvent, 0, FALSE))));
2560         return (status == WAIT_OBJECT_0);
2561     }
2562 
2563     // Waits on the given handle for the specified duration
2564     inline bool handle_wait(HANDLE hEvent, DWORD dwMilliseconds = INFINITE) WI_NOEXCEPT
2565     {
2566         DWORD status = ::WaitForSingleObjectEx(hEvent, dwMilliseconds, FALSE);
2567         __FAIL_FAST_ASSERT__((status == WAIT_TIMEOUT) || (status == WAIT_OBJECT_0));
2568         return (status == WAIT_OBJECT_0);
2569     }
2570 
2571     enum class EventOptions
2572     {
2573         None = 0x0,
2574         ManualReset = 0x1,
2575         Signaled = 0x2
2576     };
2577     DEFINE_ENUM_FLAG_OPERATORS(EventOptions);
2578 
2579     template <typename storage_t, typename err_policy = err_exception_policy>
2580     class event_t : public storage_t
2581     {
2582     public:
2583         // forward all base class constructors...
2584         template <typename... args_t>
2585         explicit event_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward<args_t>(args)...) {}
2586 
2587         // HRESULT or void error handling...
2588         typedef typename err_policy::result result;
2589 
2590         // Exception-based constructor to create an unnamed event
2591         event_t(EventOptions options)
2592         {
2593             static_assert(wistd::is_same<void, result>::value, "this constructor requires exceptions or fail fast; use the create method");
2594             create(options);
2595         }
2596 
2597         void ResetEvent() const WI_NOEXCEPT
2598         {
2599             details::ResetEvent(storage_t::get());
2600         }
2601 
2602         void SetEvent() const WI_NOEXCEPT
2603         {
2604             details::SetEvent(storage_t::get());
2605         }
2606 
2607         // Guarantees a SetEvent on the given event handle when the returned object goes out of scope
2608         // Note: call SetEvent early with the reset() method on the returned object or abort the call with the release() method
2609         WI_NODISCARD event_set_scope_exit SetEvent_scope_exit() const WI_NOEXCEPT
2610         {
2611             return wil::SetEvent_scope_exit(storage_t::get());
2612         }
2613 
2614         // Guarantees a ResetEvent on the given event handle when the returned object goes out of scope
2615         // Note: call ResetEvent early with the reset() method on the returned object or abort the call with the release() method
2616         WI_NODISCARD event_reset_scope_exit ResetEvent_scope_exit() const WI_NOEXCEPT
2617         {
2618             return wil::ResetEvent_scope_exit(storage_t::get());
2619         }
2620 
2621         // Checks if a *manual reset* event is currently signaled.  The event must not be an auto-reset event.
2622         // Use when the event will only be set once (cancellation-style) or will only be reset by the polling thread
2623         bool is_signaled() const WI_NOEXCEPT
2624         {
2625             return wil::event_is_signaled(storage_t::get());
2626         }
2627 
2628         // Basic WaitForSingleObject on the event handle with the given timeout
2629         bool wait(DWORD dwMilliseconds = INFINITE) const WI_NOEXCEPT
2630         {
2631             return wil::handle_wait(storage_t::get(), dwMilliseconds);
2632         }
2633 
2634         // Tries to create a named event -- returns false if unable to do so (gle may still be inspected with return=false)
2635         bool try_create(EventOptions options, PCWSTR name, _In_opt_ LPSECURITY_ATTRIBUTES pSecurity = nullptr, _Out_opt_ bool *pAlreadyExists = nullptr)
2636         {
2637             auto handle = ::CreateEventExW(pSecurity, name, (WI_IsFlagSet(options, EventOptions::ManualReset) ? CREATE_EVENT_MANUAL_RESET : 0) | (WI_IsFlagSet(options, EventOptions::Signaled) ? CREATE_EVENT_INITIAL_SET : 0), EVENT_ALL_ACCESS);
2638             if (!handle)
2639             {
2640                 assign_to_opt_param(pAlreadyExists, false);
2641                 return false;
2642             }
2643             assign_to_opt_param(pAlreadyExists, (::GetLastError() == ERROR_ALREADY_EXISTS));
2644             storage_t::reset(handle);
2645             return true;
2646         }
2647 
2648         // Returns HRESULT for unique_event_nothrow, void with exceptions for shared_event and unique_event
2649         result create(EventOptions options = EventOptions::None, PCWSTR name = nullptr, _In_opt_ LPSECURITY_ATTRIBUTES pSecurity = nullptr, _Out_opt_ bool *pAlreadyExists = nullptr)
2650         {
2651             return err_policy::LastErrorIfFalse(try_create(options, name, pSecurity, pAlreadyExists));
2652         }
2653 
2654         // Tries to open the named event -- returns false if unable to do so (gle may still be inspected with return=false)
2655         bool try_open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | EVENT_MODIFY_STATE, bool inheritHandle = false)
2656         {
2657             auto handle = ::OpenEventW(desiredAccess, inheritHandle, name);
2658             if (handle == nullptr)
2659             {
2660                 return false;
2661             }
2662             storage_t::reset(handle);
2663             return true;
2664         }
2665 
2666         // Returns HRESULT for unique_event_nothrow, void with exceptions for shared_event and unique_event
2667         result open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | EVENT_MODIFY_STATE, bool inheritHandle = false)
2668         {
2669             return err_policy::LastErrorIfFalse(try_open(name, desiredAccess, inheritHandle));
2670         }
2671     };
2672 
2673     typedef unique_any_t<event_t<details::unique_storage<details::handle_resource_policy>, err_returncode_policy>>     unique_event_nothrow;
2674     typedef unique_any_t<event_t<details::unique_storage<details::handle_resource_policy>, err_failfast_policy>>       unique_event_failfast;
2675 #ifdef WIL_ENABLE_EXCEPTIONS
2676     typedef unique_any_t<event_t<details::unique_storage<details::handle_resource_policy>, err_exception_policy>>      unique_event;
2677 #endif
2678 
2679 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
2680     enum class SlimEventType
2681     {
2682         AutoReset,
2683         ManualReset,
2684     };
2685 
2686     /** A lean and mean event class.
2687     This class provides a very similar API to `wil::unique_event` but doesn't require a kernel object.
2688 
2689     The two variants of this class are:
2690     - `wil::slim_event_auto_reset`
2691     - `wil::slim_event_manual_reset`
2692 
2693     In addition, `wil::slim_event_auto_reset` has the alias `wil::slim_event`.
2694 
2695     Some key differences to `wil::unique_event` include:
2696     - There is no 'create()' function, as initialization occurs in the constructor and can't fail.
2697     - The move functions have been deleted.
2698     - For auto-reset events, the `is_signaled()` function doesn't reset the event. (Use `ResetEvent()` instead.)
2699     - The `ResetEvent()` function returns the previous state of the event.
2700     - To create a manual reset event, use `wil::slim_event_manual_reset'.
2701     ~~~~
2702     wil::slim_event finished;
2703     std::thread doStuff([&finished] () {
2704         Sleep(10);
2705         finished.SetEvent();
2706     });
2707     finished.wait();
2708 
2709     std::shared_ptr<wil::slim_event> CreateSharedEvent(bool startSignaled)
2710     {
2711         return std::make_shared<wil::slim_event>(startSignaled);
2712     }
2713     ~~~~ */
2714     template <SlimEventType Type>
2715     class slim_event_t
2716     {
2717     public:
2718         slim_event_t() WI_NOEXCEPT = default;
2719 
2720         slim_event_t(bool isSignaled) WI_NOEXCEPT :
2721             m_isSignaled(isSignaled ? TRUE : FALSE)
2722         {
2723         }
2724 
2725         // Cannot change memory location.
2726         slim_event_t(const slim_event_t&) = delete;
2727         slim_event_t(slim_event_t&&) = delete;
2728         slim_event_t& operator=(const slim_event_t&) = delete;
2729         slim_event_t& operator=(slim_event_t&&) = delete;
2730 
2731         // Returns the previous state of the event.
2732         bool ResetEvent() WI_NOEXCEPT
2733         {
2734             return !!InterlockedExchange(&m_isSignaled, FALSE);
2735         }
2736 
2737         void SetEvent() WI_NOEXCEPT
2738         {
2739             // FYI: 'WakeByAddress*' invokes a full memory barrier.
2740             WriteRelease(&m_isSignaled, TRUE);
2741 
2742             #pragma warning(suppress:4127) // conditional expression is constant
2743             if (Type == SlimEventType::AutoReset)
2744             {
2745                 WakeByAddressSingle(&m_isSignaled);
2746             }
2747             else
2748             {
2749                 WakeByAddressAll(&m_isSignaled);
2750             }
2751         }
2752 
2753         // Checks if the event is currently signaled.
2754         // Note: Unlike Win32 auto-reset event objects, this will not reset the event.
2755         bool is_signaled() const WI_NOEXCEPT
2756         {
2757             return !!ReadAcquire(&m_isSignaled);
2758         }
2759 
2760         bool wait(DWORD timeoutMiliseconds) WI_NOEXCEPT
2761         {
2762             if (timeoutMiliseconds == 0)
2763             {
2764                 return TryAcquireEvent();
2765             }
2766             else if (timeoutMiliseconds == INFINITE)
2767             {
2768                 return wait();
2769             }
2770 
2771             UINT64 startTime;
2772             QueryUnbiasedInterruptTime(&startTime);
2773 
2774             UINT64 elapsedTimeMilliseconds = 0;
2775 
2776             while (!TryAcquireEvent())
2777             {
2778                 if (elapsedTimeMilliseconds >= timeoutMiliseconds)
2779                 {
2780                     return false;
2781                 }
2782 
2783                 DWORD newTimeout = static_cast<DWORD>(timeoutMiliseconds - elapsedTimeMilliseconds);
2784 
2785                 if (!WaitForSignal(newTimeout))
2786                 {
2787                     return false;
2788                 }
2789 
2790                 UINT64 currTime;
2791                 QueryUnbiasedInterruptTime(&currTime);
2792 
2793                 elapsedTimeMilliseconds = (currTime - startTime) / (10 * 1000);
2794             }
2795 
2796             return true;
2797         }
2798 
2799         bool wait() WI_NOEXCEPT
2800         {
2801             while (!TryAcquireEvent())
2802             {
2803                 if (!WaitForSignal(INFINITE))
2804                 {
2805                     return false;
2806                 }
2807             }
2808 
2809             return true;
2810         }
2811 
2812     private:
2813         bool TryAcquireEvent() WI_NOEXCEPT
2814         {
2815             #pragma warning(suppress:4127) // conditional expression is constant
2816             if (Type == SlimEventType::AutoReset)
2817             {
2818                 return ResetEvent();
2819             }
2820             else
2821             {
2822                 return is_signaled();
2823             }
2824         }
2825 
2826         bool WaitForSignal(DWORD timeoutMiliseconds) WI_NOEXCEPT
2827         {
2828             LONG falseValue = FALSE;
2829             BOOL waitResult = WaitOnAddress(&m_isSignaled, &falseValue, sizeof(m_isSignaled), timeoutMiliseconds);
2830             __FAIL_FAST_ASSERT__(waitResult || ::GetLastError() == ERROR_TIMEOUT);
2831             return !!waitResult;
2832         }
2833 
2834         LONG m_isSignaled = FALSE;
2835     };
2836 
2837     /** An event object that will atomically revert to an unsignaled state anytime a `wait()` call succeeds (i.e. returns true). */
2838     using slim_event_auto_reset = slim_event_t<SlimEventType::AutoReset>;
2839 
2840     /** An event object that once signaled remains that way forever, unless `ResetEvent()` is called. */
2841     using slim_event_manual_reset = slim_event_t<SlimEventType::ManualReset>;
2842 
2843     /** An alias for `wil::slim_event_auto_reset`. */
2844     using slim_event = slim_event_auto_reset;
2845 
2846 #endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
2847 
2848     typedef unique_any<HANDLE, decltype(&details::ReleaseMutex), details::ReleaseMutex, details::pointer_access_none> mutex_release_scope_exit;
2849 
2850     WI_NODISCARD inline mutex_release_scope_exit ReleaseMutex_scope_exit(_In_ HANDLE hMutex) WI_NOEXCEPT
2851     {
2852         __FAIL_FAST_ASSERT__(hMutex != nullptr);
2853         return mutex_release_scope_exit(hMutex);
2854     }
2855 
2856     // For efficiency, avoid using mutexes when an srwlock or condition variable will do.
2857     template <typename storage_t, typename err_policy = err_exception_policy>
2858     class mutex_t : public storage_t
2859     {
2860     public:
2861         // forward all base class constructors...
2862         template <typename... args_t>
2863         explicit mutex_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward<args_t>(args)...) {}
2864 
2865         // HRESULT or void error handling...
2866         typedef typename err_policy::result result;
2867 
2868         // Exception-based constructor to create a mutex (prefer unnamed (nullptr) for the name)
2869         mutex_t(_In_opt_ PCWSTR name)
2870         {
2871             static_assert(wistd::is_same<void, result>::value, "this constructor requires exceptions or fail fast; use the create method");
2872             create(name);
2873         }
2874 
2875         void ReleaseMutex() const WI_NOEXCEPT
2876         {
2877             details::ReleaseMutex(storage_t::get());
2878         }
2879 
2880         WI_NODISCARD mutex_release_scope_exit ReleaseMutex_scope_exit() const WI_NOEXCEPT
2881         {
2882             return wil::ReleaseMutex_scope_exit(storage_t::get());
2883         }
2884 
2885         WI_NODISCARD mutex_release_scope_exit acquire(_Out_opt_ DWORD *pStatus = nullptr, DWORD dwMilliseconds = INFINITE, BOOL bAlertable = FALSE)  const WI_NOEXCEPT
2886         {
2887             auto handle = storage_t::get();
2888             DWORD status = ::WaitForSingleObjectEx(handle, dwMilliseconds, bAlertable);
2889             assign_to_opt_param(pStatus, status);
2890             __FAIL_FAST_ASSERT__((status == WAIT_TIMEOUT) || (status == WAIT_OBJECT_0) || (status == WAIT_ABANDONED) || (bAlertable && (status == WAIT_IO_COMPLETION)));
2891             return mutex_release_scope_exit(((status == WAIT_OBJECT_0) || (status == WAIT_ABANDONED)) ? handle : nullptr);
2892         }
2893 
2894         // Tries to create a named mutex -- returns false if unable to do so (gle may still be inspected with return=false)
2895         bool try_create(_In_opt_ PCWSTR name, DWORD dwFlags = 0, DWORD desiredAccess = MUTEX_ALL_ACCESS, _In_opt_ PSECURITY_ATTRIBUTES pMutexAttributes = nullptr)
2896         {
2897             auto handle = ::CreateMutexExW(pMutexAttributes, name, dwFlags, desiredAccess);
2898             if (handle == nullptr)
2899             {
2900                 return false;
2901             }
2902             storage_t::reset(handle);
2903             return true;
2904         }
2905 
2906         // Returns HRESULT for unique_mutex_nothrow, void with exceptions for shared_mutex and unique_mutex
2907         result create(_In_opt_ PCWSTR name = nullptr, DWORD dwFlags = 0, DWORD desiredAccess = MUTEX_ALL_ACCESS, _In_opt_ PSECURITY_ATTRIBUTES pMutexAttributes = nullptr)
2908         {
2909             return err_policy::LastErrorIfFalse(try_create(name, dwFlags, desiredAccess, pMutexAttributes));
2910         }
2911 
2912         // Tries to open a named mutex -- returns false if unable to do so (gle may still be inspected with return=false)
2913         bool try_open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | MUTEX_MODIFY_STATE, bool inheritHandle = false)
2914         {
2915             auto handle = ::OpenMutexW(desiredAccess, inheritHandle, name);
2916             if (handle == nullptr)
2917             {
2918                 return false;
2919             }
2920             storage_t::reset(handle);
2921             return true;
2922         }
2923 
2924         // Returns HRESULT for unique_mutex_nothrow, void with exceptions for shared_mutex and unique_mutex
2925         result open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | MUTEX_MODIFY_STATE, bool inheritHandle = false)
2926         {
2927             return err_policy::LastErrorIfFalse(try_open(name, desiredAccess, inheritHandle));
2928         }
2929     };
2930 
2931     typedef unique_any_t<mutex_t<details::unique_storage<details::handle_resource_policy>, err_returncode_policy>>     unique_mutex_nothrow;
2932     typedef unique_any_t<mutex_t<details::unique_storage<details::handle_resource_policy>, err_failfast_policy>>       unique_mutex_failfast;
2933 #ifdef WIL_ENABLE_EXCEPTIONS
2934     typedef unique_any_t<mutex_t<details::unique_storage<details::handle_resource_policy>, err_exception_policy>>      unique_mutex;
2935 #endif
2936 
2937     typedef unique_any<HANDLE, decltype(&details::ReleaseSemaphore), details::ReleaseSemaphore, details::pointer_access_none> semaphore_release_scope_exit;
2938 
2939     WI_NODISCARD inline semaphore_release_scope_exit ReleaseSemaphore_scope_exit(_In_ HANDLE hSemaphore) WI_NOEXCEPT
2940     {
2941         __FAIL_FAST_ASSERT__(hSemaphore != nullptr);
2942         return semaphore_release_scope_exit(hSemaphore);
2943     }
2944 
2945     template <typename storage_t, typename err_policy = err_exception_policy>
2946     class semaphore_t : public storage_t
2947     {
2948     public:
2949         // forward all base class constructors...
2950         template <typename... args_t>
2951         explicit semaphore_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward<args_t>(args)...) {}
2952 
2953         // HRESULT or void error handling...
2954         typedef typename err_policy::result result;
2955 
2956         // Note that for custom-constructors the type given the constructor has to match exactly as not all implicit conversions will make it through the
2957         // 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).
2958         explicit semaphore_t(int initialCount, int maximumCount, _In_opt_ PCWSTR name = nullptr, DWORD desiredAccess = SEMAPHORE_ALL_ACCESS, _In_opt_ PSECURITY_ATTRIBUTES pSemaphoreAttributes = nullptr)
2959         {
2960             static_assert(wistd::is_same<void, result>::value, "this constructor requires exceptions or fail fast; use the create method");
2961             create(initialCount, maximumCount, name, desiredAccess, pSemaphoreAttributes);
2962         }
2963 
2964         void ReleaseSemaphore(long nReleaseCount = 1, _In_opt_ long *pnPreviousCount = nullptr) WI_NOEXCEPT
2965         {
2966             long nPreviousCount = 0;
2967             __FAIL_FAST_ASSERT__(::ReleaseSemaphore(storage_t::get(), nReleaseCount, &nPreviousCount));
2968             assign_to_opt_param(pnPreviousCount, nPreviousCount);
2969         }
2970 
2971         WI_NODISCARD semaphore_release_scope_exit ReleaseSemaphore_scope_exit() WI_NOEXCEPT
2972         {
2973             return wil::ReleaseSemaphore_scope_exit(storage_t::get());
2974         }
2975 
2976         WI_NODISCARD semaphore_release_scope_exit acquire(_Out_opt_ DWORD *pStatus = nullptr, DWORD dwMilliseconds = INFINITE, BOOL bAlertable = FALSE) WI_NOEXCEPT
2977         {
2978             auto handle = storage_t::get();
2979             DWORD status = ::WaitForSingleObjectEx(handle, dwMilliseconds, bAlertable);
2980             assign_to_opt_param(pStatus, status);
2981             __FAIL_FAST_ASSERT__((status == WAIT_TIMEOUT) || (status == WAIT_OBJECT_0) || (bAlertable && (status == WAIT_IO_COMPLETION)));
2982             return semaphore_release_scope_exit((status == WAIT_OBJECT_0) ? handle : nullptr);
2983         }
2984 
2985         // Tries to create a named event -- returns false if unable to do so (gle may still be inspected with return=false)
2986         bool try_create(LONG lInitialCount, LONG lMaximumCount, _In_opt_ PCWSTR name, DWORD desiredAccess = SEMAPHORE_ALL_ACCESS, _In_opt_ PSECURITY_ATTRIBUTES pSemaphoreAttributes = nullptr)
2987         {
2988             auto handle = ::CreateSemaphoreExW(pSemaphoreAttributes, lInitialCount, lMaximumCount, name, 0, desiredAccess);
2989             if (handle == nullptr)
2990             {
2991                 return false;
2992             }
2993             storage_t::reset(handle);
2994             return true;
2995         }
2996 
2997         // Returns HRESULT for unique_semaphore_nothrow, void with exceptions for shared_event and unique_event
2998         result create(LONG lInitialCount, LONG lMaximumCount, _In_opt_ PCWSTR name = nullptr, DWORD desiredAccess = SEMAPHORE_ALL_ACCESS, _In_opt_ PSECURITY_ATTRIBUTES pSemaphoreAttributes = nullptr)
2999         {
3000             return err_policy::LastErrorIfFalse(try_create(lInitialCount, lMaximumCount, name, desiredAccess, pSemaphoreAttributes));
3001         }
3002 
3003         // Tries to open the named semaphore -- returns false if unable to do so (gle may still be inspected with return=false)
3004         bool try_open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | SEMAPHORE_MODIFY_STATE, bool inheritHandle = false)
3005         {
3006             auto handle = ::OpenSemaphoreW(desiredAccess, inheritHandle, name);
3007             if (handle == nullptr)
3008             {
3009                 return false;
3010             }
3011             storage_t::reset(handle);
3012             return true;
3013         }
3014 
3015         // Returns HRESULT for unique_semaphore_nothrow, void with exceptions for shared_semaphore and unique_semaphore
3016         result open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | SEMAPHORE_MODIFY_STATE, bool inheritHandle = false)
3017         {
3018             return err_policy::LastErrorIfFalse(try_open(name, desiredAccess, inheritHandle));
3019         }
3020     };
3021 
3022     typedef unique_any_t<semaphore_t<details::unique_storage<details::handle_resource_policy>, err_returncode_policy>>  unique_semaphore_nothrow;
3023     typedef unique_any_t<semaphore_t<details::unique_storage<details::handle_resource_policy>, err_failfast_policy>>    unique_semaphore_failfast;
3024 #ifdef WIL_ENABLE_EXCEPTIONS
3025     typedef unique_any_t<semaphore_t<details::unique_storage<details::handle_resource_policy>, err_exception_policy>>   unique_semaphore;
3026 #endif
3027 
3028     typedef unique_any<SRWLOCK *, decltype(&::ReleaseSRWLockExclusive), ::ReleaseSRWLockExclusive, details::pointer_access_noaddress> rwlock_release_exclusive_scope_exit;
3029     typedef unique_any<SRWLOCK *, decltype(&::ReleaseSRWLockShared), ::ReleaseSRWLockShared, details::pointer_access_noaddress> rwlock_release_shared_scope_exit;
3030 
3031     WI_NODISCARD inline rwlock_release_exclusive_scope_exit AcquireSRWLockExclusive(_Inout_ SRWLOCK *plock) WI_NOEXCEPT
3032     {
3033         ::AcquireSRWLockExclusive(plock);
3034         return rwlock_release_exclusive_scope_exit(plock);
3035     }
3036 
3037     WI_NODISCARD inline rwlock_release_shared_scope_exit AcquireSRWLockShared(_Inout_ SRWLOCK *plock) WI_NOEXCEPT
3038     {
3039         ::AcquireSRWLockShared(plock);
3040         return rwlock_release_shared_scope_exit(plock);
3041     }
3042 
3043     WI_NODISCARD inline rwlock_release_exclusive_scope_exit TryAcquireSRWLockExclusive(_Inout_ SRWLOCK *plock) WI_NOEXCEPT
3044     {
3045         return rwlock_release_exclusive_scope_exit(::TryAcquireSRWLockExclusive(plock) ? plock : nullptr);
3046     }
3047 
3048     WI_NODISCARD inline rwlock_release_shared_scope_exit TryAcquireSRWLockShared(_Inout_ SRWLOCK *plock) WI_NOEXCEPT
3049     {
3050         return rwlock_release_shared_scope_exit(::TryAcquireSRWLockShared(plock) ? plock : nullptr);
3051     }
3052 
3053     class srwlock
3054     {
3055     public:
3056         srwlock(const srwlock&) = delete;
3057         srwlock(srwlock&&) = delete;
3058         srwlock& operator=(const srwlock&) = delete;
3059         srwlock& operator=(srwlock&&) = delete;
3060 
3061         srwlock() = default;
3062 
3063         WI_NODISCARD rwlock_release_exclusive_scope_exit lock_exclusive() WI_NOEXCEPT
3064         {
3065             return wil::AcquireSRWLockExclusive(&m_lock);
3066         }
3067 
3068         WI_NODISCARD rwlock_release_exclusive_scope_exit try_lock_exclusive() WI_NOEXCEPT
3069         {
3070             return wil::TryAcquireSRWLockExclusive(&m_lock);
3071         }
3072 
3073         WI_NODISCARD rwlock_release_shared_scope_exit lock_shared() WI_NOEXCEPT
3074         {
3075             return wil::AcquireSRWLockShared(&m_lock);
3076         }
3077 
3078         WI_NODISCARD rwlock_release_shared_scope_exit try_lock_shared() WI_NOEXCEPT
3079         {
3080             return wil::TryAcquireSRWLockShared(&m_lock);
3081         }
3082 
3083     private:
3084         SRWLOCK m_lock = SRWLOCK_INIT;
3085     };
3086 
3087     typedef unique_any<CRITICAL_SECTION *, decltype(&::LeaveCriticalSection), ::LeaveCriticalSection, details::pointer_access_noaddress> cs_leave_scope_exit;
3088 
3089     WI_NODISCARD inline cs_leave_scope_exit EnterCriticalSection(_Inout_ CRITICAL_SECTION *pcs) WI_NOEXCEPT
3090     {
3091         ::EnterCriticalSection(pcs);
3092         return cs_leave_scope_exit(pcs);
3093     }
3094 
3095     WI_NODISCARD inline cs_leave_scope_exit TryEnterCriticalSection(_Inout_ CRITICAL_SECTION *pcs) WI_NOEXCEPT
3096     {
3097         return cs_leave_scope_exit(::TryEnterCriticalSection(pcs) ? pcs : nullptr);
3098     }
3099 
3100     // Critical sections are worse than srwlocks in performance and memory usage (their only unique attribute
3101     // being recursive acquisition). Prefer srwlocks over critical sections when you don't need recursive acquisition.
3102     class critical_section
3103     {
3104     public:
3105         critical_section(const critical_section&) = delete;
3106         critical_section(critical_section&&) = delete;
3107         critical_section& operator=(const critical_section&) = delete;
3108         critical_section& operator=(critical_section&&) = delete;
3109 
3110         critical_section(ULONG spincount = 0) WI_NOEXCEPT
3111         {
3112             // Initialization will not fail without invalid params...
3113             ::InitializeCriticalSectionEx(&m_cs, spincount, 0);
3114         }
3115 
3116         ~critical_section() WI_NOEXCEPT
3117         {
3118             ::DeleteCriticalSection(&m_cs);
3119         }
3120 
3121         WI_NODISCARD cs_leave_scope_exit lock() WI_NOEXCEPT
3122         {
3123             return wil::EnterCriticalSection(&m_cs);
3124         }
3125 
3126         WI_NODISCARD cs_leave_scope_exit try_lock() WI_NOEXCEPT
3127         {
3128             return wil::TryEnterCriticalSection(&m_cs);
3129         }
3130 
3131     private:
3132         CRITICAL_SECTION m_cs;
3133     };
3134 
3135     class condition_variable
3136     {
3137     public:
3138         condition_variable(const condition_variable&) = delete;
3139         condition_variable(condition_variable&&) = delete;
3140         condition_variable& operator=(const condition_variable&) = delete;
3141         condition_variable& operator=(condition_variable&&) = delete;
3142 
3143         condition_variable() = default;
3144 
3145         void notify_one() WI_NOEXCEPT
3146         {
3147             ::WakeConditionVariable(&m_cv);
3148         }
3149 
3150         void notify_all() WI_NOEXCEPT
3151         {
3152             ::WakeAllConditionVariable(&m_cv);
3153         }
3154 
3155         void wait(const cs_leave_scope_exit& lock) WI_NOEXCEPT
3156         {
3157             wait_for(lock, INFINITE);
3158         }
3159 
3160         void wait(const rwlock_release_exclusive_scope_exit& lock) WI_NOEXCEPT
3161         {
3162             wait_for(lock, INFINITE);
3163         }
3164 
3165         void wait(const rwlock_release_shared_scope_exit& lock) WI_NOEXCEPT
3166         {
3167             wait_for(lock, INFINITE);
3168         }
3169 
3170         bool wait_for(const cs_leave_scope_exit& lock, DWORD timeoutMs) WI_NOEXCEPT
3171         {
3172             bool result = !!::SleepConditionVariableCS(&m_cv, lock.get(), timeoutMs);
3173             __FAIL_FAST_ASSERT__(result || ::GetLastError() == ERROR_TIMEOUT);
3174             return result;
3175         }
3176 
3177         bool wait_for(const rwlock_release_exclusive_scope_exit& lock, DWORD timeoutMs) WI_NOEXCEPT
3178         {
3179             bool result = !!::SleepConditionVariableSRW(&m_cv, lock.get(), timeoutMs, 0);
3180             __FAIL_FAST_ASSERT__(result || ::GetLastError() == ERROR_TIMEOUT);
3181             return result;
3182         }
3183 
3184         bool wait_for(const rwlock_release_shared_scope_exit& lock, DWORD timeoutMs) WI_NOEXCEPT
3185         {
3186             bool result = !!::SleepConditionVariableSRW(&m_cv, lock.get(), timeoutMs, CONDITION_VARIABLE_LOCKMODE_SHARED);
3187             __FAIL_FAST_ASSERT__(result || ::GetLastError() == ERROR_TIMEOUT);
3188             return result;
3189         }
3190 
3191     private:
3192         CONDITION_VARIABLE m_cv = CONDITION_VARIABLE_INIT;
3193     };
3194 
3195     /// @cond
3196     namespace details
3197     {
3198         template<typename string_class> struct string_allocator
3199         {
3200             static void* allocate(size_t /*size*/) WI_NOEXCEPT
3201             {
3202                 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.");
3203                 return nullptr;
3204             }
3205         };
3206     }
3207     /// @endcond
3208 
3209     // This string helper does not support the ansi wil string helpers
3210     template<typename string_type>
3211     PCWSTR string_get_not_null(const string_type& string)
3212     {
3213         return string ? string.get() : L"";
3214     }
3215 
3216 #ifndef MAKE_UNIQUE_STRING_MAX_CCH
3217 #define MAKE_UNIQUE_STRING_MAX_CCH     2147483647  // max buffer size, in characters, that we support (same as INT_MAX)
3218 #endif
3219 
3220     /** Copies a string (up to the given length) into memory allocated with a specified allocator returning null on failure.
3221     Use `wil::make_unique_string_nothrow()` for string resources returned from APIs that must satisfy a memory allocation contract
3222     that requires use of a specific allocator and free function (CoTaskMemAlloc/CoTaskMemFree, LocalAlloc/LocalFree, GlobalAlloc/GlobalFree, etc.).
3223     ~~~
3224     auto str = wil::make_unique_string_nothrow<wil::unique_cotaskmem_string>(L"a string of words", 8);
3225     RETURN_IF_NULL_ALLOC(str);
3226     std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string"
3227 
3228     auto str = wil::make_unique_string_nothrow<unique_hlocal_string>(L"a string");
3229     RETURN_IF_NULL_ALLOC(str);
3230     std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string"
3231 
3232     NOTE: If source is not null terminated, then length MUST be equal to or less than the size
3233           of the buffer pointed to by source.
3234     ~~~
3235     */
3236     template<typename string_type> string_type make_unique_string_nothrow(
3237         _When_((source != nullptr) && length != static_cast<size_t>(-1), _In_reads_(length))
3238         _When_((source != nullptr) && length == static_cast<size_t>(-1), _In_z_)
3239         const wchar_t* source, size_t length = static_cast<size_t>(-1)) WI_NOEXCEPT
3240     {
3241         // guard against invalid parameters (null source with -1 length)
3242         FAIL_FAST_IF(!source && (length == static_cast<size_t>(-1)));
3243 
3244         // When the source string exists, calculate the number of characters to copy up to either
3245         // 1) the length that is given
3246         // 2) the length of the source string. When the source does not exist, use the given length
3247         //    for calculating both the size of allocated buffer and the number of characters to copy.
3248         size_t lengthToCopy = length;
3249         if (source)
3250         {
3251             size_t maxLength = length < MAKE_UNIQUE_STRING_MAX_CCH ? length : MAKE_UNIQUE_STRING_MAX_CCH;
3252             PCWSTR endOfSource = source;
3253             while (maxLength && (*endOfSource != L'\0'))
3254             {
3255                 endOfSource++;
3256                 maxLength--;
3257             }
3258             lengthToCopy = endOfSource - source;
3259         }
3260 
3261         if (length == static_cast<size_t>(-1))
3262         {
3263             length = lengthToCopy;
3264         }
3265         const size_t allocatedBytes = (length + 1) * sizeof(*source);
3266         auto result = static_cast<PWSTR>(details::string_allocator<string_type>::allocate(allocatedBytes));
3267 
3268         if (result)
3269         {
3270             if (source)
3271             {
3272                 const size_t bytesToCopy = lengthToCopy * sizeof(*source);
3273                 memcpy_s(result, allocatedBytes, source, bytesToCopy);
3274                 result[lengthToCopy] = L'\0'; // ensure the copied string is zero terminated
3275             }
3276             else
3277             {
3278                 *result = L'\0'; // ensure null terminated in the "reserve space" use case.
3279             }
3280             result[length] = L'\0'; // ensure the final char of the buffer is zero terminated
3281         }
3282         return string_type(result);
3283     }
3284 #ifndef WIL_NO_ANSI_STRINGS
3285     template<typename string_type> string_type make_unique_ansistring_nothrow(
3286         _When_((source != nullptr) && length != static_cast<size_t>(-1), _In_reads_(length))
3287         _When_((source != nullptr) && length == static_cast<size_t>(-1), _In_z_)
3288         PCSTR source, size_t length = static_cast<size_t>(-1)) WI_NOEXCEPT
3289     {
3290         // guard against invalid parameters (null source with -1 length)
3291         FAIL_FAST_IF(!source && (length == static_cast<size_t>(-1)));
3292 
3293         if (length == static_cast<size_t>(-1))
3294         {
3295             length = strlen(source);
3296         }
3297         const size_t cb = (length + 1) * sizeof(*source);
3298         auto result = static_cast<PSTR>(details::string_allocator<string_type>::allocate(cb));
3299         if (result)
3300         {
3301             if (source)
3302             {
3303                 memcpy_s(result, cb, source, cb - sizeof(*source));
3304             }
3305             else
3306             {
3307                 *result = '\0'; // ensure null terminated in the "reserve space" use case.
3308             }
3309             result[length] = '\0'; // ensure zero terminated
3310         }
3311         return string_type(result);
3312     }
3313 #endif // WIL_NO_ANSI_STRINGS
3314 
3315     /** Copies a given string into memory allocated with a specified allocator that will fail fast on failure.
3316     The use of variadic templates parameters supports the 2 forms of make_unique_string, see those for more details.
3317     */
3318     template<typename string_type> string_type make_unique_string_failfast(
3319         _When_((source != nullptr) && length != static_cast<size_t>(-1), _In_reads_(length))
3320         _When_((source != nullptr) && length == static_cast<size_t>(-1), _In_z_)
3321         PCWSTR source, size_t length = static_cast<size_t>(-1)) WI_NOEXCEPT
3322     {
3323         auto result(make_unique_string_nothrow<string_type>(source, length));
3324         FAIL_FAST_IF_NULL_ALLOC(result);
3325         return result;
3326     }
3327 
3328 #ifndef WIL_NO_ANSI_STRINGS
3329     template<typename string_type> string_type make_unique_ansistring_failfast(
3330         _When_((source != nullptr) && length != static_cast<size_t>(-1), _In_reads_(length))
3331         _When_((source != nullptr) && length == static_cast<size_t>(-1), _In_z_)
3332         PCSTR source, size_t length = static_cast<size_t>(-1)) WI_NOEXCEPT
3333     {
3334         auto result(make_unique_ansistring_nothrow<string_type>(source, length));
3335         FAIL_FAST_IF_NULL_ALLOC(result);
3336         return result;
3337     }
3338 #endif // WIL_NO_ANSI_STRINGS
3339 
3340 #ifdef WIL_ENABLE_EXCEPTIONS
3341     /** Copies a given string into memory allocated with a specified allocator that will throw on failure.
3342     The use of variadic templates parameters supports the 2 forms of make_unique_string, see those for more details.
3343     */
3344     template<typename string_type> string_type make_unique_string(
3345         _When_((source != nullptr) && length != static_cast<size_t>(-1), _In_reads_(length))
3346         _When_((source != nullptr) && length == static_cast<size_t>(-1), _In_z_)
3347         PCWSTR source, size_t length = static_cast<size_t>(-1))
3348     {
3349         auto result(make_unique_string_nothrow<string_type>(source, length));
3350         THROW_IF_NULL_ALLOC(result);
3351         return result;
3352     }
3353 #ifndef WIL_NO_ANSI_STRINGS
3354     template<typename string_type> string_type make_unique_ansistring(
3355         _When_((source != nullptr) && length != static_cast<size_t>(-1), _In_reads_(length))
3356         _When_((source != nullptr) && length == static_cast<size_t>(-1), _In_z_)
3357         PCSTR source, size_t length = static_cast<size_t>(-1))
3358     {
3359         auto result(make_unique_ansistring_nothrow<string_type>(source, length));
3360         THROW_IF_NULL_ALLOC(result);
3361         return result;
3362     }
3363 #endif // WIL_NO_ANSI_STRINGS
3364 #endif // WIL_ENABLE_EXCEPTIONS
3365 
3366     /// @cond
3367     namespace details
3368     {
3369         // string_maker abstracts creating a string for common string types. This form supports the
3370         // wil::unique_xxx_string types. Specializations of other types like HSTRING and std::wstring
3371         // are found in wil\winrt.h and wil\stl.h.
3372         // This design supports creating the string in a single step or using two phase construction.
3373 
3374         template<typename string_type> struct string_maker
3375         {
3376             HRESULT make(
3377                 _When_((source != nullptr) && length != static_cast<size_t>(-1), _In_reads_(length))
3378                 _When_((source != nullptr) && length == static_cast<size_t>(-1), _In_z_)
3379                 const wchar_t* source,
3380                 size_t length)
3381             {
3382                 m_value = make_unique_string_nothrow<string_type>(source, length);
3383                 return m_value ? S_OK : E_OUTOFMEMORY;
3384             }
3385 
3386             wchar_t* buffer() { WI_ASSERT(m_value.get());  return m_value.get(); }
3387 
3388             string_type release() { return wistd::move(m_value); }
3389 
3390             // Utility to abstract access to the null terminated m_value of all string types.
3391             static PCWSTR get(const string_type& value) { return value.get(); }
3392 
3393         private:
3394             string_type m_value; // a wil::unique_xxx_string type.
3395         };
3396 
3397         struct SecureZeroData
3398         {
3399             void *pointer;
3400             size_t sizeBytes;
3401             SecureZeroData(void *pointer_, size_t sizeBytes_ = 0) WI_NOEXCEPT { pointer = pointer_; sizeBytes = sizeBytes_; }
3402             operator void *() const WI_NOEXCEPT { return pointer; }
3403             static void Close(SecureZeroData data) WI_NOEXCEPT { ::SecureZeroMemory(data.pointer, data.sizeBytes); }
3404         };
3405     }
3406     /// @endcond
3407 
3408     typedef unique_any<void*, decltype(&details::SecureZeroData::Close), details::SecureZeroData::Close, details::pointer_access_all, details::SecureZeroData> secure_zero_memory_scope_exit;
3409 
3410     WI_NODISCARD inline secure_zero_memory_scope_exit SecureZeroMemory_scope_exit(_In_reads_bytes_(sizeBytes) void* pSource, size_t sizeBytes)
3411     {
3412         return secure_zero_memory_scope_exit(details::SecureZeroData(pSource, sizeBytes));
3413     }
3414 
3415     WI_NODISCARD inline secure_zero_memory_scope_exit SecureZeroMemory_scope_exit(_In_ PWSTR initializedString)
3416     {
3417         return SecureZeroMemory_scope_exit(static_cast<void*>(initializedString), wcslen(initializedString) * sizeof(initializedString[0]));
3418     }
3419 
3420     /// @cond
3421     namespace details
3422     {
3423         inline void __stdcall FreeProcessHeap(_Pre_opt_valid_ _Frees_ptr_opt_ void* p)
3424         {
3425             ::HeapFree(::GetProcessHeap(), 0, p);
3426         }
3427     }
3428     /// @endcond
3429 
3430     struct process_heap_deleter
3431     {
3432         template <typename T>
3433         void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const
3434         {
3435             details::FreeProcessHeap(p);
3436         }
3437     };
3438 
3439     struct virtualalloc_deleter
3440     {
3441         template<typename T>
3442         void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const
3443         {
3444             ::VirtualFree(p, 0, MEM_RELEASE);
3445         }
3446     };
3447 
3448     struct mapview_deleter
3449     {
3450         template<typename T>
3451         void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const
3452         {
3453             ::UnmapViewOfFile(p);
3454         }
3455     };
3456 
3457     template <typename T = void>
3458     using unique_process_heap_ptr = wistd::unique_ptr<T, process_heap_deleter>;
3459 
3460     typedef unique_any<PWSTR, decltype(&details::FreeProcessHeap), details::FreeProcessHeap> unique_process_heap_string;
3461 
3462     /// @cond
3463     namespace details
3464     {
3465         template<> struct string_allocator<unique_process_heap_string>
3466         {
3467             static _Ret_opt_bytecap_(size) void* allocate(size_t size) WI_NOEXCEPT
3468             {
3469                 return ::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, size);
3470             }
3471         };
3472     }
3473     /// @endcond
3474 
3475     /** Manages a typed pointer allocated with VirtualAlloc
3476     A specialization of wistd::unique_ptr<> that frees via VirtualFree(p, 0, MEM_RELEASE).
3477     */
3478     template<typename T = void>
3479     using unique_virtualalloc_ptr = wistd::unique_ptr<T, virtualalloc_deleter>;
3480 
3481     /** Manages a typed pointer allocated with MapViewOfFile
3482     A specialization of wistd::unique_ptr<> that frees via UnmapViewOfFile(p).
3483     */
3484     template<typename T>
3485     using unique_mapview_ptr = wistd::unique_ptr<T, mapview_deleter>;
3486 
3487 #endif // __WIL_WINBASE_
3488 
3489 #if defined(__WIL_WINBASE_) && defined(__NOTHROW_T_DEFINED) && !defined(__WIL_WINBASE_NOTHROW_T_DEFINED)
3490 #define __WIL_WINBASE_NOTHROW_T_DEFINED
3491     // unique_event_watcher, unique_event_watcher_nothrow, unique_event_watcher_failfast
3492     //
3493     // Clients must include <new> or <new.h> to enable use of this class as it uses new(std::nothrow).
3494     // This is to avoid the dependency on those headers that some clients can't tolerate.
3495     //
3496     // These classes makes it easy to execute a provided function when an event
3497     // is signaled. It will create the event handle for you, take ownership of one
3498     // or duplicate a handle provided. It supports the ability to signal the
3499     // event using SetEvent() and SetEvent_scope_exit();
3500     //
3501     // This can be used to support producer-consumer pattern
3502     // where a producer updates some state then signals the event when done.
3503     // The consumer will consume that state in the callback provided to unique_event_watcher.
3504     //
3505     // Note, multiple signals may coalesce into a single callback.
3506     //
3507     // Example use of throwing version:
3508     // auto globalStateWatcher = wil::make_event_watcher([]
3509     //     {
3510     //         currentState = GetGlobalState();
3511     //     });
3512     //
3513     // UpdateGlobalState(value);
3514     // globalStateWatcher.SetEvent(); // signal observers so they can update
3515     //
3516     // Example use of non-throwing version:
3517     // auto globalStateWatcher = wil::make_event_watcher_nothrow([]
3518     //     {
3519     //         currentState = GetGlobalState();
3520     //     });
3521     // RETURN_IF_NULL_ALLOC(globalStateWatcher);
3522     //
3523     // UpdateGlobalState(value);
3524     // globalStateWatcher.SetEvent(); // signal observers so they can update
3525 
3526     /// @cond
3527     namespace details
3528     {
3529         struct event_watcher_state
3530         {
3531             event_watcher_state(unique_event_nothrow &&eventHandle, wistd::function<void()> &&callback)
3532                 : m_callback(wistd::move(callback)), m_event(wistd::move(eventHandle))
3533             {
3534             }
3535             wistd::function<void()> m_callback;
3536             unique_event_nothrow m_event;
3537             // The thread pool must be last to ensure that the other members are valid
3538             // when it is destructed as it will reference them.
3539             unique_threadpool_wait m_threadPoolWait;
3540         };
3541 
3542         inline void delete_event_watcher_state(_In_opt_ event_watcher_state *watcherStorage) { delete watcherStorage; }
3543 
3544         typedef resource_policy<event_watcher_state *, decltype(&delete_event_watcher_state),
3545             delete_event_watcher_state, details::pointer_access_none> event_watcher_state_resource_policy;
3546     }
3547     /// @endcond
3548 
3549     template <typename storage_t, typename err_policy = err_exception_policy>
3550     class event_watcher_t : public storage_t
3551     {
3552     public:
3553         // forward all base class constructors...
3554         template <typename... args_t>
3555         explicit event_watcher_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward<args_t>(args)...) {}
3556 
3557         // HRESULT or void error handling...
3558         typedef typename err_policy::result result;
3559 
3560         // Exception-based constructors
3561         template <typename err_policy>
3562         event_watcher_t(unique_any_t<event_t<details::unique_storage<details::handle_resource_policy>, err_policy>> &&eventHandle, wistd::function<void()> &&callback)
3563         {
3564             static_assert(wistd::is_same<void, result>::value, "this constructor requires exceptions or fail fast; use the create method");
3565             create(wistd::move(eventHandle), wistd::move(callback));
3566         }
3567 
3568         event_watcher_t(_In_ HANDLE eventHandle, wistd::function<void()> &&callback)
3569         {
3570             static_assert(wistd::is_same<void, result>::value, "this constructor requires exceptions or fail fast; use the create method");
3571             create(eventHandle, wistd::move(callback));
3572         }
3573 
3574         event_watcher_t(wistd::function<void()> &&callback)
3575         {
3576             static_assert(wistd::is_same<void, result>::value, "this constructor requires exceptions or fail fast; use the create method");
3577             create(wistd::move(callback));
3578         }
3579 
3580         template <typename event_err_policy>
3581         result create(unique_any_t<event_t<details::unique_storage<details::handle_resource_policy>, event_err_policy>> &&eventHandle,
3582             wistd::function<void()> &&callback)
3583         {
3584             return err_policy::HResult(create_take_hevent_ownership(eventHandle.release(), wistd::move(callback)));
3585         }
3586 
3587         // Creates the event that you will be watching.
3588         result create(wistd::function<void()> &&callback)
3589         {
3590             unique_event_nothrow eventHandle;
3591             HRESULT hr = eventHandle.create(EventOptions::ManualReset); // auto-reset is supported too.
3592             if (FAILED(hr))
3593             {
3594                 return err_policy::HResult(hr);
3595             }
3596             return err_policy::HResult(create_take_hevent_ownership(eventHandle.release(), wistd::move(callback)));
3597         }
3598 
3599         // Input is an event handler that is duplicated into this class.
3600         result create(_In_ HANDLE eventHandle, wistd::function<void()> &&callback)
3601         {
3602             unique_event_nothrow ownedHandle;
3603             if (!DuplicateHandle(GetCurrentProcess(), eventHandle, GetCurrentProcess(), &ownedHandle, 0, FALSE, DUPLICATE_SAME_ACCESS))
3604             {
3605                 return err_policy::LastError();
3606             }
3607             return err_policy::HResult(create_take_hevent_ownership(ownedHandle.release(), wistd::move(callback)));
3608         }
3609 
3610         // Provide access to the inner event and the very common SetEvent() method on it.
3611         unique_event_nothrow const& get_event() const WI_NOEXCEPT { return storage_t::get()->m_event; }
3612         void SetEvent() const WI_NOEXCEPT { storage_t::get()->m_event.SetEvent(); }
3613 
3614     private:
3615 
3616         // 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).
3617         static void CALLBACK wait_callback(PTP_CALLBACK_INSTANCE, void *context, TP_WAIT *pThreadPoolWait, TP_WAIT_RESULT)
3618         {
3619             auto pThis = static_cast<details::event_watcher_state *>(context);
3620             // Manual events must be re-set to avoid missing the last notification.
3621             pThis->m_event.ResetEvent();
3622             // Call the client before re-arming to ensure that multiple callbacks don't
3623             // run concurrently.
3624             pThis->m_callback();
3625             SetThreadpoolWait(pThreadPoolWait, pThis->m_event.get(), nullptr); // valid params ensure success
3626         }
3627 
3628         // To avoid template expansion (if unique_event/unique_event_nothrow forms were used) this base
3629         // create function takes a raw handle and assumes its ownership, even on failure.
3630         HRESULT create_take_hevent_ownership(_In_ HANDLE rawHandleOwnershipTaken, wistd::function<void()> &&callback)
3631         {
3632             __FAIL_FAST_ASSERT__(rawHandleOwnershipTaken != nullptr); // invalid parameter
3633             unique_event_nothrow eventHandle(rawHandleOwnershipTaken);
3634             wistd::unique_ptr<details::event_watcher_state> watcherState(new(std::nothrow) details::event_watcher_state(wistd::move(eventHandle), wistd::move(callback)));
3635             RETURN_IF_NULL_ALLOC(watcherState);
3636 
3637             watcherState->m_threadPoolWait.reset(CreateThreadpoolWait(wait_callback, watcherState.get(), nullptr));
3638             RETURN_LAST_ERROR_IF(!watcherState->m_threadPoolWait);
3639             storage_t::reset(watcherState.release()); // no more failures after this, pass ownership
3640             SetThreadpoolWait(storage_t::get()->m_threadPoolWait.get(), storage_t::get()->m_event.get(), nullptr);
3641             return S_OK;
3642         }
3643     };
3644 
3645     typedef unique_any_t<event_watcher_t<details::unique_storage<details::event_watcher_state_resource_policy>, err_returncode_policy>> unique_event_watcher_nothrow;
3646     typedef unique_any_t<event_watcher_t<details::unique_storage<details::event_watcher_state_resource_policy>, err_failfast_policy>> unique_event_watcher_failfast;
3647 
3648     template <typename err_policy>
3649     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
3650     {
3651         unique_event_watcher_nothrow watcher;
3652         watcher.create(wistd::move(eventHandle), wistd::move(callback));
3653         return watcher; // caller must test for success using if (watcher)
3654     }
3655 
3656     inline unique_event_watcher_nothrow make_event_watcher_nothrow(_In_ HANDLE eventHandle, wistd::function<void()> &&callback) WI_NOEXCEPT
3657     {
3658         unique_event_watcher_nothrow watcher;
3659         watcher.create(eventHandle, wistd::move(callback));
3660         return watcher; // caller must test for success using if (watcher)
3661     }
3662 
3663     inline unique_event_watcher_nothrow make_event_watcher_nothrow(wistd::function<void()> &&callback) WI_NOEXCEPT
3664     {
3665         unique_event_watcher_nothrow watcher;
3666         watcher.create(wistd::move(callback));
3667         return watcher; // caller must test for success using if (watcher)
3668     }
3669 
3670     template <typename err_policy>
3671     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)
3672     {
3673         return unique_event_watcher_failfast(wistd::move(eventHandle), wistd::move(callback));
3674     }
3675 
3676     inline unique_event_watcher_failfast make_event_watcher_failfast(_In_ HANDLE eventHandle, wistd::function<void()> &&callback)
3677     {
3678         return unique_event_watcher_failfast(eventHandle, wistd::move(callback));
3679     }
3680 
3681     inline unique_event_watcher_failfast make_event_watcher_failfast(wistd::function<void()> &&callback)
3682     {
3683         return unique_event_watcher_failfast(wistd::move(callback));
3684     }
3685 
3686 #ifdef WIL_ENABLE_EXCEPTIONS
3687     typedef unique_any_t<event_watcher_t<details::unique_storage<details::event_watcher_state_resource_policy>, err_exception_policy>> unique_event_watcher;
3688 
3689     template <typename err_policy>
3690     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)
3691     {
3692         return unique_event_watcher(wistd::move(eventHandle), wistd::move(callback));
3693     }
3694 
3695     inline unique_event_watcher make_event_watcher(_In_ HANDLE eventHandle, wistd::function<void()> &&callback)
3696     {
3697         return unique_event_watcher(eventHandle, wistd::move(callback));
3698     }
3699 
3700     inline unique_event_watcher make_event_watcher(wistd::function<void()> &&callback)
3701     {
3702         return unique_event_watcher(wistd::move(callback));
3703     }
3704 #endif // WIL_ENABLE_EXCEPTIONS
3705 
3706 #endif // __WIL_WINBASE_NOTHROW_T_DEFINED
3707 
3708 #if defined(__WIL_WINBASE_) && !defined(__WIL_WINBASE_STL) && defined(WIL_RESOURCE_STL)
3709 #define __WIL_WINBASE_STL
3710     typedef shared_any_t<event_t<details::shared_storage<unique_event>>> shared_event;
3711     typedef shared_any_t<mutex_t<details::shared_storage<unique_mutex>>> shared_mutex;
3712     typedef shared_any_t<semaphore_t<details::shared_storage<unique_semaphore>>> shared_semaphore;
3713     typedef shared_any<unique_hfile> shared_hfile;
3714     typedef shared_any<unique_handle> shared_handle;
3715     typedef shared_any<unique_hfind> shared_hfind;
3716     typedef shared_any<unique_hmodule> shared_hmodule;
3717 
3718 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
3719     typedef shared_any<unique_threadpool_wait> shared_threadpool_wait;
3720     typedef shared_any<unique_threadpool_wait_nocancel> shared_threadpool_wait_nocancel;
3721     typedef shared_any<unique_threadpool_work> shared_threadpool_work;
3722     typedef shared_any<unique_threadpool_work_nocancel> shared_threadpool_work_nocancel;
3723 
3724     typedef shared_any<unique_hfind_change> shared_hfind_change;
3725 #endif
3726 
3727     typedef weak_any<shared_event> weak_event;
3728     typedef weak_any<shared_mutex> weak_mutex;
3729     typedef weak_any<shared_semaphore> weak_semaphore;
3730     typedef weak_any<shared_hfile> weak_hfile;
3731     typedef weak_any<shared_handle> weak_handle;
3732     typedef weak_any<shared_hfind> weak_hfind;
3733     typedef weak_any<shared_hmodule> weak_hmodule;
3734 
3735 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
3736     typedef weak_any<shared_threadpool_wait> weak_threadpool_wait;
3737     typedef weak_any<shared_threadpool_wait_nocancel> weak_threadpool_wait_nocancel;
3738     typedef weak_any<shared_threadpool_work> weak_threadpool_work;
3739     typedef weak_any<shared_threadpool_work_nocancel> weak_threadpool_work_nocancel;
3740 
3741     typedef weak_any<shared_hfind_change> weak_hfind_change;
3742 #endif
3743 
3744 #endif // __WIL_WINBASE_STL
3745 
3746 #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)
3747 #define __WIL_WINBASE_NOTHROW_T_DEFINED_STL
3748     typedef shared_any_t<event_watcher_t<details::shared_storage<unique_event_watcher>>> shared_event_watcher;
3749     typedef weak_any<shared_event_watcher> weak_event_watcher;
3750 #endif // __WIL_WINBASE_NOTHROW_T_DEFINED_STL
3751 
3752 #if defined(__WIL_WINBASE_) && !defined(__WIL_WINBASE_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
3753 #define __WIL_WINBASE_DESKTOP
3754     /// @cond
3755     namespace details
3756     {
3757         inline void __stdcall DestroyPrivateObjectSecurity(_Pre_opt_valid_ _Frees_ptr_opt_ PSECURITY_DESCRIPTOR pObjectDescriptor) WI_NOEXCEPT
3758         {
3759             ::DestroyPrivateObjectSecurity(&pObjectDescriptor);
3760         }
3761     }
3762     /// @endcond
3763 
3764     using hlocal_deleter = function_deleter<decltype(&::LocalFree), LocalFree>;
3765 
3766     template <typename T = void>
3767     using unique_hlocal_ptr = wistd::unique_ptr<T, hlocal_deleter>;
3768 
3769     /** Provides `std::make_unique()` semantics for resources allocated with `LocalAlloc()` in a context that may not throw upon allocation failure.
3770     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()`.
3771     Use `wil::make_unique_nothrow()` when `LocalAlloc()` is not required.
3772 
3773     Allocations are initialized with placement new and will call constructors (if present), but this does not guarantee initialization.
3774 
3775     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.
3776     ~~~
3777     auto foo = wil::make_unique_hlocal_nothrow<Foo>();
3778     if (foo)
3779     {
3780     // initialize allocated Foo object as appropriate
3781     }
3782     ~~~
3783     */
3784     template <typename T, typename... Args>
3785     inline typename wistd::enable_if<!wistd::is_array<T>::value, unique_hlocal_ptr<T>>::type make_unique_hlocal_nothrow(Args&&... args)
3786     {
3787         static_assert(wistd::is_trivially_destructible<T>::value, "T has a destructor that won't be run when used with this function; use make_unique instead");
3788         unique_hlocal_ptr<T> sp(static_cast<T*>(::LocalAlloc(LMEM_FIXED, sizeof(T))));
3789         if (sp)
3790         {
3791             // use placement new to initialize memory from the previous allocation
3792             new (sp.get()) T(wistd::forward<Args>(args)...);
3793         }
3794         return sp;
3795     }
3796 
3797     /** Provides `std::make_unique()` semantics for array resources allocated with `LocalAlloc()` in a context that may not throw upon allocation failure.
3798     See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details.
3799     ~~~
3800     const size_t size = 42;
3801     auto foos = wil::make_unique_hlocal_nothrow<Foo[]>(size);
3802     if (foos)
3803     {
3804     for (auto& elem : wil::make_range(foos.get(), size))
3805     {
3806     // initialize allocated Foo objects as appropriate
3807     }
3808     }
3809     ~~~
3810     */
3811     template <typename T>
3812     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)
3813     {
3814         typedef typename wistd::remove_extent<T>::type E;
3815         static_assert(wistd::is_trivially_destructible<E>::value, "E has a destructor that won't be run when used with this function; use make_unique instead");
3816         FAIL_FAST_IF((__WI_SIZE_MAX / sizeof(E)) < size);
3817         size_t allocSize = sizeof(E) * size;
3818         unique_hlocal_ptr<T> sp(static_cast<E*>(::LocalAlloc(LMEM_FIXED, allocSize)));
3819         if (sp)
3820         {
3821             // use placement new to initialize memory from the previous allocation;
3822             // note that array placement new cannot be used as the standard allows for operator new[]
3823             // to consume overhead in the allocation for internal bookkeeping
3824             for (auto& elem : make_range(static_cast<E*>(sp.get()), size))
3825             {
3826                 new (&elem) E();
3827             }
3828         }
3829         return sp;
3830     }
3831 
3832     /** Provides `std::make_unique()` semantics for resources allocated with `LocalAlloc()` in a context that must fail fast upon allocation failure.
3833     See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details.
3834     ~~~
3835     auto foo = wil::make_unique_hlocal_failfast<Foo>();
3836     // initialize allocated Foo object as appropriate
3837     ~~~
3838     */
3839     template <typename T, typename... Args>
3840     inline typename wistd::enable_if<!wistd::is_array<T>::value, unique_hlocal_ptr<T>>::type make_unique_hlocal_failfast(Args&&... args)
3841     {
3842         unique_hlocal_ptr<T> result(make_unique_hlocal_nothrow<T>(wistd::forward<Args>(args)...));
3843         FAIL_FAST_IF_NULL_ALLOC(result);
3844         return result;
3845     }
3846 
3847     /** Provides `std::make_unique()` semantics for array resources allocated with `LocalAlloc()` in a context that must fail fast upon allocation failure.
3848     See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details.
3849     ~~~
3850     const size_t size = 42;
3851     auto foos = wil::make_unique_hlocal_failfast<Foo[]>(size);
3852     for (auto& elem : wil::make_range(foos.get(), size))
3853     {
3854     // initialize allocated Foo objects as appropriate
3855     }
3856     ~~~
3857     */
3858     template <typename T>
3859     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)
3860     {
3861         unique_hlocal_ptr<T> result(make_unique_hlocal_nothrow<T>(size));
3862         FAIL_FAST_IF_NULL_ALLOC(result);
3863         return result;
3864     }
3865 
3866 #ifdef WIL_ENABLE_EXCEPTIONS
3867     /** Provides `std::make_unique()` semantics for resources allocated with `LocalAlloc()`.
3868     See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details.
3869     ~~~
3870     auto foo = wil::make_unique_hlocal<Foo>();
3871     // initialize allocated Foo object as appropriate
3872     ~~~
3873     */
3874     template <typename T, typename... Args>
3875     inline typename wistd::enable_if<!wistd::is_array<T>::value, unique_hlocal_ptr<T>>::type make_unique_hlocal(Args&&... args)
3876     {
3877         unique_hlocal_ptr<T> result(make_unique_hlocal_nothrow<T>(wistd::forward<Args>(args)...));
3878         THROW_IF_NULL_ALLOC(result);
3879         return result;
3880     }
3881 
3882     /** Provides `std::make_unique()` semantics for array resources allocated with `LocalAlloc()`.
3883     See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details.
3884     ~~~
3885     const size_t size = 42;
3886     auto foos = wil::make_unique_hlocal<Foo[]>(size);
3887     for (auto& elem : wil::make_range(foos.get(), size))
3888     {
3889     // initialize allocated Foo objects as appropriate
3890     }
3891     ~~~
3892     */
3893     template <typename T>
3894     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)
3895     {
3896         unique_hlocal_ptr<T> result(make_unique_hlocal_nothrow<T>(size));
3897         THROW_IF_NULL_ALLOC(result);
3898         return result;
3899     }
3900 #endif // WIL_ENABLE_EXCEPTIONS
3901 
3902     typedef unique_any<HLOCAL, decltype(&::LocalFree), ::LocalFree> unique_hlocal;
3903     typedef unique_any<PWSTR, decltype(&::LocalFree), ::LocalFree> unique_hlocal_string;
3904 #ifndef WIL_NO_ANSI_STRINGS
3905     typedef unique_any<PSTR, decltype(&::LocalFree), ::LocalFree> unique_hlocal_ansistring;
3906 #endif // WIL_NO_ANSI_STRINGS
3907 
3908     /// @cond
3909     namespace details
3910     {
3911         struct localalloc_allocator
3912         {
3913             static _Ret_opt_bytecap_(size) void* allocate(size_t size) WI_NOEXCEPT
3914             {
3915                 return ::LocalAlloc(LMEM_FIXED, size);
3916             }
3917         };
3918 
3919         template<> struct string_allocator<unique_hlocal_string> : localalloc_allocator {};
3920 #ifndef WIL_NO_ANSI_STRINGS
3921         template<> struct string_allocator<unique_hlocal_ansistring> : localalloc_allocator {};
3922 #endif // WIL_NO_ANSI_STRINGS
3923     }
3924     /// @endcond
3925 
3926     inline auto make_hlocal_string_nothrow(
3927         _When_((source != nullptr) && length != static_cast<size_t>(-1), _In_reads_(length))
3928         _When_((source != nullptr) && length == static_cast<size_t>(-1), _In_z_)
3929         PCWSTR source, size_t length = static_cast<size_t>(-1)) WI_NOEXCEPT
3930     {
3931         return make_unique_string_nothrow<unique_hlocal_string>(source, length);
3932     }
3933 
3934     inline auto make_hlocal_string_failfast(
3935         _When_((source != nullptr) && length != static_cast<size_t>(-1), _In_reads_(length))
3936         _When_((source != nullptr) && length == static_cast<size_t>(-1), _In_z_)
3937         PCWSTR source, size_t length = static_cast<size_t>(-1)) WI_NOEXCEPT
3938     {
3939         return make_unique_string_failfast<unique_hlocal_string>(source, length);
3940     }
3941 
3942 #ifndef WIL_NO_ANSI_STRINGS
3943     inline auto make_hlocal_ansistring_nothrow(
3944         _When_((source != nullptr) && length != static_cast<size_t>(-1), _In_reads_(length))
3945         _When_((source != nullptr) && length == static_cast<size_t>(-1), _In_z_)
3946         PCSTR source, size_t length = static_cast<size_t>(-1)) WI_NOEXCEPT
3947     {
3948         return make_unique_ansistring_nothrow<unique_hlocal_ansistring>(source, length);
3949     }
3950 
3951     inline auto make_hlocal_ansistring_failfast(
3952         _When_((source != nullptr) && length != static_cast<size_t>(-1), _In_reads_(length))
3953         _When_((source != nullptr) && length == static_cast<size_t>(-1), _In_z_)
3954         PCSTR source, size_t length = static_cast<size_t>(-1)) WI_NOEXCEPT
3955     {
3956         return make_unique_ansistring_failfast<unique_hlocal_ansistring>(source, length);
3957     }
3958 #endif
3959 
3960 #ifdef WIL_ENABLE_EXCEPTIONS
3961     inline auto make_hlocal_string(
3962         _When_((source != nullptr) && length != static_cast<size_t>(-1), _In_reads_(length))
3963         _When_((source != nullptr) && length == static_cast<size_t>(-1), _In_z_)
3964         PCWSTR source, size_t length = static_cast<size_t>(-1))
3965     {
3966         return make_unique_string<unique_hlocal_string>(source, length);
3967     }
3968 
3969 #ifndef WIL_NO_ANSI_STRINGS
3970     inline auto make_hlocal_ansistring(
3971         _When_((source != nullptr) && length != static_cast<size_t>(-1), _In_reads_(length))
3972         _When_((source != nullptr) && length == static_cast<size_t>(-1), _In_z_)
3973         PCSTR source, size_t length = static_cast<size_t>(-1))
3974     {
3975         return make_unique_ansistring<unique_hlocal_ansistring>(source, length);
3976     }
3977 #endif // WIL_NO_ANSI_STRINGS
3978 #endif // WIL_ENABLE_EXCEPTIONS
3979 
3980     struct hlocal_secure_deleter
3981     {
3982         template <typename T>
3983         void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const
3984         {
3985             if (p)
3986             {
3987 #pragma warning(suppress: 26006 26007) // LocalSize() ensures proper buffer length
3988                 ::SecureZeroMemory(p, ::LocalSize(p)); // this is safe since LocalSize() returns 0 on failure
3989                 ::LocalFree(p);
3990             }
3991         }
3992     };
3993 
3994     template <typename T = void>
3995     using unique_hlocal_secure_ptr = wistd::unique_ptr<T, hlocal_secure_deleter>;
3996 
3997     /** Provides `std::make_unique()` semantics for secure resources allocated with `LocalAlloc()` in a context that may not throw upon allocation failure.
3998     See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details.
3999     ~~~
4000     auto foo = wil::make_unique_hlocal_secure_nothrow<Foo>();
4001     if (foo)
4002     {
4003     // initialize allocated Foo object as appropriate
4004     }
4005     ~~~
4006     */
4007     template <typename T, typename... Args>
4008     inline typename wistd::enable_if<!wistd::is_array<T>::value, unique_hlocal_secure_ptr<T>>::type make_unique_hlocal_secure_nothrow(Args&&... args)
4009     {
4010         return unique_hlocal_secure_ptr<T>(make_unique_hlocal_nothrow<T>(wistd::forward<Args>(args)...).release());
4011     }
4012 
4013     /** Provides `std::make_unique()` semantics for secure array resources allocated with `LocalAlloc()` in a context that may not throw upon allocation failure.
4014     See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details.
4015     ~~~
4016     const size_t size = 42;
4017     auto foos = wil::make_unique_hlocal_secure_nothrow<Foo[]>(size);
4018     if (foos)
4019     {
4020     for (auto& elem : wil::make_range(foos.get(), size))
4021     {
4022     // initialize allocated Foo objects as appropriate
4023     }
4024     }
4025     ~~~
4026     */
4027     template <typename T>
4028     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)
4029     {
4030         return unique_hlocal_secure_ptr<T>(make_unique_hlocal_nothrow<T>(size).release());
4031     }
4032 
4033     /** Provides `std::make_unique()` semantics for secure resources allocated with `LocalAlloc()` in a context that must fail fast upon allocation failure.
4034     See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details.
4035     ~~~
4036     auto foo = wil::make_unique_hlocal_secure_failfast<Foo>();
4037     // initialize allocated Foo object as appropriate
4038     ~~~
4039     */
4040     template <typename T, typename... Args>
4041     inline typename wistd::enable_if<!wistd::is_array<T>::value, unique_hlocal_secure_ptr<T>>::type make_unique_hlocal_secure_failfast(Args&&... args)
4042     {
4043         unique_hlocal_secure_ptr<T> result(make_unique_hlocal_secure_nothrow<T>(wistd::forward<Args>(args)...));
4044         FAIL_FAST_IF_NULL_ALLOC(result);
4045         return result;
4046     }
4047 
4048     /** Provides `std::make_unique()` semantics for secure array resources allocated with `LocalAlloc()` in a context that must fail fast upon allocation failure.
4049     See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details.
4050     ~~~
4051     const size_t size = 42;
4052     auto foos = wil::make_unique_hlocal_secure_failfast<Foo[]>(size);
4053     for (auto& elem : wil::make_range(foos.get(), size))
4054     {
4055     // initialize allocated Foo objects as appropriate
4056     }
4057     ~~~
4058     */
4059     template <typename T>
4060     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)
4061     {
4062         unique_hlocal_secure_ptr<T> result(make_unique_hlocal_secure_nothrow<T>(size));
4063         FAIL_FAST_IF_NULL_ALLOC(result);
4064         return result;
4065     }
4066 
4067 #ifdef WIL_ENABLE_EXCEPTIONS
4068     /** Provides `std::make_unique()` semantics for secure resources allocated with `LocalAlloc()`.
4069     See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details.
4070     ~~~
4071     auto foo = wil::make_unique_hlocal_secure<Foo>();
4072     // initialize allocated Foo object as appropriate
4073     ~~~
4074     */
4075     template <typename T, typename... Args>
4076     inline typename wistd::enable_if<!wistd::is_array<T>::value, unique_hlocal_secure_ptr<T>>::type make_unique_hlocal_secure(Args&&... args)
4077     {
4078         unique_hlocal_secure_ptr<T> result(make_unique_hlocal_secure_nothrow<T>(wistd::forward<Args>(args)...));
4079         THROW_IF_NULL_ALLOC(result);
4080         return result;
4081     }
4082 
4083     /** Provides `std::make_unique()` semantics for secure array resources allocated with `LocalAlloc()`.
4084     See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details.
4085     ~~~
4086     const size_t size = 42;
4087     auto foos = wil::make_unique_hlocal_secure<Foo[]>(size);
4088     for (auto& elem : wil::make_range(foos.get(), size))
4089     {
4090     // initialize allocated Foo objects as appropriate
4091     }
4092     ~~~
4093     */
4094     template <typename T>
4095     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)
4096     {
4097         unique_hlocal_secure_ptr<T> result(make_unique_hlocal_secure_nothrow<T>(size));
4098         THROW_IF_NULL_ALLOC(result);
4099         return result;
4100     }
4101 #endif // WIL_ENABLE_EXCEPTIONS
4102 
4103     typedef unique_hlocal_secure_ptr<wchar_t[]> unique_hlocal_string_secure;
4104 
4105     /** Copies a given string into secure memory allocated with `LocalAlloc()` in a context that may not throw upon allocation failure.
4106     See the overload of `wil::make_hlocal_string_nothrow()` with supplied length for more details.
4107     ~~~
4108     auto str = wil::make_hlocal_string_secure_nothrow(L"a string");
4109     RETURN_IF_NULL_ALLOC(str);
4110     std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string"
4111     ~~~
4112     */
4113     inline auto make_hlocal_string_secure_nothrow(_In_ PCWSTR source) WI_NOEXCEPT
4114     {
4115         return unique_hlocal_string_secure(make_hlocal_string_nothrow(source).release());
4116     }
4117 
4118     /** Copies a given string into secure memory allocated with `LocalAlloc()` in a context that must fail fast upon allocation failure.
4119     See the overload of `wil::make_hlocal_string_nothrow()` with supplied length for more details.
4120     ~~~
4121     auto str = wil::make_hlocal_string_secure_failfast(L"a string");
4122     std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string"
4123     ~~~
4124     */
4125     inline auto make_hlocal_string_secure_failfast(_In_ PCWSTR source) WI_NOEXCEPT
4126     {
4127         unique_hlocal_string_secure result(make_hlocal_string_secure_nothrow(source));
4128         FAIL_FAST_IF_NULL_ALLOC(result);
4129         return result;
4130     }
4131 
4132 #ifdef WIL_ENABLE_EXCEPTIONS
4133     /** Copies a given string into secure memory allocated with `LocalAlloc()`.
4134     See the overload of `wil::make_hlocal_string_nothrow()` with supplied length for more details.
4135     ~~~
4136     auto str = wil::make_hlocal_string_secure(L"a string");
4137     std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string"
4138     ~~~
4139     */
4140     inline auto make_hlocal_string_secure(_In_ PCWSTR source)
4141     {
4142         unique_hlocal_string_secure result(make_hlocal_string_secure_nothrow(source));
4143         THROW_IF_NULL_ALLOC(result);
4144         return result;
4145     }
4146 #endif
4147 
4148     using hglobal_deleter = function_deleter<decltype(&::GlobalFree), ::GlobalFree>;
4149 
4150     template <typename T = void>
4151     using unique_hglobal_ptr = wistd::unique_ptr<T, hglobal_deleter>;
4152 
4153     typedef unique_any<HGLOBAL, decltype(&::GlobalFree), ::GlobalFree> unique_hglobal;
4154     typedef unique_any<PWSTR, decltype(&::GlobalFree), ::GlobalFree> unique_hglobal_string;
4155 #ifndef WIL_NO_ANSI_STRINGS
4156     typedef unique_any<PSTR, decltype(&::GlobalFree), ::GlobalFree> unique_hglobal_ansistring;
4157 #endif // WIL_NO_ANSI_STRINGS
4158 
4159     /// @cond
4160     namespace details
4161     {
4162         template<> struct string_allocator<unique_hglobal_string>
4163         {
4164             static _Ret_opt_bytecap_(size) void* allocate(size_t size) WI_NOEXCEPT
4165             {
4166                 return ::GlobalAlloc(GPTR, size);
4167             }
4168         };
4169     }
4170     /// @endcond
4171 
4172     inline auto make_process_heap_string_nothrow(
4173         _When_((source != nullptr) && length != static_cast<size_t>(-1), _In_reads_(length))
4174         _When_((source != nullptr) && length == static_cast<size_t>(-1), _In_z_)
4175         PCWSTR source, size_t length = static_cast<size_t>(-1)) WI_NOEXCEPT
4176     {
4177         return make_unique_string_nothrow<unique_process_heap_string>(source, length);
4178     }
4179 
4180     inline auto make_process_heap_string_failfast(
4181         _When_((source != nullptr) && length != static_cast<size_t>(-1), _In_reads_(length))
4182         _When_((source != nullptr) && length == static_cast<size_t>(-1), _In_z_)
4183         PCWSTR source, size_t length = static_cast<size_t>(-1)) WI_NOEXCEPT
4184     {
4185         return make_unique_string_failfast<unique_process_heap_string>(source, length);
4186     }
4187 
4188 #ifdef WIL_ENABLE_EXCEPTIONS
4189     inline auto make_process_heap_string(
4190         _When_((source != nullptr) && length != static_cast<size_t>(-1), _In_reads_(length))
4191         _When_((source != nullptr) && length == static_cast<size_t>(-1), _In_z_)
4192         PCWSTR source, size_t length = static_cast<size_t>(-1))
4193     {
4194         return make_unique_string<unique_process_heap_string>(source, length);
4195     }
4196 #endif // WIL_ENABLE_EXCEPTIONS
4197 
4198     typedef unique_any_handle_null<decltype(&::HeapDestroy), ::HeapDestroy> unique_hheap;
4199     typedef unique_any<DWORD, decltype(&::TlsFree), ::TlsFree, details::pointer_access_all, DWORD, DWORD, TLS_OUT_OF_INDEXES, DWORD> unique_tls;
4200     typedef unique_any<PSECURITY_DESCRIPTOR, decltype(&::LocalFree), ::LocalFree> unique_hlocal_security_descriptor;
4201     typedef unique_any<PSECURITY_DESCRIPTOR, decltype(&details::DestroyPrivateObjectSecurity), details::DestroyPrivateObjectSecurity> unique_private_security_descriptor;
4202 
4203 #if defined(_WINUSER_) && !defined(__WIL__WINUSER_)
4204 #define __WIL__WINUSER_
4205     typedef unique_any<HACCEL, decltype(&::DestroyAcceleratorTable), ::DestroyAcceleratorTable> unique_haccel;
4206     typedef unique_any<HCURSOR, decltype(&::DestroyCursor), ::DestroyCursor> unique_hcursor;
4207     typedef unique_any<HWND, decltype(&::DestroyWindow), ::DestroyWindow> unique_hwnd;
4208 #if !defined(NOUSER) && !defined(NOWH)
4209     typedef unique_any<HHOOK, decltype(&::UnhookWindowsHookEx), ::UnhookWindowsHookEx> unique_hhook;
4210 #endif
4211 #if !defined(NOWINABLE)
4212     typedef unique_any<HWINEVENTHOOK, decltype(&::UnhookWinEvent), ::UnhookWinEvent> unique_hwineventhook;
4213 #endif
4214 #endif // __WIL__WINUSER_
4215 
4216 #if !defined(NOGDI) && !defined(NODESKTOP)
4217     typedef unique_any<HDESK, decltype(&::CloseDesktop), ::CloseDesktop> unique_hdesk;
4218     typedef unique_any<HWINSTA, decltype(&::CloseWindowStation), ::CloseWindowStation> unique_hwinsta;
4219 #endif // !defined(NOGDI) && !defined(NODESKTOP)
4220 
4221 #endif
4222 #if defined(__WIL_WINBASE_DESKTOP) && !defined(__WIL_WINBASE_DESKTOP_STL) && defined(WIL_RESOURCE_STL)
4223 #define __WIL_WINBASE_DESKTOP_STL
4224     typedef shared_any<unique_hheap> shared_hheap;
4225     typedef shared_any<unique_hlocal> shared_hlocal;
4226     typedef shared_any<unique_tls> shared_tls;
4227     typedef shared_any<unique_hlocal_security_descriptor> shared_hlocal_security_descriptor;
4228     typedef shared_any<unique_private_security_descriptor> shared_private_security_descriptor;
4229     typedef shared_any<unique_haccel> shared_haccel;
4230     typedef shared_any<unique_hcursor> shared_hcursor;
4231 #if !defined(NOGDI) && !defined(NODESKTOP)
4232     typedef shared_any<unique_hdesk> shared_hdesk;
4233     typedef shared_any<unique_hwinsta> shared_hwinsta;
4234 #endif // !defined(NOGDI) && !defined(NODESKTOP)
4235     typedef shared_any<unique_hwnd> shared_hwnd;
4236 #if !defined(NOUSER) && !defined(NOWH)
4237     typedef shared_any<unique_hhook> shared_hhook;
4238 #endif
4239 #if !defined(NOWINABLE)
4240     typedef shared_any<unique_hwineventhook> shared_hwineventhook;
4241 #endif
4242 
4243     typedef weak_any<shared_hheap> weak_hheap;
4244     typedef weak_any<shared_hlocal> weak_hlocal;
4245     typedef weak_any<shared_tls> weak_tls;
4246     typedef weak_any<shared_hlocal_security_descriptor> weak_hlocal_security_descriptor;
4247     typedef weak_any<shared_private_security_descriptor> weak_private_security_descriptor;
4248     typedef weak_any<shared_haccel> weak_haccel;
4249     typedef weak_any<shared_hcursor> weak_hcursor;
4250 #if !defined(NOGDI) && !defined(NODESKTOP)
4251     typedef weak_any<shared_hdesk> weak_hdesk;
4252     typedef weak_any<shared_hwinsta> weak_hwinsta;
4253 #endif // !defined(NOGDI) && !defined(NODESKTOP)
4254     typedef weak_any<shared_hwnd> weak_hwnd;
4255 #if !defined(NOUSER) && !defined(NOWH)
4256     typedef weak_any<shared_hhook> weak_hhook;
4257 #endif
4258 #if !defined(NOWINABLE)
4259     typedef weak_any<shared_hwineventhook> weak_hwineventhook;
4260 #endif
4261 #endif // __WIL_WINBASE_DESKTOP_STL
4262 
4263 #if defined(_COMBASEAPI_H_) && !defined(__WIL__COMBASEAPI_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && !defined(WIL_KERNEL_MODE)
4264 #define __WIL__COMBASEAPI_H_
4265 #if (NTDDI_VERSION >= NTDDI_WIN8)
4266     typedef unique_any<CO_MTA_USAGE_COOKIE, decltype(&::CoDecrementMTAUsage), ::CoDecrementMTAUsage> unique_mta_usage_cookie;
4267 #endif
4268 
4269     typedef unique_any<DWORD, decltype(&::CoRevokeClassObject), ::CoRevokeClassObject> unique_com_class_object_cookie;
4270 
4271     /// @cond
4272     namespace details
4273     {
4274         inline void __stdcall MultiQiCleanup(_In_ MULTI_QI* multiQi)
4275         {
4276             if (multiQi->pItf)
4277             {
4278                 multiQi->pItf->Release();
4279                 multiQi->pItf = nullptr;
4280             }
4281         }
4282     }
4283     /// @endcond
4284 
4285     //! A type that calls CoRevertToSelf on destruction (or reset()).
4286     using unique_coreverttoself_call = unique_call<decltype(&::CoRevertToSelf), ::CoRevertToSelf>;
4287 
4288     //! Calls CoImpersonateClient and fail-fasts if it fails; returns an RAII object that reverts
4289     WI_NODISCARD inline unique_coreverttoself_call CoImpersonateClient_failfast()
4290     {
4291         FAIL_FAST_IF_FAILED(::CoImpersonateClient());
4292         return unique_coreverttoself_call();
4293     }
4294 
4295     typedef unique_struct<MULTI_QI, decltype(&details::MultiQiCleanup), details::MultiQiCleanup> unique_multi_qi;
4296 #endif // __WIL__COMBASEAPI_H_
4297 #if defined(__WIL__COMBASEAPI_H_) && defined(WIL_ENABLE_EXCEPTIONS) && !defined(__WIL__COMBASEAPI_H_EXCEPTIONAL)
4298 #define __WIL__COMBASEAPI_H_EXCEPTIONAL
4299     WI_NODISCARD inline unique_coreverttoself_call CoImpersonateClient()
4300     {
4301         THROW_IF_FAILED(::CoImpersonateClient());
4302         return unique_coreverttoself_call();
4303     }
4304 #endif
4305 #if defined(__WIL__COMBASEAPI_H_) && !defined(__WIL__COMBASEAPI_H__STL) && defined(WIL_RESOURCE_STL) && (NTDDI_VERSION >= NTDDI_WIN8)
4306 #define __WIL__COMBASEAPI_H__STL
4307     typedef shared_any<unique_mta_usage_cookie> shared_mta_usage_cookie;
4308     typedef weak_any<shared_mta_usage_cookie> weak_mta_usage_cookie;
4309 #endif // __WIL__COMBASEAPI_H__STL
4310 
4311 #if defined(_COMBASEAPI_H_) && !defined(__WIL__COMBASEAPI_H_APP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) && !defined(WIL_KERNEL_MODE)
4312 #define __WIL__COMBASEAPI_H_APP
4313     //! A type that calls CoUninitialize on destruction (or reset()).
4314     using unique_couninitialize_call = unique_call<decltype(&::CoUninitialize), ::CoUninitialize>;
4315 
4316     //! Calls CoInitializeEx and fail-fasts if it fails; returns an RAII object that reverts
4317     WI_NODISCARD inline unique_couninitialize_call CoInitializeEx_failfast(DWORD coinitFlags = 0 /*COINIT_MULTITHREADED*/)
4318     {
4319         FAIL_FAST_IF_FAILED(::CoInitializeEx(nullptr, coinitFlags));
4320         return unique_couninitialize_call();
4321     }
4322 #endif // __WIL__COMBASEAPI_H_APP
4323 #if defined(__WIL__COMBASEAPI_H_APP) && defined(WIL_ENABLE_EXCEPTIONS) && !defined(__WIL__COMBASEAPI_H_APPEXCEPTIONAL)
4324 #define __WIL__COMBASEAPI_H_APPEXCEPTIONAL
4325     WI_NODISCARD inline unique_couninitialize_call CoInitializeEx(DWORD coinitFlags = 0 /*COINIT_MULTITHREADED*/)
4326     {
4327         THROW_IF_FAILED(::CoInitializeEx(nullptr, coinitFlags));
4328         return unique_couninitialize_call();
4329     }
4330 #endif
4331 
4332 #if defined(__ROAPI_H_) && !defined(__WIL__ROAPI_H_APP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) && (NTDDI_VERSION >= NTDDI_WIN8)
4333 #define __WIL__ROAPI_H_APP
4334 
4335     typedef unique_any<RO_REGISTRATION_COOKIE, decltype(&::RoRevokeActivationFactories), ::RoRevokeActivationFactories> unique_ro_registration_cookie;
4336 
4337     //! A type that calls RoUninitialize on destruction (or reset()).
4338     //! Use as a replacement for Windows::Foundation::Uninitialize.
4339     using unique_rouninitialize_call = unique_call<decltype(&::RoUninitialize), ::RoUninitialize>;
4340 
4341     //! Calls RoInitialize and fail-fasts if it fails; returns an RAII object that reverts
4342     //! Use as a replacement for Windows::Foundation::Initialize
4343     WI_NODISCARD inline unique_rouninitialize_call RoInitialize_failfast(RO_INIT_TYPE initType = RO_INIT_MULTITHREADED)
4344     {
4345         FAIL_FAST_IF_FAILED(::RoInitialize(initType));
4346         return unique_rouninitialize_call();
4347     }
4348 #endif // __WIL__ROAPI_H_APP
4349 #if defined(__WIL__ROAPI_H_APP) && defined(WIL_ENABLE_EXCEPTIONS) && !defined(__WIL__ROAPI_H_APPEXCEPTIONAL)
4350 #define __WIL__ROAPI_H_APPEXCEPTIONAL
4351     //! Calls RoInitialize and throws an exception if it fails; returns an RAII object that reverts
4352     //! Use as a replacement for Windows::Foundation::Initialize
4353     WI_NODISCARD inline unique_rouninitialize_call RoInitialize(RO_INIT_TYPE initType = RO_INIT_MULTITHREADED)
4354     {
4355         THROW_IF_FAILED(::RoInitialize(initType));
4356         return unique_rouninitialize_call();
4357     }
4358 #endif
4359 
4360 #if defined(__WINSTRING_H_) && !defined(__WIL__WINSTRING_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
4361 #define __WIL__WINSTRING_H_
4362     typedef unique_any<HSTRING, decltype(&::WindowsDeleteString), ::WindowsDeleteString> unique_hstring;
4363 
4364     template<> inline unique_hstring make_unique_string_nothrow<unique_hstring>(
4365         _When_((source != nullptr) && length != static_cast<size_t>(-1), _In_reads_(length))
4366         _When_((source != nullptr) && length == static_cast<size_t>(-1), _In_z_)
4367         PCWSTR source, size_t length) WI_NOEXCEPT
4368     {
4369         WI_ASSERT(source != nullptr); // the HSTRING version of this function does not suport this case
4370         if (length == static_cast<size_t>(-1))
4371         {
4372             length = wcslen(source);
4373         }
4374 
4375         unique_hstring result;
4376         ::WindowsCreateString(source, static_cast<UINT32>(length), &result);
4377         return result;
4378     }
4379 
4380     typedef unique_any<HSTRING_BUFFER, decltype(&::WindowsDeleteStringBuffer), ::WindowsDeleteStringBuffer> unique_hstring_buffer;
4381 
4382     /** Promotes an hstring_buffer to an HSTRING.
4383     When an HSTRING_BUFFER object is promoted to a real string it must not be passed to WindowsDeleteString. The caller owns the
4384     HSTRING afterwards.
4385     ~~~
4386     HRESULT Type::MakePath(_Out_ HSTRING* path)
4387     {
4388         wchar_t* bufferStorage = nullptr;
4389         wil::unique_hstring_buffer theBuffer;
4390         RETURN_IF_FAILED(::WindowsPreallocateStringBuffer(65, &bufferStorage, &theBuffer));
4391         RETURN_IF_FAILED(::PathCchCombine(bufferStorage, 65, m_foo, m_bar));
4392         RETURN_IF_FAILED(wil::make_hstring_from_buffer_nothrow(wistd::move(theBuffer), path)));
4393         return S_OK;
4394     }
4395     ~~~
4396     */
4397     inline HRESULT make_hstring_from_buffer_nothrow(unique_hstring_buffer&& source, _Out_ HSTRING* promoted)
4398     {
4399         HRESULT hr = ::WindowsPromoteStringBuffer(source.get(), promoted);
4400         if (SUCCEEDED(hr))
4401         {
4402             source.release();
4403         }
4404         return hr;
4405     }
4406 
4407     //! A fail-fast variant of `make_hstring_from_buffer_nothrow`
4408     inline unique_hstring make_hstring_from_buffer_failfast(unique_hstring_buffer&& source)
4409     {
4410         unique_hstring result;
4411         FAIL_FAST_IF_FAILED(make_hstring_from_buffer_nothrow(wistd::move(source), &result));
4412         return result;
4413     }
4414 
4415 #if defined WIL_ENABLE_EXCEPTIONS
4416     /** Promotes an hstring_buffer to an HSTRING.
4417     When an HSTRING_BUFFER object is promoted to a real string it must not be passed to WindowsDeleteString. The caller owns the
4418     HSTRING afterwards.
4419     ~~~
4420     wil::unique_hstring Type::Make()
4421     {
4422         wchar_t* bufferStorage = nullptr;
4423         wil::unique_hstring_buffer theBuffer;
4424         THROW_IF_FAILED(::WindowsPreallocateStringBuffer(65, &bufferStorage, &theBuffer));
4425         THROW_IF_FAILED(::PathCchCombine(bufferStorage, 65, m_foo, m_bar));
4426         return wil::make_hstring_from_buffer(wistd::move(theBuffer));
4427     }
4428     ~~~
4429     */
4430     inline unique_hstring make_hstring_from_buffer(unique_hstring_buffer&& source)
4431     {
4432         unique_hstring result;
4433         THROW_IF_FAILED(make_hstring_from_buffer_nothrow(wistd::move(source), &result));
4434         return result;
4435     }
4436 #endif
4437 
4438     /// @cond
4439     namespace details
4440     {
4441         template<> struct string_maker<unique_hstring>
4442         {
4443             string_maker() = default;
4444             string_maker(const string_maker&) = delete;
4445             void operator=(const string_maker&) = delete;
4446             string_maker& operator=(string_maker&& source) WI_NOEXCEPT
4447             {
4448                 m_value = wistd::move(source.m_value);
4449                 m_bufferHandle = wistd::move(source.m_bufferHandle);
4450                 m_charBuffer = wistd::exchange(source.m_charBuffer, nullptr);
4451                 return *this;
4452             }
4453 
4454             HRESULT make(
4455                 _When_((source != nullptr) && length != static_cast<size_t>(-1), _In_reads_(length))
4456                 _When_((source != nullptr) && length == static_cast<size_t>(-1), _In_z_)
4457                 const wchar_t* source,
4458                 size_t length)
4459             {
4460                 if (source)
4461                 {
4462                     RETURN_IF_FAILED(WindowsCreateString(source, static_cast<UINT32>(length), &m_value));
4463                 }
4464                 else
4465                 {
4466                     // Need to set it to the empty string to support the empty string case.
4467                     m_value.reset();
4468                     RETURN_IF_FAILED(WindowsPreallocateStringBuffer(static_cast<UINT32>(length), &m_charBuffer, &m_bufferHandle));
4469                 }
4470                 return S_OK;
4471             }
4472 
4473             wchar_t* buffer() { WI_ASSERT(m_charBuffer != nullptr);  return m_charBuffer; }
4474             const wchar_t* buffer() const { return m_charBuffer; }
4475 
4476             unique_hstring release()
4477             {
4478                 m_charBuffer = nullptr;
4479                 if (m_bufferHandle)
4480                 {
4481                     return make_hstring_from_buffer_failfast(wistd::move(m_bufferHandle));
4482                 }
4483                 return wistd::move(m_value);
4484             }
4485 
4486             static PCWSTR get(const wil::unique_hstring& value) { return WindowsGetStringRawBuffer(value.get(), nullptr); }
4487 
4488         private:
4489             unique_hstring m_value;
4490             unique_hstring_buffer m_bufferHandle;
4491             wchar_t* m_charBuffer = nullptr;
4492         };
4493     }
4494     /// @endcond
4495 
4496     // str_raw_ptr is an overloaded function that retrieves a const pointer to the first character in a string's buffer.
4497     // This is the overload for HSTRING.  Other overloads available above.
4498     inline PCWSTR str_raw_ptr(HSTRING str)
4499     {
4500         return WindowsGetStringRawBuffer(str, nullptr);
4501     }
4502 
4503     inline PCWSTR str_raw_ptr(const unique_hstring& str)
4504     {
4505         return str_raw_ptr(str.get());
4506     }
4507 
4508 #endif // __WIL__WINSTRING_H_
4509 #if defined(__WIL__WINSTRING_H_) && !defined(__WIL__WINSTRING_H_STL) && defined(WIL_RESOURCE_STL)
4510 #define __WIL__WINSTRING_H_STL
4511     typedef shared_any<unique_hstring> shared_hstring;
4512     typedef shared_any<unique_hstring_buffer> shared_hstring_buffer;
4513     typedef weak_any<shared_hstring> weak_hstring;
4514     typedef weak_any<shared_hstring_buffer> weak_hstring_buffer;
4515 #endif // __WIL__WINSTRING_H_STL
4516 
4517 
4518 #if defined(_WINREG_) && !defined(__WIL_WINREG_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(WIL_KERNEL_MODE)
4519 #define __WIL_WINREG_
4520     typedef unique_any<HKEY, decltype(&::RegCloseKey), ::RegCloseKey> unique_hkey;
4521 #endif // __WIL_WINREG_
4522 #if defined(__WIL_WINREG_) && !defined(__WIL_WINREG_STL) && defined(WIL_RESOURCE_STL)
4523 #define __WIL_WINREG_STL
4524     typedef shared_any<unique_hkey> shared_hkey;
4525     typedef weak_any<shared_hkey> weak_hkey;
4526 #endif // __WIL_WINREG_STL
4527 
4528 #if defined(__propidl_h__) && !defined(_WIL__propidl_h__) && !defined(WIL_KERNEL_MODE)
4529 #define _WIL__propidl_h__
4530     using unique_prop_variant = wil::unique_struct<PROPVARIANT, decltype(&::PropVariantClear), ::PropVariantClear, decltype(&::PropVariantInit), ::PropVariantInit>;
4531 #endif // _WIL__propidl_h__
4532 
4533 #if defined(_OLEAUTO_H_) && !defined(__WIL_OLEAUTO_H_) && !defined(WIL_KERNEL_MODE) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
4534 #define __WIL_OLEAUTO_H_
4535     using unique_variant = wil::unique_struct<VARIANT, decltype(&::VariantClear), ::VariantClear, decltype(&::VariantInit), ::VariantInit>;
4536     typedef unique_any<BSTR, decltype(&::SysFreeString), ::SysFreeString> unique_bstr;
4537 
4538     inline wil::unique_bstr make_bstr_nothrow(PCWSTR source) WI_NOEXCEPT
4539     {
4540         return wil::unique_bstr(::SysAllocString(source));
4541     }
4542 
4543     inline wil::unique_bstr make_bstr_failfast(PCWSTR source) WI_NOEXCEPT
4544     {
4545         return wil::unique_bstr(FAIL_FAST_IF_NULL_ALLOC(::SysAllocString(source)));
4546     }
4547 
4548 #ifdef WIL_ENABLE_EXCEPTIONS
4549     inline wil::unique_bstr make_bstr(PCWSTR source)
4550     {
4551         wil::unique_bstr result(make_bstr_nothrow(source));
4552         THROW_IF_NULL_ALLOC(result);
4553         return result;
4554     }
4555 #endif // WIL_ENABLE_EXCEPTIONS
4556 
4557 #endif // __WIL_OLEAUTO_H_
4558 #if defined(__WIL_OLEAUTO_H_) && !defined(__WIL_OLEAUTO_H_STL) && defined(WIL_RESOURCE_STL)
4559 #define __WIL_OLEAUTO_H_STL
4560     typedef shared_any<unique_bstr> shared_bstr;
4561     typedef weak_any<shared_bstr> weak_bstr;
4562 #endif // __WIL_OLEAUTO_H_STL
4563 
4564 
4565 #if (defined(_WININET_) || defined(_DUBINET_)) && !defined(__WIL_WININET_)
4566 #define __WIL_WININET_
4567     typedef unique_any<HINTERNET, decltype(&::InternetCloseHandle), ::InternetCloseHandle> unique_hinternet;
4568 #endif // __WIL_WININET_
4569 #if defined(__WIL_WININET_) && !defined(__WIL_WININET_STL) && defined(WIL_RESOURCE_STL)
4570 #define __WIL_WININET_STL
4571     typedef shared_any<unique_hinternet> shared_hinternet;
4572     typedef weak_any<shared_hinternet> weak_hinternet;
4573 #endif // __WIL_WININET_STL
4574 
4575 
4576 #if defined(_WINHTTPX_) && !defined(__WIL_WINHTTP_)
4577 #define __WIL_WINHTTP_
4578     typedef unique_any<HINTERNET, decltype(&::WinHttpCloseHandle), ::WinHttpCloseHandle> unique_winhttp_hinternet;
4579 #endif // __WIL_WINHTTP_
4580 #if defined(__WIL_WINHTTP_) && !defined(__WIL_WINHTTP_STL) && defined(WIL_RESOURCE_STL)
4581 #define __WIL_WINHTTP_STL
4582     typedef shared_any<unique_winhttp_hinternet> shared_winhttp_hinternet;
4583     typedef weak_any<shared_winhttp_hinternet> weak_winhttp_hinternet;
4584 #endif // __WIL_WINHTTP_STL
4585 
4586 
4587 #if defined(_WINSOCKAPI_) && !defined(__WIL_WINSOCKAPI_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
4588 #define __WIL_WINSOCKAPI_
4589     typedef unique_any<SOCKET, int (WINAPI*)(SOCKET), ::closesocket, details::pointer_access_all, SOCKET, SOCKET, INVALID_SOCKET, SOCKET> unique_socket;
4590 #endif // __WIL_WINSOCKAPI_
4591 #if defined(__WIL_WINSOCKAPI_) && !defined(__WIL_WINSOCKAPI_STL) && defined(WIL_RESOURCE_STL)
4592 #define __WIL_WINSOCKAPI_STL
4593     typedef shared_any<unique_socket> shared_socket;
4594     typedef weak_any<shared_socket> weak_socket;
4595 #endif // __WIL_WINSOCKAPI_STL
4596 
4597 
4598 #if defined(_WINGDI_) && !defined(__WIL_WINGDI_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(NOGDI) && !defined(WIL_KERNEL_MODE)
4599 #define __WIL_WINGDI_
4600     struct window_dc
4601     {
4602         HDC dc;
4603         HWND hwnd;
4604         window_dc(HDC dc_, HWND hwnd_ = nullptr) WI_NOEXCEPT { dc = dc_; hwnd = hwnd_; }
4605         operator HDC() const WI_NOEXCEPT { return dc; }
4606         static void close(window_dc wdc) WI_NOEXCEPT { ::ReleaseDC(wdc.hwnd, wdc.dc); }
4607     };
4608     typedef unique_any<HDC, decltype(&window_dc::close), window_dc::close, details::pointer_access_all, window_dc> unique_hdc_window;
4609 
4610     struct paint_dc
4611     {
4612         HWND hwnd;
4613         PAINTSTRUCT ps;
4614         paint_dc(HDC hdc = nullptr) { ::ZeroMemory(this, sizeof(*this)); ps.hdc = hdc; }
4615         operator HDC() const WI_NOEXCEPT { return ps.hdc; }
4616         static void close(paint_dc pdc) WI_NOEXCEPT { ::EndPaint(pdc.hwnd, &pdc.ps); }
4617     };
4618     typedef unique_any<HDC, decltype(&paint_dc::close), paint_dc::close, details::pointer_access_all, paint_dc> unique_hdc_paint;
4619 
4620     struct select_result
4621     {
4622         HGDIOBJ hgdi;
4623         HDC hdc;
4624         select_result(HGDIOBJ hgdi_, HDC hdc_ = nullptr) WI_NOEXCEPT { hgdi = hgdi_; hdc = hdc_; }
4625         operator HGDIOBJ() const WI_NOEXCEPT { return hgdi; }
4626         static void close(select_result sr) WI_NOEXCEPT { ::SelectObject(sr.hdc, sr.hgdi); }
4627     };
4628     typedef unique_any<HGDIOBJ, decltype(&select_result::close), select_result::close, details::pointer_access_all, select_result> unique_select_object;
4629 
4630     inline unique_hdc_window GetDC(HWND hwnd) WI_NOEXCEPT
4631     {
4632         return unique_hdc_window(window_dc(::GetDC(hwnd), hwnd));
4633     }
4634 
4635     inline unique_hdc_window GetWindowDC(HWND hwnd) WI_NOEXCEPT
4636     {
4637         return unique_hdc_window(window_dc(::GetWindowDC(hwnd), hwnd));
4638     }
4639 
4640     inline unique_hdc_paint BeginPaint(HWND hwnd, _Out_opt_ PPAINTSTRUCT pPaintStruct = nullptr) WI_NOEXCEPT
4641     {
4642         paint_dc pdc;
4643         pdc.hwnd = hwnd;
4644         HDC hdc = ::BeginPaint(hwnd, &pdc.ps);
4645         assign_to_opt_param(pPaintStruct, pdc.ps);
4646         return (hdc == nullptr) ? unique_hdc_paint() : unique_hdc_paint(pdc);
4647     }
4648 
4649     inline unique_select_object SelectObject(HDC hdc, HGDIOBJ gdiobj) WI_NOEXCEPT
4650     {
4651         return unique_select_object(select_result(::SelectObject(hdc, gdiobj), hdc));
4652     }
4653 
4654     typedef unique_any<HGDIOBJ, decltype(&::DeleteObject), ::DeleteObject> unique_hgdiobj;
4655     typedef unique_any<HPEN, decltype(&::DeleteObject), ::DeleteObject> unique_hpen;
4656     typedef unique_any<HBRUSH, decltype(&::DeleteObject), ::DeleteObject> unique_hbrush;
4657     typedef unique_any<HFONT, decltype(&::DeleteObject), ::DeleteObject> unique_hfont;
4658     typedef unique_any<HBITMAP, decltype(&::DeleteObject), ::DeleteObject> unique_hbitmap;
4659     typedef unique_any<HRGN, decltype(&::DeleteObject), ::DeleteObject> unique_hrgn;
4660     typedef unique_any<HPALETTE, decltype(&::DeleteObject), ::DeleteObject> unique_hpalette;
4661     typedef unique_any<HDC, decltype(&::DeleteDC), ::DeleteDC> unique_hdc;
4662     typedef unique_any<HICON, decltype(&::DestroyIcon), ::DestroyIcon> unique_hicon;
4663 #if !defined(NOMENUS)
4664     typedef unique_any<HMENU, decltype(&::DestroyMenu), ::DestroyMenu> unique_hmenu;
4665 #endif // !defined(NOMENUS)
4666 #endif // __WIL_WINGDI_
4667 #if defined(__WIL_WINGDI_) && !defined(__WIL_WINGDI_STL) && defined(WIL_RESOURCE_STL)
4668 #define __WIL_WINGDI_STL
4669     typedef shared_any<unique_hgdiobj> shared_hgdiobj;
4670     typedef shared_any<unique_hpen> shared_hpen;
4671     typedef shared_any<unique_hbrush> shared_hbrush;
4672     typedef shared_any<unique_hfont> shared_hfont;
4673     typedef shared_any<unique_hbitmap> shared_hbitmap;
4674     typedef shared_any<unique_hrgn> shared_hrgn;
4675     typedef shared_any<unique_hpalette> shared_hpalette;
4676     typedef shared_any<unique_hdc> shared_hdc;
4677     typedef shared_any<unique_hicon> shared_hicon;
4678 #if !defined(NOMENUS)
4679     typedef shared_any<unique_hmenu> shared_hmenu;
4680 #endif // !defined(NOMENUS)
4681 
4682     typedef weak_any<shared_hgdiobj> weak_hgdiobj;
4683     typedef weak_any<shared_hpen> weak_hpen;
4684     typedef weak_any<shared_hbrush> weak_hbrush;
4685     typedef weak_any<shared_hfont> weak_hfont;
4686     typedef weak_any<shared_hbitmap> weak_hbitmap;
4687     typedef weak_any<shared_hrgn> weak_hrgn;
4688     typedef weak_any<shared_hpalette> weak_hpalette;
4689     typedef weak_any<shared_hdc> weak_hdc;
4690     typedef weak_any<shared_hicon> weak_hicon;
4691 #if !defined(NOMENUS)
4692     typedef weak_any<shared_hmenu> weak_hmenu;
4693 #endif // !defined(NOMENUS)
4694 #endif // __WIL_WINGDI_STL
4695 
4696 #if defined(_INC_WTSAPI) && !defined(__WIL_WTSAPI)
4697 #define __WIL_WTSAPI
4698     template<typename T>
4699     using unique_wtsmem_ptr = wistd::unique_ptr<T, function_deleter<decltype(&WTSFreeMemory), WTSFreeMemory>>;
4700 #endif // __WIL_WTSAPI
4701 
4702 #if defined(_WINSCARD_H_) && !defined(__WIL_WINSCARD_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
4703 #define __WIL_WINSCARD_H_
4704     typedef unique_any<SCARDCONTEXT, decltype(&::SCardReleaseContext), ::SCardReleaseContext> unique_scardctx;
4705 #endif // __WIL_WINSCARD_H_
4706 #if defined(__WIL_WINSCARD_H_) && !defined(__WIL_WINSCARD_H_STL) && defined(WIL_RESOURCE_STL)
4707 #define __WIL_WINSCARD_H_STL
4708     typedef shared_any<unique_scardctx> shared_scardctx;
4709     typedef weak_any<shared_scardctx> weak_scardctx;
4710 #endif // __WIL_WINSCARD_H_STL
4711 
4712 
4713 #if defined(__WINCRYPT_H__) && !defined(__WIL__WINCRYPT_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
4714 #define __WIL__WINCRYPT_H__
4715     /// @cond
4716     namespace details
4717     {
4718         inline void __stdcall CertCloseStoreNoParam(_Pre_opt_valid_ _Frees_ptr_opt_ HCERTSTORE hCertStore) WI_NOEXCEPT
4719         {
4720             ::CertCloseStore(hCertStore, 0);
4721         }
4722 
4723         inline void __stdcall CryptReleaseContextNoParam(_Pre_opt_valid_ _Frees_ptr_opt_ HCRYPTPROV hCryptCtx) WI_NOEXCEPT
4724         {
4725             ::CryptReleaseContext(hCryptCtx, 0);
4726         }
4727     }
4728     /// @endcond
4729 
4730     typedef unique_any<PCCERT_CONTEXT, decltype(&::CertFreeCertificateContext), ::CertFreeCertificateContext> unique_cert_context;
4731     typedef unique_any<PCCERT_CHAIN_CONTEXT, decltype(&::CertFreeCertificateChain), ::CertFreeCertificateChain> unique_cert_chain_context;
4732     typedef unique_any<HCERTSTORE, decltype(&details::CertCloseStoreNoParam), details::CertCloseStoreNoParam> unique_hcertstore;
4733     typedef unique_any<HCRYPTPROV, decltype(&details::CryptReleaseContextNoParam), details::CryptReleaseContextNoParam> unique_hcryptprov;
4734     typedef unique_any<HCRYPTKEY, decltype(&::CryptDestroyKey), ::CryptDestroyKey> unique_hcryptkey;
4735     typedef unique_any<HCRYPTHASH, decltype(&::CryptDestroyHash), ::CryptDestroyHash> unique_hcrypthash;
4736 #endif // __WIL__WINCRYPT_H__
4737 #if defined(__WIL__WINCRYPT_H__) && !defined(__WIL__WINCRYPT_H__STL) && defined(WIL_RESOURCE_STL)
4738 #define __WIL__WINCRYPT_H__STL
4739     typedef shared_any<unique_cert_context> shared_cert_context;
4740     typedef shared_any<unique_cert_chain_context> shared_cert_chain_context;
4741     typedef shared_any<unique_hcertstore> shared_hcertstore;
4742     typedef shared_any<unique_hcryptprov> shared_hcryptprov;
4743     typedef shared_any<unique_hcryptkey> shared_hcryptkey;
4744     typedef shared_any<unique_hcrypthash> shared_hcrypthash;
4745 
4746     typedef weak_any<shared_cert_context> weak_cert_context;
4747     typedef weak_any<shared_cert_chain_context> weak_cert_chain_context;
4748     typedef weak_any<shared_hcertstore> weak_hcertstore;
4749     typedef weak_any<shared_hcryptprov> weak_hcryptprov;
4750     typedef weak_any<shared_hcryptkey> weak_hcryptkey;
4751     typedef weak_any<shared_hcrypthash> weak_hcrypthash;
4752 #endif // __WIL__WINCRYPT_H__STL
4753 
4754 
4755 #if defined(__NCRYPT_H__) && !defined(__WIL_NCRYPT_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
4756 #define __WIL_NCRYPT_H__
4757     using ncrypt_deleter = function_deleter<decltype(&::NCryptFreeBuffer), NCryptFreeBuffer>;
4758 
4759     template <typename T>
4760     using unique_ncrypt_ptr = wistd::unique_ptr<T, ncrypt_deleter>;
4761 
4762     typedef unique_any<NCRYPT_PROV_HANDLE, decltype(&::NCryptFreeObject), ::NCryptFreeObject> unique_ncrypt_prov;
4763     typedef unique_any<NCRYPT_KEY_HANDLE, decltype(&::NCryptFreeObject), ::NCryptFreeObject> unique_ncrypt_key;
4764     typedef unique_any<NCRYPT_SECRET_HANDLE, decltype(&::NCryptFreeObject), ::NCryptFreeObject> unique_ncrypt_secret;
4765 #endif // __WIL_NCRYPT_H__
4766 #if defined(__WIL_NCRYPT_H__) && !defined(__WIL_NCRYPT_H_STL) && defined(WIL_RESOURCE_STL)
4767 #define __WIL_NCRYPT_H_STL
4768     typedef shared_any<unique_ncrypt_prov> shared_ncrypt_prov;
4769     typedef shared_any<unique_ncrypt_key> shared_ncrypt_key;
4770     typedef shared_any<unique_ncrypt_secret> shared_ncrypt_secret;
4771 
4772     typedef weak_any<shared_ncrypt_prov> weak_ncrypt_prov;
4773     typedef weak_any<shared_ncrypt_key> weak_ncrypt_key;
4774     typedef weak_any<shared_ncrypt_secret> weak_ncrypt_secret;
4775 #endif // __WIL_NCRYPT_H_STL
4776 
4777 #if defined(__BCRYPT_H__) && !defined(__WIL_BCRYPT_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
4778 #define __WIL_BCRYPT_H__
4779     /// @cond
4780     namespace details
4781     {
4782         inline void __stdcall BCryptCloseAlgorithmProviderNoFlags(_Pre_opt_valid_ _Frees_ptr_opt_ BCRYPT_ALG_HANDLE hAlgorithm) WI_NOEXCEPT
4783         {
4784             if (hAlgorithm)
4785             {
4786                 ::BCryptCloseAlgorithmProvider(hAlgorithm, 0);
4787             }
4788         }
4789     }
4790     /// @endcond
4791 
4792     using bcrypt_deleter = function_deleter<decltype(&::BCryptFreeBuffer), BCryptFreeBuffer>;
4793 
4794     template <typename T>
4795     using unique_bcrypt_ptr = wistd::unique_ptr<T, bcrypt_deleter>;
4796 
4797     typedef unique_any<BCRYPT_ALG_HANDLE, decltype(&details::BCryptCloseAlgorithmProviderNoFlags), details::BCryptCloseAlgorithmProviderNoFlags> unique_bcrypt_algorithm;
4798     typedef unique_any<BCRYPT_HASH_HANDLE, decltype(&::BCryptDestroyHash), ::BCryptDestroyHash> unique_bcrypt_hash;
4799     typedef unique_any<BCRYPT_KEY_HANDLE, decltype(&::BCryptDestroyKey), ::BCryptDestroyKey> unique_bcrypt_key;
4800     typedef unique_any<BCRYPT_SECRET_HANDLE, decltype(&::BCryptDestroySecret), ::BCryptDestroySecret> unique_bcrypt_secret;
4801 #endif // __WIL_BCRYPT_H__
4802 #if defined(__WIL_BCRYPT_H__) && !defined(__WIL_BCRYPT_H_STL) && defined(WIL_RESOURCE_STL)
4803 #define __WIL_BCRYPT_H_STL
4804     typedef shared_any<unique_bcrypt_algorithm> shared_bcrypt_algorithm;
4805     typedef shared_any<unique_bcrypt_hash> shared_bcrypt_hash;
4806     typedef shared_any<unique_bcrypt_key> shared_bcrypt_key;
4807     typedef shared_any<unique_bcrypt_secret> shared_bcrypt_secret;
4808 
4809     typedef weak_any<shared_bcrypt_algorithm> weak_bcrypt_algorithm;
4810     typedef weak_any<shared_bcrypt_hash> weak_bcrypt_hash;
4811     typedef weak_any<unique_bcrypt_key> weak_bcrypt_key;
4812     typedef weak_any<shared_bcrypt_secret> weak_bcrypt_secret;
4813 #endif // __WIL_BCRYPT_H_STL
4814 
4815 
4816 #if defined(__RPCNDR_H__) && !defined(__WIL__RPCNDR_H__) && !defined(WIL_KERNEL_MODE)
4817 #define __WIL__RPCNDR_H__
4818 
4819     //! Function deleter for use with pointers allocated by MIDL_user_allocate
4820     using midl_deleter = function_deleter<decltype(&::MIDL_user_free), MIDL_user_free>;
4821 
4822     //! Unique-ptr holding a type allocated by MIDL_user_alloc or returned from an RPC invocation
4823     template<typename T = void> using unique_midl_ptr = wistd::unique_ptr<T, midl_deleter>;
4824 
4825     //! Unique-ptr for strings allocated by MIDL_user_alloc
4826     using unique_midl_string = unique_midl_ptr<wchar_t>;
4827 #ifndef WIL_NO_ANSI_STRINGS
4828     using unique_midl_ansistring = unique_midl_ptr<char>;
4829 #endif
4830 
4831     namespace details
4832     {
4833         struct midl_allocator
4834         {
4835             static _Ret_opt_bytecap_(size) void* allocate(size_t size) WI_NOEXCEPT
4836             {
4837                 return ::MIDL_user_allocate(size);
4838             }
4839         };
4840 
4841         // Specialization to support construction of unique_midl_string instances
4842         template<> struct string_allocator<unique_midl_string> : midl_allocator {};
4843 
4844 #ifndef WIL_NO_ANSI_STRINGS
4845         template<> struct string_allocator<unique_midl_ansistring> : midl_allocator {};
4846 #endif
4847     }
4848 #endif // __WIL__RPCNDR_H__
4849 
4850 #if defined(_OBJBASE_H_) && !defined(__WIL_OBJBASE_H_) && !defined(WIL_KERNEL_MODE)
4851 #define __WIL_OBJBASE_H_
4852     using cotaskmem_deleter = function_deleter<decltype(&::CoTaskMemFree), ::CoTaskMemFree>;
4853 
4854     template <typename T = void>
4855     using unique_cotaskmem_ptr = wistd::unique_ptr<T, cotaskmem_deleter>;
4856 
4857     template <typename T>
4858     using unique_cotaskmem_array_ptr = unique_array_ptr<T, cotaskmem_deleter>;
4859 
4860     /** Provides `std::make_unique()` semantics for resources allocated with `CoTaskMemAlloc()` in a context that may not throw upon allocation failure.
4861     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()`.
4862     Use `wil::make_unique_nothrow()` when `CoTaskMemAlloc()` is not required.
4863 
4864     Allocations are initialized with placement new and will call constructors (if present), but this does not guarantee initialization.
4865 
4866     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.
4867     ~~~
4868     auto foo = wil::make_unique_cotaskmem_nothrow<Foo>();
4869     if (foo)
4870     {
4871     // initialize allocated Foo object as appropriate
4872     }
4873     ~~~
4874     */
4875     template <typename T, typename... Args>
4876     inline typename wistd::enable_if<!wistd::is_array<T>::value, unique_cotaskmem_ptr<T>>::type make_unique_cotaskmem_nothrow(Args&&... args)
4877     {
4878         static_assert(wistd::is_trivially_destructible<T>::value, "T has a destructor that won't be run when used with this function; use make_unique instead");
4879         unique_cotaskmem_ptr<T> sp(static_cast<T*>(::CoTaskMemAlloc(sizeof(T))));
4880         if (sp)
4881         {
4882             // use placement new to initialize memory from the previous allocation
4883             new (sp.get()) T(wistd::forward<Args>(args)...);
4884         }
4885         return sp;
4886     }
4887 
4888     /** Provides `std::make_unique()` semantics for array resources allocated with `CoTaskMemAlloc()` in a context that may not throw upon allocation failure.
4889     See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details.
4890     ~~~
4891     const size_t size = 42;
4892     auto foos = wil::make_unique_cotaskmem_nothrow<Foo[]>(size);
4893     if (foos)
4894     {
4895     for (auto& elem : wil::make_range(foos.get(), size))
4896     {
4897     // initialize allocated Foo objects as appropriate
4898     }
4899     }
4900     ~~~
4901     */
4902     template <typename T>
4903     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)
4904     {
4905         typedef typename wistd::remove_extent<T>::type E;
4906         static_assert(wistd::is_trivially_destructible<E>::value, "E has a destructor that won't be run when used with this function; use make_unique instead");
4907         FAIL_FAST_IF((__WI_SIZE_MAX / sizeof(E)) < size);
4908         size_t allocSize = sizeof(E) * size;
4909         unique_cotaskmem_ptr<T> sp(static_cast<E*>(::CoTaskMemAlloc(allocSize)));
4910         if (sp)
4911         {
4912             // use placement new to initialize memory from the previous allocation;
4913             // note that array placement new cannot be used as the standard allows for operator new[]
4914             // to consume overhead in the allocation for internal bookkeeping
4915             for (auto& elem : make_range(static_cast<E*>(sp.get()), size))
4916             {
4917                 new (&elem) E();
4918             }
4919         }
4920         return sp;
4921     }
4922 
4923     /** Provides `std::make_unique()` semantics for resources allocated with `CoTaskMemAlloc()` in a context that must fail fast upon allocation failure.
4924     See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details.
4925     ~~~
4926     auto foo = wil::make_unique_cotaskmem_failfast<Foo>();
4927     // initialize allocated Foo object as appropriate
4928     ~~~
4929     */
4930     template <typename T, typename... Args>
4931     inline typename wistd::enable_if<!wistd::is_array<T>::value, unique_cotaskmem_ptr<T>>::type make_unique_cotaskmem_failfast(Args&&... args)
4932     {
4933         unique_cotaskmem_ptr<T> result(make_unique_cotaskmem_nothrow<T>(wistd::forward<Args>(args)...));
4934         FAIL_FAST_IF_NULL_ALLOC(result);
4935         return result;
4936     }
4937 
4938     /** Provides `std::make_unique()` semantics for array resources allocated with `CoTaskMemAlloc()` in a context that must fail fast upon allocation failure.
4939     See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details.
4940     ~~~
4941     const size_t size = 42;
4942     auto foos = wil::make_unique_cotaskmem_failfast<Foo[]>(size);
4943     for (auto& elem : wil::make_range(foos.get(), size))
4944     {
4945     // initialize allocated Foo objects as appropriate
4946     }
4947     ~~~
4948     */
4949     template <typename T>
4950     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)
4951     {
4952         unique_cotaskmem_ptr<T> result(make_unique_cotaskmem_nothrow<T>(size));
4953         FAIL_FAST_IF_NULL_ALLOC(result);
4954         return result;
4955     }
4956 
4957 #ifdef WIL_ENABLE_EXCEPTIONS
4958     /** Provides `std::make_unique()` semantics for resources allocated with `CoTaskMemAlloc()`.
4959     See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details.
4960     ~~~
4961     auto foo = wil::make_unique_cotaskmem<Foo>();
4962     // initialize allocated Foo object as appropriate
4963     ~~~
4964     */
4965     template <typename T, typename... Args>
4966     inline typename wistd::enable_if<!wistd::is_array<T>::value, unique_cotaskmem_ptr<T>>::type make_unique_cotaskmem(Args&&... args)
4967     {
4968         unique_cotaskmem_ptr<T> result(make_unique_cotaskmem_nothrow<T>(wistd::forward<Args>(args)...));
4969         THROW_IF_NULL_ALLOC(result);
4970         return result;
4971     }
4972 
4973     /** Provides `std::make_unique()` semantics for array resources allocated with `CoTaskMemAlloc()`.
4974     See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details.
4975     ~~~
4976     const size_t size = 42;
4977     auto foos = wil::make_unique_cotaskmem<Foo[]>(size);
4978     for (auto& elem : wil::make_range(foos.get(), size))
4979     {
4980     // initialize allocated Foo objects as appropriate
4981     }
4982     ~~~
4983     */
4984     template <typename T>
4985     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)
4986     {
4987         unique_cotaskmem_ptr<T> result(make_unique_cotaskmem_nothrow<T>(size));
4988         THROW_IF_NULL_ALLOC(result);
4989         return result;
4990     }
4991 #endif // WIL_ENABLE_EXCEPTIONS
4992 
4993     typedef unique_any<void*, decltype(&::CoTaskMemFree), ::CoTaskMemFree> unique_cotaskmem;
4994     typedef unique_any<PWSTR, decltype(&::CoTaskMemFree), ::CoTaskMemFree> unique_cotaskmem_string;
4995 #ifndef WIL_NO_ANSI_STRINGS
4996     typedef unique_any<PSTR, decltype(&::CoTaskMemFree), ::CoTaskMemFree> unique_cotaskmem_ansistring;
4997 #endif // WIL_NO_ANSI_STRINGS
4998 
4999     /// @cond
5000     namespace details
5001     {
5002         struct cotaskmem_allocator
5003         {
5004             static _Ret_opt_bytecap_(size) void* allocate(size_t size) WI_NOEXCEPT
5005             {
5006                 return ::CoTaskMemAlloc(size);
5007             }
5008         };
5009 
5010         template<> struct string_allocator<unique_cotaskmem_string> : cotaskmem_allocator {};
5011 
5012 #ifndef WIL_NO_ANSI_STRINGS
5013         template<> struct string_allocator<unique_cotaskmem_ansistring> : cotaskmem_allocator {};
5014 #endif // WIL_NO_ANSI_STRINGS
5015     }
5016     /// @endcond
5017 
5018     inline auto make_cotaskmem_string_nothrow(
5019         _When_((source != nullptr) && length != static_cast<size_t>(-1), _In_reads_(length))
5020         _When_((source != nullptr) && length == static_cast<size_t>(-1), _In_z_)
5021         PCWSTR source, size_t length = static_cast<size_t>(-1)) WI_NOEXCEPT
5022     {
5023         return make_unique_string_nothrow<unique_cotaskmem_string>(source, length);
5024     }
5025 
5026     inline auto make_cotaskmem_string_failfast(
5027         _When_((source != nullptr) && length != static_cast<size_t>(-1), _In_reads_(length))
5028         _When_((source != nullptr) && length == static_cast<size_t>(-1), _In_z_)
5029         PCWSTR source, size_t length = static_cast<size_t>(-1)) WI_NOEXCEPT
5030     {
5031         return make_unique_string_failfast<unique_cotaskmem_string>(source, length);
5032     }
5033 
5034 #ifdef WIL_ENABLE_EXCEPTIONS
5035     inline auto make_cotaskmem_string(
5036         _When_((source != nullptr) && length != static_cast<size_t>(-1), _In_reads_(length))
5037         _When_((source != nullptr) && length == static_cast<size_t>(-1), _In_z_)
5038         PCWSTR source, size_t length = static_cast<size_t>(-1))
5039     {
5040         return make_unique_string<unique_cotaskmem_string>(source, length);
5041     }
5042 
5043 #endif // WIL_ENABLE_EXCEPTIONS
5044 #endif // __WIL_OBJBASE_H_
5045 #if defined(__WIL_OBJBASE_H_) && !defined(__WIL_OBJBASE_H_STL) && defined(WIL_RESOURCE_STL)
5046 #define __WIL_OBJBASE_H_STL
5047     typedef shared_any<unique_cotaskmem> shared_cotaskmem;
5048     typedef weak_any<shared_cotaskmem> weak_cotaskmem;
5049     typedef shared_any<unique_cotaskmem_string> shared_cotaskmem_string;
5050     typedef weak_any<shared_cotaskmem_string> weak_cotaskmem_string;
5051 #endif // __WIL_OBJBASE_H_STL
5052 
5053 #if defined(__WIL_OBJBASE_H_) && defined(__WIL_WINBASE_) && !defined(__WIL_OBJBASE_AND_WINBASE_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
5054 #define __WIL_OBJBASE_AND_WINBASE_H_
5055 
5056     struct cotaskmem_secure_deleter
5057     {
5058         template <typename T>
5059         void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const
5060         {
5061             if (p)
5062             {
5063                 IMalloc* malloc;
5064                 if (SUCCEEDED(::CoGetMalloc(1, &malloc)))
5065                 {
5066                     size_t const size = malloc->GetSize(p);
5067                     if (size != static_cast<size_t>(-1))
5068                     {
5069                         ::SecureZeroMemory(p, size);
5070                     }
5071                     malloc->Release();
5072                 }
5073                 ::CoTaskMemFree(p);
5074             }
5075         }
5076     };
5077 
5078     template <typename T = void>
5079     using unique_cotaskmem_secure_ptr = wistd::unique_ptr<T, cotaskmem_secure_deleter>;
5080 
5081     /** Provides `std::make_unique()` semantics for secure resources allocated with `CoTaskMemAlloc()` in a context that may not throw upon allocation failure.
5082     See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details.
5083     ~~~
5084     auto foo = wil::make_unique_cotaskmem_secure_nothrow<Foo>();
5085     if (foo)
5086     {
5087     // initialize allocated Foo object as appropriate
5088     }
5089     ~~~
5090     */
5091     template <typename T, typename... Args>
5092     inline typename wistd::enable_if<!wistd::is_array<T>::value, unique_cotaskmem_secure_ptr<T>>::type make_unique_cotaskmem_secure_nothrow(Args&&... args)
5093     {
5094         return unique_cotaskmem_secure_ptr<T>(make_unique_cotaskmem_nothrow<T>(wistd::forward<Args>(args)...).release());
5095     }
5096 
5097     /** Provides `std::make_unique()` semantics for secure array resources allocated with `CoTaskMemAlloc()` in a context that may not throw upon allocation failure.
5098     See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details.
5099     ~~~
5100     const size_t size = 42;
5101     auto foos = wil::make_unique_cotaskmem_secure_nothrow<Foo[]>(size);
5102     if (foos)
5103     {
5104     for (auto& elem : wil::make_range(foos.get(), size))
5105     {
5106     // initialize allocated Foo objects as appropriate
5107     }
5108     }
5109     ~~~
5110     */
5111     template <typename T>
5112     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)
5113     {
5114         return unique_cotaskmem_secure_ptr<T>(make_unique_cotaskmem_nothrow<T>(size).release());
5115     }
5116 
5117     /** Provides `std::make_unique()` semantics for secure resources allocated with `CoTaskMemAlloc()` in a context that must fail fast upon allocation failure.
5118     See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details.
5119     ~~~
5120     auto foo = wil::make_unique_cotaskmem_secure_failfast<Foo>();
5121     // initialize allocated Foo object as appropriate
5122     ~~~
5123     */
5124     template <typename T, typename... Args>
5125     inline typename wistd::enable_if<!wistd::is_array<T>::value, unique_cotaskmem_secure_ptr<T>>::type make_unique_cotaskmem_secure_failfast(Args&&... args)
5126     {
5127         unique_cotaskmem_secure_ptr<T> result(make_unique_cotaskmem_secure_nothrow<T>(wistd::forward<Args>(args)...));
5128         FAIL_FAST_IF_NULL_ALLOC(result);
5129         return result;
5130     }
5131 
5132     /** Provides `std::make_unique()` semantics for secure array resources allocated with `CoTaskMemAlloc()` in a context that must fail fast upon allocation failure.
5133     See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details.
5134     ~~~
5135     const size_t size = 42;
5136     auto foos = wil::make_unique_cotaskmem_secure_failfast<Foo[]>(size);
5137     for (auto& elem : wil::make_range(foos.get(), size))
5138     {
5139     // initialize allocated Foo objects as appropriate
5140     }
5141     ~~~
5142     */
5143     template <typename T>
5144     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)
5145     {
5146         unique_cotaskmem_secure_ptr<T> result(make_unique_cotaskmem_secure_nothrow<T>(size));
5147         FAIL_FAST_IF_NULL_ALLOC(result);
5148         return result;
5149     }
5150 
5151 #ifdef WIL_ENABLE_EXCEPTIONS
5152     /** Provides `std::make_unique()` semantics for secure resources allocated with `CoTaskMemAlloc()`.
5153     See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details.
5154     ~~~
5155     auto foo = wil::make_unique_cotaskmem_secure<Foo>();
5156     // initialize allocated Foo object as appropriate
5157     ~~~
5158     */
5159     template <typename T, typename... Args>
5160     inline typename wistd::enable_if<!wistd::is_array<T>::value, unique_cotaskmem_secure_ptr<T>>::type make_unique_cotaskmem_secure(Args&&... args)
5161     {
5162         unique_cotaskmem_secure_ptr<T> result(make_unique_cotaskmem_secure_nothrow<T>(wistd::forward<Args>(args)...));
5163         THROW_IF_NULL_ALLOC(result);
5164         return result;
5165     }
5166 
5167     /** Provides `std::make_unique()` semantics for secure array resources allocated with `CoTaskMemAlloc()`.
5168     See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details.
5169     ~~~
5170     const size_t size = 42;
5171     auto foos = wil::make_unique_cotaskmem_secure<Foo[]>(size);
5172     for (auto& elem : wil::make_range(foos.get(), size))
5173     {
5174     // initialize allocated Foo objects as appropriate
5175     }
5176     ~~~
5177     */
5178     template <typename T>
5179     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)
5180     {
5181         unique_cotaskmem_secure_ptr<T> result(make_unique_cotaskmem_secure_nothrow<T>(size));
5182         THROW_IF_NULL_ALLOC(result);
5183         return result;
5184     }
5185 #endif // WIL_ENABLE_EXCEPTIONS
5186 
5187     typedef unique_cotaskmem_secure_ptr<wchar_t[]> unique_cotaskmem_string_secure;
5188 
5189     /** Copies a given string into secure memory allocated with `CoTaskMemAlloc()` in a context that may not throw upon allocation failure.
5190     See the overload of `wil::make_cotaskmem_string_nothrow()` with supplied length for more details.
5191     ~~~
5192     auto str = wil::make_cotaskmem_string_secure_nothrow(L"a string");
5193     if (str)
5194     {
5195     std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string"
5196     }
5197     ~~~
5198     */
5199     inline unique_cotaskmem_string_secure make_cotaskmem_string_secure_nothrow(_In_ PCWSTR source) WI_NOEXCEPT
5200     {
5201         return unique_cotaskmem_string_secure(make_cotaskmem_string_nothrow(source).release());
5202     }
5203 
5204     /** Copies a given string into secure memory allocated with `CoTaskMemAlloc()` in a context that must fail fast upon allocation failure.
5205     See the overload of `wil::make_cotaskmem_string_nothrow()` with supplied length for more details.
5206     ~~~
5207     auto str = wil::make_cotaskmem_string_secure_failfast(L"a string");
5208     std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string"
5209     ~~~
5210     */
5211     inline unique_cotaskmem_string_secure make_cotaskmem_string_secure_failfast(_In_ PCWSTR source) WI_NOEXCEPT
5212     {
5213         unique_cotaskmem_string_secure result(make_cotaskmem_string_secure_nothrow(source));
5214         FAIL_FAST_IF_NULL_ALLOC(result);
5215         return result;
5216     }
5217 
5218 #ifdef WIL_ENABLE_EXCEPTIONS
5219     /** Copies a given string into secure memory allocated with `CoTaskMemAlloc()`.
5220     See the overload of `wil::make_cotaskmem_string_nothrow()` with supplied length for more details.
5221     ~~~
5222     auto str = wil::make_cotaskmem_string_secure(L"a string");
5223     std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string"
5224     ~~~
5225     */
5226     inline unique_cotaskmem_string_secure make_cotaskmem_string_secure(_In_ PCWSTR source)
5227     {
5228         unique_cotaskmem_string_secure result(make_cotaskmem_string_secure_nothrow(source));
5229         THROW_IF_NULL_ALLOC(result);
5230         return result;
5231     }
5232 #endif
5233 #endif // __WIL_OBJBASE_AND_WINBASE_H_
5234 
5235 #if defined(_OLE2_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(__WIL_OLE2_H_) && !defined(WIL_KERNEL_MODE)
5236 #define __WIL_OLE2_H_
5237     typedef unique_struct<STGMEDIUM, decltype(&::ReleaseStgMedium), ::ReleaseStgMedium> unique_stg_medium;
5238     struct unique_hglobal_locked : public unique_any<void*, decltype(&::GlobalUnlock), ::GlobalUnlock>
5239     {
5240         unique_hglobal_locked() = delete;
5241 
5242         explicit unique_hglobal_locked(HGLOBAL global) : unique_any<void*, decltype(&::GlobalUnlock), ::GlobalUnlock>(global)
5243         {
5244             // GlobalLock returns a pointer to the associated global memory block and that's what callers care about.
5245             m_globalMemory = GlobalLock(global);
5246             if (!m_globalMemory)
5247             {
5248                 release();
5249             }
5250         }
5251 
5252         explicit unique_hglobal_locked(unique_hglobal& global) : unique_hglobal_locked(global.get())
5253         {
5254         }
5255 
5256         explicit unique_hglobal_locked(STGMEDIUM& medium) : unique_hglobal_locked(medium.hGlobal)
5257         {
5258         }
5259 
5260         pointer get() const
5261         {
5262             return m_globalMemory;
5263         }
5264 
5265     private:
5266         pointer m_globalMemory;
5267     };
5268 
5269     //! A type that calls OleUninitialize on destruction (or reset()).
5270     //! Use as a replacement for Windows::Foundation::Uninitialize.
5271     using unique_oleuninitialize_call = unique_call<decltype(&::OleUninitialize), ::OleUninitialize>;
5272 
5273     //! Calls RoInitialize and fail-fasts if it fails; returns an RAII object that reverts
5274     //! Use as a replacement for Windows::Foundation::Initialize
5275     _Check_return_ inline unique_oleuninitialize_call OleInitialize_failfast()
5276     {
5277         FAIL_FAST_IF_FAILED(::OleInitialize(nullptr));
5278         return unique_oleuninitialize_call();
5279     }
5280 #endif // __WIL_OLE2_H_
5281 
5282 #if defined(__WIL_OLE2_H_) && defined(WIL_ENABLE_EXCEPTIONS) && !defined(__WIL_OLE2_H_EXCEPTIONAL)
5283 #define __WIL_OLE2_H_EXCEPTIONAL
5284     //! Calls RoInitialize and throws an exception if it fails; returns an RAII object that reverts
5285     //! Use as a replacement for Windows::Foundation::Initialize
5286     _Check_return_ inline unique_oleuninitialize_call OleInitialize()
5287     {
5288         THROW_IF_FAILED(::OleInitialize(nullptr));
5289         return unique_oleuninitialize_call();
5290     }
5291 #endif
5292 
5293 #if defined(_INC_COMMCTRL) && !defined(__WIL_INC_COMMCTRL) && !defined(WIL_KERNEL_MODE)
5294 #define __WIL_INC_COMMCTRL
5295     typedef unique_any<HIMAGELIST, decltype(&::ImageList_Destroy), ::ImageList_Destroy> unique_himagelist;
5296 #endif // __WIL_INC_COMMCTRL
5297 #if defined(__WIL_INC_COMMCTRL) && !defined(__WIL_INC_COMMCTRL_STL) && defined(WIL_RESOURCE_STL)
5298 #define __WIL_INC_COMMCTRL_STL
5299     typedef shared_any<unique_himagelist> shared_himagelist;
5300     typedef weak_any<shared_himagelist> weak_himagelist;
5301 #endif // __WIL_INC_COMMCTRL_STL
5302 
5303 #if defined(_UXTHEME_H_) && !defined(__WIL_INC_UXTHEME) && !defined(WIL_KERNEL_MODE)
5304 #define __WIL_INC_UXTHEME
5305     typedef unique_any<HTHEME, decltype(&::CloseThemeData), ::CloseThemeData> unique_htheme;
5306 #endif // __WIL_INC_UXTHEME
5307 
5308 #if defined(_WINSVC_) && !defined(__WIL_HANDLE_H_WINSVC) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(WIL_KERNEL_MODE)
5309 #define __WIL_HANDLE_H_WINSVC
5310     typedef unique_any<SC_HANDLE, decltype(&::CloseServiceHandle), ::CloseServiceHandle> unique_schandle;
5311 #endif // __WIL_HANDLE_H_WINSVC
5312 #if defined(__WIL_HANDLE_H_WINSVC) && !defined(__WIL_HANDLE_H_WINSVC_STL) && defined(WIL_RESOURCE_STL)
5313 #define __WIL_HANDLE_H_WINSVC_STL
5314     typedef shared_any<unique_schandle> shared_schandle;
5315     typedef weak_any<shared_schandle> weak_schandle;
5316 #endif // __WIL_HANDLE_H_WINSVC_STL
5317 
5318 #if defined(_INC_STDIO) && !defined(__WIL_INC_STDIO) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(WIL_KERNEL_MODE)
5319 #define __WIL_INC_STDIO
5320     typedef unique_any<FILE*, decltype(&::_pclose), ::_pclose> unique_pipe;
5321     typedef unique_any<FILE*, decltype(&::fclose), ::fclose> unique_file;
5322 #endif // __WIL_INC_STDIO
5323 #if defined(__WIL_INC_STDIO) && !defined(__WIL__INC_STDIO_STL) && defined(WIL_RESOURCE_STL)
5324 #define __WIL__INC_STDIO_STL
5325     typedef shared_any<unique_pipe> shared_pipe;
5326     typedef weak_any<shared_pipe> weak_pipe;
5327     typedef shared_any<unique_file> shared_file;
5328     typedef weak_any<unique_file> weak_file;
5329 #endif // __WIL__INC_STDIO_STL
5330 
5331 #if defined(_NTLSA_) && !defined(__WIL_NTLSA_) && !defined(WIL_KERNEL_MODE)
5332 #define __WIL_NTLSA_
5333     typedef unique_any<LSA_HANDLE, decltype(&::LsaClose), ::LsaClose> unique_hlsa;
5334 
5335     using lsa_freemem_deleter = function_deleter<decltype(&::LsaFreeMemory), LsaFreeMemory>;
5336 
5337     template <typename T>
5338     using unique_lsamem_ptr = wistd::unique_ptr<T, lsa_freemem_deleter>;
5339 #endif // _NTLSA_
5340 #if defined(_NTLSA_) && !defined(__WIL_NTLSA_STL) && defined(WIL_RESOURCE_STL)
5341 #define __WIL_NTLSA_STL
5342     typedef shared_any<unique_hlsa> shared_hlsa;
5343     typedef weak_any<shared_hlsa> weak_hlsa;
5344 #endif // _NTLSA_
5345 
5346 #if defined(_LSALOOKUP_) && !defined(__WIL_LSALOOKUP_)
5347 #define __WIL_LSALOOKUP_
5348     typedef unique_any<LSA_HANDLE, decltype(&::LsaLookupClose), ::LsaLookupClose> unique_hlsalookup;
5349 
5350     using lsalookup_freemem_deleter = function_deleter<decltype(&::LsaLookupFreeMemory), LsaLookupFreeMemory>;
5351 
5352     template <typename T>
5353     using unique_lsalookupmem_ptr = wistd::unique_ptr<T, lsalookup_freemem_deleter>;
5354 #endif // _LSALOOKUP_
5355 #if defined(_LSALOOKUP_) && !defined(__WIL_LSALOOKUP_STL) && defined(WIL_RESOURCE_STL)
5356 #define __WIL_LSALOOKUP_STL
5357     typedef shared_any<unique_hlsalookup> shared_hlsalookup;
5358     typedef weak_any<shared_hlsalookup> weak_hlsalookup;
5359 #endif // _LSALOOKUP_
5360 
5361 #if defined(_NTLSA_IFS_) && !defined(__WIL_HANDLE_H_NTLSA_IFS_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
5362 #define __WIL_HANDLE_H_NTLSA_IFS_
5363     using lsa_deleter = function_deleter<decltype(&::LsaFreeReturnBuffer), LsaFreeReturnBuffer>;
5364 
5365     template <typename T>
5366     using unique_lsa_ptr = wistd::unique_ptr<T, lsa_deleter>;
5367 #endif // __WIL_HANDLE_H_NTLSA_IFS_
5368 
5369 #if defined(__WERAPI_H__) && !defined(__WIL_WERAPI_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
5370 #define __WIL_WERAPI_H__
5371     typedef unique_any<HREPORT, decltype(&WerReportCloseHandle), WerReportCloseHandle> unique_wer_report;
5372 #endif
5373 
5374 #if defined(__MIDLES_H__) && !defined(__WIL_MIDLES_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
5375 #define __WIL_MIDLES_H__
5376     typedef unique_any<handle_t, decltype(&::MesHandleFree), ::MesHandleFree> unique_rpc_pickle;
5377 #endif
5378 #if defined(__WIL_MIDLES_H__) && !defined(__WIL_MIDLES_H_STL) && defined(WIL_RESOURCE_STL)
5379 #define __WIL_MIDLES_H_STL
5380     typedef shared_any<unique_rpc_pickle> shared_rpc_pickle;
5381     typedef weak_any<shared_rpc_pickle> weak_rpc_pickle;
5382 #endif
5383 
5384 #if defined(__RPCDCE_H__) && !defined(__WIL_RPCDCE_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
5385 #define __WIL_RPCDCE_H__
5386     /// @cond
5387     namespace details
5388     {
5389         inline void __stdcall WpRpcBindingFree(_Pre_opt_valid_ _Frees_ptr_opt_ RPC_BINDING_HANDLE binding)
5390         {
5391             ::RpcBindingFree(&binding);
5392         }
5393 
5394         inline void __stdcall WpRpcBindingVectorFree(_Pre_opt_valid_ _Frees_ptr_opt_ RPC_BINDING_VECTOR* bindingVector)
5395         {
5396             ::RpcBindingVectorFree(&bindingVector);
5397         }
5398 
5399         inline void __stdcall WpRpcStringFree(_Pre_opt_valid_ _Frees_ptr_opt_ RPC_WSTR wstr)
5400         {
5401             ::RpcStringFreeW(&wstr);
5402         }
5403     }
5404     /// @endcond
5405 
5406     typedef unique_any<RPC_BINDING_HANDLE, decltype(&details::WpRpcBindingFree), details::WpRpcBindingFree> unique_rpc_binding;
5407     typedef unique_any<RPC_BINDING_VECTOR*, decltype(&details::WpRpcBindingVectorFree), details::WpRpcBindingVectorFree> unique_rpc_binding_vector;
5408     typedef unique_any<RPC_WSTR, decltype(&details::WpRpcStringFree), details::WpRpcStringFree> unique_rpc_wstr;
5409 #endif
5410 #if defined(__WIL_RPCDCE_H__) && !defined(__WIL_RPCDCE_H_STL) && defined(WIL_RESOURCE_STL)
5411 #define __WIL_RPCDCE_H_STL
5412     typedef shared_any<unique_rpc_binding> shared_rpc_binding;
5413     typedef weak_any<shared_rpc_binding> weak_rpc_binding;
5414     typedef shared_any<unique_rpc_binding_vector> shared_rpc_binding_vector;
5415     typedef weak_any<shared_rpc_binding_vector> weak_rpc_binding_vector;
5416     typedef shared_any<unique_rpc_wstr> shared_rpc_wstr;
5417     typedef weak_any<unique_rpc_wstr> weak_rpc_wstr;
5418 #endif
5419 
5420 #if defined(_WCMAPI_H) && !defined(__WIL_WCMAPI_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
5421 #define __WIL_WCMAPI_H_
5422     using wcm_deleter = function_deleter<decltype(&::WcmFreeMemory), WcmFreeMemory>;
5423 
5424     template<typename T>
5425     using unique_wcm_ptr = wistd::unique_ptr<T, wcm_deleter>;
5426 #endif
5427 
5428 #if defined(_NETIOAPI_H_) && defined(_WS2IPDEF_) && defined(MIB_INVALID_TEREDO_PORT_NUMBER) && !defined(__WIL_NETIOAPI_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
5429 #define __WIL_NETIOAPI_H_
5430     typedef unique_any<PMIB_IF_TABLE2, decltype(&::FreeMibTable), ::FreeMibTable> unique_mib_iftable;
5431 #endif
5432 #if defined(__WIL_NETIOAPI_H_) && !defined(__WIL_NETIOAPI_H_STL) && defined(WIL_RESOURCE_STL)
5433 #define __WIL_NETIOAPI_H_STL
5434     typedef shared_any<unique_mib_iftable> shared_mib_iftable;
5435     typedef weak_any<shared_mib_iftable> weak_mib_iftable;
5436 #endif
5437 
5438 #if defined(_WLAN_WLANAPI_H) && !defined(__WIL_WLAN_WLANAPI_H) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
5439 #define __WIL_WLAN_WLANAPI_H
5440     using wlan_deleter = function_deleter<decltype(&::WlanFreeMemory), ::WlanFreeMemory>;
5441 
5442     template<typename T>
5443     using unique_wlan_ptr = wistd::unique_ptr < T, wlan_deleter >;
5444 
5445     /// @cond
5446     namespace details
5447     {
5448         inline void __stdcall CloseWlanHandle(_Frees_ptr_ HANDLE hClientHandle)
5449         {
5450             ::WlanCloseHandle(hClientHandle, nullptr);
5451         }
5452     }
5453     /// @endcond
5454 
5455     typedef unique_any<HANDLE, decltype(&details::CloseWlanHandle), details::CloseWlanHandle, details::pointer_access_all, HANDLE, INT_PTR, -1> unique_wlan_handle;
5456 #endif
5457 #if defined(__WIL_WLAN_WLANAPI_H) && !defined(__WIL_WLAN_WLANAPI_H_STL) && defined(WIL_RESOURCE_STL)
5458 #define __WIL_WLAN_WLANAPI_H_STL
5459     typedef shared_any<unique_wlan_handle> shared_wlan_handle;
5460     typedef weak_any<shared_wlan_handle> weak_wlan_handle;
5461 #endif
5462 
5463 #if defined(_HPOWERNOTIFY_DEF_) && !defined(__WIL_HPOWERNOTIFY_DEF_H_) && !defined(WIL_KERNEL_MODE)
5464 #define __WIL_HPOWERNOTIFY_DEF_H_
5465     typedef unique_any<HPOWERNOTIFY, decltype(&::UnregisterPowerSettingNotification), ::UnregisterPowerSettingNotification> unique_hpowernotify;
5466 #endif
5467 
5468 #if defined(__WIL_WINBASE_DESKTOP) && defined(SID_DEFINED) && !defined(__WIL_PSID_DEF_H_)
5469 #define __WIL_PSID_DEF_H_
5470     typedef unique_any<PSID, decltype(&::LocalFree), ::LocalFree> unique_any_psid;
5471 #if defined(_OBJBASE_H_)
5472     typedef unique_any<PSID, decltype(&::CoTaskMemFree), ::CoTaskMemFree> unique_cotaskmem_psid;
5473 #endif
5474 #endif
5475 
5476 #if defined(_PROCESSTHREADSAPI_H_) && !defined(__WIL_PROCESSTHREADSAPI_H_DESK_SYS) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && !defined(WIL_KERNEL_MODE)
5477 #define __WIL_PROCESSTHREADSAPI_H_DESK_SYS
5478     /// @cond
5479     namespace details
5480     {
5481         inline void __stdcall CloseProcessInformation(_In_ PROCESS_INFORMATION* p)
5482         {
5483             if (p->hProcess)
5484             {
5485                 CloseHandle(p->hProcess);
5486             }
5487 
5488             if (p->hThread)
5489             {
5490                 CloseHandle(p->hThread);
5491             }
5492         }
5493     }
5494     /// @endcond
5495 
5496     /** Manages the outbound parameter containing handles returned by `CreateProcess()` and related methods.
5497     ~~~
5498     unique_process_information process;
5499     CreateProcessW(..., CREATE_SUSPENDED, ..., &process);
5500     THROW_IF_WIN32_BOOL_FALSE(ResumeThread(process.hThread));
5501     THROW_LAST_ERROR_IF(WaitForSingleObject(process.hProcess, INFINITE) != WAIT_OBJECT_0);
5502     ~~~
5503     */
5504     using unique_process_information = unique_struct<PROCESS_INFORMATION, decltype(&details::CloseProcessInformation), details::CloseProcessInformation>;
5505 #endif
5506 
5507 #if defined(_PROCESSENV_) && !defined(__WIL__PROCESSENV_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
5508 #define __WIL__PROCESSENV_
5509     /** Manages lifecycle of an environment-strings block
5510     ~~~
5511     wil::unique_environstrings_ptr env { ::GetEnvironmentStringsW() };
5512     const wchar_t *nextVar = env.get();
5513     while (nextVar && *nextVar)
5514     {
5515         // consume 'nextVar'
5516         nextVar += wcslen(nextVar) + 1;
5517     }
5518     ~~~
5519     */
5520     using unique_environstrings_ptr = wistd::unique_ptr<wchar_t, function_deleter<decltype(&::FreeEnvironmentStringsW), FreeEnvironmentStringsW>>;
5521 
5522 #ifndef WIL_NO_ANSI_STRINGS
5523     //! ANSI equivalent to unique_environstrings_ptr;
5524     using unique_environansistrings_ptr = wistd::unique_ptr<char, function_deleter<decltype(&::FreeEnvironmentStringsA), FreeEnvironmentStringsA>>;
5525 #endif
5526 #endif
5527 
5528 #if defined(_APPMODEL_H_) && !defined(__WIL_APPMODEL_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
5529 #define __WIL_APPMODEL_H_
5530     typedef unique_any<PACKAGE_INFO_REFERENCE, decltype(&::ClosePackageInfo), ::ClosePackageInfo> unique_package_info_reference;
5531 #endif // __WIL_APPMODEL_H_
5532 #if defined(__WIL_APPMODEL_H_) && !defined(__WIL_APPMODEL_H_STL) && defined(WIL_RESOURCE_STL)
5533 #define __WIL_APPMODEL_H_STL
5534     typedef shared_any<unique_package_info_reference> shared_package_info_reference;
5535     typedef weak_any<shared_package_info_reference> weak_package_info_reference;
5536 #endif // __WIL_APPMODEL_H_STL
5537 
5538 #if defined(WDFAPI) && !defined(__WIL_WDFAPI)
5539 #define __WIL_WDFAPI
5540 
5541     namespace details
5542     {
5543         template<typename TWDFOBJECT>
5544         using wdf_object_resource_policy = resource_policy<TWDFOBJECT, decltype(&::WdfObjectDelete), &::WdfObjectDelete>;
5545     }
5546 
5547     template<typename TWDFOBJECT>
5548     using unique_wdf_any = unique_any_t<details::unique_storage<details::wdf_object_resource_policy<TWDFOBJECT>>>;
5549 
5550     using unique_wdf_object          = unique_wdf_any<WDFOBJECT>;
5551 
5552     using unique_wdf_timer           = unique_wdf_any<WDFTIMER>;
5553     using unique_wdf_work_item       = unique_wdf_any<WDFWORKITEM>;
5554 
5555     using unique_wdf_memory          = unique_wdf_any<WDFMEMORY>;
5556 
5557     using unique_wdf_dma_enabler     = unique_wdf_any<WDFDMAENABLER>;
5558     using unique_wdf_dma_transaction = unique_wdf_any<WDFDMATRANSACTION>;
5559     using unique_wdf_common_buffer   = unique_wdf_any<WDFCOMMONBUFFER>;
5560 
5561     using unique_wdf_key             = unique_wdf_any<WDFKEY>;
5562     using unique_wdf_string          = unique_wdf_any<WDFSTRING>;
5563     using unique_wdf_collection      = unique_wdf_any<WDFCOLLECTION>;
5564 
5565     using wdf_wait_lock_release_scope_exit =
5566         unique_any<
5567             WDFWAITLOCK,
5568             decltype(&::WdfWaitLockRelease),
5569             ::WdfWaitLockRelease,
5570             details::pointer_access_none>;
5571 
5572     inline
5573     WI_NODISCARD
5574     _IRQL_requires_max_(PASSIVE_LEVEL)
5575     _Acquires_lock_(lock)
5576     wdf_wait_lock_release_scope_exit
5577     acquire_wdf_wait_lock(WDFWAITLOCK lock) WI_NOEXCEPT
5578     {
5579         ::WdfWaitLockAcquire(lock, nullptr);
5580         return wdf_wait_lock_release_scope_exit(lock);
5581     }
5582 
5583     inline
5584     WI_NODISCARD
5585     _IRQL_requires_max_(APC_LEVEL)
5586     _When_(return, _Acquires_lock_(lock))
5587     wdf_wait_lock_release_scope_exit
5588     try_acquire_wdf_wait_lock(WDFWAITLOCK lock) WI_NOEXCEPT
5589     {
5590         LONGLONG timeout = 0;
5591         NTSTATUS status = ::WdfWaitLockAcquire(lock, &timeout);
5592         if (status == STATUS_SUCCESS)
5593         {
5594             return wdf_wait_lock_release_scope_exit(lock);
5595         }
5596         else
5597         {
5598             return wdf_wait_lock_release_scope_exit();
5599         }
5600     }
5601 
5602     using wdf_spin_lock_release_scope_exit =
5603         unique_any<
5604             WDFSPINLOCK,
5605             decltype(&::WdfSpinLockRelease),
5606             ::WdfSpinLockRelease,
5607             details::pointer_access_none>;
5608 
5609     inline
5610     WI_NODISCARD
5611     _IRQL_requires_max_(DISPATCH_LEVEL)
5612     _IRQL_raises_(DISPATCH_LEVEL)
5613     _Acquires_lock_(lock)
5614     wdf_spin_lock_release_scope_exit
5615     acquire_wdf_spin_lock(WDFSPINLOCK lock) WI_NOEXCEPT
5616     {
5617         ::WdfSpinLockAcquire(lock);
5618         return wdf_spin_lock_release_scope_exit(lock);
5619     }
5620 
5621     namespace details
5622     {
5623         template<typename TWDFLOCK>
5624         using unique_wdf_lock_storage = unique_storage<wdf_object_resource_policy<TWDFLOCK>>;
5625 
5626         class unique_wdf_spin_lock_storage : public unique_wdf_lock_storage<WDFSPINLOCK>
5627         {
5628             using wdf_lock_storage_t = unique_wdf_lock_storage<WDFSPINLOCK>;
5629 
5630         public:
5631 
5632             using pointer = wdf_lock_storage_t::pointer;
5633 
5634             // Forward all base class constructors, but have it be explicit.
5635             template <typename... args_t>
5636             explicit unique_wdf_spin_lock_storage(args_t&& ... args) WI_NOEXCEPT : wdf_lock_storage_t(wistd::forward<args_t>(args)...) {}
5637 
5638             NTSTATUS create(_In_opt_ WDF_OBJECT_ATTRIBUTES* attributes = WDF_NO_OBJECT_ATTRIBUTES)
5639             {
5640                 return ::WdfSpinLockCreate(attributes, out_param(*this));
5641             }
5642 
5643             WI_NODISCARD
5644             _IRQL_requires_max_(DISPATCH_LEVEL)
5645             _IRQL_raises_(DISPATCH_LEVEL)
5646             wdf_spin_lock_release_scope_exit acquire() WI_NOEXCEPT
5647             {
5648                 return wil::acquire_wdf_spin_lock(wdf_lock_storage_t::get());
5649             }
5650         };
5651 
5652         class unique_wdf_wait_lock_storage : public unique_wdf_lock_storage<WDFWAITLOCK>
5653         {
5654             using wdf_lock_storage_t = unique_wdf_lock_storage<WDFWAITLOCK>;
5655 
5656         public:
5657 
5658             using pointer = wdf_lock_storage_t::pointer;
5659 
5660             // Forward all base class constructors, but have it be explicit.
5661             template <typename... args_t>
5662             explicit unique_wdf_wait_lock_storage(args_t&& ... args) WI_NOEXCEPT : wdf_lock_storage_t(wistd::forward<args_t>(args)...) {}
5663 
5664             NTSTATUS create(_In_opt_ WDF_OBJECT_ATTRIBUTES* attributes = WDF_NO_OBJECT_ATTRIBUTES)
5665             {
5666                 return ::WdfWaitLockCreate(attributes, out_param(*this));
5667             }
5668 
5669             WI_NODISCARD
5670             _IRQL_requires_max_(PASSIVE_LEVEL)
5671             wdf_wait_lock_release_scope_exit acquire() WI_NOEXCEPT
5672             {
5673                 return wil::acquire_wdf_wait_lock(wdf_lock_storage_t::get());
5674             }
5675 
5676             WI_NODISCARD
5677             _IRQL_requires_max_(APC_LEVEL)
5678             wdf_wait_lock_release_scope_exit try_acquire() WI_NOEXCEPT
5679             {
5680                 return wil::try_acquire_wdf_wait_lock(wdf_lock_storage_t::get());
5681             }
5682         };
5683     }
5684 
5685     using unique_wdf_wait_lock = unique_any_t<details::unique_wdf_wait_lock_storage>;
5686     using unique_wdf_spin_lock = unique_any_t<details::unique_wdf_spin_lock_storage>;
5687 
5688     template<typename TWDFOBJECT>
5689     struct wdf_object_reference
5690     {
5691         TWDFOBJECT wdfObject = WDF_NO_HANDLE;
5692         PVOID tag = nullptr;
5693 
5694         wdf_object_reference() WI_NOEXCEPT = default;
5695 
5696         wdf_object_reference(TWDFOBJECT wdfObject, PVOID tag = nullptr) WI_NOEXCEPT
5697             : wdfObject(wdfObject), tag(tag)
5698         {
5699         }
5700 
5701         operator TWDFOBJECT() const WI_NOEXCEPT
5702         {
5703             return wdfObject;
5704         }
5705 
5706         static void close(const wdf_object_reference& wdfObjectReference) WI_NOEXCEPT
5707         {
5708             // We don't use WdfObjectDereferenceActual because there is no way to provide the
5709             // correct __LINE__ and __FILE__, but if you use RAII all the way, you shouldn't have to
5710             // worry about where it was released, only where it was acquired.
5711             WdfObjectDereferenceWithTag(wdfObjectReference.wdfObject, wdfObjectReference.tag);
5712         }
5713     };
5714 
5715     template<typename TWDFOBJECT>
5716     using unique_wdf_object_reference = unique_any<TWDFOBJECT, decltype(wdf_object_reference<TWDFOBJECT>::close),
5717         &wdf_object_reference<TWDFOBJECT>::close, details::pointer_access_noaddress, wdf_object_reference<TWDFOBJECT>>;
5718 
5719     // Increment the ref-count on a WDF object a unique_wdf_object_reference for it. Use
5720     // WI_WdfObjectReferenceIncrement to automatically use the call-site source location. Use this
5721     // function only if the call-site source location is obtained from elsewhere (i.e., plumbed
5722     // through other abstractions).
5723     template<typename TWDFOBJECT>
5724     inline WI_NODISCARD unique_wdf_object_reference<TWDFOBJECT> wdf_object_reference_increment(
5725         TWDFOBJECT wdfObject, PVOID tag, LONG lineNumber, PCSTR fileName) WI_NOEXCEPT
5726     {
5727         // Parameter is incorrectly marked as non-const, so the const-cast is required.
5728         ::WdfObjectReferenceActual(wdfObject, tag, lineNumber, const_cast<char*>(fileName));
5729         return unique_wdf_object_reference<TWDFOBJECT>{ wdf_object_reference<TWDFOBJECT>{ wdfObject, tag } };
5730     }
5731 
5732 // A macro so that we can capture __LINE__ and __FILE__.
5733 #define WI_WdfObjectReferenceIncrement(wdfObject, tag) \
5734     wil::wdf_object_reference_increment(wdfObject, tag, __LINE__, __FILE__)
5735 
5736 #endif
5737 
5738 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && \
5739     defined(_CFGMGR32_H_) && \
5740     (WINVER >= _WIN32_WINNT_WIN8) && \
5741     !defined(__WIL_CFGMGR32_H_)
5742 #define __WIL_CFGMGR32_H_
5743     typedef unique_any<HCMNOTIFICATION, decltype(&::CM_Unregister_Notification), ::CM_Unregister_Notification> unique_hcmnotification;
5744 #endif
5745 
5746 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && \
5747     defined(_SWDEVICE_H_) && \
5748     (WINVER >= _WIN32_WINNT_WIN8) && \
5749     !defined(__WIL_SWDEVICE_H_)
5750 #define __WIL_SWDEVICE_H_
5751         typedef unique_any<HSWDEVICE, decltype(&::SwDeviceClose), ::SwDeviceClose> unique_hswdevice;
5752 #endif
5753 
5754 #if defined(WIL_KERNEL_MODE) && (defined(_WDMDDK_) || defined(_NTDDK_)) && !defined(__WIL_RESOURCE_WDM)
5755 #define __WIL_RESOURCE_WDM
5756 
5757     namespace details
5758     {
5759         struct kspin_lock_saved_irql
5760         {
5761             PKSPIN_LOCK spinLock = nullptr;
5762             KIRQL savedIrql = PASSIVE_LEVEL;
5763 
5764             kspin_lock_saved_irql() = default;
5765 
5766             kspin_lock_saved_irql(PKSPIN_LOCK /* spinLock */)
5767             {
5768                 // This constructor exists simply to allow conversion of the pointer type to
5769                 // pointer_storage type when constructing an invalid instance. The spinLock pointer
5770                 // is expected to be nullptr.
5771             }
5772 
5773             // Exists to satisfy the interconvertibility requirement for pointer_storage and
5774             // pointer.
5775             explicit operator PKSPIN_LOCK() const
5776             {
5777                 return spinLock;
5778             }
5779 
5780             _IRQL_requires_(DISPATCH_LEVEL)
5781             static
5782             void Release(_In_ _IRQL_restores_ const kspin_lock_saved_irql& spinLockSavedIrql)
5783             {
5784                 KeReleaseSpinLock(spinLockSavedIrql.spinLock, spinLockSavedIrql.savedIrql);
5785             }
5786         };
5787 
5788         // On some architectures KeReleaseSpinLockFromDpcLevel is a macro, and we need a thunk
5789         // function we can take the address of.
5790         inline
5791         _IRQL_requires_min_(DISPATCH_LEVEL)
5792         void __stdcall ReleaseSpinLockFromDpcLevel(_Inout_ PKSPIN_LOCK spinLock) WI_NOEXCEPT
5793         {
5794             KeReleaseSpinLockFromDpcLevel(spinLock);
5795         }
5796     }
5797 
5798     using kspin_lock_guard = unique_any<PKSPIN_LOCK, decltype(details::kspin_lock_saved_irql::Release), &details::kspin_lock_saved_irql::Release,
5799         details::pointer_access_none, details::kspin_lock_saved_irql>;
5800 
5801     using kspin_lock_at_dpc_guard = unique_any<PKSPIN_LOCK, decltype(details::ReleaseSpinLockFromDpcLevel), &details::ReleaseSpinLockFromDpcLevel,
5802         details::pointer_access_none>;
5803 
5804     inline
5805     WI_NODISCARD
5806     _IRQL_requires_max_(DISPATCH_LEVEL)
5807     _IRQL_saves_
5808     _IRQL_raises_(DISPATCH_LEVEL)
5809     kspin_lock_guard
5810     acquire_kspin_lock(_In_ PKSPIN_LOCK spinLock)
5811     {
5812         details::kspin_lock_saved_irql spinLockSavedIrql;
5813         KeAcquireSpinLock(spinLock, &spinLockSavedIrql.savedIrql);
5814         spinLockSavedIrql.spinLock = spinLock;
5815         return kspin_lock_guard(spinLockSavedIrql);
5816     }
5817 
5818     inline
5819     WI_NODISCARD
5820     _IRQL_requires_min_(DISPATCH_LEVEL)
5821     kspin_lock_at_dpc_guard
5822     acquire_kspin_lock_at_dpc(_In_ PKSPIN_LOCK spinLock)
5823     {
5824         KeAcquireSpinLockAtDpcLevel(spinLock);
5825         return kspin_lock_at_dpc_guard(spinLock);
5826     }
5827 
5828     class kernel_spin_lock
5829     {
5830     public:
5831 
5832         kernel_spin_lock() WI_NOEXCEPT
5833         {
5834             ::KeInitializeSpinLock(&m_kSpinLock);
5835         }
5836 
5837         ~kernel_spin_lock() = default;
5838 
5839         // Cannot change memory location.
5840         kernel_spin_lock(const kernel_spin_lock&) = delete;
5841         kernel_spin_lock& operator=(const kernel_spin_lock&) = delete;
5842         kernel_spin_lock(kernel_spin_lock&&) = delete;
5843         kernel_spin_lock& operator=(kernel_spin_lock&&) = delete;
5844 
5845         WI_NODISCARD
5846         _IRQL_requires_max_(DISPATCH_LEVEL)
5847         _IRQL_saves_
5848         _IRQL_raises_(DISPATCH_LEVEL)
5849         kspin_lock_guard acquire() WI_NOEXCEPT
5850         {
5851             return acquire_kspin_lock(&m_kSpinLock);
5852         }
5853 
5854         WI_NODISCARD
5855         _IRQL_requires_min_(DISPATCH_LEVEL)
5856         kspin_lock_at_dpc_guard acquire_at_dpc() WI_NOEXCEPT
5857         {
5858             return acquire_kspin_lock_at_dpc(&m_kSpinLock);
5859         }
5860 
5861     private:
5862 
5863         KSPIN_LOCK m_kSpinLock;
5864     };
5865 
5866     namespace details
5867     {
5868         template <EVENT_TYPE eventType>
5869         class kernel_event_t
5870         {
5871         public:
5872 
5873             explicit kernel_event_t(bool isSignaled = false) WI_NOEXCEPT
5874             {
5875                 ::KeInitializeEvent(&m_kernelEvent, static_cast<EVENT_TYPE>(eventType), isSignaled ? TRUE : FALSE);
5876             }
5877 
5878             // Cannot change memory location.
5879             kernel_event_t(const kernel_event_t&) = delete;
5880             kernel_event_t(kernel_event_t&&) = delete;
5881             kernel_event_t& operator=(const kernel_event_t&) = delete;
5882             kernel_event_t& operator=(kernel_event_t&&) = delete;
5883 
5884             // Get the underlying KEVENT structure for more advanced usages like
5885             // KeWaitForMultipleObjects or KeWaitForSingleObject with non-default parameters.
5886             PRKEVENT get() WI_NOEXCEPT
5887             {
5888                 return &m_kernelEvent;
5889             }
5890 
5891             void clear() WI_NOEXCEPT
5892             {
5893                 // The most common use-case is to clear the event with no interest in its previous
5894                 // value. Hence, that is the functionality we provide by default. If the previous
5895                 // value is required, one may .get() the underlying event object and call
5896                 // ::KeResetEvent().
5897                 ::KeClearEvent(&m_kernelEvent);
5898             }
5899 
5900             // Returns the previous state of the event.
5901             bool set(KPRIORITY increment = IO_NO_INCREMENT) WI_NOEXCEPT
5902             {
5903                 return ::KeSetEvent(&m_kernelEvent, increment, FALSE) ? true : false;
5904             }
5905 
5906             // Checks if the event is currently signaled. Does not change the state of the event.
5907             bool is_signaled() const WI_NOEXCEPT
5908             {
5909                 return ::KeReadStateEvent(const_cast<PRKEVENT>(&m_kernelEvent)) ? true : false;
5910             }
5911 
5912             // Return true if the wait was satisfied. Time is specified in 100ns units, relative
5913             // (negative) or absolute (positive). For more details, see the documentation of
5914             // KeWaitForSingleObject.
5915             bool wait(LONGLONG waitTime) WI_NOEXCEPT
5916             {
5917                 LARGE_INTEGER duration;
5918                 duration.QuadPart = waitTime;
5919                 return wait_for_single_object(&duration);
5920             }
5921 
5922             // Waits indefinitely for the event to be signaled.
5923             void wait() WI_NOEXCEPT
5924             {
5925                 wait_for_single_object(nullptr);
5926             }
5927 
5928         private:
5929 
5930             bool wait_for_single_object(_In_opt_ LARGE_INTEGER* waitDuration) WI_NOEXCEPT
5931             {
5932                 auto status = ::KeWaitForSingleObject(&m_kernelEvent, Executive, KernelMode, FALSE, waitDuration);
5933 
5934                 // We specified Executive and non-alertable, which means some of the return values are
5935                 // not possible.
5936                 WI_ASSERT((status == STATUS_SUCCESS) || (status == STATUS_TIMEOUT));
5937                 return (status == STATUS_SUCCESS);
5938             }
5939 
5940             KEVENT m_kernelEvent;
5941         };
5942     }
5943 
5944     using kernel_event_auto_reset = details::kernel_event_t<SynchronizationEvent>;
5945     using kernel_event_manual_reset = details::kernel_event_t<NotificationEvent>;
5946     using kernel_event = kernel_event_auto_reset; // For parity with the default for other WIL event types.
5947 
5948     namespace details
5949     {
5950         // Define a templated type for pool functions in order to satisfy overload resolution below
5951         template <typename pointer, ULONG tag>
5952         struct pool_helpers
5953         {
5954             static inline
5955             _IRQL_requires_max_(DISPATCH_LEVEL)
5956             void __stdcall FreePoolWithTag(pointer value) WI_NOEXCEPT
5957             {
5958                 if (value)
5959                 {
5960                     ExFreePoolWithTag(value, tag);
5961                 }
5962             }
5963         };
5964     }
5965 
5966     template <typename pointer, ULONG tag = 0>
5967     using unique_tagged_pool_ptr = unique_any<pointer, decltype(details::pool_helpers<pointer, tag>::FreePoolWithTag), &details::pool_helpers<pointer, tag>::FreePoolWithTag>;
5968 
5969     // For use with IRPs that need to be IoFreeIrp'ed when done, typically allocated using IoAllocateIrp.
5970     using unique_allocated_irp = wil::unique_any<PIRP, decltype(&::IoFreeIrp), ::IoFreeIrp, details::pointer_access_noaddress>;
5971     using unique_io_workitem = wil::unique_any<PIO_WORKITEM, decltype(&::IoFreeWorkItem), ::IoFreeWorkItem, details::pointer_access_noaddress>;
5972 
5973 #endif // __WIL_RESOURCE_WDM
5974 
5975 #if defined(WIL_KERNEL_MODE) && (defined(_WDMDDK_) || defined(_ZWAPI_)) && !defined(__WIL_RESOURCE_ZWAPI)
5976 #define __WIL_RESOURCE_ZWAPI
5977 
5978     using unique_kernel_handle = wil::unique_any<HANDLE, decltype(&::ZwClose), ::ZwClose>;
5979 
5980 #endif // __WIL_RESOURCE_ZWAPI
5981 
5982 } // namespace wil
5983 
5984 #pragma warning(pop)
5985