-
Notifications
You must be signed in to change notification settings - Fork 242
WinRT and COM wrappers internals
WinRT and COM wrappers internals
This page describes the internals of the WinRT and COM wrappers. The internals are subject to change at any time. They are described here to aid in debugging and to provide guidance to future WIL implementors.
// wil::details namespace
typedef wistd::integral_constant<char, 0> tag_com_query;
typedef wistd::integral_constant<char, 1> tag_try_com_query;
typedef wistd::integral_constant<char, 2> tag_com_copy;
typedef wistd::integral_constant<char, 3> tag_try_com_copy;
These are marker types passed to the com_ptr_t
constructor to indicate how the constructor should
treat the constructor parameter.
Tag | Purpose | What happens |
---|---|---|
wil::details::tag_com_query |
Construct for query
|
Throw or fail-fast if the query fails. (Not used by return-code policy.) |
wil::details::tag_try_com_query |
Construct for try_query
|
Construct empty wrapper if the query fails. |
wil::details::tag_com_copy |
Construct for copy
|
Throw or fail-fast if the copy fails. Construct empty wrapper if the source is null. |
wil::details::tag_try_com_copy |
Construct for try_copy
|
Construct empty wrapper if the copy fails or the source is null. |
// wil::details namespace
template<class TFrom, class TTo>
struct is_com_convertible;
A type-traits class that behaves the same
as std::is_convertible
, but allows ambiguous
conversions if the TFrom
is a COM interface.
(COM interfaces are detected by checking if they are abstract.)
The implementation takes advantage of a quirk of
MSVC in which the __is_convertible_to
intrinsic
erroneously reports true
for an ambiguous conversion.
This bug has been fixed in MSVC, so is_com_convertible
now returns false
for ambiguous COM base classes.
This is not an issue in practice because COM interfaces cannot have multiple base classes. Implementations can have multiple base classes, but it is proper to reject the ambiguous conversion in that case, because there is no way to say "Give me a pointer to any of the compatible base classes, I don't care which one."
The implementation of the query
and copy
method families relies upon
a "query policy" object, a traits type which describes how a COM pointer
is converted to other COM pointers.
The query policy must support the following two methods:
template<typename T>
static HRESULT query(T* ptr, REFIID riid, void** result);
template<typename T, typename TResult>
static HRESULT query(T* ptr, TResult** result);
The functions query the ptr
(which will not be null)
for the target interface, either specified at runtime (riid
)
or compile-time (__uuidof(*result)
).
On failure, *result
is set to nullptr
.
To obtain the appropriate query policy for a type,
use the query_policy_t
template type:
// wil::details namespace
template <typename T>
struct query_policy_helper
{
typedef default_query_policy type; // see below
};
template <typename T>
using query_policy_t = typename query_policy_helper<typename wistd::remove_pointer<T>::type>::type;
The template type parameter to query_policy_t
can be a COM interface or a pointer to a COM interface.
To define a custom query policy, specialize
the query_policy_helper
template.
The default query policy performs the a QueryInterface
to obtain the result from the source.
In the special case where TResult
is a COM base class
of T
, the QueryInterface
is optimized out by simply
copying the raw pointer and performing an AddRef
.
The optimization is performed by calling an overloaded helper
function with the result of is_com_convertible
.
By default, all COM pointers use the default query policy.
The query_policy_helper
is specialized so that
the weak query policy is used for IWeakReference
.
The weak query policy resolves the weak pointer, and performs the query on the resolved pointer. If either step fails, then the weak query fails.
You cannot query the weak query policy for
IWeakReference
itself.
In the special case where TResult
is
IInspectable
, the second QueryInterface
is optimized out.
Again, the optimization is performed by calling an
overloaded helper function.
The query_policy_helper
is specialized so that
the agile query policy is used for IAgileReference
.
The agile query policy resolves the agile reference to desired result interface.
You cannot query the agile query policy for
IAgileReference
itself.