25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

6015 lines
239 KiB

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