You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2836 lines
125KB

  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. #ifndef __WIL_COM_INCLUDED
  12. #define __WIL_COM_INCLUDED
  13. #include <WeakReference.h>
  14. #include <combaseapi.h>
  15. #include "result.h"
  16. #include "resource.h" // last to ensure _COMBASEAPI_H_ protected definitions are available
  17. // Forward declaration within WIL (see https://msdn.microsoft.com/en-us/library/br244983.aspx)
  18. /// @cond
  19. namespace Microsoft
  20. {
  21. namespace WRL
  22. {
  23. template <typename T>
  24. class ComPtr;
  25. }
  26. }
  27. /// @endcond
  28. namespace wil
  29. {
  30. /// @cond
  31. namespace details
  32. {
  33. // We can't directly use wistd::is_convertible as it returns TRUE for an ambiguous conversion.
  34. // Adding is_abstract to the mix, enables us to allow conversion for interfaces, but deny it for
  35. // classes (where the multiple inheritance causes ambiguity).
  36. // NOTE: I've reached out to vcsig on this topic and it turns out that __is_convertible_to should NEVER
  37. // return true for ambiguous conversions. This was a bug in our compiler that has since been fixed.
  38. // Eventually, once that fix propagates we can move to a more efficient __is_convertible_to without
  39. // the added complexity.
  40. template <class TFrom, class TTo>
  41. struct is_com_convertible :
  42. wistd::bool_constant<__is_convertible_to(TFrom, TTo) && (__is_abstract(TFrom) || wistd::is_same<TFrom, TTo>::value)>
  43. {
  44. };
  45. typedef wistd::integral_constant<char, 0> tag_com_query;
  46. typedef wistd::integral_constant<char, 1> tag_try_com_query;
  47. typedef wistd::integral_constant<char, 2> tag_com_copy;
  48. typedef wistd::integral_constant<char, 3> tag_try_com_copy;
  49. class default_query_policy
  50. {
  51. public:
  52. template <typename T>
  53. inline static HRESULT query(_In_ T* ptr, REFIID riid, _COM_Outptr_ void** result)
  54. {
  55. return ptr->QueryInterface(riid, result);
  56. }
  57. template <typename T, typename TResult>
  58. inline static HRESULT query(_In_ T* ptr, _COM_Outptr_ TResult** result)
  59. {
  60. return query_dispatch(ptr, typename details::is_com_convertible<T*, TResult*>::type(), result);
  61. }
  62. private:
  63. template <typename T, typename TResult>
  64. inline static HRESULT query_dispatch(_In_ T* ptr, wistd::true_type, _COM_Outptr_ TResult** result) // convertible
  65. {
  66. *result = ptr;
  67. (*result)->AddRef();
  68. return S_OK;
  69. }
  70. template <typename T, typename TResult>
  71. inline static HRESULT query_dispatch(_In_ T* ptr, wistd::false_type, _COM_Outptr_ TResult** result) // not convertible
  72. {
  73. auto hr = ptr->QueryInterface(IID_PPV_ARGS(result));
  74. __analysis_assume(SUCCEEDED(hr) || (*result == nullptr));
  75. return hr;
  76. }
  77. };
  78. template <typename T>
  79. struct query_policy_helper
  80. {
  81. typedef default_query_policy type;
  82. };
  83. class weak_query_policy
  84. {
  85. public:
  86. inline static HRESULT query(_In_ IWeakReference* ptr, REFIID riid, _COM_Outptr_ void** result)
  87. {
  88. WI_ASSERT_MSG(riid != __uuidof(IWeakReference), "Cannot resolve a weak reference to IWeakReference");
  89. *result = nullptr;
  90. IInspectable* temp;
  91. HRESULT hr = ptr->Resolve(__uuidof(IInspectable), reinterpret_cast<IInspectable**>(&temp));
  92. if (SUCCEEDED(hr))
  93. {
  94. if (temp == nullptr)
  95. {
  96. return E_NOT_SET;
  97. }
  98. hr = temp->QueryInterface(riid, result);
  99. __analysis_assume(SUCCEEDED(hr) || (*result == nullptr));
  100. temp->Release();
  101. }
  102. return hr;
  103. }
  104. template <typename TResult>
  105. inline static HRESULT query(_In_ IWeakReference* ptr, _COM_Outptr_ TResult** result)
  106. {
  107. static_assert(!wistd::is_same<IWeakReference, TResult>::value, "Cannot resolve a weak reference to IWeakReference");
  108. return query_dispatch(ptr, wistd::is_base_of<IInspectable, TResult>(), result);
  109. }
  110. private:
  111. template <typename TResult>
  112. static HRESULT query_dispatch(_In_ IWeakReference* ptr, wistd::true_type, _COM_Outptr_ TResult** result)
  113. {
  114. auto hr = ptr->Resolve(__uuidof(TResult), reinterpret_cast<IInspectable**>(result));
  115. if (SUCCEEDED(hr) && (*result == nullptr))
  116. {
  117. hr = E_NOT_SET;
  118. }
  119. __analysis_assume(SUCCEEDED(hr) || (*result == nullptr));
  120. return hr;
  121. }
  122. template <typename TResult>
  123. static HRESULT query_dispatch(_In_ IWeakReference* ptr, wistd::false_type, _COM_Outptr_ TResult** result)
  124. {
  125. return query(ptr, IID_PPV_ARGS(result));
  126. }
  127. };
  128. template <>
  129. struct query_policy_helper<IWeakReference>
  130. {
  131. typedef weak_query_policy type;
  132. };
  133. #if (NTDDI_VERSION >= NTDDI_WINBLUE)
  134. class agile_query_policy
  135. {
  136. public:
  137. inline static HRESULT query(_In_ IAgileReference* ptr, REFIID riid, _COM_Outptr_ void** result)
  138. {
  139. WI_ASSERT_MSG(riid != __uuidof(IAgileReference), "Cannot resolve a agile reference to IAgileReference");
  140. auto hr = ptr->Resolve(riid, result);
  141. __analysis_assume(SUCCEEDED(hr) || (*result == nullptr)); // IAgileReference::Resolve not annotated correctly
  142. return hr;
  143. }
  144. template <typename TResult>
  145. static HRESULT query(_In_ IAgileReference* ptr, _COM_Outptr_ TResult** result)
  146. {
  147. static_assert(!wistd::is_same<IAgileReference, TResult>::value, "Cannot resolve a agile reference to IAgileReference");
  148. return query(ptr, __uuidof(TResult), reinterpret_cast<void**>(result));
  149. }
  150. };
  151. template <>
  152. struct query_policy_helper<IAgileReference>
  153. {
  154. typedef agile_query_policy type;
  155. };
  156. #endif
  157. template <typename T>
  158. using query_policy_t = typename query_policy_helper<typename wistd::remove_pointer<T>::type>::type;
  159. } // details
  160. /// @endcond
  161. //! Represents the base template type that implements com_ptr, com_weak_ref, and com_agile_ref.
  162. //! See @ref page_comptr for more background. See @ref page_query for more information on querying with WIL.
  163. //! @tparam T Represents the type being held by the com_ptr_t.
  164. //! For com_ptr, this will always be the interface being represented. For com_weak_ref, this will always be
  165. //! IWeakReference. For com_agile_ref, this will always be IAgileReference.
  166. //! @tparam err_policy Represents the error policy for the class (error codes, exceptions, or fail fast; see @ref page_errors)
  167. template <typename T, typename err_policy = err_exception_policy>
  168. class com_ptr_t
  169. {
  170. private:
  171. typedef typename wistd::add_lvalue_reference<T>::type element_type_reference;
  172. typedef details::query_policy_t<T> query_policy;
  173. public:
  174. //! The function return result (HRESULT or void) for the given err_policy (see @ref page_errors).
  175. typedef typename err_policy::result result;
  176. //! The template type `T` being held by the com_ptr_t.
  177. typedef T element_type;
  178. //! A pointer to the template type `T` being held by the com_ptr_t (what `get()` returns).
  179. typedef T* pointer;
  180. //! @name Constructors
  181. //! @{
  182. //! Default constructor (holds nullptr).
  183. com_ptr_t() WI_NOEXCEPT :
  184. m_ptr(nullptr)
  185. {
  186. }
  187. //! Implicit construction from nullptr_t (holds nullptr).
  188. com_ptr_t(wistd::nullptr_t) WI_NOEXCEPT :
  189. com_ptr_t()
  190. {
  191. }
  192. //! Implicit construction from a compatible raw interface pointer (AddRef's the parameter).
  193. com_ptr_t(pointer ptr) WI_NOEXCEPT :
  194. m_ptr(ptr)
  195. {
  196. if (m_ptr)
  197. {
  198. m_ptr->AddRef();
  199. }
  200. }
  201. //! Copy-construction from a like `com_ptr_t` (copies and AddRef's the parameter).
  202. com_ptr_t(const com_ptr_t& other) WI_NOEXCEPT :
  203. com_ptr_t(other.get())
  204. {
  205. }
  206. //! Copy-construction from a convertible `com_ptr_t` (copies and AddRef's the parameter).
  207. template <class U, typename err, class = wistd::enable_if_t<__is_convertible_to(U*, pointer)>>
  208. com_ptr_t(const com_ptr_t<U, err>& other) WI_NOEXCEPT :
  209. com_ptr_t(static_cast<pointer>(other.get()))
  210. {
  211. }
  212. //! Move construction from a like `com_ptr_t` (avoids AddRef/Release by moving from the parameter).
  213. com_ptr_t(com_ptr_t&& other) WI_NOEXCEPT :
  214. m_ptr(other.detach())
  215. {
  216. }
  217. //! Move construction from a compatible `com_ptr_t` (avoids AddRef/Release by moving from the parameter).
  218. template <class U, typename err, class = wistd::enable_if_t<__is_convertible_to(U*, pointer)>>
  219. com_ptr_t(com_ptr_t<U, err>&& other) WI_NOEXCEPT :
  220. m_ptr(other.detach())
  221. {
  222. }
  223. //! @}
  224. //! Destructor (releases the pointer).
  225. ~com_ptr_t() WI_NOEXCEPT
  226. {
  227. if (m_ptr)
  228. {
  229. m_ptr->Release();
  230. }
  231. }
  232. //! @name Assignment operators
  233. //! @{
  234. //! Assign to nullptr (releases the current pointer, holds nullptr).
  235. com_ptr_t& operator=(wistd::nullptr_t) WI_NOEXCEPT
  236. {
  237. reset();
  238. return *this;
  239. }
  240. //! Assign a compatible raw interface pointer (releases current pointer, copies and AddRef's the parameter).
  241. com_ptr_t& operator=(pointer other) WI_NOEXCEPT
  242. {
  243. auto ptr = m_ptr;
  244. m_ptr = other;
  245. if (m_ptr)
  246. {
  247. m_ptr->AddRef();
  248. }
  249. if (ptr)
  250. {
  251. ptr->Release();
  252. }
  253. return *this;
  254. }
  255. //! Assign a like `com_ptr_t` (releases current pointer, copies and AddRef's the parameter).
  256. com_ptr_t& operator=(const com_ptr_t& other) WI_NOEXCEPT
  257. {
  258. return operator=(other.get());
  259. }
  260. //! Assign a convertible `com_ptr_t` (releases current pointer, copies and AddRef's the parameter).
  261. template <class U, typename err, class = wistd::enable_if_t<__is_convertible_to(U*, pointer)>>
  262. com_ptr_t& operator=(const com_ptr_t<U, err>& other) WI_NOEXCEPT
  263. {
  264. return operator=(static_cast<pointer>(other.get()));
  265. }
  266. //! Move assign from a like `com_ptr_t` (releases current pointer, avoids AddRef/Release by moving the parameter).
  267. com_ptr_t& operator=(com_ptr_t&& other) WI_NOEXCEPT
  268. {
  269. WI_ASSERT_MSG(this != wistd::addressof(other), "R-Values should be unique: self assignment is a bug");
  270. attach(other.detach());
  271. return *this;
  272. }
  273. //! Move assignment from a compatible `com_ptr_t` (releases current pointer, avoids AddRef/Release by moving from the parameter).
  274. template <class U, typename err, class = wistd::enable_if_t<__is_convertible_to(U*, pointer)>>
  275. com_ptr_t& operator=(com_ptr_t<U, err>&& other) WI_NOEXCEPT
  276. {
  277. attach(other.detach());
  278. return *this;
  279. }
  280. //! @}
  281. //! @name Modifiers
  282. //! @{
  283. //! Swap pointers with an another named com_ptr_t object.
  284. template <typename err>
  285. void swap(com_ptr_t<T, err>& other) WI_NOEXCEPT
  286. {
  287. auto ptr = m_ptr;
  288. m_ptr = other.m_ptr;
  289. other.m_ptr = ptr;
  290. }
  291. //! Swap pointers with a rvalue reference to another com_ptr_t object.
  292. template <typename err>
  293. void swap(com_ptr_t<T, err>&& other) WI_NOEXCEPT
  294. {
  295. swap(other);
  296. }
  297. //! Releases the pointer and sets it to nullptr.
  298. void reset() WI_NOEXCEPT
  299. {
  300. auto ptr = m_ptr;
  301. m_ptr = nullptr;
  302. if (ptr)
  303. {
  304. ptr->Release();
  305. }
  306. }
  307. //! Releases the pointer and sets it to nullptr.
  308. void reset(wistd::nullptr_t) WI_NOEXCEPT
  309. {
  310. reset();
  311. }
  312. //! Takes ownership of a compatible raw interface pointer (releases pointer, copies but DOES NOT AddRef the parameter).
  313. void attach(pointer other) WI_NOEXCEPT
  314. {
  315. auto ptr = m_ptr;
  316. m_ptr = other;
  317. if (ptr)
  318. {
  319. ULONG ref;
  320. ref = ptr->Release();
  321. WI_ASSERT_MSG(((other != ptr) || (ref > 0)), "Bug: Attaching the same already assigned, destructed pointer");
  322. }
  323. }
  324. //! Relinquishes ownership and returns the internal interface pointer (DOES NOT release the detached pointer, sets class pointer to null).
  325. WI_NODISCARD pointer detach() WI_NOEXCEPT
  326. {
  327. auto temp = m_ptr;
  328. m_ptr = nullptr;
  329. return temp;
  330. }
  331. //! Returns the address of the internal pointer (releases ownership of the pointer BEFORE returning the address).
  332. //! The pointer is explicitly released to prevent accidental leaks of the pointer. Coding standards generally indicate that
  333. //! there is little valid `_Inout_` use of `IInterface**`, making this safe to do under typical use.
  334. //! @see addressof
  335. //! ~~~~
  336. //! STDAPI GetMuffin(IMuffin **muffin);
  337. //! wil::com_ptr<IMuffin> myMuffin;
  338. //! THROW_IF_FAILED(GetMuffin(myMuffin.put()));
  339. //! ~~~~
  340. pointer* put() WI_NOEXCEPT
  341. {
  342. reset();
  343. return &m_ptr;
  344. }
  345. //! Returns the address of the internal pointer casted to void** (releases ownership of the pointer BEFORE returning the address).
  346. //! @see put
  347. void** put_void() WI_NOEXCEPT
  348. {
  349. return reinterpret_cast<void**>(put());
  350. }
  351. //! Returns the address of the internal pointer casted to IUnknown** (releases ownership of the pointer BEFORE returning the address).
  352. //! @see put
  353. IUnknown** put_unknown() WI_NOEXCEPT
  354. {
  355. return reinterpret_cast<IUnknown**>(put());
  356. }
  357. //! Returns the address of the internal pointer (releases ownership of the pointer BEFORE returning the address).
  358. //! The pointer is explicitly released to prevent accidental leaks of the pointer. Coding standards generally indicate that
  359. //! there is little valid `_Inout_` use of `IInterface**`, making this safe to do under typical use. Since this behavior is not always immediately
  360. //! apparent, prefer to scope variables as close to use as possible (generally avoiding use of the same com_ptr variable in successive calls to
  361. //! receive an output interface).
  362. //! @see addressof
  363. pointer* operator&() WI_NOEXCEPT
  364. {
  365. return put();
  366. }
  367. //! Returns the address of the internal pointer (does not release the pointer; should not be used for `_Out_` parameters)
  368. pointer* addressof() WI_NOEXCEPT
  369. {
  370. return &m_ptr;
  371. }
  372. //! @}
  373. //! @name Inspection
  374. //! @{
  375. //! Returns the address of the const internal pointer (does not release the pointer)
  376. const pointer* addressof() const WI_NOEXCEPT
  377. {
  378. return &m_ptr;
  379. }
  380. //! Returns 'true' if the pointer is assigned (NOT nullptr)
  381. explicit operator bool() const WI_NOEXCEPT
  382. {
  383. return (m_ptr != nullptr);
  384. }
  385. //! Returns the pointer
  386. pointer get() const WI_NOEXCEPT
  387. {
  388. return m_ptr;
  389. }
  390. //! Allows direct calls against the pointer (AV on internal nullptr)
  391. pointer operator->() const WI_NOEXCEPT
  392. {
  393. return m_ptr;
  394. }
  395. //! Dereferences the pointer (AV on internal nullptr)
  396. element_type_reference operator*() const WI_NOEXCEPT
  397. {
  398. return *m_ptr;
  399. }
  400. //! @}
  401. //! @name Query helpers
  402. //! * Retrieves the requested interface
  403. //! * AV if the pointer is null
  404. //! * Produce an error if the requested interface is unsupported
  405. //!
  406. //! See @ref page_query for more information
  407. //! @{
  408. //! Query and return a smart pointer matching the interface specified by 'U': `auto foo = m_ptr.query<IFoo>();`.
  409. //! See @ref page_query for more information.
  410. //!
  411. //! This method is the primary method that should be used to query a com_ptr in exception-based or fail-fast based code.
  412. //! Error-code returning code should use @ref query_to so that the returned HRESULT can be examined. In the following
  413. //! examples, `m_ptr` is an exception-based or fail-fast based com_ptr, com_weak_ref, or com_agile_ref:
  414. //! ~~~~
  415. //! auto foo = ptr.query<IFoo>();
  416. //! foo->Method1();
  417. //! foo->Method2();
  418. //! ~~~~
  419. //! For simple single-method calls, this method allows removing the temporary that holds the com_ptr:
  420. //! ~~~~
  421. //! ptr.query<IFoo>()->Method1();
  422. //! ~~~~
  423. //! @tparam U Represents the interface being queried
  424. //! @return A `com_ptr_t` pointer to the given interface `U`. The pointer is guaranteed not null. The returned
  425. //! `com_ptr_t` type will be @ref com_ptr or @ref com_ptr_failfast (matching the error handling form of the
  426. //! pointer being queried (exception based or fail-fast).
  427. template <class U>
  428. inline com_ptr_t<U, err_policy> query() const
  429. {
  430. static_assert(wistd::is_same<void, result>::value, "query requires exceptions or fail fast; use try_query or query_to");
  431. return com_ptr_t<U, err_policy>(m_ptr, details::tag_com_query());
  432. }
  433. //! Query for the interface of the given out parameter `U`: `ptr.query_to(&foo);`.
  434. //! See @ref page_query for more information.
  435. //!
  436. //! For fail-fast and exception-based behavior this routine should primarily be used to write to out parameters and @ref query should
  437. //! be used to perform most queries. For error-code based code, this routine is the primary method that should be used to query a com_ptr.
  438. //!
  439. //! Error-code based samples:
  440. //! ~~~~
  441. //! // class member being queried:
  442. //! wil::com_ptr_nothrow<IUnknown> m_ptr;
  443. //!
  444. //! // simple query example:
  445. //! wil::com_ptr_nothrow<IFoo> foo;
  446. //! RETURN_IF_FAILED(m_ptr.query_to(&foo));
  447. //! foo->FooMethod1();
  448. //!
  449. //! // output parameter example:
  450. //! HRESULT GetFoo(_COM_Outptr_ IFoo** fooPtr)
  451. //! {
  452. //! RETURN_IF_FAILED(m_ptr.query_to(fooPtr));
  453. //! return S_OK;
  454. //! }
  455. //! ~~~~
  456. //! Exception or fail-fast samples:
  457. //! ~~~~
  458. //! // class member being queried
  459. //! wil::com_ptr<IUnknown> m_ptr;
  460. //!
  461. //! void GetFoo(_COM_Outptr_ IFoo** fooPtr)
  462. //! {
  463. //! m_ptr.query_to(fooPtr);
  464. //! }
  465. //! ~~~~
  466. //! @tparam U Represents the interface being queried (type of the output parameter). This interface does not need to
  467. //! be specified directly. Rely upon template type deduction to pick up the type from the output parameter.
  468. //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be assigned null on failure.
  469. //! @return For the nothrow (error code-based) classes (@ref com_ptr_nothrow, @ref com_weak_ref_nothrow, @ref com_agile_ref_nothrow) this
  470. //! method returns an `HRESULT` indicating whether the query was successful. Exception-based and fail-fast based classes
  471. //! do not return a value (void).
  472. template <class U>
  473. result query_to(_COM_Outptr_ U** ptrResult) const
  474. {
  475. // Prefast cannot see through the error policy + query_policy mapping and as a result fires 6388 and 28196 for this function.
  476. // Suppression is also not working. Wrapping this entire function in #pragma warning(disable: 6388 28196) does not stop all of the prefast errors
  477. // from being emitted.
  478. #if defined(_PREFAST_)
  479. *ptrResult = nullptr;
  480. return err_policy::HResult(E_NOINTERFACE);
  481. #else
  482. return err_policy::HResult(query_policy::query(m_ptr, ptrResult));
  483. #endif
  484. }
  485. //! Query for the requested interface using the iid, ppv pattern: `ptr.query_to(riid, ptr);`.
  486. //! See @ref page_query for more information.
  487. //!
  488. //! This method is built to implement an API boundary that exposes a returned pointer to a caller through the REFIID and void** pointer
  489. //! pattern (like QueryInterface). This pattern should not be used outside of that pattern (through IID_PPV_ARGS) as it is less efficient
  490. //! than the typed version of @ref query_to which can elide the QueryInterface in favor of AddRef when the types are convertible.
  491. //! ~~~~
  492. //! // class member being queried:
  493. //! wil::com_ptr_nothrow<IUnknown> m_ptr;
  494. //!
  495. //! // output parameter example:
  496. //! HRESULT GetFoo(REFIID riid, _COM_Outptr_ void** ptrResult)
  497. //! {
  498. //! RETURN_IF_FAILED(m_ptr.query_to(riid, ptrResult));
  499. //! return S_OK;
  500. //! }
  501. //! ~~~~
  502. //! @param riid The interface to query for.
  503. //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be assigned null on failure.
  504. //! @return For the nothrow (error code-based) classes (@ref com_ptr_nothrow, @ref com_weak_ref_nothrow, @ref com_agile_ref_nothrow) this
  505. //! method returns an `HRESULT` indicating whether the query was successful. Exception-based and fail-fast based classes
  506. //! do not return a value (void).
  507. result query_to(REFIID riid, _COM_Outptr_ void** ptrResult) const
  508. {
  509. // Prefast cannot see through the error policy + query_policy mapping and as a result and as a result fires 6388 and 28196 for this function.
  510. // Suppression is also not working. Wrapping this entire function in #pragma warning(disable: 6388 28196) does not stop the prefast errors
  511. // from being emitted.
  512. #if defined(_PREFAST_)
  513. *ptrResult = nullptr;
  514. return err_policy::HResult(E_NOINTERFACE);
  515. #else
  516. return err_policy::HResult(query_policy::query(m_ptr, riid, ptrResult));
  517. #endif
  518. }
  519. //! @}
  520. //! @name Try query helpers
  521. //! * Attempts to retrieves the requested interface
  522. //! * AV if the pointer is null
  523. //! * Produce null if the requested interface is unsupported
  524. //! * bool returns 'true' when query was successful
  525. //!
  526. //! See @ref page_query for more information.
  527. //! @{
  528. //! Attempt a query and return a smart pointer matching the interface specified by 'U': `auto foo = m_ptr.try_query<IFoo>();` (null result when interface is unsupported).
  529. //! See @ref page_query for more information.
  530. //!
  531. //! This method can be used to query a com_ptr for an interface when it's known that support for that interface is
  532. //! optional (failing the query should not produce an error). The caller must examine the returned pointer to see
  533. //! if it's null before using it:
  534. //! ~~~~
  535. //! auto foo = ptr.try_query<IFoo>();
  536. //! if (foo)
  537. //! {
  538. //! foo->Method1();
  539. //! foo->Method2();
  540. //! }
  541. //! ~~~~
  542. //! @tparam U Represents the interface being queried
  543. //! @return A `com_ptr_t` pointer to the given interface `U`. The returned pointer will be null if the interface is
  544. //! not supported. The returned `com_ptr_t` will have the same error handling policy (exceptions, failfast or error codes) as
  545. //! the pointer being queried.
  546. template <class U>
  547. inline com_ptr_t<U, err_policy> try_query() const
  548. {
  549. return com_ptr_t<U, err_policy>(m_ptr, details::tag_try_com_query());
  550. }
  551. //! Attempts to query for the interface matching the given output parameter; returns a bool indicating if the query was successful (non-null).
  552. //! See @ref page_query for more information.
  553. //!
  554. //! This method can be used to perform a query against a non-null interface when it's known that support for that interface is
  555. //! optional (failing the query should not produce an error). The caller must examine the returned bool before using the returned pointer.
  556. //! ~~~~
  557. //! wil::com_ptr_nothrow<IFoo> foo;
  558. //! if (ptr.try_query_to(&foo))
  559. //! {
  560. //! foo->Method1();
  561. //! foo->Method2();
  562. //! }
  563. //! ~~~~
  564. //! @param ptrResult The pointer to query for. The interface to query is deduced from the type of this out parameter; do not specify
  565. //! the type directly to the template.
  566. //! @return A `bool` indicating `true` of the query was successful (the returned parameter is non-null).
  567. template <class U>
  568. _Success_return_ bool try_query_to(_COM_Outptr_ U** ptrResult) const
  569. {
  570. return SUCCEEDED(query_policy::query(m_ptr, ptrResult));
  571. }
  572. //! Attempts a query for the requested interface using the iid, ppv pattern: `ptr.try_query_to(riid, ptr);`.
  573. //! See @ref page_query for more information.
  574. //!
  575. //! This method is built to implement an API boundary that exposes a returned pointer to a caller through the REFIID and void** pointer
  576. //! pattern (like QueryInterface). The key distinction is that this routine does not produce an error if the request isn't fulfilled, so
  577. //! it's appropriate for `_COM_Outptr_result_maybenull_` cases. This pattern should not be used outside of that pattern (through IID_PPV_ARGS) as
  578. //! it is less efficient than the typed version of @ref try_query_to which can elide the QueryInterface in favor of AddRef when the types are convertible.
  579. //! The caller must examine the returned bool before using the returned pointer.
  580. //! ~~~~
  581. //! // class member being queried:
  582. //! wil::com_ptr_nothrow<IUnknown> m_ptr;
  583. //!
  584. //! // output parameter example (result may be null):
  585. //! HRESULT GetFoo(REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult)
  586. //! {
  587. //! m_ptr.try_query_to(riid, ptrResult);
  588. //! return S_OK;
  589. //! }
  590. //! ~~~~
  591. //! @param riid The interface to query for.
  592. //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be assigned null on failure.
  593. //! @return A `bool` indicating `true` of the query was successful (the returned parameter is non-null).
  594. _Success_return_ bool try_query_to(REFIID riid, _COM_Outptr_ void** ptrResult) const
  595. {
  596. return SUCCEEDED(query_policy::query(m_ptr, riid, ptrResult));
  597. }
  598. //! @}
  599. //! @name Copy helpers
  600. //! * Retrieves the requested interface
  601. //! * Succeeds with null if the pointer is null
  602. //! * Produce an error if the requested interface is unsupported
  603. //!
  604. //! See @ref page_query for more information.
  605. //! @{
  606. //! Query and return a smart pointer matching the interface specified by 'U': `auto foo = m_ptr.copy<IFoo>();` (succeeds and returns a null ptr if the queried pointer is null).
  607. //! See @ref page_query for more information.
  608. //!
  609. //! This method is identical to @ref query with the exception that it can be used when the pointer is null. When used
  610. //! against a null pointer, the returned pointer will always be null and an error will not be produced. Like query it will
  611. //! produce an error for a non-null pointer that does not support the requested interface.
  612. //! @tparam U Represents the interface being queried
  613. //! @return A `com_ptr_t` pointer to the given interface `U`. The pointer will be null ONLY if the pointer being queried is null. The returned
  614. //! `com_ptr_t` type will be @ref com_ptr or @ref com_ptr_failfast (matching the error handling form of the
  615. //! pointer being queried (exception based or fail-fast).
  616. template <class U>
  617. inline com_ptr_t<U, err_policy> copy() const
  618. {
  619. static_assert(wistd::is_same<void, result>::value, "copy requires exceptions or fail fast; use the try_copy or copy_to method");
  620. return com_ptr_t<U, err_policy>(m_ptr, details::tag_com_copy());
  621. }
  622. //! Query for the interface of the given out parameter `U`: `ptr.copy_to(&foo);` (succeeds and returns null ptr if the queried pointer is null).
  623. //! See @ref page_query for more information.
  624. //!
  625. //! This method is identical to @ref query_to with the exception that it can be used when the pointer is null. When used
  626. //! against a null pointer, the returned pointer will always be null and an error will not be produced. Like query_to it will
  627. //! produce an error for a non-null pointer that does not support the requested interface.
  628. //! @tparam U Represents the interface being queried (type of the output parameter). This interface does not need to
  629. //! be specified directly. Rely upon template type deduction to pick up the type from the output parameter.
  630. //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be assigned null on failure OR assigned null
  631. //! when the source pointer is null.
  632. //! @return For the nothrow (error code-based) classes (@ref com_ptr_nothrow, @ref com_weak_ref_nothrow, @ref com_agile_ref_nothrow) this
  633. //! method returns an `HRESULT` indicating whether the query was successful. Copying a null value is considered success. Exception-based
  634. //! and fail-fast based classes do not return a value (void).
  635. template <class U>
  636. result copy_to(_COM_Outptr_result_maybenull_ U** ptrResult) const
  637. {
  638. if (m_ptr)
  639. {
  640. // Prefast cannot see through the error policy + query_policy mapping and as a result and as a result fires 6388 and 28196 for this function.
  641. // Suppression is also not working. Wrapping this entire function in #pragma warning(disable: 6388 28196) does not stop the prefast errors
  642. // from being emitted.
  643. #if defined(_PREFAST_)
  644. *ptrResult = nullptr;
  645. return err_policy::HResult(E_NOINTERFACE);
  646. #else
  647. return err_policy::HResult(query_policy::query(m_ptr, ptrResult));
  648. #endif
  649. }
  650. *ptrResult = nullptr;
  651. return err_policy::OK();
  652. }
  653. //! Query for the requested interface using the iid, ppv pattern: `ptr.copy_to(riid, ptr);`. (succeeds and returns null ptr if the queried pointer is null).
  654. //! See @ref page_query for more information.
  655. //!
  656. //! Identical to the corresponding @ref query_to method with the exception that it can be used when the pointer is null. When used
  657. //! against a null pointer, the returned pointer will always be null and an error will not be produced. Like query_to it will
  658. //! produce an error for a non-null pointer that does not support the requested interface.
  659. //! @param riid The interface to query for.
  660. //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be assigned null on failure OR assigned null
  661. //! when the source pointer is null.
  662. //! @return For the nothrow (error code-based) classes (@ref com_ptr_nothrow, @ref com_weak_ref_nothrow, @ref com_agile_ref_nothrow) this
  663. //! method returns an `HRESULT` indicating whether the query was successful. Copying a null value is considered success. Exception-based
  664. //! and fail-fast based classes do not return a value (void).
  665. result copy_to(REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult) const
  666. {
  667. if (m_ptr)
  668. {
  669. // Prefast cannot see through the error policy + query_policy mapping and as a result and as a result fires 6388 and 28196 for this function.
  670. // Suppression is also not working. Wrapping this entire function in #pragma warning(disable: 6388 28196) does not stop the prefast errors
  671. // from being emitted.
  672. #if defined(_PREFAST_)
  673. *ptrResult = nullptr;
  674. return err_policy::HResult(E_NOINTERFACE);
  675. #else
  676. return err_policy::HResult(query_policy::query(m_ptr, riid, ptrResult));
  677. #endif
  678. }
  679. *ptrResult = nullptr;
  680. return err_policy::OK();
  681. }
  682. //! @}
  683. //! @name Try copy helpers
  684. //! * Attempts to retrieves the requested interface
  685. //! * Successfully produces null if the queried pointer is already null
  686. //! * Produce null if the requested interface is unsupported
  687. //! * bool returns 'false' ONLY when the queried pointer is not null and the requested interface is unsupported
  688. //!
  689. //! See @ref page_query for more information.
  690. //! @{
  691. //! Attempt a query and return a smart pointer matching the interface specified by 'U': `auto foo = m_ptr.try_query<IFoo>();` (null result when interface is unsupported or queried pointer is null).
  692. //! See @ref page_query for more information.
  693. //!
  694. //! Identical to the corresponding @ref try_query method with the exception that it can be used when the pointer is null. When used
  695. //! against a null pointer, the returned pointer will always be null and an error will not be produced.
  696. //! @tparam U Represents the interface being queried
  697. //! @return A `com_ptr_t` pointer to the given interface `U`. The returned pointer will be null if the interface was
  698. //! not supported or the pointer being queried is null. The returned `com_ptr_t` will have the same error handling
  699. //! policy (exceptions, failfast or error codes) as the pointer being queried.
  700. template <class U>
  701. inline com_ptr_t<U, err_policy> try_copy() const
  702. {
  703. return com_ptr_t<U, err_policy>(m_ptr, details::tag_try_com_copy());
  704. }
  705. //! Attempts to query for the interface matching the given output parameter; returns a bool indicating if the query was successful (returns `false` if the pointer is null).
  706. //! See @ref page_query for more information.
  707. //!
  708. //! Identical to the corresponding @ref try_query_to method with the exception that it can be used when the pointer is null. When used
  709. //! against a null pointer, the returned pointer will be null and the return value will be `false`.
  710. //! @param ptrResult The pointer to query for. The interface to query is deduced from the type of this out parameter; do not specify
  711. //! the type directly to the template.
  712. //! @return A `bool` indicating `true` of the query was successful (the returned parameter is non-null).
  713. template <class U>
  714. _Success_return_ bool try_copy_to(_COM_Outptr_result_maybenull_ U** ptrResult) const
  715. {
  716. if (m_ptr)
  717. {
  718. return SUCCEEDED(query_policy::query(m_ptr, ptrResult));
  719. }
  720. *ptrResult = nullptr;
  721. return false;
  722. }
  723. //! Attempts a query for the requested interface using the iid, ppv pattern: `ptr.try_query_to(riid, ptr);` (returns `false` if the pointer is null)
  724. //! See @ref page_query for more information.
  725. //!
  726. //! Identical to the corresponding @ref try_query_to method with the exception that it can be used when the pointer is null. When used
  727. //! against a null pointer, the returned pointer will be null and the return value will be `false`.
  728. //! @param riid The interface to query for.
  729. //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be assigned null on failure or
  730. //! if the source pointer being queried is null.
  731. //! @return A `bool` indicating `true` of the query was successful (the returned parameter is non-null). Querying a null
  732. //! pointer will return `false` with a null result.
  733. _Success_return_ bool try_copy_to(REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult) const
  734. {
  735. if (m_ptr)
  736. {
  737. return SUCCEEDED(query_policy::query(m_ptr, riid, ptrResult));
  738. }
  739. *ptrResult = nullptr;
  740. return false;
  741. }
  742. //! @}
  743. //! @name WRL compatibility
  744. //! @{
  745. //! Copy construct from a compatible WRL ComPtr<T>.
  746. template <class U, class = wistd::enable_if_t<__is_convertible_to(U*, pointer)>>
  747. com_ptr_t(const Microsoft::WRL::ComPtr<U>& other) WI_NOEXCEPT :
  748. com_ptr_t(static_cast<pointer>(other.Get()))
  749. {
  750. }
  751. //! Move construct from a compatible WRL ComPtr<T>.
  752. template <class U, class = wistd::enable_if_t<__is_convertible_to(U*, pointer)>>
  753. com_ptr_t(Microsoft::WRL::ComPtr<U>&& other) WI_NOEXCEPT :
  754. m_ptr(other.Detach())
  755. {
  756. }
  757. //! Assign from a compatible WRL ComPtr<T>.
  758. template <class U, class = wistd::enable_if_t<__is_convertible_to(U*, pointer)>>
  759. com_ptr_t& operator=(const Microsoft::WRL::ComPtr<U>& other) WI_NOEXCEPT
  760. {
  761. return operator=(static_cast<pointer>(other.Get()));
  762. }
  763. //! Move assign from a compatible WRL ComPtr<T>.
  764. template <class U, class = wistd::enable_if_t<__is_convertible_to(U*, pointer)>>
  765. com_ptr_t& operator=(Microsoft::WRL::ComPtr<U>&& other) WI_NOEXCEPT
  766. {
  767. attach(other.Detach());
  768. return *this;
  769. }
  770. //! Swap pointers with a WRL ComPtr<T> to the same interface.
  771. void swap(Microsoft::WRL::ComPtr<T>& other) WI_NOEXCEPT
  772. {
  773. auto ptr = m_ptr;
  774. m_ptr = other.Detach();
  775. other.Attach(ptr);
  776. }
  777. //! Swap pointers with a rvalue reference to a WRL ComPtr<T> to the same interface.
  778. void swap(Microsoft::WRL::ComPtr<T>&& other) WI_NOEXCEPT
  779. {
  780. swap(other);
  781. }
  782. //! @} // WRL compatibility
  783. public:
  784. // Internal Helpers
  785. /// @cond
  786. template <class U>
  787. inline com_ptr_t(_In_ U* ptr, details::tag_com_query)
  788. {
  789. err_policy::HResult(details::query_policy_t<U>::query(ptr, &m_ptr));
  790. }
  791. template <class U>
  792. inline com_ptr_t(_In_ U* ptr, details::tag_try_com_query) WI_NOEXCEPT
  793. {
  794. details::query_policy_t<U>::query(ptr, &m_ptr);
  795. }
  796. template <class U>
  797. inline com_ptr_t(_In_ U* ptr, details::tag_com_copy)
  798. {
  799. if (ptr)
  800. {
  801. err_policy::HResult(details::query_policy_t<U>::query(ptr, &m_ptr));
  802. return;
  803. }
  804. m_ptr = nullptr;
  805. }
  806. template <class U>
  807. inline com_ptr_t(_In_ U* ptr, details::tag_try_com_copy) WI_NOEXCEPT
  808. {
  809. if (ptr)
  810. {
  811. details::query_policy_t<U>::query(ptr, &m_ptr);
  812. return;
  813. }
  814. m_ptr = nullptr;
  815. }
  816. /// @endcond
  817. private:
  818. pointer m_ptr;
  819. };
  820. // Error-policy driven forms of com_ptr
  821. #ifdef WIL_ENABLE_EXCEPTIONS
  822. //! COM pointer, errors throw exceptions (see @ref com_ptr_t for details)
  823. template <typename T>
  824. using com_ptr = com_ptr_t<T, err_exception_policy>;
  825. #endif
  826. //! COM pointer, errors return error codes (see @ref com_ptr_t for details)
  827. template <typename T>
  828. using com_ptr_nothrow = com_ptr_t<T, err_returncode_policy>;
  829. //! COM pointer, errors fail-fast (see @ref com_ptr_t for details)
  830. template <typename T>
  831. using com_ptr_failfast = com_ptr_t<T, err_failfast_policy>;
  832. // Global operators / swap
  833. //! Swaps the given com pointers that have different error handling.
  834. //! Note that there are also corresponding versions to allow you to swap any wil com_ptr<T> with a WRL ComPtr<T>.
  835. template <typename T, typename ErrLeft, typename ErrRight>
  836. inline void swap(com_ptr_t<T, ErrLeft>& left, com_ptr_t<T, ErrRight>& right) WI_NOEXCEPT
  837. {
  838. left.swap(right);
  839. }
  840. //! Swaps the given com pointers that have the same error handling.
  841. template <typename T, typename Err>
  842. inline void swap(com_ptr_t<T, Err>& left, com_ptr_t<T, Err>& right) WI_NOEXCEPT
  843. {
  844. left.swap(right);
  845. }
  846. //! Compare two com pointers.
  847. //! Compares the two raw com pointers for equivalence. Does NOT compare object identity with a QI for IUnknown.
  848. //!
  849. //! Note that documentation for all of the various comparators has not been generated to reduce global function
  850. //! clutter, but ALL standard comparison operators are supported between wil com_ptr<T> objects, nullptr_t, and
  851. //! WRL ComPtr<T>.
  852. template <typename TLeft, typename ErrLeft, typename TRight, typename ErrRight>
  853. inline bool operator==(const com_ptr_t<TLeft, ErrLeft>& left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
  854. {
  855. static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible");
  856. return (left.get() == right.get());
  857. }
  858. // We don't document all of the global comparison operators (reduce clutter)
  859. /// @cond
  860. template <typename TLeft, typename ErrLeft, typename TRight, typename ErrRight>
  861. inline bool operator<(const com_ptr_t<TLeft, ErrLeft>& left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
  862. {
  863. static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible");
  864. return (left.get() < right.get());
  865. }
  866. template <typename TLeft, typename ErrLeft>
  867. inline bool operator==(const com_ptr_t<TLeft, ErrLeft>& left, wistd::nullptr_t) WI_NOEXCEPT
  868. {
  869. return (left.get() == nullptr);
  870. }
  871. template <typename TLeft, typename ErrLeft, typename TRight, typename ErrRight>
  872. inline bool operator!=(const com_ptr_t<TLeft, ErrLeft>& left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
  873. { return (!(left == right)); }
  874. template <typename TLeft, typename ErrLeft, typename TRight, typename ErrRight>
  875. inline bool operator>=(const com_ptr_t<TLeft, ErrLeft>& left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
  876. { return (!(left < right)); }
  877. template <typename TLeft, typename ErrLeft, typename TRight, typename ErrRight>
  878. inline bool operator>(const com_ptr_t<TLeft, ErrLeft>& left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
  879. { return (right < left); }
  880. template <typename TLeft, typename ErrLeft, typename TRight, typename ErrRight>
  881. inline bool operator<=(const com_ptr_t<TLeft, ErrLeft>& left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
  882. { return (!(right < left)); }
  883. template <typename TRight, typename ErrRight>
  884. inline bool operator==(wistd::nullptr_t, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
  885. {
  886. return (right.get() == nullptr);
  887. }
  888. template <typename TLeft, typename ErrLeft>
  889. inline bool operator!=(const com_ptr_t<TLeft, ErrLeft>& left, wistd::nullptr_t) WI_NOEXCEPT
  890. { return (!(left == nullptr)); }
  891. template <typename TRight, typename ErrRight>
  892. inline bool operator!=(wistd::nullptr_t, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
  893. { return (!(right == nullptr)); }
  894. // WRL ComPtr support
  895. template <typename T, typename ErrLeft>
  896. inline void swap(com_ptr_t<T, ErrLeft>& left, Microsoft::WRL::ComPtr<T>& right) WI_NOEXCEPT
  897. {
  898. left.swap(right);
  899. }
  900. template <typename TLeft, typename ErrLeft, typename TRight>
  901. inline bool operator==(const com_ptr_t<TLeft, ErrLeft>& left, const Microsoft::WRL::ComPtr<TRight>& right) WI_NOEXCEPT
  902. {
  903. static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible");
  904. return (left.get() == right.Get());
  905. }
  906. template <typename TLeft, typename ErrLeft, typename TRight>
  907. inline bool operator<(const com_ptr_t<TLeft, ErrLeft>& left, const Microsoft::WRL::ComPtr<TRight>& right) WI_NOEXCEPT
  908. {
  909. static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible");
  910. return (left.get() < right.Get());
  911. }
  912. template <typename TLeft, typename ErrLeft, typename TRight>
  913. inline bool operator!=(const com_ptr_t<TLeft, ErrLeft>& left, const Microsoft::WRL::ComPtr<TRight>& right) WI_NOEXCEPT
  914. { return (!(left == right)); }
  915. template <typename TLeft, typename ErrLeft, typename TRight>
  916. inline bool operator>=(const com_ptr_t<TLeft, ErrLeft>& left, const Microsoft::WRL::ComPtr<TRight>& right) WI_NOEXCEPT
  917. { return (!(left < right)); }
  918. template <typename TLeft, typename ErrLeft, typename TRight>
  919. inline bool operator>(const com_ptr_t<TLeft, ErrLeft>& left, const Microsoft::WRL::ComPtr<TRight>& right) WI_NOEXCEPT
  920. { return (right < left); }
  921. template <typename TLeft, typename ErrLeft, typename TRight>
  922. inline bool operator<=(const com_ptr_t<TLeft, ErrLeft>& left, const Microsoft::WRL::ComPtr<TRight>& right) WI_NOEXCEPT
  923. { return (!(right < left)); }
  924. template <typename T, typename ErrRight>
  925. inline void swap(Microsoft::WRL::ComPtr<T>& left, com_ptr_t<T, ErrRight>& right) WI_NOEXCEPT
  926. {
  927. right.swap(left);
  928. }
  929. template <typename TLeft, typename TRight, typename ErrRight>
  930. inline bool operator==(const Microsoft::WRL::ComPtr<TLeft>& left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
  931. {
  932. static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible");
  933. return (left.Get() == right.get());
  934. }
  935. template <typename TLeft, typename TRight, typename ErrRight>
  936. inline bool operator<(const Microsoft::WRL::ComPtr<TLeft>& left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
  937. {
  938. static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible");
  939. return (left.Get() < right.get());
  940. }
  941. template <typename TLeft, typename TRight, typename ErrRight>
  942. inline bool operator!=(const Microsoft::WRL::ComPtr<TLeft>& left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
  943. { return (!(left == right)); }
  944. template <typename TLeft, typename TRight, typename ErrRight>
  945. inline bool operator>=(const Microsoft::WRL::ComPtr<TLeft>& left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
  946. { return (!(left < right)); }
  947. template <typename TLeft, typename TRight, typename ErrRight>
  948. inline bool operator>(const Microsoft::WRL::ComPtr<TLeft>& left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
  949. { return (right < left); }
  950. template <typename TLeft, typename TRight, typename ErrRight>
  951. inline bool operator<=(const Microsoft::WRL::ComPtr<TLeft>& left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
  952. { return (!(right < left)); }
  953. // raw COM pointer support
  954. //
  955. // Use these for convenience and to avoid unnecessary AddRef/Release cyles when using raw
  956. // pointers to access STL containers. Specify std::less<> to benefit from operator<.
  957. //
  958. // Example: std::set<wil::com_ptr<IUnknown>, std::less<>> set;
  959. template <typename TLeft, typename ErrLeft, typename TRight>
  960. inline bool operator==(const com_ptr_t<TLeft, ErrLeft>& left, TRight* right) WI_NOEXCEPT
  961. {
  962. static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible");
  963. return (left.get() == right);
  964. }
  965. template <typename TLeft, typename ErrLeft, typename TRight>
  966. inline bool operator<(const com_ptr_t<TLeft, ErrLeft>& left, TRight* right) WI_NOEXCEPT
  967. {
  968. static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible");
  969. return (left.get() < right);
  970. }
  971. template <typename TLeft, typename ErrLeft, typename TRight>
  972. inline bool operator!=(const com_ptr_t<TLeft, ErrLeft>& left, TRight* right) WI_NOEXCEPT
  973. { return (!(left == right)); }
  974. template <typename TLeft, typename ErrLeft, typename TRight>
  975. inline bool operator>=(const com_ptr_t<TLeft, ErrLeft>& left, TRight* right) WI_NOEXCEPT
  976. { return (!(left < right)); }
  977. template <typename TLeft, typename ErrLeft, typename TRight>
  978. inline bool operator>(const com_ptr_t<TLeft, ErrLeft>& left, TRight* right) WI_NOEXCEPT
  979. { return (right < left); }
  980. template <typename TLeft, typename ErrLeft, typename TRight>
  981. inline bool operator<=(const com_ptr_t<TLeft, ErrLeft>& left, TRight* right) WI_NOEXCEPT
  982. { return (!(right < left)); }
  983. template <typename TLeft, typename TRight, typename ErrRight>
  984. inline bool operator==(TLeft* left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
  985. {
  986. static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible");
  987. return (left == right.get());
  988. }
  989. template <typename TLeft, typename TRight, typename ErrRight>
  990. inline bool operator<(TLeft* left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
  991. {
  992. static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible");
  993. return (left < right.get());
  994. }
  995. template <typename TLeft, typename TRight, typename ErrRight>
  996. inline bool operator!=(TLeft* left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
  997. { return (!(left == right)); }
  998. template <typename TLeft, typename TRight, typename ErrRight>
  999. inline bool operator>=(TLeft* left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
  1000. { return (!(left < right)); }
  1001. template <typename TLeft, typename TRight, typename ErrRight>
  1002. inline bool operator>(TLeft* left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
  1003. { return (right < left); }
  1004. template <typename TLeft, typename TRight, typename ErrRight>
  1005. inline bool operator<=(TLeft* left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
  1006. { return (!(right < left)); }
  1007. // suppress documentation of every single comparison operator
  1008. /// @endcond
  1009. //! An overloaded function that retrieves the raw com pointer from a raw pointer, wil::com_ptr_t<T>, WRL ComPtr<T>, or Platform::Object^.
  1010. //! This function is primarily useful by library or helper code. It allows code to be written to accept a forwarding reference
  1011. //! template that can be used as an input com pointer. That input com pointer is allowed to be any of:
  1012. //! * Raw Pointer: `T* com_raw_ptr(T* ptr)`
  1013. //! * Wil com_ptr: `T* com_raw_ptr(const wil::com_ptr_t<T, err>& ptr)`
  1014. //! * WRL ComPtr: `T* com_raw_ptr(const Microsoft::WRL::ComPtr<T>& ptr)`
  1015. //! * C++/CX hat: `IInspectable* com_raw_ptr(Platform::Object^ ptr)`
  1016. //!
  1017. //! Which in turn allows code like the following to be written:
  1018. //! ~~~~
  1019. //! template <typename U, typename T>
  1020. //! void com_query_to(T&& ptrSource, _COM_Outptr_ U** ptrResult)
  1021. //! {
  1022. //! auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1023. //! // decltype(raw) has the type of the inner pointer and raw is guaranteed to be a raw com pointer
  1024. //! ~~~~
  1025. template <typename T>
  1026. T* com_raw_ptr(T* ptr)
  1027. {
  1028. return ptr;
  1029. }
  1030. /// @cond
  1031. template <typename T, typename err>
  1032. T* com_raw_ptr(const wil::com_ptr_t<T, err>& ptr)
  1033. {
  1034. return ptr.get();
  1035. }
  1036. template <typename T>
  1037. T* com_raw_ptr(const Microsoft::WRL::ComPtr<T>& ptr)
  1038. {
  1039. return ptr.Get();
  1040. }
  1041. #ifdef __cplusplus_winrt
  1042. template <typename T>
  1043. inline IInspectable* com_raw_ptr(T^ ptr)
  1044. {
  1045. return reinterpret_cast<IInspectable*>(static_cast<::Platform::Object^>(ptr));
  1046. }
  1047. #endif
  1048. /// @endcond
  1049. //! @name Stand-alone query helpers
  1050. //! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr
  1051. //! * Retrieves the requested interface
  1052. //! * AV if the source pointer is null
  1053. //! * Produce an error if the requested interface is unsupported
  1054. //!
  1055. //! See @ref page_query for more information
  1056. //! @{
  1057. #ifdef WIL_ENABLE_EXCEPTIONS
  1058. //! Queries for the specified interface and returns an exception-based wil::com_ptr to that interface (exception if unsupported).
  1059. //! See @ref page_query for more information.
  1060. //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null
  1061. //! @tparam U Represents the interface being queried
  1062. //! @return A `wil::com_ptr<U>` pointer to the given interface `U`. The returned pointer is guaranteed not null.
  1063. template <typename U, typename T>
  1064. inline com_ptr<U> com_query(T&& ptrSource)
  1065. {
  1066. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1067. return com_ptr<U>(raw, details::tag_com_query());
  1068. }
  1069. #endif
  1070. //! Queries for the specified interface and returns a fail-fast-based wil::com_ptr_failfast to that interface (fail-fast if unsupported).
  1071. //! See @ref page_query for more information.
  1072. //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null
  1073. //! @tparam U Represents the interface being queried
  1074. //! @return A `wil::com_ptr<U>` pointer to the given interface `U`. The returned pointer is guaranteed not null.
  1075. template <typename U, typename T>
  1076. inline com_ptr_failfast<U> com_query_failfast(T&& ptrSource)
  1077. {
  1078. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1079. return com_ptr_failfast<U>(raw, details::tag_com_query());
  1080. }
  1081. #ifdef WIL_ENABLE_EXCEPTIONS
  1082. //! Queries for the interface specified by the type of the output parameter (throws an exception if unsupported).
  1083. //! See @ref page_query for more information.
  1084. //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null
  1085. //! @param ptrResult Represents the output pointer to populate. The returned pointer is guaranteed not null.
  1086. template <typename U, typename T>
  1087. _Success_true_ void com_query_to(T&& ptrSource, _COM_Outptr_ U** ptrResult)
  1088. {
  1089. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1090. THROW_IF_FAILED(details::query_policy_t<decltype(raw)>::query(raw, ptrResult));
  1091. __analysis_assume(*ptrResult != nullptr);
  1092. }
  1093. #endif
  1094. //! Queries for the interface specified by the type of the output parameter (fail-fast if unsupported).
  1095. //! See @ref page_query for more information.
  1096. //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null
  1097. //! @param ptrResult Represents the output pointer to populate. The returned pointer is guaranteed not null.
  1098. template <typename U, typename T>
  1099. _Success_true_ void com_query_to_failfast(T&& ptrSource, _COM_Outptr_ U** ptrResult)
  1100. {
  1101. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1102. FAIL_FAST_IF_FAILED(details::query_policy_t<decltype(raw)>::query(raw, ptrResult));
  1103. __analysis_assume(*ptrResult != nullptr);
  1104. }
  1105. //! Queries for the interface specified by the type of the output parameter (returns an error if unsupported).
  1106. //! See @ref page_query for more information.
  1107. //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null
  1108. //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null upon failure.
  1109. //! @return Returns an HRESULT representing whether the query succeeded.
  1110. template <typename U, typename T>
  1111. HRESULT com_query_to_nothrow(T&& ptrSource, _COM_Outptr_ U** ptrResult)
  1112. {
  1113. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1114. auto hr = details::query_policy_t<decltype(raw)>::query(raw, ptrResult);
  1115. __analysis_assume(SUCCEEDED(hr) || (*ptrResult == nullptr));
  1116. RETURN_HR(hr);
  1117. }
  1118. #ifdef WIL_ENABLE_EXCEPTIONS
  1119. //! Queries for the interface specified by the given REFIID parameter (throws an exception if unsupported).
  1120. //! See @ref page_query for more information.
  1121. //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null
  1122. //! @param riid The interface to query for
  1123. //! @param ptrResult Represents the output pointer to populate. The returned pointer is guaranteed not null.
  1124. template <typename T>
  1125. _Success_true_ void com_query_to(T&& ptrSource, REFIID riid, _COM_Outptr_ void** ptrResult)
  1126. {
  1127. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1128. THROW_IF_FAILED(details::query_policy_t<decltype(raw)>::query(raw, riid, ptrResult));
  1129. __analysis_assume(*ptrResult != nullptr);
  1130. }
  1131. #endif
  1132. //! Queries for the interface specified by the given REFIID parameter (fail-fast if unsupported).
  1133. //! See @ref page_query for more information.
  1134. //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null
  1135. //! @param riid The interface to query for
  1136. //! @param ptrResult Represents the output pointer to populate. The returned pointer is guaranteed not null.
  1137. template <typename T>
  1138. _Success_true_ void com_query_to_failfast(T&& ptrSource, REFIID riid, _COM_Outptr_ void** ptrResult)
  1139. {
  1140. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1141. FAIL_FAST_IF_FAILED(details::query_policy_t<decltype(raw)>::query(raw, riid, ptrResult));
  1142. __analysis_assume(*ptrResult != nullptr);
  1143. }
  1144. //! Queries for the interface specified by the given REFIID parameter (returns an error if unsupported).
  1145. //! See @ref page_query for more information.
  1146. //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null
  1147. //! @param riid The interface to query for
  1148. //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null upon failure.
  1149. template <typename T>
  1150. HRESULT com_query_to_nothrow(T&& ptrSource, REFIID riid, _COM_Outptr_ void** ptrResult)
  1151. {
  1152. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1153. auto hr = details::query_policy_t<decltype(raw)>::query(raw, riid, ptrResult);
  1154. __analysis_assume(SUCCEEDED(hr) || (*ptrResult == nullptr));
  1155. RETURN_HR(hr);
  1156. }
  1157. //! @}
  1158. //! @name Stand-alone try query helpers
  1159. //! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr
  1160. //! * Attempts to retrieves the requested interface
  1161. //! * AV if the source pointer is null
  1162. //! * Produce null if the requested interface is unsupported
  1163. //! * bool returns 'true' when query was successful (non-null return result)
  1164. //!
  1165. //! See @ref page_query for more information.
  1166. //! @{
  1167. #ifdef WIL_ENABLE_EXCEPTIONS
  1168. //! Attempts a query for the specified interface and returns an exception-based wil::com_ptr to that interface (returns null if unsupported).
  1169. //! See @ref page_query for more information.
  1170. //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null
  1171. //! @tparam U Represents the interface being queried
  1172. //! @return A `wil::com_ptr<U>` pointer to the given interface `U`. The returned pointer is null if the requested interface was not supported.
  1173. template <class U, typename T>
  1174. inline com_ptr<U> try_com_query(T&& ptrSource)
  1175. {
  1176. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1177. return com_ptr<U>(raw, details::tag_try_com_query());
  1178. }
  1179. #endif
  1180. //! Attempts a query for the specified interface and returns an fail-fast wil::com_ptr_failfast to that interface (returns null if unsupported).
  1181. //! See @ref page_query for more information.
  1182. //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null
  1183. //! @tparam U Represents the interface being queried
  1184. //! @return A `wil::com_ptr_failfast<U>` pointer to the given interface `U`. The returned pointer is null if the requested interface was not supported.
  1185. template <class U, typename T>
  1186. inline com_ptr_failfast<U> try_com_query_failfast(T&& ptrSource)
  1187. {
  1188. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1189. return com_ptr_failfast<U>(raw, details::tag_try_com_query());
  1190. }
  1191. //! Attempts a query for the specified interface and returns an error-code-based wil::com_ptr_nothrow to that interface (returns null if unsupported).
  1192. //! See @ref page_query for more information.
  1193. //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null
  1194. //! @tparam U Represents the interface being queried
  1195. //! @return A `wil::com_ptr_nothrow<U>` pointer to the given interface `U`. The returned pointer is null if the requested interface was not supported.
  1196. template <class U, typename T>
  1197. inline com_ptr_nothrow<U> try_com_query_nothrow(T&& ptrSource)
  1198. {
  1199. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1200. return com_ptr_nothrow<U>(raw, details::tag_try_com_query());
  1201. }
  1202. //! Attempts a query for the interface specified by the type of the output parameter (returns `false` if unsupported).
  1203. //! See @ref page_query for more information.
  1204. //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null.
  1205. //! @param ptrResult Represents the output pointer to populate. If the interface is unsupported, the returned pointer will be null.
  1206. //! @return A bool value representing whether the query was successful (non-null return result).
  1207. template <typename U, typename T>
  1208. _Success_return_ bool try_com_query_to(T&& ptrSource, _COM_Outptr_ U** ptrResult)
  1209. {
  1210. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1211. return (SUCCEEDED(details::query_policy_t<decltype(raw)>::query(raw, ptrResult)));
  1212. }
  1213. //! Attempts a query for the interface specified by the type of the output parameter (returns `false` if unsupported).
  1214. //! See @ref page_query for more information.
  1215. //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null.
  1216. //! @param riid The interface to query for
  1217. //! @param ptrResult Represents the output pointer to populate. If the interface is unsupported, the returned pointer will be null.
  1218. //! @return A bool value representing whether the query was successful (non-null return result).
  1219. template <typename T>
  1220. _Success_return_ bool try_com_query_to(T&& ptrSource, REFIID riid, _COM_Outptr_ void** ptrResult)
  1221. {
  1222. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1223. return (SUCCEEDED(details::query_policy_t<decltype(raw)>::query(raw, riid, ptrResult)));
  1224. }
  1225. //! @}
  1226. //! @name Stand-alone copy helpers
  1227. //! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr
  1228. //! * Retrieves the requested interface
  1229. //! * Succeeds with null if the source pointer is null
  1230. //! * Produce an error if the requested interface is unsupported
  1231. //!
  1232. //! See @ref page_query for more information
  1233. //! @{
  1234. #ifdef WIL_ENABLE_EXCEPTIONS
  1235. //! Queries for the specified interface and returns an exception-based wil::com_ptr to that interface (exception if unsupported, preserves null).
  1236. //! See @ref page_query for more information.
  1237. //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null
  1238. //! @tparam U Represents the interface being queried
  1239. //! @return A `wil::com_ptr<U>` pointer to the given interface `U`. The returned pointer will be null only if the source is null.
  1240. template <class U, typename T>
  1241. inline com_ptr<U> com_copy(T&& ptrSource)
  1242. {
  1243. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1244. return com_ptr<U>(raw, details::tag_com_copy());
  1245. }
  1246. #endif
  1247. //! Queries for the specified interface and returns a fail-fast-based wil::com_ptr_failfast to that interface (fail-fast if unsupported, preserves null).
  1248. //! See @ref page_query for more information.
  1249. //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null
  1250. //! @tparam U Represents the interface being queried
  1251. //! @return A `wil::com_ptr<U>` pointer to the given interface `U`. The returned pointer will be null only if the source is null.
  1252. template <class U, typename T>
  1253. inline com_ptr_failfast<U> com_copy_failfast(T&& ptrSource)
  1254. {
  1255. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1256. return com_ptr_failfast<U>(raw, details::tag_com_copy());
  1257. }
  1258. #ifdef WIL_ENABLE_EXCEPTIONS
  1259. //! Queries for the interface specified by the type of the output parameter (throws an exception if unsupported, preserves null).
  1260. //! See @ref page_query for more information.
  1261. //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null
  1262. //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null only if the source is null.
  1263. template <typename U, typename T>
  1264. _Success_true_ void com_copy_to(T&& ptrSource, _COM_Outptr_result_maybenull_ U** ptrResult)
  1265. {
  1266. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1267. if (raw)
  1268. {
  1269. THROW_IF_FAILED(details::query_policy_t<decltype(raw)>::query(raw, ptrResult));
  1270. return;
  1271. }
  1272. *ptrResult = nullptr;
  1273. }
  1274. #endif
  1275. //! Queries for the interface specified by the type of the output parameter (fail-fast if unsupported, preserves null).
  1276. //! See @ref page_query for more information.
  1277. //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null
  1278. //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null only if the source is null.
  1279. template <typename U, typename T>
  1280. _Success_true_ void com_copy_to_failfast(T&& ptrSource, _COM_Outptr_result_maybenull_ U** ptrResult)
  1281. {
  1282. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1283. if (raw)
  1284. {
  1285. FAIL_FAST_IF_FAILED(details::query_policy_t<decltype(raw)>::query(raw, ptrResult));
  1286. return;
  1287. }
  1288. *ptrResult = nullptr;
  1289. }
  1290. //! Queries for the interface specified by the type of the output parameter (returns an error if unsupported, preserves null).
  1291. //! See @ref page_query for more information.
  1292. //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null
  1293. //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null upon failure or if the source is null.
  1294. //! @return Returns an HRESULT representing whether the query succeeded (returns S_OK if the source is null).
  1295. template <typename U, typename T>
  1296. HRESULT com_copy_to_nothrow(T&& ptrSource, _COM_Outptr_result_maybenull_ U** ptrResult)
  1297. {
  1298. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1299. if (raw)
  1300. {
  1301. RETURN_HR(details::query_policy_t<decltype(raw)>::query(raw, ptrResult));
  1302. }
  1303. *ptrResult = nullptr;
  1304. return S_OK;
  1305. }
  1306. #ifdef WIL_ENABLE_EXCEPTIONS
  1307. //! Queries for the interface specified by the given REFIID parameter (throws an exception if unsupported, preserves null).
  1308. //! See @ref page_query for more information.
  1309. //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null
  1310. //! @param riid The interface to query for
  1311. //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null only if the source is null.
  1312. template <typename T>
  1313. _Success_true_ void com_copy_to(T&& ptrSource, REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult)
  1314. {
  1315. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1316. if (raw)
  1317. {
  1318. THROW_IF_FAILED(details::query_policy_t<decltype(raw)>::query(raw, riid, ptrResult));
  1319. return;
  1320. }
  1321. *ptrResult = nullptr;
  1322. }
  1323. #endif
  1324. //! Queries for the interface specified by the given REFIID parameter (fail-fast if unsupported, preserves null).
  1325. //! See @ref page_query for more information.
  1326. //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null
  1327. //! @param riid The interface to query for
  1328. //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null only if the source is null.
  1329. template <typename T>
  1330. _Success_true_ void com_copy_to_failfast(T&& ptrSource, REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult)
  1331. {
  1332. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1333. if (raw)
  1334. {
  1335. FAIL_FAST_IF_FAILED(details::query_policy_t<decltype(raw)>::query(raw, riid, ptrResult));
  1336. return;
  1337. }
  1338. *ptrResult = nullptr;
  1339. }
  1340. //! Queries for the interface specified by the given REFIID parameter (returns an error if unsupported, preserves null).
  1341. //! See @ref page_query for more information.
  1342. //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null
  1343. //! @param riid The interface to query for
  1344. //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null upon failure or if the source is null.
  1345. //! @return Returns an HRESULT representing whether the query succeeded (returns S_OK if the source is null).
  1346. template <typename T>
  1347. HRESULT com_copy_to_nothrow(T&& ptrSource, REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult)
  1348. {
  1349. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1350. if (raw)
  1351. {
  1352. RETURN_HR(details::query_policy_t<decltype(raw)>::query(raw, riid, ptrResult));
  1353. }
  1354. *ptrResult = nullptr;
  1355. return S_OK;
  1356. }
  1357. //! @}
  1358. //! @name Stand-alone try copy helpers
  1359. //! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr
  1360. //! * Attempts to retrieves the requested interface
  1361. //! * Succeeds with null if the source pointer is null
  1362. //! * Produce null if the requested interface is unsupported
  1363. //! * bool returns 'true' when query was successful (non-null return result)
  1364. //!
  1365. //! See @ref page_query for more information.
  1366. //! @{
  1367. #ifdef WIL_ENABLE_EXCEPTIONS
  1368. //! Attempts a query for the specified interface and returns an exception-based wil::com_ptr to that interface (returns null if unsupported, preserves null).
  1369. //! See @ref page_query for more information.
  1370. //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null
  1371. //! @tparam U Represents the interface being queried
  1372. //! @return A `wil::com_ptr<U>` pointer to the given interface `U`. The returned pointer is null if the requested interface was not supported.
  1373. template <class U, typename T>
  1374. inline com_ptr<U> try_com_copy(T&& ptrSource)
  1375. {
  1376. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1377. return com_ptr<U>(raw, details::tag_try_com_copy());
  1378. }
  1379. #endif
  1380. //! Attempts a query for the specified interface and returns an fail-fast wil::com_ptr_failfast to that interface (returns null if unsupported, preserves null).
  1381. //! See @ref page_query for more information.
  1382. //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null
  1383. //! @tparam U Represents the interface being queried
  1384. //! @return A `wil::com_ptr_failfast<U>` pointer to the given interface `U`. The returned pointer is null if the requested interface was not supported.
  1385. template <class U, typename T>
  1386. inline com_ptr_failfast<U> try_com_copy_failfast(T&& ptrSource)
  1387. {
  1388. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1389. return com_ptr_failfast<U>(raw, details::tag_try_com_copy());
  1390. }
  1391. //! Attempts a query for the specified interface and returns an error-code-based wil::com_ptr_nothrow to that interface (returns null if unsupported, preserves null).
  1392. //! See @ref page_query for more information.
  1393. //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null
  1394. //! @tparam U Represents the interface being queried
  1395. //! @return A `wil::com_ptr_nothrow<U>` pointer to the given interface `U`. The returned pointer is null if the requested interface was not supported.
  1396. template <class U, typename T>
  1397. inline com_ptr_nothrow<U> try_com_copy_nothrow(T&& ptrSource)
  1398. {
  1399. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1400. return com_ptr_nothrow<U>(raw, details::tag_try_com_copy());
  1401. }
  1402. //! Attempts a query for the interface specified by the type of the output parameter (returns `false` if unsupported, preserves null).
  1403. //! See @ref page_query for more information.
  1404. //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null.
  1405. //! @param ptrResult Represents the output pointer to populate. If the interface is unsupported, the returned pointer will be null.
  1406. //! @return A bool value representing whether the query was successful (non-null return result).
  1407. template <typename U, typename T>
  1408. _Success_return_ bool try_com_copy_to(T&& ptrSource, _COM_Outptr_result_maybenull_ U** ptrResult)
  1409. {
  1410. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1411. if (raw)
  1412. {
  1413. return SUCCEEDED(details::query_policy_t<decltype(raw)>::query(raw, ptrResult));
  1414. }
  1415. *ptrResult = nullptr;
  1416. return false;
  1417. }
  1418. //! Attempts a query for the interface specified by the type of the output parameter (returns `false` if unsupported, preserves null).
  1419. //! See @ref page_query for more information.
  1420. //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null.
  1421. //! @param riid The interface to query for
  1422. //! @param ptrResult Represents the output pointer to populate. If the interface is unsupported, the returned pointer will be null.
  1423. //! @return A bool value representing whether the query was successful (non-null return result).
  1424. template <typename T>
  1425. _Success_return_ bool try_com_copy_to(T&& ptrSource, REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult)
  1426. {
  1427. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1428. if (raw)
  1429. {
  1430. return SUCCEEDED(details::query_policy_t<decltype(raw)>::query(raw, riid, ptrResult));
  1431. }
  1432. *ptrResult = nullptr;
  1433. return false;
  1434. }
  1435. //! @}
  1436. #ifdef __cplusplus_winrt
  1437. //! @name Stand-alone helpers to query for CX ref ("hat") types from ABI COM types.
  1438. //! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr
  1439. //! * Retrieves the requested C++/CX interface or ref class.
  1440. //! * Preserves null if the source pointer is null
  1441. //! * Produce an error if the requested interface is unsupported
  1442. //!
  1443. //! See @ref page_query for more information
  1444. //! @{
  1445. template <typename T>
  1446. ::Platform::Object^ cx_object_from_abi(T&& ptr) WI_NOEXCEPT
  1447. {
  1448. IInspectable* const inspectable = com_raw_ptr(wistd::forward<T>(ptr));
  1449. return reinterpret_cast<::Platform::Object^>(inspectable);
  1450. }
  1451. template <typename U, typename T>
  1452. inline U^ cx_safe_cast(T&& ptrSource)
  1453. {
  1454. return safe_cast<U^>(cx_object_from_abi(wistd::forward<T>(ptrSource)));
  1455. }
  1456. template <typename U, typename T>
  1457. inline U^ cx_dynamic_cast(T&& ptrSource) WI_NOEXCEPT
  1458. {
  1459. return dynamic_cast<U^>(cx_object_from_abi(wistd::forward<T>(ptrSource)));
  1460. }
  1461. //! @}
  1462. #endif
  1463. //*****************************************************************************
  1464. // Agile References
  1465. //*****************************************************************************
  1466. #if (NTDDI_VERSION >= NTDDI_WINBLUE)
  1467. #ifdef WIL_ENABLE_EXCEPTIONS
  1468. //! Agile reference to a COM interface, errors throw exceptions (see @ref com_ptr_t and @ref com_agile_query for details)
  1469. using com_agile_ref = com_ptr<IAgileReference>;
  1470. #endif
  1471. //! Agile reference to a COM interface, errors return error codes (see @ref com_ptr_t and @ref com_agile_query_nothrow for details)
  1472. using com_agile_ref_nothrow = com_ptr_nothrow<IAgileReference>;
  1473. //! Agile reference to a COM interface, errors fail fast (see @ref com_ptr_t and @ref com_agile_query_failfast for details)
  1474. using com_agile_ref_failfast = com_ptr_failfast<IAgileReference>;
  1475. //! @name Create agile reference helpers
  1476. //! * Attempts to retrieve an agile reference to the requested interface (see [RoGetAgileReference](https://msdn.microsoft.com/en-us/library/dn269839.aspx))
  1477. //! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr
  1478. //! * `query` methods AV if the source pointer is null
  1479. //! * `copy` methods succeed with null if the source pointer is null
  1480. //! * Accept optional [AgileReferenceOptions](https://msdn.microsoft.com/en-us/library/dn269836.aspx)
  1481. //!
  1482. //! See @ref page_query for more information on resolving an agile ref
  1483. //! @{
  1484. #ifdef WIL_ENABLE_EXCEPTIONS
  1485. //! return a com_agile_ref representing the given source pointer (throws an exception on failure)
  1486. template <typename T>
  1487. com_agile_ref com_agile_query(T&& ptrSource, AgileReferenceOptions options = AGILEREFERENCE_DEFAULT)
  1488. {
  1489. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1490. com_agile_ref agileRef;
  1491. THROW_IF_FAILED(::RoGetAgileReference(options, __uuidof(raw), raw, &agileRef));
  1492. return agileRef;
  1493. }
  1494. #endif
  1495. //! return a com_agile_ref_failfast representing the given source pointer (fail-fast on failure)
  1496. template <typename T>
  1497. com_agile_ref_failfast com_agile_query_failfast(T&& ptrSource, AgileReferenceOptions options = AGILEREFERENCE_DEFAULT)
  1498. {
  1499. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1500. com_agile_ref_failfast agileRef;
  1501. FAIL_FAST_IF_FAILED(::RoGetAgileReference(options, __uuidof(raw), raw, &agileRef));
  1502. return agileRef;
  1503. }
  1504. //! return a com_agile_ref_nothrow representing the given source pointer (returns an HRESULT on failure)
  1505. template <typename T>
  1506. HRESULT com_agile_query_nothrow(T&& ptrSource, _COM_Outptr_ IAgileReference** ptrResult, AgileReferenceOptions options = AGILEREFERENCE_DEFAULT)
  1507. {
  1508. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1509. auto hr = ::RoGetAgileReference(options, __uuidof(raw), raw, ptrResult);
  1510. __analysis_assume(SUCCEEDED(hr) || (*ptrResult == nullptr));
  1511. RETURN_HR(hr);
  1512. }
  1513. #ifdef WIL_ENABLE_EXCEPTIONS
  1514. //! return a com_agile_ref representing the given source pointer (throws an exception on failure, source maybe null)
  1515. template <typename T>
  1516. com_agile_ref com_agile_copy(T&& ptrSource, AgileReferenceOptions options = AGILEREFERENCE_DEFAULT)
  1517. {
  1518. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1519. com_agile_ref agileRef;
  1520. if (raw)
  1521. {
  1522. THROW_IF_FAILED(::RoGetAgileReference(options, __uuidof(raw), raw, &agileRef));
  1523. }
  1524. return agileRef;
  1525. }
  1526. #endif
  1527. //! return a com_agile_ref_failfast representing the given source pointer (fail-fast on failure, source maybe null)
  1528. template <typename T>
  1529. com_agile_ref_failfast com_agile_copy_failfast(T&& ptrSource, AgileReferenceOptions options = AGILEREFERENCE_DEFAULT)
  1530. {
  1531. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1532. com_agile_ref_failfast agileRef;
  1533. if (raw)
  1534. {
  1535. FAIL_FAST_IF_FAILED(::RoGetAgileReference(options, __uuidof(raw), raw, &agileRef));
  1536. }
  1537. return agileRef;
  1538. }
  1539. //! return an agile ref (com_agile_ref_XXX or other representation) representing the given source pointer (return error on failure, source maybe null)
  1540. template <typename T>
  1541. HRESULT com_agile_copy_nothrow(T&& ptrSource, _COM_Outptr_result_maybenull_ IAgileReference** ptrResult, AgileReferenceOptions options = AGILEREFERENCE_DEFAULT)
  1542. {
  1543. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1544. if (raw)
  1545. {
  1546. RETURN_HR(::RoGetAgileReference(options, __uuidof(raw), raw, ptrResult));
  1547. }
  1548. *ptrResult = nullptr;
  1549. return S_OK;
  1550. }
  1551. //! @}
  1552. #endif
  1553. //*****************************************************************************
  1554. // Weak References
  1555. //*****************************************************************************
  1556. namespace details
  1557. {
  1558. template <typename T>
  1559. HRESULT GetWeakReference(T* ptr, _COM_Outptr_ IWeakReference** weakReference)
  1560. {
  1561. static_assert(!wistd::is_same<IWeakReference, T>::value, "Cannot get an IWeakReference to an IWeakReference");
  1562. *weakReference = nullptr;
  1563. com_ptr_nothrow<IWeakReferenceSource> source;
  1564. HRESULT hr = ptr->QueryInterface(IID_PPV_ARGS(&source));
  1565. if (SUCCEEDED(hr))
  1566. {
  1567. hr = source->GetWeakReference(weakReference);
  1568. }
  1569. return hr;
  1570. }
  1571. }
  1572. #ifdef WIL_ENABLE_EXCEPTIONS
  1573. //! Weak reference to a COM interface, errors throw exceptions (see @ref com_ptr_t and @ref com_weak_query for details)
  1574. using com_weak_ref = com_ptr<IWeakReference>;
  1575. #endif
  1576. //! Weak reference to a COM interface, errors return error codes (see @ref com_ptr_t and @ref com_weak_query_nothrow for details)
  1577. using com_weak_ref_nothrow = com_ptr_nothrow<IWeakReference>;
  1578. //! Weak reference to a COM interface, errors fail fast (see @ref com_ptr_t and @ref com_weak_query_failfast for details)
  1579. using com_weak_ref_failfast = com_ptr_failfast<IWeakReference>;
  1580. //! @name Create weak reference helpers
  1581. //! * Attempts to retrieve a weak reference to the requested interface (see WRL's similar [WeakRef](https://msdn.microsoft.com/en-us/library/br244853.aspx))
  1582. //! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr
  1583. //! * `query` methods AV if the source pointer is null
  1584. //! * `copy` methods succeed with null if the source pointer is null
  1585. //!
  1586. //! See @ref page_query for more information on resolving a weak ref
  1587. //! @{
  1588. #ifdef WIL_ENABLE_EXCEPTIONS
  1589. //! return a com_weak_ref representing the given source pointer (throws an exception on failure)
  1590. template <typename T>
  1591. com_weak_ref com_weak_query(T&& ptrSource)
  1592. {
  1593. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1594. com_weak_ref weakRef;
  1595. THROW_IF_FAILED(details::GetWeakReference(raw, &weakRef));
  1596. return weakRef;
  1597. }
  1598. #endif
  1599. //! return a com_weak_ref_failfast representing the given source pointer (fail-fast on failure)
  1600. template <typename T>
  1601. com_weak_ref_failfast com_weak_query_failfast(T&& ptrSource)
  1602. {
  1603. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1604. com_weak_ref_failfast weakRef;
  1605. FAIL_FAST_IF_FAILED(details::GetWeakReference(raw, &weakRef));
  1606. return weakRef;
  1607. }
  1608. //! return a com_weak_ref_nothrow representing the given source pointer (returns an HRESULT on failure)
  1609. template <typename T>
  1610. HRESULT com_weak_query_nothrow(T&& ptrSource, _COM_Outptr_ IWeakReference** ptrResult)
  1611. {
  1612. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1613. auto hr = details::GetWeakReference(raw, ptrResult);
  1614. __analysis_assume(SUCCEEDED(hr) || (*ptrResult == nullptr));
  1615. RETURN_HR(hr);
  1616. }
  1617. #ifdef WIL_ENABLE_EXCEPTIONS
  1618. //! return a com_weak_ref representing the given source pointer (throws an exception on failure, source maybe null)
  1619. template <typename T>
  1620. com_weak_ref com_weak_copy(T&& ptrSource)
  1621. {
  1622. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1623. com_weak_ref weakRef;
  1624. if (raw)
  1625. {
  1626. THROW_IF_FAILED(details::GetWeakReference(raw, &weakRef));
  1627. }
  1628. return weakRef;
  1629. }
  1630. #endif
  1631. //! return a com_weak_ref_failfast representing the given source pointer (fail-fast on failure, source maybe null)
  1632. template <typename T>
  1633. com_weak_ref_failfast com_weak_copy_failfast(T&& ptrSource)
  1634. {
  1635. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1636. com_weak_ref_failfast weakRef;
  1637. if (raw)
  1638. {
  1639. FAIL_FAST_IF_FAILED(details::GetWeakReference(raw, &weakRef));
  1640. }
  1641. return weakRef;
  1642. }
  1643. //! return a com_weak_ref_failfast representing the given source pointer (fail-fast on failure, source maybe null)
  1644. template <typename T>
  1645. HRESULT com_weak_copy_nothrow(T&& ptrSource, _COM_Outptr_result_maybenull_ IWeakReference** ptrResult)
  1646. {
  1647. auto raw = com_raw_ptr(wistd::forward<T>(ptrSource));
  1648. if (raw)
  1649. {
  1650. RETURN_HR(details::GetWeakReference(raw, ptrResult));
  1651. }
  1652. *ptrResult = nullptr;
  1653. return S_OK;
  1654. }
  1655. #pragma region COM Object Helpers
  1656. template <typename T>
  1657. inline bool is_agile(T&& ptrSource)
  1658. {
  1659. wil::com_ptr_nothrow<IAgileObject> agileObject;
  1660. return SUCCEEDED(com_raw_ptr(wistd::forward<T>(ptrSource))->QueryInterface(IID_PPV_ARGS(&agileObject)));
  1661. }
  1662. /** constructs a COM object using an CLSID on a specific interface or IUnknown.*/
  1663. template<typename Interface = IUnknown, typename error_policy = err_exception_policy>
  1664. wil::com_ptr_t<Interface, error_policy> CoCreateInstance(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER)
  1665. {
  1666. wil::com_ptr_t<Interface, error_policy> result;
  1667. error_policy::HResult(::CoCreateInstance(rclsid, nullptr, dwClsContext, IID_PPV_ARGS(&result)));
  1668. return result;
  1669. }
  1670. /** constructs a COM object using the class as the identifier (that has an associated CLSID) on a specific interface or IUnknown. */
  1671. template<typename Class, typename Interface = IUnknown, typename error_policy = err_exception_policy>
  1672. wil::com_ptr_t<Interface, error_policy> CoCreateInstance(DWORD dwClsContext = CLSCTX_INPROC_SERVER)
  1673. {
  1674. return CoCreateInstance<Interface, error_policy>(__uuidof(Class), dwClsContext);
  1675. }
  1676. /** constructs a COM object using an CLSID on a specific interface or IUnknown. */
  1677. template<typename Interface = IUnknown>
  1678. wil::com_ptr_failfast<Interface> CoCreateInstanceFailFast(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER)
  1679. {
  1680. return CoCreateInstance<Interface, err_failfast_policy>(rclsid, dwClsContext);
  1681. }
  1682. /** constructs a COM object using the class as the identifier (that has an associated CLSID) on a specific interface or IUnknown. */
  1683. template<typename Class, typename Interface = IUnknown>
  1684. wil::com_ptr_failfast<Interface> CoCreateInstanceFailFast(DWORD dwClsContext = CLSCTX_INPROC_SERVER)
  1685. {
  1686. return CoCreateInstanceFailFast<Interface>(__uuidof(Class), dwClsContext);
  1687. }
  1688. /** constructs a COM object using an CLSID on a specific interface or IUnknown.
  1689. Note, failures are reported as a null result, the HRESULT is lost. */
  1690. template<typename Interface = IUnknown>
  1691. wil::com_ptr_nothrow<Interface> CoCreateInstanceNoThrow(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER)
  1692. {
  1693. return CoCreateInstance<Interface, err_returncode_policy>(rclsid, dwClsContext);
  1694. }
  1695. /** constructs a COM object using the class as the identifier (that has an associated CLSID) on a specific interface or IUnknown.
  1696. Note, failures are reported as a null result, the HRESULT is lost. */
  1697. template<typename Class, typename Interface = IUnknown>
  1698. wil::com_ptr_nothrow<Interface> CoCreateInstanceNoThrow(DWORD dwClsContext = CLSCTX_INPROC_SERVER)
  1699. {
  1700. return CoCreateInstanceNoThrow<Interface>(__uuidof(Class), dwClsContext);
  1701. }
  1702. /** constructs a COM object class factory using an CLSID on IClassFactory or a specific interface. */
  1703. template<typename Interface = IClassFactory, typename error_policy = err_exception_policy>
  1704. wil::com_ptr_t<Interface, error_policy> CoGetClassObject(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER)
  1705. {
  1706. wil::com_ptr_t<Interface, error_policy> result;
  1707. error_policy::HResult(CoGetClassObject(rclsid, dwClsContext, nullptr, IID_PPV_ARGS(&result)));
  1708. return result;
  1709. }
  1710. /** constructs a COM object class factory using the class as the identifier (that has an associated CLSID)
  1711. on IClassFactory or a specific interface. */
  1712. template<typename Class, typename Interface = IClassFactory, typename error_policy = err_exception_policy>
  1713. wil::com_ptr_t<Interface, error_policy> CoGetClassObject(DWORD dwClsContext = CLSCTX_INPROC_SERVER)
  1714. {
  1715. return CoGetClassObject<Interface, error_policy>(__uuidof(Class), dwClsContext);
  1716. }
  1717. /** constructs a COM object class factory using an CLSID on IClassFactory or a specific interface. */
  1718. template<typename Interface = IClassFactory>
  1719. wil::com_ptr_failfast<Interface> CoGetClassObjectFailFast(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER)
  1720. {
  1721. return CoGetClassObject<Interface, err_failfast_policy>(rclsid, dwClsContext);
  1722. }
  1723. /** constructs a COM object class factory using the class as the identifier (that has an associated CLSID)
  1724. on IClassFactory or a specific interface. */
  1725. template<typename Class, typename Interface = IClassFactory>
  1726. wil::com_ptr_failfast<Interface> CoGetClassObjectFailFast(DWORD dwClsContext = CLSCTX_INPROC_SERVER)
  1727. {
  1728. return CoGetClassObjectFailFast<Interface>(__uuidof(Class), dwClsContext);
  1729. }
  1730. /** constructs a COM object class factory using an CLSID on IClassFactory or a specific interface.
  1731. Note, failures are reported as a null result, the HRESULT is lost. */
  1732. template<typename Interface = IClassFactory>
  1733. wil::com_ptr_nothrow<Interface> CoGetClassObjectNoThrow(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER)
  1734. {
  1735. return CoGetClassObject<Interface, err_returncode_policy>(rclsid, dwClsContext);
  1736. }
  1737. /** constructs a COM object class factory using the class as the identifier (that has an associated CLSID)
  1738. on IClassFactory or a specific interface.
  1739. Note, failures are reported as a null result, the HRESULT is lost. */
  1740. template<typename Class, typename Interface = IClassFactory>
  1741. wil::com_ptr_nothrow<Interface> CoGetClassObjectNoThrow(DWORD dwClsContext = CLSCTX_INPROC_SERVER)
  1742. {
  1743. return CoGetClassObjectNoThrow<Interface>(__uuidof(Class), dwClsContext);
  1744. }
  1745. #pragma endregion
  1746. #pragma region Stream helpers
  1747. /** Read data from a stream into a buffer.
  1748. Reads up to a certain number of bytes into a buffer. Returns the amount of data written, which
  1749. may be less than the amount requested if the stream ran out.
  1750. ~~~~
  1751. IStream* source = // ...
  1752. ULONG dataBlob = 0;
  1753. size_t read = 0;
  1754. RETURN_IF_FAILED(wil::stream_read_partial_nothrow(source, &dataBlob, sizeof(dataBlob), &read));
  1755. if (read != sizeof(dataBlob))
  1756. {
  1757. // end of stream, probably
  1758. }
  1759. else if (dataBlob == 0x8675309)
  1760. {
  1761. DoThing(dataBlob);
  1762. }
  1763. ~~~~
  1764. @param stream The stream from which to read at most `size` bytes.
  1765. @param data A buffer into which up to `size` bytes will be read
  1766. @param size The size, in bytes, of the buffer pointed to by `data`
  1767. @param wrote The amount, in bytes, of data read from `stream` into `data`
  1768. */
  1769. inline HRESULT stream_read_partial_nothrow(_In_ ISequentialStream* stream, _Out_writes_bytes_to_(size, *wrote) void* data, unsigned long size, unsigned long *wrote)
  1770. {
  1771. RETURN_HR(stream->Read(data, size, wrote));
  1772. }
  1773. /** Read an exact number of bytes from a stream into a buffer.
  1774. Fails if the stream didn't read all the bytes requested.
  1775. ~~~~
  1776. IStream* source = // ...
  1777. ULONG dataBlob = 0;
  1778. RETURN_IF_FAILED(wil::stream_read_nothrow(source, &dataBlob, sizeof(dataBlob)));
  1779. if (dataBlob == 0x8675309)
  1780. {
  1781. DoThing(dataBlob);
  1782. }
  1783. ~~~~
  1784. @param stream The stream from which to read at most `size` bytes.
  1785. @param data A buffer into which up to `size` bytes will be read
  1786. @param size The size, in bytes, of the buffer pointed to by `data`
  1787. @return The underlying stream read result, or HRESULT_FROM_WIN32(ERROR_INVALID_DATA) if the stream
  1788. did not read the complete buffer.
  1789. */
  1790. inline HRESULT stream_read_nothrow(_In_ ISequentialStream* stream, _Out_writes_bytes_all_(size) void* data, unsigned long size)
  1791. {
  1792. unsigned long didRead;
  1793. RETURN_IF_FAILED(stream_read_partial_nothrow(stream, data, size, &didRead));
  1794. RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), didRead != size);
  1795. return S_OK;
  1796. }
  1797. /** Read from a stream into a POD type.
  1798. Fails if the stream didn't have enough bytes.
  1799. ~~~~
  1800. IStream* source = // ...
  1801. MY_HEADER header{};
  1802. RETURN_IF_FAILED(wil::stream_read_nothrow(source, &header));
  1803. if (header.Version == 0x8675309)
  1804. {
  1805. ConsumeOldHeader(stream, header);
  1806. }
  1807. ~~~~
  1808. @param stream The stream from which to read at most `size` bytes.
  1809. @param pThing The POD data type to read from the stream.
  1810. @return The underlying stream read result, or HRESULT_FROM_WIN32(ERROR_INVALID_DATA) if the stream
  1811. did not read the complete buffer.
  1812. */
  1813. template<typename T> HRESULT stream_read_nothrow(_In_ ISequentialStream* stream, _Out_ T* pThing)
  1814. {
  1815. static_assert(__is_pod(T), "Type must be POD.");
  1816. return stream_read_nothrow(stream, pThing, sizeof(T));
  1817. }
  1818. /** Write an exact number of bytes to a stream from a buffer.
  1819. Fails if the stream didn't read write the bytes requested.
  1820. ~~~~
  1821. IStream* source = // ...
  1822. ULONG dataBlob = 0x8675309;
  1823. RETURN_IF_FAILED(wil::stream_write_nothrow(source, &dataBlob, sizeof(dataBlob)));
  1824. ~~~~
  1825. @param stream The stream to which to write at most `size` bytes.
  1826. @param data A buffer from which up to `size` bytes will be read
  1827. @param size The size, in bytes, of the buffer pointed to by `data`
  1828. */
  1829. inline HRESULT stream_write_nothrow(_In_ ISequentialStream* stream, _In_reads_bytes_(size) const void* data, unsigned long size)
  1830. {
  1831. unsigned long wrote;
  1832. RETURN_IF_FAILED(stream->Write(data, size, &wrote));
  1833. RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), wrote != size);
  1834. return S_OK;
  1835. }
  1836. /** Write a POD type to a stream.
  1837. Fails if not all the bytes were written.
  1838. ~~~~
  1839. IStream* source = // ...
  1840. MY_HEADER header { 0x8675309, HEADER_FLAG_1 | HEADER_FLAG_2 };
  1841. RETURN_IF_FAILED(wil::stream_write_nothrow(source, header));
  1842. ULONGLONG value = 16;
  1843. RETURN_IF_FAILED(wil::stream_write_nothrow(source, value));
  1844. ~~~~
  1845. @param stream The stream to which to write `thing`
  1846. @param thing The POD data type to write to the stream.
  1847. */
  1848. template<typename T> inline HRESULT stream_write_nothrow(_In_ ISequentialStream* stream, const T& thing)
  1849. {
  1850. return stream_write_nothrow(stream, wistd::addressof(thing), sizeof(thing));
  1851. }
  1852. /** Retrieve the size of this stream, in bytes
  1853. ~~~~
  1854. IStream* source = // ...
  1855. ULONGLONG size;
  1856. RETURN_IF_FAILED(wil::stream_size_nothrow(source, &size));
  1857. RETURN_HR_IF(E_INVALIDARG, size > ULONG_MAX);
  1858. ~~~~
  1859. @param stream The stream whose size is to be returned in `value`
  1860. @param value The size, in bytes, reported by `stream`
  1861. */
  1862. inline HRESULT stream_size_nothrow(_In_ IStream* stream, _Out_ unsigned long long* value)
  1863. {
  1864. STATSTG st{};
  1865. RETURN_IF_FAILED(stream->Stat(&st, STATFLAG_NONAME));
  1866. *value = st.cbSize.QuadPart;
  1867. return S_OK;
  1868. }
  1869. /** Seek a stream to a relative offset or absolute position
  1870. ~~~~
  1871. IStream* source = // ...
  1872. unsigned long long landed;
  1873. RETURN_IF_FAILED(wil::stream_seek_nothrow(source, 16, STREAM_SEEK_CUR, &landed));
  1874. RETURN_IF_FAILED(wil::stream_seek_nothrow(source, -5, STREAM_SEEK_END));
  1875. RETURN_IF_FAILED(wil::stream_seek_nothrow(source, LLONG_MAX, STREAM_SEEK_CUR));
  1876. ~~~~
  1877. @param stream The stream to seek
  1878. @param offset The position, in bytes from the current position, to seek
  1879. @param from The starting point from which to seek, from the STREAM_SEEK_* set of values
  1880. @param value Optionally recieves the new absolute position from the stream
  1881. */
  1882. inline HRESULT stream_seek_nothrow(_In_ IStream* stream, long long offset, unsigned long from, _Out_opt_ unsigned long long* value = nullptr)
  1883. {
  1884. LARGE_INTEGER amount;
  1885. ULARGE_INTEGER landed{};
  1886. amount.QuadPart = offset;
  1887. RETURN_IF_FAILED(stream->Seek(amount, from, value ? &landed : nullptr));
  1888. assign_to_opt_param(value, landed.QuadPart);
  1889. return S_OK;
  1890. }
  1891. /** Seek a stream to an absolute offset
  1892. ~~~~
  1893. IStream* source = // ...
  1894. RETURN_HR(wil::stream_set_position_nothrow(source, 16));
  1895. ~~~~
  1896. @param stream The stream whose size is to be returned in `value`
  1897. @param offset The position, in bytes from the start of the stream, to seek to
  1898. @param value Optionally recieves the new absolute position from the stream
  1899. */
  1900. inline HRESULT stream_set_position_nothrow(_In_ IStream* stream, unsigned long long offset, _Out_opt_ unsigned long long* value = nullptr)
  1901. {
  1902. // IStream::Seek(..., _SET) interprets the first parameter as an unsigned value.
  1903. return stream_seek_nothrow(stream, static_cast<long long>(offset), STREAM_SEEK_SET, value);
  1904. }
  1905. /** Seek a relative amount in a stream
  1906. ~~~~
  1907. IStream* source = // ...
  1908. RETURN_IF_FAILED(wil::stream_seek_from_current_position_nothrow(source, -16));
  1909. ULONGLONG newPosition;
  1910. RETURN_IF_FAILED(wil::stream_seek_from_current_position_nothrow(source, 16, &newPosition));
  1911. ~~~~
  1912. @param stream The stream whose location is to be moved
  1913. @param amount The offset, in bytes, to seek the stream.
  1914. @param value Set to the new absolute steam position, in bytes
  1915. */
  1916. inline HRESULT stream_seek_from_current_position_nothrow(_In_ IStream* stream, long long amount, _Out_opt_ unsigned long long* value = nullptr)
  1917. {
  1918. return stream_seek_nothrow(stream, amount, STREAM_SEEK_CUR, value);
  1919. }
  1920. /** Determine the current byte position in the stream
  1921. ~~~~
  1922. IStream* source = // ...
  1923. ULONGLONG currentPos;
  1924. RETURN_IF_FAILED(wil::stream_get_position_nothrow(source, &currentPos));
  1925. ~~~~
  1926. @param stream The stream whose location is to be moved
  1927. @param position Set to the current absolute steam position, in bytes
  1928. */
  1929. inline HRESULT stream_get_position_nothrow(_In_ IStream* stream, _Out_ unsigned long long* position)
  1930. {
  1931. return stream_seek_from_current_position_nothrow(stream, 0, position);
  1932. }
  1933. /** Moves the stream to absolute position 0
  1934. ~~~~
  1935. IStream* source = // ...
  1936. RETURN_IF_FAILED(wil::stream_reset_nothrow(source));
  1937. ~~~~
  1938. @param stream The stream whose location is to be moved
  1939. */
  1940. inline HRESULT stream_reset_nothrow(_In_ IStream* stream)
  1941. {
  1942. return stream_set_position_nothrow(stream, 0);
  1943. }
  1944. /** Copy data from one stream to another, returning the final amount copied.
  1945. ~~~~
  1946. IStream* source = // ...
  1947. IStream* target = // ...
  1948. ULONGLONG copied;
  1949. RETURN_IF_FAILED(wil::stream_copy_bytes_nothrow(source, target, sizeof(MyType), &copied));
  1950. if (copied < sizeof(MyType))
  1951. {
  1952. DoSomethingAboutPartialCopy();
  1953. }
  1954. ~~~~
  1955. @param source The stream from which to copy at most `amount` bytes
  1956. @param target The steam to which to copy at most `amount` bytes
  1957. @param amount The maximum number of bytes to copy from `source` to `target`
  1958. @param pCopied If non-null, set to the number of bytes copied between the two.
  1959. */
  1960. inline HRESULT stream_copy_bytes_nothrow(_In_ IStream* source, _In_ IStream* target, unsigned long long amount, _Out_opt_ unsigned long long* pCopied = nullptr)
  1961. {
  1962. ULARGE_INTEGER toCopy;
  1963. ULARGE_INTEGER copied;
  1964. toCopy.QuadPart = amount;
  1965. RETURN_IF_FAILED(source->CopyTo(target, toCopy, nullptr, &copied));
  1966. assign_to_opt_param(pCopied, copied.QuadPart);
  1967. return S_OK;
  1968. }
  1969. /** Copy all data from one stream to another, returning the final amount copied.
  1970. ~~~~
  1971. IStream* source = // ...
  1972. IStream* target = // ...
  1973. ULONGLONG copied;
  1974. RETURN_IF_FAILED(wil::stream_copy_all_nothrow(source, target, &copied));
  1975. if (copied < 8)
  1976. {
  1977. DoSomethingAboutPartialCopy();
  1978. }
  1979. ~~~~
  1980. @param source The stream from which to copy all content
  1981. @param target The steam to which to copy all content
  1982. @param pCopied If non-null, set to the number of bytes copied between the two.
  1983. */
  1984. inline HRESULT stream_copy_all_nothrow(_In_ IStream* source, _In_ IStream* target, _Out_opt_ unsigned long long* pCopied = nullptr)
  1985. {
  1986. return stream_copy_bytes_nothrow(source, target, ULLONG_MAX, pCopied);
  1987. }
  1988. /** Copies an exact amount of data from one stream to another, failing otherwise
  1989. ~~~~
  1990. IStream* source = // ...
  1991. IStream* target = // ...
  1992. RETURN_IF_FAILED(wil::stream_copy_all_nothrow(source, target, 16));
  1993. ~~~~
  1994. @param source The stream from which to copy at most `amount` bytes
  1995. @param target The steam to which to copy at most `amount` bytes
  1996. @param amount The number of bytes to copy from `source` to `target`
  1997. */
  1998. inline HRESULT stream_copy_exact_nothrow(_In_ IStream* source, _In_ IStream* target, unsigned long long amount)
  1999. {
  2000. unsigned long long copied;
  2001. RETURN_IF_FAILED(stream_copy_bytes_nothrow(source, target, ULLONG_MAX, &copied));
  2002. RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), copied != amount);
  2003. return S_OK;
  2004. }
  2005. //! Controls behavior when reading a zero-length string from a stream
  2006. enum class empty_string_options
  2007. {
  2008. //! Zero-length strings are returned as nullptr
  2009. returns_null,
  2010. //! Zero-length strings are allocated and returned with zero characters
  2011. returns_empty,
  2012. };
  2013. #ifdef __WIL_OBJBASE_H_
  2014. /** Read a string from a stream and returns an allocated copy
  2015. Deserializes strings in streams written by both IStream_WriteStr and wil::stream_write_string[_nothrow]. The format
  2016. is a single 16-bit quantity, followed by that many wchar_ts. The returned string is allocated with CoTaskMemAlloc.
  2017. Returns a zero-length (but non-null) string if the stream contained a zero-length string.
  2018. ~~~~
  2019. IStream* source = // ...
  2020. wil::unique_cotaskmem_string content;
  2021. RETURN_IF_FAILED(wil::stream_read_string_nothrow(source, &content));
  2022. if (wcscmp(content.get(), L"waffles") == 0)
  2023. {
  2024. // Waffles!
  2025. }
  2026. ~~~~
  2027. @param source The stream from which to read a string
  2028. @param value Set to point to the allocated result of reading a string from `source`
  2029. */
  2030. inline HRESULT stream_read_string_nothrow(
  2031. _In_ ISequentialStream* source,
  2032. _When_(options == empty_string_options::returns_empty, _Outptr_result_z_) _When_(options == empty_string_options::returns_null, _Outptr_result_maybenull_z_) wchar_t** value,
  2033. empty_string_options options = empty_string_options::returns_empty)
  2034. {
  2035. unsigned short cch;
  2036. RETURN_IF_FAILED(stream_read_nothrow(source, &cch));
  2037. if ((cch == 0) && (options == empty_string_options::returns_null))
  2038. {
  2039. *value = nullptr;
  2040. }
  2041. else
  2042. {
  2043. auto allocated = make_unique_cotaskmem_nothrow<wchar_t[]>(static_cast<size_t>(cch) + 1);
  2044. RETURN_IF_NULL_ALLOC(allocated);
  2045. RETURN_IF_FAILED(stream_read_nothrow(source, allocated.get(), static_cast<unsigned long>(cch) * sizeof(wchar_t)));
  2046. allocated[cch] = 0;
  2047. *value = allocated.release();
  2048. }
  2049. return S_OK;
  2050. }
  2051. #endif // __WIL_OBJBASE_H
  2052. /** Write a string to a stream
  2053. Serializes a string into a stream by putting its length and then the wchar_ts in the string
  2054. into the stream. Zero-length strings have their length but no data written. This is the
  2055. form expected by IStream_ReadStr and wil::string_read_stream.
  2056. ~~~~
  2057. IStream* target = // ...
  2058. RETURN_IF_FAILED(wil::stream_write_string_nothrow(target, L"Waffles", 3));
  2059. // Produces wchar_t[] { 0x3, L'W', L'a', L'f' };
  2060. ~~~~
  2061. @param target The stream to which to write a string
  2062. @param source The string to write. Can be null if `writeLength` is zero
  2063. @param writeLength The number of characters to write from source into `target`
  2064. */
  2065. inline HRESULT stream_write_string_nothrow(_In_ ISequentialStream* target, _In_reads_opt_(writeLength) const wchar_t* source, _In_ size_t writeLength)
  2066. {
  2067. FAIL_FAST_IF(writeLength > USHRT_MAX);
  2068. RETURN_IF_FAILED(stream_write_nothrow(target, static_cast<unsigned short>(writeLength)));
  2069. if (writeLength > 0)
  2070. {
  2071. RETURN_IF_FAILED(stream_write_nothrow(target, source, static_cast<unsigned short>(writeLength) * sizeof(wchar_t)));
  2072. }
  2073. return S_OK;
  2074. }
  2075. /** Write a string to a stream
  2076. Serializes a string into a stream by putting its length and then the wchar_ts in the string
  2077. into the stream. Zero-length strings have their length but no data written. This is the
  2078. form expected by IStream_ReadStr and wil::string_read_stream.
  2079. ~~~~
  2080. IStream* target = // ...
  2081. RETURN_IF_FAILED(wil::stream_write_string_nothrow(target, L"Waffles"));
  2082. // Produces wchar_t[] { 0x3, L'W', L'a', L'f', L'f', L'l', L'e', L's' };
  2083. ~~~~
  2084. @param target The stream to which to write a string
  2085. @param source The string to write. When nullptr, a zero-length string is written.
  2086. */
  2087. inline HRESULT stream_write_string_nothrow(_In_ ISequentialStream* target, _In_opt_z_ const wchar_t* source)
  2088. {
  2089. return stream_write_string_nothrow(target, source, source ? wcslen(source) : 0);
  2090. }
  2091. #ifdef WIL_ENABLE_EXCEPTIONS
  2092. /** Read data from a stream into a buffer.
  2093. ~~~~
  2094. IStream* source = // ...
  2095. ULONG dataBlob = 0;
  2096. auto read = wil::stream_read_partial(source, &dataBlob, sizeof(dataBlob));
  2097. if (read != sizeof(dataBlob))
  2098. {
  2099. // end of stream, probably
  2100. }
  2101. else if (dataBlob == 0x8675309)
  2102. {
  2103. DoThing(dataBlob);
  2104. }
  2105. ~~~~
  2106. @param stream The stream from which to read at most `size` bytes.
  2107. @param data A buffer into which up to `size` bytes will be read
  2108. @param size The size, in bytes, of the buffer pointed to by `data`
  2109. @return The amount, in bytes, of data read from `stream` into `data`
  2110. */
  2111. inline unsigned long stream_read_partial(_In_ ISequentialStream* stream, _Out_writes_bytes_to_(size, return) void* data, unsigned long size)
  2112. {
  2113. unsigned long didRead;
  2114. THROW_IF_FAILED(stream_read_partial_nothrow(stream, data, size, &didRead));
  2115. return didRead;
  2116. }
  2117. /** Read an exact number of bytes from a stream into a buffer.
  2118. Fails if the stream didn't read all the bytes requested by throwing HRESULT_FROM_WIN32(ERROR_INVALID_DATA).
  2119. ~~~~
  2120. IStream* source = // ...
  2121. ULONG dataBlob = 0;
  2122. wil::stream_read(source, &dataBlob, sizeof(dataBlob));
  2123. if (dataBlob == 0x8675309)
  2124. {
  2125. DoThing(dataBlob);
  2126. }
  2127. ~~~~
  2128. @param stream The stream from which to read at most `size` bytes.
  2129. @param data A buffer into which up to `size` bytes will be read
  2130. @param size The size, in bytes, of the buffer pointed to by `data`
  2131. */
  2132. inline void stream_read(_In_ ISequentialStream* stream, _Out_writes_bytes_all_(size) void* data, unsigned long size)
  2133. {
  2134. THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), stream_read_partial(stream, data, size) != size);
  2135. }
  2136. /** Read from a stream into a POD type.
  2137. Fails if the stream didn't have enough bytes by throwing HRESULT_FROM_WIN32(ERROR_INVALID_DATA).
  2138. ~~~~
  2139. IStream* source = // ...
  2140. MY_HEADER header = wil::stream_read<MY_HEADER>(source);
  2141. if (header.Version == 0x8675309)
  2142. {
  2143. ConsumeOldHeader(stream, header);
  2144. }
  2145. ~~~~
  2146. @param stream The stream from which to read at most `sizeof(T)` bytes.
  2147. @return An instance of `T` read from the stream
  2148. */
  2149. template<typename T> T stream_read(_In_ ISequentialStream* stream)
  2150. {
  2151. static_assert(__is_pod(T), "Read type must be POD");
  2152. T temp{};
  2153. stream_read(stream, &temp, sizeof(temp));
  2154. return temp;
  2155. }
  2156. /** Write an exact number of bytes to a stream from a buffer.
  2157. Fails if the stream didn't read write the bytes requested.
  2158. ~~~~
  2159. IStream* source = // ...
  2160. ULONG dataBlob = 0;
  2161. wil::stream_write(source, dataBlob, sizeof(dataBlob));
  2162. ~~~~
  2163. @param stream The stream to which to write at most `size` bytes.
  2164. @param data A buffer from which up to `size` bytes will be read
  2165. @param size The size, in bytes, of the buffer pointed to by `data`
  2166. */
  2167. inline void stream_write(_In_ ISequentialStream* stream, _In_reads_bytes_(size) const void* data, unsigned long size)
  2168. {
  2169. THROW_IF_FAILED(stream_write_nothrow(stream, data, size));
  2170. }
  2171. /** Write a POD type to a stream.
  2172. Fails if the stream didn't accept the entire size.
  2173. ~~~~
  2174. IStream* target = // ...
  2175. MY_HEADER header { 0x8675309, HEADER_FLAG_1 | HEADER_FLAG_2 };
  2176. wil::stream_write(target, header)
  2177. wil::stream_write<ULONGLONG>(target, 16);
  2178. ~~~~
  2179. @param stream The stream to which to write `thing`
  2180. @param thing The POD data type to write to the stream.
  2181. */
  2182. template<typename T> inline void stream_write(_In_ ISequentialStream* stream, const T& thing)
  2183. {
  2184. stream_write(stream, wistd::addressof(thing), sizeof(thing));
  2185. }
  2186. /** Retrieve the size of this stream, in bytes
  2187. ~~~~
  2188. IStream* source = // ...
  2189. ULONGLONG size = wil::stream_size(source);
  2190. ~~~~
  2191. @param stream The stream whose size is to be returned in `value`
  2192. @return The size, in bytes, reported by `stream`
  2193. */
  2194. inline unsigned long long stream_size(_In_ IStream* stream)
  2195. {
  2196. unsigned long long size;
  2197. THROW_IF_FAILED(stream_size_nothrow(stream, &size));
  2198. return size;
  2199. }
  2200. /** Seek a stream to an absolute offset
  2201. ~~~~
  2202. IStream* source = // ...
  2203. wil::stream_set_position(source, sizeof(HEADER));
  2204. ~~~~
  2205. @param stream The stream whose size is to be returned in `value`
  2206. @param offset The offset, in bytes, to seek the stream.
  2207. @return The new absolute stream position, in bytes
  2208. */
  2209. inline unsigned long long stream_set_position(_In_ IStream* stream, unsigned long long offset)
  2210. {
  2211. unsigned long long landed;
  2212. THROW_IF_FAILED(stream_set_position_nothrow(stream, offset, &landed));
  2213. return landed;
  2214. }
  2215. /** Seek a relative amount in a stream
  2216. ~~~~
  2217. IStream* source = // ...
  2218. ULONGLONG newPosition = wil::stream_seek_from_current_position(source, 16);
  2219. ~~~~
  2220. @param stream The stream whose location is to be moved
  2221. @param amount The offset, in bytes, to seek the stream.
  2222. @return The new absolute stream position, in bytes
  2223. */
  2224. inline unsigned long long stream_seek_from_current_position(_In_ IStream* stream, long long amount)
  2225. {
  2226. unsigned long long landed;
  2227. THROW_IF_FAILED(stream_seek_from_current_position_nothrow(stream, amount, &landed));
  2228. return landed;
  2229. }
  2230. /** Determine the current byte position in the stream
  2231. ~~~~
  2232. IStream* source = // ...
  2233. ULONGLONG currentPos = wil::stream_get_position(source);
  2234. ~~~~
  2235. @param stream The stream whose location is to be moved
  2236. @return The current position reported by `stream`
  2237. */
  2238. inline unsigned long long stream_get_position(_In_ IStream* stream)
  2239. {
  2240. return stream_seek_from_current_position(stream, 0);
  2241. }
  2242. /** Moves the stream to absolute position 0
  2243. ~~~~
  2244. IStream* source = // ...
  2245. wil::stream_reset(source);
  2246. ASSERT(wil::stream_get_position(source) == 0);
  2247. ~~~~
  2248. @param stream The stream whose location is to be moved
  2249. */
  2250. inline void stream_reset(_In_ IStream* stream)
  2251. {
  2252. stream_set_position(stream, 0);
  2253. }
  2254. /** Copy data from one stream to another
  2255. ~~~~
  2256. IStream* source = // ...
  2257. IStream* target = // ...
  2258. ULONGLONG copied = ;
  2259. if (wil::stream_copy_bytes(source, target, sizeof(Header)) < sizeof(Header))
  2260. {
  2261. DoSomethingAboutPartialCopy();
  2262. }
  2263. ~~~~
  2264. @param source The stream from which to copy at most `amount` bytes
  2265. @param target The steam to which to copy at most `amount` bytes
  2266. @param amount The maximum number of bytes to copy from `source` to `target`
  2267. @return The number of bytes copied between the two streams
  2268. */
  2269. inline unsigned long long stream_copy_bytes(_In_ IStream* source, _In_ IStream* target, unsigned long long amount)
  2270. {
  2271. unsigned long long copied;
  2272. THROW_IF_FAILED(stream_copy_bytes_nothrow(source, target, amount, &copied));
  2273. return copied;
  2274. }
  2275. /** Copy all data from one stream to another
  2276. ~~~~
  2277. IStream* source = // ...
  2278. IStream* target = // ...
  2279. ULONGLONG copied = wil::stream_copy_all(source, target);
  2280. ~~~~
  2281. @param source The stream from which to copy all content
  2282. @param target The steam to which to copy all content
  2283. @return The number of bytes copied between the two.
  2284. */
  2285. inline unsigned long long stream_copy_all(_In_ IStream* source, _In_ IStream* target)
  2286. {
  2287. return stream_copy_bytes(source, target, ULLONG_MAX);
  2288. }
  2289. /** Copies an exact amount of data from one stream to another, failing otherwise
  2290. ~~~~
  2291. IStream* source = // ...
  2292. IStream* target = // ...
  2293. wil::stream_copy_all_nothrow(source, target, sizeof(SOMETHING));
  2294. ~~~~
  2295. @param source The stream from which to copy at most `amount` bytes
  2296. @param target The steam to which to copy at most `amount` bytes
  2297. @param amount The number of bytes to copy from `source` to `target`
  2298. */
  2299. inline void stream_copy_exact(_In_ IStream* source, _In_ IStream* target, unsigned long long amount)
  2300. {
  2301. THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), stream_copy_bytes(source, target, amount) != amount);
  2302. }
  2303. #ifdef __WIL_OBJBASE_H_
  2304. /** Read a string from a stream and returns an allocated copy
  2305. Deserializes strings in streams written by both IStream_WriteStr and wil::stream_write_string[_nothrow]. The format
  2306. is a single 16-bit quantity, followed by that many wchar_ts. The returned string is allocated with CoTaskMemAlloc.
  2307. Returns a zero-length (but non-null) string if the stream contained a zero-length string.
  2308. ~~~~
  2309. IStream* source = // ...
  2310. wil::unique_cotaskmem_string content = wil::stream_read_string(source);
  2311. if (wcscmp(content.get(), L"waffles") == 0)
  2312. {
  2313. // Waffles!
  2314. }
  2315. ~~~~
  2316. @param source The stream from which to read a string
  2317. @return An non-null string (but possibly zero lengh) string read from `source`
  2318. */
  2319. inline wil::unique_cotaskmem_string stream_read_string(_In_ ISequentialStream* source, empty_string_options options = empty_string_options::returns_empty)
  2320. {
  2321. wil::unique_cotaskmem_string result;
  2322. THROW_IF_FAILED(stream_read_string_nothrow(source, &result, options));
  2323. return result;
  2324. }
  2325. #endif // __WIL_OBJBASE_H
  2326. /** Write a string to a stream
  2327. Serializes a string into a stream by putting its length and then the wchar_ts in the string
  2328. into the stream. Zero-length strings have their length but no data written. This is the
  2329. form expected by IStream_ReadStr and wil::string_read_stream.
  2330. ~~~~
  2331. IStream* target = // ...
  2332. wil::stream_write_string(target, L"Waffles", 3);
  2333. ~~~~
  2334. @param target The stream to which to write a string
  2335. @param source The string to write. Can be null if `writeLength` is zero
  2336. @param writeLength The number of characters to write from source into `target`
  2337. */
  2338. inline void stream_write_string(_In_ ISequentialStream* target, _In_reads_opt_(toWriteCch) const wchar_t* source, _In_ size_t toWriteCch)
  2339. {
  2340. THROW_IF_FAILED(stream_write_string_nothrow(target, source, toWriteCch));
  2341. }
  2342. /** Write a string to a stream
  2343. Serializes a string into a stream by putting its length and then the wchar_ts in the string
  2344. into the stream. Zero-length strings have their length but no data written.This is the
  2345. form expected by IStream_ReadStr and wil::string_read_stream.
  2346. ~~~~
  2347. IStream* target = // ...
  2348. wil::stream_write_string(target, L"Waffles");
  2349. ~~~~
  2350. @param target The stream to which to write a string
  2351. @param source The string to write. When nullptr, a zero-length string is written.
  2352. */
  2353. inline void stream_write_string(_In_ ISequentialStream* target, _In_opt_z_ const wchar_t* source)
  2354. {
  2355. THROW_IF_FAILED(stream_write_string_nothrow(target, source, source ? wcslen(source) : 0));
  2356. }
  2357. /** Saves and restores the position of a stream
  2358. Useful for potentially reading data from a stream, or being able to read ahead, then reset
  2359. back to where one left off, such as conditionally reading content from a stream.
  2360. ~~~~
  2361. void MaybeConsumeStream(IStream* stream)
  2362. {
  2363. // On error, reset the read position in the stream to where we left off
  2364. auto saver = wil::stream_position_saver(stream);
  2365. auto header = wil::stream_read<MY_HEADER>(stream);
  2366. for (ULONG i = 0; i < header.Count; ++i)
  2367. {
  2368. ProcessElement(wil::stream_read<MY_ELEMENT>(stream));
  2369. }
  2370. }
  2371. ~~~~
  2372. */
  2373. class stream_position_saver
  2374. {
  2375. public:
  2376. //! Constructs a saver from the current position of this stream
  2377. //! @param stream The stream instance whose position is to be saved.
  2378. explicit stream_position_saver(_In_opt_ IStream* stream) :
  2379. m_stream(stream),
  2380. m_position(stream ? stream_get_position(stream) : 0)
  2381. {
  2382. }
  2383. ~stream_position_saver()
  2384. {
  2385. if (m_stream)
  2386. {
  2387. LOG_IF_FAILED(stream_set_position_nothrow(m_stream.get(), m_position));
  2388. }
  2389. }
  2390. /** Updates the current position in the stream
  2391. ~~~~
  2392. // Read a size marker from the stream, then advance that much.
  2393. IStream* stream1 = // ...
  2394. auto saver = wil::stream_position_saver(stream1);
  2395. auto size = wil::stream_read<long>(stream1);
  2396. wil::stream_seek_from_current_position(stream, size);
  2397. saver.update();
  2398. ~~~~
  2399. */
  2400. void update()
  2401. {
  2402. m_position = stream_get_position(m_stream.get());
  2403. }
  2404. //! Returns the current position being saved for the stream
  2405. //! @returns The position, in bytes, being saved for the stream
  2406. unsigned long long position() const
  2407. {
  2408. return m_position;
  2409. }
  2410. /** Resets the position saver to manage a new stream
  2411. Reverts the position of any stream this saver is currently holding a place for.
  2412. ~~~~
  2413. IStream* stream1 = // ...
  2414. IStream* stream2 = // ...
  2415. auto saver = wil::stream_position_saver(stream1);
  2416. if (wil::stream_read<MyType>(stream1).Flags != 0)
  2417. {
  2418. saver.reset(stream2); // position in stream1 is reverted, now holding stream2
  2419. }
  2420. ~~~~
  2421. @param stream The stream whose position is to be saved
  2422. */
  2423. void reset(_In_ IStream* stream)
  2424. {
  2425. reset();
  2426. m_stream = stream;
  2427. m_position = wil::stream_get_position(m_stream.get());
  2428. }
  2429. /** Resets the position of the stream
  2430. ~~~~
  2431. IStream* stream1 = // ...
  2432. auto saver = wil::stream_position_saver(stream1);
  2433. MyType mt = wil::stream_read<MyType>(stream1);
  2434. if (mt.Flags & MyTypeFlags::Extended)
  2435. {
  2436. saver.reset();
  2437. ProcessExtended(stream1, wil::stream_read<MyTypeExtended>(stream1));
  2438. }
  2439. else
  2440. {
  2441. ProcessStandard(stream1, mt);
  2442. }
  2443. ~~~~
  2444. */
  2445. void reset()
  2446. {
  2447. if (m_stream)
  2448. {
  2449. wil::stream_set_position(m_stream.get(), m_position);
  2450. }
  2451. }
  2452. /** Stops saving the position of the stream
  2453. ~~~~
  2454. // The stream has either a standard or extended header, followed by interesting content.
  2455. // Read either one, leaving the stream after the headers have been read off. On failure,
  2456. // the stream's position is restored.
  2457. std::pair<MyType, MyTypeExtended> get_headers(_In_ IStream* source)
  2458. {
  2459. auto saver = wil::stream_position_saver(stream1);
  2460. MyType mt = wil::stream_read<MyType>(stream1);
  2461. MyTypeExtended mte{};
  2462. if (mt.Flags & MyTypeFlags::Extended)
  2463. {
  2464. mte = wil::stream_read<MyTypeExtended>(stream1);
  2465. }
  2466. saver.dismiss();
  2467. return { mt, mte };
  2468. }
  2469. ~~~~
  2470. */
  2471. void dismiss()
  2472. {
  2473. m_stream.reset();
  2474. }
  2475. stream_position_saver(stream_position_saver&&) = default;
  2476. stream_position_saver& operator=(stream_position_saver&&) = default;
  2477. stream_position_saver(const stream_position_saver&) = delete;
  2478. void operator=(const stream_position_saver&) = delete;
  2479. private:
  2480. com_ptr<IStream> m_stream;
  2481. unsigned long long m_position;
  2482. };
  2483. #endif // WIL_ENABLE_EXCEPTIONS
  2484. #pragma endregion // stream helpers
  2485. #if defined(__IObjectWithSite_INTERFACE_DEFINED__)
  2486. /// @cond
  2487. namespace details
  2488. {
  2489. inline void __stdcall SetSiteNull(IObjectWithSite* objWithSite)
  2490. {
  2491. objWithSite->SetSite(nullptr); // break the cycle
  2492. }
  2493. } // details
  2494. /// @endcond
  2495. using unique_set_site_null_call = wil::unique_com_call<IObjectWithSite, decltype(details::SetSiteNull), details::SetSiteNull>;
  2496. /** RAII support for managing the site chain. This function sets the site pointer on an object and return an object
  2497. that resets it on destruction to break the cycle.
  2498. Note, this does not preserve the existing site if there is one (an uncommon case) so only use this when that is not required.
  2499. ~~~
  2500. auto cleanup = wil::com_set_site(execCommand.get(), serviceProvider->GetAsSite());
  2501. ~~~
  2502. Include ocidl.h before wil\com.h to use this.
  2503. */
  2504. WI_NODISCARD inline unique_set_site_null_call com_set_site(_In_opt_ IUnknown* obj, _In_opt_ IUnknown* site)
  2505. {
  2506. wil::com_ptr_nothrow<IObjectWithSite> objWithSite;
  2507. if (site && wil::try_com_copy_to(obj, &objWithSite))
  2508. {
  2509. objWithSite->SetSite(site);
  2510. }
  2511. return unique_set_site_null_call(objWithSite.get());
  2512. }
  2513. /** Iterate over each object in a site chain. Useful for debugging site issues, here is sample use.
  2514. ~~~
  2515. void OutputDebugSiteChainWatchWindowText(IUnknown* site)
  2516. {
  2517. OutputDebugStringW(L"Copy and paste these entries into the Visual Studio Watch Window\n");
  2518. wil::for_each_site(site, [](IUnknown* site)
  2519. {
  2520. wchar_t msg[64];
  2521. StringCchPrintfW(msg, ARRAYSIZE(msg), L"((IUnknown*)0x%p)->__vfptr[0]\n", site);
  2522. OutputDebugStringW(msg);
  2523. });
  2524. }
  2525. */
  2526. template<typename TLambda>
  2527. void for_each_site(_In_opt_ IUnknown* siteInput, TLambda&& callback)
  2528. {
  2529. wil::com_ptr_nothrow<IUnknown> site(siteInput);
  2530. while (site)
  2531. {
  2532. callback(site.get());
  2533. auto objWithSite = site.try_query<IObjectWithSite>();
  2534. site.reset();
  2535. if (objWithSite)
  2536. {
  2537. objWithSite->GetSite(IID_PPV_ARGS(&site));
  2538. }
  2539. }
  2540. }
  2541. #endif // __IObjectWithSite_INTERFACE_DEFINED__
  2542. } // wil
  2543. #endif