您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

2833 行
125 KiB

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