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