Reputation: 639
I found this code snippet here.
wil::com_ptr<IStream> stream;
CHECK_FAILURE(SHCreateStreamOnFileEx(
L"assets/EdgeWebView2-80.jpg", STGM_READ, FILE_ATTRIBUTE_NORMAL,
FALSE, nullptr, &stream));
According to the manual of SHCreateStreamOnFileEx
, the type of the last argument is supposed to be IStream **
. However the code snippet passes a wil::com_ptr<IStream> *
to the function instead of a IStream **
. I'm wondering how it works. Does wil::com_ptr<IStream>
overload operator &
(aka "address of")?
By the way, I cannot find the online manual of wil::com_ptr
. Is it the same as winrt::com_ptr struct template (C++/WinRT)? Thanks.
Upvotes: 0
Views: 284
Reputation: 51355
The Windows Implementation Libraries (WIL) has its documentation published through its repository's wiki. The wil::com_ptr_t
class template1 is described on the WinRT and COM wrappers page.
The section on Object management methods lists three class members that allow clients to get the address of the stored interface pointer:
T** addressof()
Returns the address of the internal pointer without releasing the current COM object. Do not use this for_Out_
parameters2 because it will leak the current COM object. For_Out_
parameters, use the&
operator, which releases the current COM object before returning the address.T** put()
Releases the current COM object and returns the address of the internal pointer. Use this method when passing thecom_ptr_t
as a_Out_
parameter.T** operator&()
Same asput()
.
So to answer the literal question: Yes, wil::com_ptr_t
does overload operator&()
to return the address of the internal interface pointer after doing some housekeeping.
wil::com_ptr_t
is unrelated to the winrt::com_ptr
class template3, part of the C++/WinRT library. Neither of them are related to ATL's CComPtr
or Visual Studio's _com_ptr_t
. Those are the four official implementations, and while all of them have the same goal of automating lifetime management of COM objects they are subtly different in their implementations, with surprising consequences4.
The differences are in the following areas:
Constructors with an interface pointer argument
Implementations get to choose whether they assume ownership of the passed in interface pointer, or model shared ownership leaving the caller with the responsibility of Release()
-ing the incoming interface pointer.
Assignment operators accepting an interface pointer
Same as above concerning the incoming pointer, with the added twist of having to handle the case where the instance is already holding an interface pointer. Implementations can:
Release()
the current interface prior to assigning the incoming interface pointerRetrieving the address of the raw interface pointer
Similar to the assignment above, the case where the smart pointer instance is already holding an interface needs to be handled, one way or another:
addressof()
)Release()
the current interface (e.g. put()
)nullptr
If you decide to use a COM smart pointer implementation, make sure you have a firm grasp on its semantics. The same literal piece of C++ code will potentially behave differently depending on the library in use.
1 wil::com_ptr
is an alias template for wil::com_ptr_t
with the err_policy
template argument set to err_exception_policy
.
2 The snippet in the question could have safely passed stream.addressof()
even though ppstm
is marked as an _Out_
parameter. I'm guessing that the author used operator&()
instead for consistency, readability, and maintainability.
3 While the WIL and C++/WinRT are independent libraries they can interoperate with surprisingly little effort.
4 We're using a smart pointer, so we can't possibly be the source of the leak
Upvotes: 1