зеркало из https://github.com/microsoft/cppwinrt.git
1413 строки
43 KiB
C++
1413 строки
43 KiB
C++
|
|
namespace winrt::impl
|
|
{
|
|
struct marker
|
|
{
|
|
marker() = delete;
|
|
};
|
|
}
|
|
|
|
WINRT_EXPORT namespace winrt
|
|
{
|
|
struct non_agile : impl::marker {};
|
|
struct no_weak_ref : impl::marker {};
|
|
struct composing : impl::marker {};
|
|
struct composable : impl::marker {};
|
|
struct no_module_lock : impl::marker {};
|
|
struct static_lifetime : impl::marker {};
|
|
|
|
template <typename Interface>
|
|
struct cloaked : Interface {};
|
|
|
|
template <typename D, typename... I>
|
|
struct implements;
|
|
}
|
|
|
|
namespace winrt::impl
|
|
{
|
|
template<typename...T>
|
|
using tuple_cat_t = decltype(std::tuple_cat(std::declval<T>()...));
|
|
|
|
template <template <typename> typename Condition, typename>
|
|
struct tuple_if_base;
|
|
|
|
template <template <typename> typename Condition, typename...T>
|
|
struct tuple_if_base<Condition, std::tuple<T...>> { using type = tuple_cat_t<typename std::conditional<Condition<T>::value, std::tuple<T>, std::tuple<>>::type...>; };
|
|
|
|
template <template <typename> typename Condition, typename T>
|
|
using tuple_if = typename tuple_if_base<Condition, T>::type;
|
|
|
|
#ifdef __IUnknown_INTERFACE_DEFINED__
|
|
|
|
template <typename T>
|
|
struct is_interface : std::disjunction<std::is_base_of<Windows::Foundation::IInspectable, T>, std::conjunction<std::is_base_of<::IUnknown, T>, std::negation<is_implements<T>>>> {};
|
|
|
|
#else
|
|
|
|
template <typename T>
|
|
struct is_interface : std::is_base_of<Windows::Foundation::IInspectable, T> {};
|
|
|
|
#endif
|
|
|
|
template <typename T>
|
|
struct is_marker : std::disjunction<std::is_base_of<marker, T>, std::is_void<T>> {};
|
|
|
|
template <typename T>
|
|
struct uncloak_base
|
|
{
|
|
using type = T;
|
|
};
|
|
|
|
template <typename T>
|
|
struct uncloak_base<cloaked<T>>
|
|
{
|
|
using type = T;
|
|
};
|
|
|
|
template <typename T>
|
|
using uncloak = typename uncloak_base<T>::type;
|
|
|
|
template <typename I>
|
|
struct is_cloaked : std::disjunction<
|
|
std::is_same<Windows::Foundation::IInspectable, I>,
|
|
std::negation<std::is_base_of<Windows::Foundation::IInspectable, I>>
|
|
> {};
|
|
|
|
template <typename I>
|
|
struct is_cloaked<cloaked<I>> : std::true_type {};
|
|
|
|
template <typename D, typename I, typename Enable = void>
|
|
struct producer;
|
|
|
|
template <typename D, typename T>
|
|
struct producers_base;
|
|
|
|
template <typename D, typename I, typename Enable = void>
|
|
struct producer_convert;
|
|
|
|
template <typename T>
|
|
struct producer_ref : T
|
|
{
|
|
producer_ref(producer_ref const&) = delete;
|
|
producer_ref& operator=(producer_ref const&) = delete;
|
|
producer_ref(producer_ref&&) = delete;
|
|
producer_ref& operator=(producer_ref&&) = delete;
|
|
|
|
producer_ref(void* ptr) noexcept : T(ptr, take_ownership_from_abi)
|
|
{
|
|
}
|
|
|
|
~producer_ref() noexcept
|
|
{
|
|
detach_abi(*this);
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
struct producer_vtable
|
|
{
|
|
void* value;
|
|
};
|
|
|
|
template <typename D, typename I, typename Enable>
|
|
struct producer_convert : producer<D, typename default_interface<I>::type>
|
|
{
|
|
operator producer_ref<I> const() const noexcept
|
|
{
|
|
return { (produce<D, typename default_interface<I>::type>*)this };
|
|
}
|
|
|
|
operator producer_vtable<I> const() const noexcept
|
|
{
|
|
return { (void*)this };
|
|
}
|
|
};
|
|
|
|
template <typename D, typename...T>
|
|
struct producers_base<D, std::tuple<T...>> : producer_convert<D, T>... {};
|
|
|
|
template <typename D, typename...T>
|
|
using producers = producers_base<D, tuple_if<is_interface, std::tuple<uncloak<T>...>>>;
|
|
|
|
template <typename D, typename... I>
|
|
struct root_implements;
|
|
|
|
template <typename T, typename = std::void_t<>>
|
|
struct unwrap_implements
|
|
{
|
|
using type = T;
|
|
};
|
|
|
|
template <typename T>
|
|
struct unwrap_implements<T, std::void_t<typename T::implements_type>>
|
|
{
|
|
using type = typename T::implements_type;
|
|
};
|
|
|
|
template <typename T>
|
|
using unwrap_implements_t = typename unwrap_implements<T>::type;
|
|
|
|
template <typename...>
|
|
struct nested_implements
|
|
{};
|
|
|
|
template <typename First, typename... Rest>
|
|
struct nested_implements<First, Rest...>
|
|
: std::conditional_t<is_implements_v<First>,
|
|
impl::identity<First>, nested_implements<Rest...>>
|
|
{
|
|
static_assert(!is_implements_v<First> || !std::disjunction_v<is_implements<Rest>...>,
|
|
"Duplicate nested implements found");
|
|
};
|
|
|
|
template <typename D, typename Dummy = std::void_t<>, typename... I>
|
|
struct base_implements_impl
|
|
: impl::identity<root_implements<D, I...>> {};
|
|
|
|
template <typename D, typename... I>
|
|
struct base_implements_impl<D, std::void_t<typename nested_implements<I...>::type>, I...>
|
|
: nested_implements<I...> {};
|
|
|
|
template <typename D, typename... I>
|
|
using base_implements = base_implements_impl<D, void, I...>;
|
|
|
|
template <typename T, typename = std::void_t<>>
|
|
struct has_composable : std::false_type {};
|
|
|
|
template <typename T>
|
|
struct has_composable<T, std::void_t<typename T::composable>> : std::true_type {};
|
|
|
|
template <typename T, typename = std::void_t<>>
|
|
struct has_class_type : std::false_type {};
|
|
|
|
template <typename T>
|
|
struct has_class_type<T, std::void_t<typename T::class_type>> : std::true_type {};
|
|
|
|
template <typename>
|
|
struct has_static_lifetime : std::false_type {};
|
|
|
|
template <typename D, typename...I>
|
|
struct has_static_lifetime<implements<D, I...>> : std::disjunction<std::is_same<static_lifetime, I>...> {};
|
|
|
|
template <typename D>
|
|
inline constexpr bool has_static_lifetime_v = has_static_lifetime<typename D::implements_type>::value;
|
|
|
|
template <typename T>
|
|
void clear_abi(T*) noexcept
|
|
{}
|
|
|
|
template <typename T>
|
|
void clear_abi(T** value) noexcept
|
|
{
|
|
*value = nullptr;
|
|
}
|
|
|
|
template <typename T>
|
|
void zero_abi([[maybe_unused]] void* ptr, [[maybe_unused]] uint32_t const capacity) noexcept
|
|
{
|
|
if constexpr (!std::is_trivially_destructible_v<T>)
|
|
{
|
|
memset(ptr, 0, sizeof(T) * capacity);
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
void zero_abi([[maybe_unused]] void* ptr) noexcept
|
|
{
|
|
if constexpr (!std::is_trivially_destructible_v<T>)
|
|
{
|
|
memset(ptr, 0, sizeof(T));
|
|
}
|
|
}
|
|
}
|
|
|
|
WINRT_EXPORT namespace winrt
|
|
{
|
|
template <typename D, typename I>
|
|
D* get_self(I const& from) noexcept
|
|
{
|
|
return &static_cast<impl::produce<D, default_interface<I>>*>(get_abi(from))->shim();
|
|
}
|
|
|
|
template <typename D, typename I>
|
|
[[deprecated]] D* from_abi(I const& from) noexcept
|
|
{
|
|
return get_self<D>(from);
|
|
}
|
|
|
|
template <typename I, typename D>
|
|
impl::abi_t<I>* to_abi(impl::producer<D, I> const* from) noexcept
|
|
{
|
|
return reinterpret_cast<impl::abi_t<I>*>(const_cast<impl::producer<D, I>*>(from));
|
|
}
|
|
|
|
template <typename I, typename D>
|
|
impl::abi_t<I>* to_abi(impl::producer_convert<D, I> const* from) noexcept
|
|
{
|
|
return reinterpret_cast<impl::abi_t<I>*>((impl::producer<D, default_interface<I>>*)from);
|
|
}
|
|
}
|
|
|
|
namespace winrt::impl
|
|
{
|
|
template <typename...> struct interface_list;
|
|
|
|
template <>
|
|
struct interface_list<>
|
|
{
|
|
template <typename T, typename Predicate>
|
|
static constexpr void* find(const T*, const Predicate&) noexcept
|
|
{
|
|
return nullptr;
|
|
}
|
|
};
|
|
|
|
template <typename First, typename ... Rest>
|
|
struct interface_list<First, Rest...>
|
|
{
|
|
template <typename T, typename Predicate>
|
|
static constexpr void* find(const T* obj, const Predicate& pred) noexcept
|
|
{
|
|
if (pred.template test<First>())
|
|
{
|
|
return to_abi<First>(obj);
|
|
}
|
|
return interface_list<Rest...>::find(obj, pred);
|
|
}
|
|
using first_interface = First;
|
|
};
|
|
|
|
template <typename, typename> struct interface_list_append_impl;
|
|
|
|
template <typename... T, typename... U>
|
|
struct interface_list_append_impl<interface_list<T...>, interface_list<U...>>
|
|
{
|
|
using type = interface_list<T..., U...>;
|
|
};
|
|
|
|
template <template <typename> class, typename...>
|
|
struct filter_impl;
|
|
|
|
template <template <typename> class Predicate, typename... T>
|
|
using filter = typename filter_impl<Predicate, unwrap_implements_t<T>...>::type;
|
|
|
|
template <template <typename> class Predicate>
|
|
struct filter_impl<Predicate>
|
|
{
|
|
using type = interface_list<>;
|
|
};
|
|
|
|
template <template <typename> class Predicate, typename T, typename... Rest>
|
|
struct filter_impl<Predicate, T, Rest...>
|
|
{
|
|
using type = typename interface_list_append_impl<
|
|
std::conditional_t<
|
|
Predicate<T>::value,
|
|
interface_list<winrt::impl::uncloak<T>>,
|
|
interface_list<>
|
|
>,
|
|
typename filter_impl<Predicate, Rest...>::type
|
|
>::type;
|
|
};
|
|
|
|
template <template <typename> class Predicate, typename ... T, typename ... Rest>
|
|
struct filter_impl<Predicate, interface_list<T...>, Rest...>
|
|
{
|
|
using type = typename interface_list_append_impl<
|
|
filter<Predicate, T...>,
|
|
filter<Predicate, Rest...>
|
|
>::type;
|
|
};
|
|
|
|
template <template <typename> class Predicate, typename D, typename ... I, typename ... Rest>
|
|
struct filter_impl<Predicate, winrt::implements<D, I...>, Rest...>
|
|
{
|
|
using type = typename interface_list_append_impl<
|
|
filter<Predicate, I...>,
|
|
filter<Predicate, Rest...>
|
|
>::type;
|
|
};
|
|
|
|
template <typename T>
|
|
using implemented_interfaces = filter<is_interface, typename T::implements_type>;
|
|
|
|
template <typename T>
|
|
struct is_uncloaked_interface : std::conjunction<is_interface<T>, std::negation<winrt::impl::is_cloaked<T>>> {};
|
|
template <typename T>
|
|
using uncloaked_interfaces = filter<is_uncloaked_interface, typename T::implements_type>;
|
|
|
|
template <typename T>
|
|
struct uncloaked_iids;
|
|
|
|
template <typename ... T>
|
|
struct uncloaked_iids<interface_list<T...>>
|
|
{
|
|
#pragma warning(suppress: 4307)
|
|
static constexpr std::array<guid, sizeof...(T)> value{ winrt::guid_of<T>() ... };
|
|
};
|
|
|
|
template <typename T, typename = void>
|
|
struct implements_default_interface
|
|
{
|
|
using type = typename default_interface<typename implemented_interfaces<T>::first_interface>::type;
|
|
};
|
|
|
|
template <typename T>
|
|
struct implements_default_interface<T, std::void_t<typename T::class_type>>
|
|
{
|
|
using type = winrt::default_interface<typename T::class_type>;
|
|
};
|
|
|
|
template <typename T>
|
|
struct default_interface<T, std::void_t<typename T::implements_type>>
|
|
{
|
|
using type = typename implements_default_interface<T>::type;
|
|
};
|
|
|
|
struct iid_finder
|
|
{
|
|
const guid& m_guid;
|
|
|
|
template <typename I>
|
|
constexpr bool test() const noexcept
|
|
{
|
|
return is_guid_of<typename default_interface<I>::type>(m_guid);
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
auto find_iid(const T* obj, const guid& iid) noexcept
|
|
{
|
|
return static_cast<unknown_abi*>(implemented_interfaces<T>::find(obj, iid_finder{ iid }));
|
|
}
|
|
|
|
struct inspectable_finder
|
|
{
|
|
template <typename I>
|
|
static constexpr bool test() noexcept
|
|
{
|
|
return std::is_base_of_v<inspectable_abi, abi_t<I>>;
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
inspectable_abi* find_inspectable(const T* obj) noexcept
|
|
{
|
|
using default_interface = typename implements_default_interface<T>::type;
|
|
|
|
if constexpr (std::is_base_of_v<inspectable_abi, abi_t<default_interface>>)
|
|
{
|
|
return to_abi<default_interface>(obj);
|
|
}
|
|
else
|
|
{
|
|
return static_cast<inspectable_abi*>(implemented_interfaces<T>::find(obj, inspectable_finder{}));
|
|
}
|
|
}
|
|
|
|
template <typename I, typename = std::void_t<>>
|
|
struct runtime_class_name
|
|
{
|
|
static hstring get()
|
|
{
|
|
throw hresult_not_implemented{};
|
|
}
|
|
};
|
|
|
|
template <typename I>
|
|
struct runtime_class_name<I, std::void_t<decltype(name_v<I>)>>
|
|
{
|
|
static hstring get()
|
|
{
|
|
return hstring{ name_of<I>() };
|
|
}
|
|
};
|
|
|
|
template <typename D, typename I, typename Enable>
|
|
struct producer
|
|
{
|
|
private:
|
|
produce<D, I> vtable;
|
|
};
|
|
|
|
template <typename D, typename I, typename Enable>
|
|
struct produce_base : abi_t<I>
|
|
{
|
|
D& shim() noexcept
|
|
{
|
|
return*static_cast<D*>(reinterpret_cast<producer<D, I>*>(this));
|
|
}
|
|
|
|
int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept override
|
|
{
|
|
return shim().QueryInterface(id, object);
|
|
}
|
|
|
|
uint32_t __stdcall AddRef() noexcept override
|
|
{
|
|
return shim().AddRef();
|
|
}
|
|
|
|
uint32_t __stdcall Release() noexcept override
|
|
{
|
|
return shim().Release();
|
|
}
|
|
|
|
int32_t __stdcall GetIids(uint32_t* count, guid** array) noexcept override
|
|
{
|
|
return shim().GetIids(reinterpret_cast<count_type*>(count), reinterpret_cast<guid_type**>(array));
|
|
}
|
|
|
|
int32_t __stdcall GetRuntimeClassName(void** name) noexcept override
|
|
{
|
|
return shim().abi_GetRuntimeClassName(name);
|
|
}
|
|
|
|
int32_t __stdcall GetTrustLevel(Windows::Foundation::TrustLevel* trustLevel) noexcept final
|
|
{
|
|
return shim().abi_GetTrustLevel(trustLevel);
|
|
}
|
|
};
|
|
|
|
#ifdef __IUnknown_INTERFACE_DEFINED__
|
|
|
|
template <typename D, typename I>
|
|
struct producer<D, I, std::enable_if_t<std::is_base_of_v< ::IUnknown, I> && !is_implements_v<I>>> : I
|
|
{
|
|
};
|
|
|
|
template <typename D, typename I>
|
|
struct producer_convert<D, I, std::enable_if_t<std::is_base_of_v< ::IUnknown, I> && !is_implements_v<I>>> : producer<D, I>
|
|
{
|
|
};
|
|
|
|
#endif
|
|
|
|
struct INonDelegatingInspectable : Windows::Foundation::IUnknown
|
|
{
|
|
INonDelegatingInspectable(std::nullptr_t = nullptr) noexcept {}
|
|
};
|
|
|
|
template <> struct abi<INonDelegatingInspectable>
|
|
{
|
|
using type = inspectable_abi;
|
|
};
|
|
|
|
template <typename D>
|
|
struct produce<D, INonDelegatingInspectable> : produce_base<D, INonDelegatingInspectable>
|
|
{
|
|
int32_t __stdcall QueryInterface(const guid& id, void** object) noexcept final
|
|
{
|
|
return this->shim().NonDelegatingQueryInterface(id, object);
|
|
}
|
|
|
|
uint32_t __stdcall AddRef() noexcept final
|
|
{
|
|
return this->shim().NonDelegatingAddRef();
|
|
}
|
|
|
|
uint32_t __stdcall Release() noexcept final
|
|
{
|
|
return this->shim().NonDelegatingRelease();
|
|
}
|
|
|
|
int32_t __stdcall GetIids(uint32_t* count, guid** array) noexcept final
|
|
{
|
|
return this->shim().NonDelegatingGetIids(count, array);
|
|
}
|
|
|
|
int32_t __stdcall GetRuntimeClassName(void** name) noexcept final
|
|
{
|
|
return this->shim().NonDelegatingGetRuntimeClassName(name);
|
|
}
|
|
};
|
|
|
|
template <bool Agile>
|
|
struct weak_ref;
|
|
|
|
template <bool Agile>
|
|
struct weak_source_producer;
|
|
|
|
template <bool Agile>
|
|
struct weak_source final : IWeakReferenceSource
|
|
{
|
|
weak_ref<Agile>* that() noexcept
|
|
{
|
|
return static_cast<weak_ref<Agile>*>(reinterpret_cast<weak_source_producer<Agile>*>(this));
|
|
}
|
|
|
|
int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final
|
|
{
|
|
if (is_guid_of<IWeakReferenceSource>(id))
|
|
{
|
|
*object = static_cast<IWeakReferenceSource*>(this);
|
|
that()->increment_strong();
|
|
return 0;
|
|
}
|
|
|
|
return that()->m_object->QueryInterface(id, object);
|
|
}
|
|
|
|
uint32_t __stdcall AddRef() noexcept final
|
|
{
|
|
return that()->increment_strong();
|
|
}
|
|
|
|
uint32_t __stdcall Release() noexcept final
|
|
{
|
|
return that()->m_object->Release();
|
|
}
|
|
|
|
int32_t __stdcall GetWeakReference(IWeakReference** weakReference) noexcept final
|
|
{
|
|
*weakReference = that();
|
|
that()->AddRef();
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
template <bool Agile>
|
|
struct weak_source_producer
|
|
{
|
|
protected:
|
|
weak_source<Agile> m_source;
|
|
};
|
|
|
|
template <bool Agile>
|
|
struct weak_ref final : IWeakReference, weak_source_producer<Agile>
|
|
{
|
|
weak_ref(unknown_abi* object, uint32_t const strong) noexcept :
|
|
m_object(object),
|
|
m_strong(strong)
|
|
{
|
|
WINRT_ASSERT(object);
|
|
}
|
|
|
|
int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final
|
|
{
|
|
if (is_guid_of<IWeakReference>(id) || is_guid_of<Windows::Foundation::IUnknown>(id))
|
|
{
|
|
*object = static_cast<IWeakReference*>(this);
|
|
AddRef();
|
|
return 0;
|
|
}
|
|
|
|
if constexpr (Agile)
|
|
{
|
|
if (is_guid_of<IAgileObject>(id))
|
|
{
|
|
*object = static_cast<unknown_abi*>(this);
|
|
AddRef();
|
|
return 0;
|
|
}
|
|
|
|
if (is_guid_of<IMarshal>(id))
|
|
{
|
|
return make_marshaler(this, object);
|
|
}
|
|
}
|
|
|
|
*object = nullptr;
|
|
return error_no_interface;
|
|
}
|
|
|
|
uint32_t __stdcall AddRef() noexcept final
|
|
{
|
|
return 1 + m_weak.fetch_add(1, std::memory_order_relaxed);
|
|
}
|
|
|
|
uint32_t __stdcall Release() noexcept final
|
|
{
|
|
uint32_t const target = m_weak.fetch_sub(1, std::memory_order_relaxed) - 1;
|
|
|
|
if (target == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
return target;
|
|
}
|
|
|
|
int32_t __stdcall Resolve(guid const& id, void** objectReference) noexcept final
|
|
{
|
|
uint32_t target = m_strong.load(std::memory_order_relaxed);
|
|
|
|
while (true)
|
|
{
|
|
if (target == 0)
|
|
{
|
|
*objectReference = nullptr;
|
|
return 0;
|
|
}
|
|
|
|
if (m_strong.compare_exchange_weak(target, target + 1, std::memory_order_acquire, std::memory_order_relaxed))
|
|
{
|
|
int32_t hr = m_object->QueryInterface(id, objectReference);
|
|
m_strong.fetch_sub(1, std::memory_order_relaxed);
|
|
return hr;
|
|
}
|
|
}
|
|
}
|
|
|
|
void set_strong(uint32_t const count) noexcept
|
|
{
|
|
m_strong = count;
|
|
}
|
|
|
|
uint32_t increment_strong() noexcept
|
|
{
|
|
return 1 + m_strong.fetch_add(1, std::memory_order_relaxed);
|
|
}
|
|
|
|
uint32_t decrement_strong() noexcept
|
|
{
|
|
uint32_t const target = m_strong.fetch_sub(1, std::memory_order_release) - 1;
|
|
|
|
if (target == 0)
|
|
{
|
|
Release();
|
|
}
|
|
|
|
return target;
|
|
}
|
|
|
|
IWeakReferenceSource* get_source() noexcept
|
|
{
|
|
increment_strong();
|
|
return &this->m_source;
|
|
}
|
|
|
|
private:
|
|
template <bool T>
|
|
friend struct weak_source;
|
|
|
|
static_assert(sizeof(weak_source_producer<Agile>) == sizeof(weak_source<Agile>));
|
|
|
|
unknown_abi* m_object{};
|
|
std::atomic<uint32_t> m_strong{ 1 };
|
|
std::atomic<uint32_t> m_weak{ 1 };
|
|
};
|
|
|
|
template <bool>
|
|
struct __declspec(empty_bases) root_implements_composing_outer
|
|
{
|
|
protected:
|
|
static constexpr bool is_composing = false;
|
|
static constexpr inspectable_abi* m_inner = nullptr;
|
|
};
|
|
|
|
template <>
|
|
struct __declspec(empty_bases) root_implements_composing_outer<true>
|
|
{
|
|
template <typename Qi>
|
|
auto try_as() const noexcept
|
|
{
|
|
return m_inner.try_as<Qi>();
|
|
}
|
|
|
|
explicit operator bool() const noexcept
|
|
{
|
|
return m_inner.operator bool();
|
|
}
|
|
protected:
|
|
static constexpr bool is_composing = true;
|
|
Windows::Foundation::IInspectable m_inner;
|
|
};
|
|
|
|
template <typename D, bool>
|
|
struct __declspec(empty_bases) root_implements_composable_inner
|
|
{
|
|
protected:
|
|
static constexpr inspectable_abi* outer() noexcept { return nullptr; }
|
|
|
|
template <typename, typename, typename>
|
|
friend class produce_dispatch_to_overridable_base;
|
|
};
|
|
|
|
template <typename D>
|
|
struct __declspec(empty_bases) root_implements_composable_inner<D, true> : producer<D, INonDelegatingInspectable>
|
|
{
|
|
protected:
|
|
inspectable_abi* outer() noexcept { return m_outer; }
|
|
private:
|
|
inspectable_abi* m_outer = nullptr;
|
|
|
|
template <typename, typename, typename>
|
|
friend class produce_dispatch_to_overridable_base;
|
|
|
|
template <typename>
|
|
friend struct composable_factory;
|
|
};
|
|
|
|
template <typename D, typename... I>
|
|
struct __declspec(novtable) root_implements
|
|
: root_implements_composing_outer<std::disjunction_v<std::is_same<composing, I>...>>
|
|
, root_implements_composable_inner<D, std::disjunction_v<std::is_same<composable, I>...>>
|
|
{
|
|
using IInspectable = Windows::Foundation::IInspectable;
|
|
using root_implements_type = root_implements;
|
|
|
|
int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept
|
|
{
|
|
if (this->outer())
|
|
{
|
|
return this->outer()->QueryInterface(id, object);
|
|
}
|
|
|
|
int32_t result = query_interface(id, object);
|
|
|
|
if (result == error_no_interface && this->m_inner)
|
|
{
|
|
result = static_cast<unknown_abi*>(get_abi(this->m_inner))->QueryInterface(id, object);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
uint32_t __stdcall AddRef() noexcept
|
|
{
|
|
if (this->outer())
|
|
{
|
|
return this->outer()->AddRef();
|
|
}
|
|
|
|
return NonDelegatingAddRef();
|
|
}
|
|
|
|
uint32_t __stdcall Release() noexcept
|
|
{
|
|
if (this->outer())
|
|
{
|
|
return this->outer()->Release();
|
|
}
|
|
|
|
return NonDelegatingRelease();
|
|
}
|
|
|
|
struct abi_guard
|
|
{
|
|
abi_guard(D& derived) :
|
|
m_derived(derived)
|
|
{
|
|
m_derived.abi_enter();
|
|
}
|
|
|
|
~abi_guard()
|
|
{
|
|
m_derived.abi_exit();
|
|
}
|
|
|
|
private:
|
|
|
|
D& m_derived;
|
|
};
|
|
|
|
void abi_enter() const noexcept {}
|
|
void abi_exit() const noexcept {}
|
|
|
|
#if defined(_DEBUG) && !defined(WINRT_NO_MAKE_DETECTION)
|
|
// Please use winrt::make<T>(args...) to avoid allocating a C++/WinRT implementation type on the stack.
|
|
virtual void use_make_function_to_create_this_object() = 0;
|
|
#endif
|
|
|
|
protected:
|
|
|
|
virtual int32_t query_interface_tearoff(guid const&, void**) const noexcept
|
|
{
|
|
return error_no_interface;
|
|
}
|
|
|
|
root_implements() noexcept
|
|
{
|
|
if constexpr (use_module_lock::value)
|
|
{
|
|
++get_module_lock();
|
|
}
|
|
}
|
|
|
|
virtual ~root_implements() noexcept
|
|
{
|
|
// If a weak reference is created during destruction, this ensures that it is also destroyed.
|
|
subtract_reference();
|
|
|
|
if constexpr (use_module_lock::value)
|
|
{
|
|
--get_module_lock();
|
|
}
|
|
}
|
|
|
|
int32_t __stdcall GetIids(uint32_t* count, guid** array) noexcept
|
|
{
|
|
if (this->outer())
|
|
{
|
|
return this->outer()->GetIids(count, array);
|
|
}
|
|
|
|
return NonDelegatingGetIids(count, array);
|
|
}
|
|
|
|
int32_t __stdcall abi_GetRuntimeClassName(void** name) noexcept
|
|
{
|
|
if (this->outer())
|
|
{
|
|
return this->outer()->GetRuntimeClassName(name);
|
|
}
|
|
|
|
return NonDelegatingGetRuntimeClassName(name);
|
|
}
|
|
|
|
int32_t __stdcall abi_GetTrustLevel(Windows::Foundation::TrustLevel* trustLevel) noexcept
|
|
{
|
|
if (this->outer())
|
|
{
|
|
return this->outer()->GetTrustLevel(trustLevel);
|
|
}
|
|
|
|
return NonDelegatingGetTrustLevel(trustLevel);
|
|
}
|
|
|
|
uint32_t __stdcall NonDelegatingAddRef() noexcept
|
|
{
|
|
if constexpr (is_weak_ref_source::value)
|
|
{
|
|
uintptr_t count_or_pointer = m_references.load(std::memory_order_relaxed);
|
|
|
|
while (true)
|
|
{
|
|
if (is_weak_ref(count_or_pointer))
|
|
{
|
|
return decode_weak_ref(count_or_pointer)->increment_strong();
|
|
}
|
|
|
|
uintptr_t const target = count_or_pointer + 1;
|
|
|
|
if (m_references.compare_exchange_weak(count_or_pointer, target, std::memory_order_relaxed))
|
|
{
|
|
return static_cast<uint32_t>(target);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 1 + m_references.fetch_add(1, std::memory_order_relaxed);
|
|
}
|
|
}
|
|
|
|
uint32_t __stdcall NonDelegatingRelease() noexcept
|
|
{
|
|
uint32_t const target = subtract_reference();
|
|
|
|
if (target == 0)
|
|
{
|
|
// If a weak reference was previously created, the m_references value will not be stable value (won't be zero).
|
|
// This ensures destruction has a stable value during destruction.
|
|
m_references = 1;
|
|
|
|
if constexpr (has_final_release::value)
|
|
{
|
|
D::final_release(std::unique_ptr<D>(static_cast<D*>(this)));
|
|
}
|
|
else
|
|
{
|
|
delete this;
|
|
}
|
|
}
|
|
|
|
return target;
|
|
}
|
|
|
|
int32_t __stdcall NonDelegatingQueryInterface(const guid& id, void** object) noexcept
|
|
{
|
|
if (is_guid_of<Windows::Foundation::IInspectable>(id) || is_guid_of<Windows::Foundation::IUnknown>(id))
|
|
{
|
|
auto result = to_abi<INonDelegatingInspectable>(this);
|
|
NonDelegatingAddRef();
|
|
*object = result;
|
|
return 0;
|
|
}
|
|
|
|
int32_t result = query_interface(id, object);
|
|
|
|
if (result == error_no_interface && this->m_inner)
|
|
{
|
|
result = static_cast<unknown_abi*>(get_abi(this->m_inner))->QueryInterface(id, object);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
int32_t __stdcall NonDelegatingGetIids(uint32_t* count, guid** array) noexcept
|
|
{
|
|
const auto& local_iids = static_cast<D*>(this)->get_local_iids();
|
|
const uint32_t& local_count = local_iids.first;
|
|
if constexpr (root_implements_type::is_composing)
|
|
{
|
|
if (local_count > 0)
|
|
{
|
|
const com_array<guid>& inner_iids = get_interfaces(root_implements_type::m_inner);
|
|
*count = local_count + inner_iids.size();
|
|
*array = static_cast<guid*>(WINRT_CoTaskMemAlloc(sizeof(guid)*(*count)));
|
|
if (*array == nullptr)
|
|
{
|
|
return error_bad_alloc;
|
|
}
|
|
*array = std::copy(local_iids.second, local_iids.second + local_count, *array);
|
|
std::copy(inner_iids.cbegin(), inner_iids.cend(), *array);
|
|
}
|
|
else
|
|
{
|
|
return static_cast<inspectable_abi*>(get_abi(root_implements_type::m_inner))->GetIids(count, array);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (local_count > 0)
|
|
{
|
|
*count = local_count;
|
|
*array = static_cast<guid*>(WINRT_CoTaskMemAlloc(sizeof(guid)*(*count)));
|
|
if (*array == nullptr)
|
|
{
|
|
return error_bad_alloc;
|
|
}
|
|
std::copy(local_iids.second, local_iids.second + local_count, *array);
|
|
}
|
|
else
|
|
{
|
|
*count = 0;
|
|
*array = nullptr;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int32_t __stdcall NonDelegatingGetRuntimeClassName(void** name) noexcept try
|
|
{
|
|
*name = detach_abi(static_cast<D*>(this)->GetRuntimeClassName());
|
|
return 0;
|
|
}
|
|
catch (...) { return to_hresult(); }
|
|
|
|
int32_t __stdcall NonDelegatingGetTrustLevel(Windows::Foundation::TrustLevel* trustLevel) noexcept try
|
|
{
|
|
*trustLevel = static_cast<D*>(this)->GetTrustLevel();
|
|
return 0;
|
|
}
|
|
catch (...) { return to_hresult(); }
|
|
|
|
uint32_t subtract_reference() noexcept
|
|
{
|
|
if constexpr (is_weak_ref_source::value)
|
|
{
|
|
uintptr_t count_or_pointer = m_references.load(std::memory_order_relaxed);
|
|
|
|
while (true)
|
|
{
|
|
if (is_weak_ref(count_or_pointer))
|
|
{
|
|
return decode_weak_ref(count_or_pointer)->decrement_strong();
|
|
}
|
|
|
|
uintptr_t const target = count_or_pointer - 1;
|
|
|
|
if (m_references.compare_exchange_weak(count_or_pointer, target, std::memory_order_release, std::memory_order_relaxed))
|
|
{
|
|
return static_cast<uint32_t>(target);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return m_references.fetch_sub(1, std::memory_order_release) - 1;
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
winrt::weak_ref<T> get_weak()
|
|
{
|
|
impl::IWeakReferenceSource* weak_ref = make_weak_ref();
|
|
if (!weak_ref)
|
|
{
|
|
throw std::bad_alloc{};
|
|
}
|
|
com_ptr<impl::IWeakReferenceSource> source;
|
|
attach_abi(source, weak_ref);
|
|
|
|
winrt::weak_ref<T> result;
|
|
check_hresult(source->GetWeakReference(result.put()));
|
|
return result;
|
|
}
|
|
|
|
virtual Windows::Foundation::TrustLevel GetTrustLevel() const noexcept
|
|
{
|
|
return Windows::Foundation::TrustLevel::BaseTrust;
|
|
}
|
|
|
|
using is_factory = std::disjunction<std::is_same<Windows::Foundation::IActivationFactory, I>...>;
|
|
|
|
private:
|
|
|
|
class has_final_release
|
|
{
|
|
template <typename U, typename = decltype(std::declval<U>().final_release(0))> static constexpr bool get_value(int) { return true; }
|
|
template <typename> static constexpr bool get_value(...) { return false; }
|
|
|
|
public:
|
|
|
|
static constexpr bool value = get_value<D>(0);
|
|
};
|
|
|
|
using is_agile = std::negation<std::disjunction<std::is_same<non_agile, I>...>>;
|
|
using is_inspectable = std::disjunction<std::is_base_of<Windows::Foundation::IInspectable, I>...>;
|
|
using is_weak_ref_source = std::conjunction<is_inspectable, std::negation<is_factory>, std::negation<std::disjunction<std::is_same<no_weak_ref, I>...>>>;
|
|
using use_module_lock = std::negation<std::disjunction<std::is_same<no_module_lock, I>...>>;
|
|
using weak_ref_t = impl::weak_ref<is_agile::value>;
|
|
|
|
std::atomic<std::conditional_t<is_weak_ref_source::value, uintptr_t, uint32_t>> m_references{ 1 };
|
|
|
|
int32_t query_interface(guid const& id, void** object) noexcept
|
|
{
|
|
*object = static_cast<D*>(this)->find_interface(id);
|
|
|
|
if (*object != nullptr)
|
|
{
|
|
AddRef();
|
|
return 0;
|
|
}
|
|
|
|
if constexpr (is_agile::value)
|
|
{
|
|
if (is_guid_of<IAgileObject>(id))
|
|
{
|
|
*object = get_unknown();
|
|
AddRef();
|
|
return 0;
|
|
}
|
|
|
|
if (is_guid_of<IMarshal>(id))
|
|
{
|
|
return make_marshaler(get_unknown(), object);
|
|
}
|
|
}
|
|
|
|
if constexpr (is_inspectable::value)
|
|
{
|
|
if (is_guid_of<Windows::Foundation::IInspectable>(id))
|
|
{
|
|
*object = find_inspectable();
|
|
AddRef();
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (is_guid_of<Windows::Foundation::IUnknown>(id))
|
|
{
|
|
*object = get_unknown();
|
|
AddRef();
|
|
return 0;
|
|
}
|
|
|
|
if constexpr (is_weak_ref_source::value)
|
|
{
|
|
if (is_guid_of<impl::IWeakReferenceSource>(id))
|
|
{
|
|
*object = make_weak_ref();
|
|
return *object ? error_ok : error_bad_alloc;
|
|
}
|
|
}
|
|
|
|
return query_interface_tearoff(id, object);
|
|
}
|
|
|
|
impl::IWeakReferenceSource* make_weak_ref() noexcept
|
|
{
|
|
static_assert(is_weak_ref_source::value, "This is only for weak ref support.");
|
|
uintptr_t count_or_pointer = m_references.load(std::memory_order_relaxed);
|
|
|
|
if (is_weak_ref(count_or_pointer))
|
|
{
|
|
return decode_weak_ref(count_or_pointer)->get_source();
|
|
}
|
|
|
|
com_ptr<weak_ref_t> weak_ref;
|
|
*weak_ref.put() = new (std::nothrow) weak_ref_t(get_unknown(), static_cast<uint32_t>(count_or_pointer));
|
|
|
|
if (!weak_ref)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
uintptr_t const encoding = encode_weak_ref(weak_ref.get());
|
|
|
|
for (;;)
|
|
{
|
|
if (m_references.compare_exchange_weak(count_or_pointer, encoding, std::memory_order_acq_rel, std::memory_order_relaxed))
|
|
{
|
|
impl::IWeakReferenceSource* result = weak_ref->get_source();
|
|
detach_abi(weak_ref);
|
|
return result;
|
|
}
|
|
|
|
if (is_weak_ref(count_or_pointer))
|
|
{
|
|
return decode_weak_ref(count_or_pointer)->get_source();
|
|
}
|
|
|
|
weak_ref->set_strong(static_cast<uint32_t>(count_or_pointer));
|
|
}
|
|
}
|
|
|
|
static bool is_weak_ref(intptr_t const value) noexcept
|
|
{
|
|
static_assert(is_weak_ref_source::value, "This is only for weak ref support.");
|
|
return value < 0;
|
|
}
|
|
|
|
static weak_ref_t* decode_weak_ref(uintptr_t const value) noexcept
|
|
{
|
|
static_assert(is_weak_ref_source::value, "This is only for weak ref support.");
|
|
return reinterpret_cast<weak_ref_t*>(value << 1);
|
|
}
|
|
|
|
static uintptr_t encode_weak_ref(weak_ref_t* value) noexcept
|
|
{
|
|
static_assert(is_weak_ref_source::value, "This is only for weak ref support.");
|
|
constexpr uintptr_t pointer_flag = static_cast<uintptr_t>(1) << ((sizeof(uintptr_t) * 8) - 1);
|
|
WINRT_ASSERT((reinterpret_cast<uintptr_t>(value) & 1) == 0);
|
|
return (reinterpret_cast<uintptr_t>(value) >> 1) | pointer_flag;
|
|
}
|
|
|
|
virtual unknown_abi* get_unknown() const noexcept = 0;
|
|
virtual std::pair<uint32_t, const guid*> get_local_iids() const noexcept = 0;
|
|
virtual hstring GetRuntimeClassName() const = 0;
|
|
virtual void* find_interface(guid const&) const noexcept = 0;
|
|
virtual inspectable_abi* find_inspectable() const noexcept = 0;
|
|
|
|
template <typename, typename, typename>
|
|
friend struct impl::produce_base;
|
|
|
|
template <typename, typename>
|
|
friend struct impl::produce;
|
|
};
|
|
|
|
#if defined(WINRT_NO_MAKE_DETECTION)
|
|
template <typename T>
|
|
using heap_implements = T;
|
|
#else
|
|
template <typename T>
|
|
struct heap_implements final : T
|
|
{
|
|
using T::T;
|
|
|
|
#if defined(_DEBUG)
|
|
void use_make_function_to_create_this_object() final
|
|
{
|
|
}
|
|
#endif
|
|
};
|
|
#endif
|
|
|
|
template <typename D>
|
|
auto make_factory() -> typename impl::implements_default_interface<D>::type
|
|
{
|
|
using result_type = typename impl::implements_default_interface<D>::type;
|
|
|
|
if constexpr (!has_static_lifetime_v<D>)
|
|
{
|
|
return { to_abi<result_type>(new heap_implements<D>), take_ownership_from_abi };
|
|
}
|
|
else
|
|
{
|
|
auto const lifetime_factory = get_activation_factory<impl::IStaticLifetime>(L"Windows.ApplicationModel.Core.CoreApplication");
|
|
Windows::Foundation::IUnknown collection;
|
|
check_hresult(lifetime_factory->GetCollection(put_abi(collection)));
|
|
auto const map = collection.as<IStaticLifetimeCollection>();
|
|
param::hstring const name{ name_of<typename D::instance_type>() };
|
|
result_type object{ to_abi<result_type>(new heap_implements<D>), take_ownership_from_abi };
|
|
|
|
static slim_mutex lock;
|
|
slim_lock_guard const guard{ lock };
|
|
void* result{};
|
|
map->Lookup(get_abi(name), &result);
|
|
|
|
if (result)
|
|
{
|
|
return { result, take_ownership_from_abi };
|
|
}
|
|
else
|
|
{
|
|
bool found;
|
|
check_hresult(map->Insert(get_abi(name), get_abi(object), &found));
|
|
return object;
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
auto detach_from(T&& object) noexcept
|
|
{
|
|
return detach_abi(std::forward<T>(object));
|
|
}
|
|
}
|
|
|
|
WINRT_EXPORT namespace winrt
|
|
{
|
|
template <typename D, typename... Args>
|
|
auto make(Args&&... args)
|
|
{
|
|
#if !defined(WINRT_NO_MAKE_DETECTION)
|
|
// Note: https://aka.ms/cppwinrt/detect_direct_allocations
|
|
static_assert(std::is_destructible_v<D>, "C++/WinRT implementation types must have a public destructor");
|
|
static_assert(!std::is_final_v<D>, "C++/WinRT implementation types must not be final");
|
|
#endif
|
|
|
|
using I = typename impl::implements_default_interface<D>::type;
|
|
|
|
if constexpr (std::is_same_v<I, Windows::Foundation::IActivationFactory>)
|
|
{
|
|
static_assert(sizeof...(args) == 0);
|
|
return impl::make_factory<D>();
|
|
}
|
|
else if constexpr (impl::has_composable<D>::value)
|
|
{
|
|
impl::com_ref<I> result{ to_abi<I>(new impl::heap_implements<D>(std::forward<Args>(args)...)), take_ownership_from_abi };
|
|
return result.template as<typename D::composable>();
|
|
}
|
|
else if constexpr (impl::has_class_type<D>::value)
|
|
{
|
|
static_assert(std::is_same_v<I, default_interface<typename D::class_type>>);
|
|
return typename D::class_type{ to_abi<I>(new impl::heap_implements<D>(std::forward<Args>(args)...)), take_ownership_from_abi };
|
|
}
|
|
else
|
|
{
|
|
return impl::com_ref<I>{ to_abi<I>(new impl::heap_implements<D>(std::forward<Args>(args)...)), take_ownership_from_abi };
|
|
}
|
|
}
|
|
|
|
template <typename D, typename... Args>
|
|
com_ptr<D> make_self(Args&&... args)
|
|
{
|
|
#if !defined(WINRT_NO_MAKE_DETECTION)
|
|
// Note: https://aka.ms/cppwinrt/detect_direct_allocations
|
|
static_assert(std::is_destructible_v<D>, "C++/WinRT implementation types must have a public destructor");
|
|
static_assert(!std::is_final_v<D>, "C++/WinRT implementation types must not be final");
|
|
#endif
|
|
|
|
return { new impl::heap_implements<D>(std::forward<Args>(args)...), take_ownership_from_abi };
|
|
}
|
|
|
|
template <typename D, typename... I>
|
|
struct implements : impl::producers<D, I...>, impl::base_implements<D, I...>::type
|
|
{
|
|
protected:
|
|
|
|
using base_type = typename impl::base_implements<D, I...>::type;
|
|
using root_implements_type = typename base_type::root_implements_type;
|
|
using is_factory = typename root_implements_type::is_factory;
|
|
|
|
using base_type::base_type;
|
|
|
|
public:
|
|
|
|
using implements_type = implements;
|
|
using IInspectable = Windows::Foundation::IInspectable;
|
|
|
|
weak_ref<D> get_weak()
|
|
{
|
|
return root_implements_type::template get_weak<D>();
|
|
}
|
|
|
|
com_ptr<D> get_strong() noexcept
|
|
{
|
|
com_ptr<D> result;
|
|
result.copy_from(static_cast<D*>(this));
|
|
return result;
|
|
}
|
|
|
|
template <typename T>
|
|
auto get_abi(T const& value) const noexcept
|
|
{
|
|
return winrt::get_abi(value);
|
|
}
|
|
|
|
template <typename T>
|
|
void* get_abi() const noexcept
|
|
{
|
|
return static_cast<impl::producer_vtable<T>>(*this).value;
|
|
}
|
|
|
|
operator IInspectable() const noexcept
|
|
{
|
|
IInspectable result;
|
|
copy_from_abi(result, find_inspectable());
|
|
return result;
|
|
}
|
|
|
|
impl::hresult_type __stdcall QueryInterface(impl::guid_type const& id, void** object) noexcept
|
|
{
|
|
return root_implements_type::QueryInterface(reinterpret_cast<guid const&>(id), object);
|
|
}
|
|
|
|
impl::count_type __stdcall AddRef() noexcept
|
|
{
|
|
return root_implements_type::AddRef();
|
|
}
|
|
|
|
impl::count_type __stdcall Release() noexcept
|
|
{
|
|
return root_implements_type::Release();
|
|
}
|
|
|
|
impl::hresult_type __stdcall GetIids(impl::count_type* count, impl::guid_type** iids) noexcept
|
|
{
|
|
return root_implements_type::GetIids(reinterpret_cast<uint32_t*>(count), reinterpret_cast<guid**>(iids));
|
|
}
|
|
|
|
impl::hresult_type __stdcall GetRuntimeClassName(impl::hstring_type* value) noexcept
|
|
{
|
|
return root_implements_type::abi_GetRuntimeClassName(reinterpret_cast<void**>(value));
|
|
}
|
|
|
|
using root_implements_type::GetTrustLevel;
|
|
|
|
impl::hresult_type __stdcall GetTrustLevel(impl::trust_level_type* value) noexcept
|
|
{
|
|
return root_implements_type::abi_GetTrustLevel(reinterpret_cast<Windows::Foundation::TrustLevel*>(value));
|
|
}
|
|
|
|
void* find_interface(guid const& id) const noexcept override
|
|
{
|
|
return impl::find_iid(static_cast<const D*>(this), id);
|
|
}
|
|
|
|
impl::inspectable_abi* find_inspectable() const noexcept override
|
|
{
|
|
return impl::find_inspectable(static_cast<const D*>(this));
|
|
}
|
|
|
|
std::pair<uint32_t, const guid*> get_local_iids() const noexcept override
|
|
{
|
|
using interfaces = impl::uncloaked_interfaces<D>;
|
|
using local_iids = impl::uncloaked_iids<interfaces>;
|
|
return { static_cast<uint32_t>(local_iids::value.size()), local_iids::value.data() };
|
|
}
|
|
|
|
private:
|
|
|
|
impl::unknown_abi* get_unknown() const noexcept override
|
|
{
|
|
return reinterpret_cast<impl::unknown_abi*>(to_abi<typename impl::implements_default_interface<D>::type>(this));
|
|
}
|
|
|
|
hstring GetRuntimeClassName() const override
|
|
{
|
|
return impl::runtime_class_name<typename impl::implements_default_interface<D>::type>::get();
|
|
}
|
|
|
|
template <typename, typename...>
|
|
friend struct impl::root_implements;
|
|
|
|
template <typename T>
|
|
friend struct weak_ref;
|
|
};
|
|
}
|