зеркало из https://github.com/microsoft/cppwinrt.git
428 строки
11 KiB
C++
428 строки
11 KiB
C++
|
|
namespace winrt::impl
|
|
{
|
|
#ifdef WINRT_DIAGNOSTICS
|
|
|
|
struct factory_diagnostics_info
|
|
{
|
|
bool is_agile{ true };
|
|
uint32_t requests{ 0 };
|
|
};
|
|
|
|
struct diagnostics_info
|
|
{
|
|
std::map<std::wstring_view, uint32_t> queries;
|
|
std::map<std::wstring_view, factory_diagnostics_info> factories;
|
|
};
|
|
|
|
struct diagnostics_cache
|
|
{
|
|
template <typename T>
|
|
void add_query()
|
|
{
|
|
slim_lock_guard const guard(m_lock);
|
|
++m_info.queries[name_of<T>()];
|
|
}
|
|
|
|
template <typename T>
|
|
void add_factory()
|
|
{
|
|
slim_lock_guard const guard(m_lock);
|
|
factory_diagnostics_info& factory = m_info.factories[name_of<T>()];
|
|
++factory.requests;
|
|
}
|
|
|
|
template <typename T>
|
|
void non_agile_factory()
|
|
{
|
|
slim_lock_guard const guard(m_lock);
|
|
factory_diagnostics_info& factory = m_info.factories[name_of<T>()];
|
|
factory.is_agile = false;
|
|
}
|
|
|
|
auto get()
|
|
{
|
|
slim_lock_guard const guard(m_lock);
|
|
return m_info;
|
|
}
|
|
|
|
auto detach()
|
|
{
|
|
slim_lock_guard const guard(m_lock);
|
|
return std::move(m_info);
|
|
}
|
|
|
|
private:
|
|
|
|
slim_mutex m_lock;
|
|
diagnostics_info m_info;
|
|
};
|
|
|
|
inline diagnostics_cache& get_diagnostics_info() noexcept
|
|
{
|
|
static diagnostics_cache info;
|
|
return info;
|
|
}
|
|
|
|
#endif
|
|
|
|
template <typename T>
|
|
using com_ref = std::conditional_t<std::is_base_of_v<Windows::Foundation::IUnknown, T>, T, com_ptr<T>>;
|
|
|
|
template <typename T, std::enable_if_t<is_implements_v<T>, int> = 0>
|
|
com_ref<T> wrap_as_result(void* result)
|
|
{
|
|
return { &static_cast<produce<T, typename default_interface<T>::type>*>(result)->shim(), take_ownership_from_abi };
|
|
}
|
|
|
|
template <typename T, std::enable_if_t<!is_implements_v<T>, int> = 0>
|
|
com_ref<T> wrap_as_result(void* result)
|
|
{
|
|
return { result, take_ownership_from_abi };
|
|
}
|
|
|
|
template<typename T>
|
|
struct is_classic_com_interface : std::conjunction<std::is_base_of<::IUnknown, T>, std::negation<is_implements<T>>> {};
|
|
|
|
template <typename T>
|
|
struct is_com_interface : std::disjunction<std::is_base_of<Windows::Foundation::IUnknown, T>, std::is_base_of<unknown_abi, T>, is_implements<T>, is_classic_com_interface<T>> {};
|
|
|
|
template <typename T>
|
|
inline constexpr bool is_com_interface_v = is_com_interface<T>::value;
|
|
|
|
// You must include <winrt/Windows.Foundation.h> to use this overload.
|
|
template <typename To, typename From, std::enable_if_t<!is_com_interface_v<To>, int> = 0>
|
|
auto as(From* ptr);
|
|
|
|
template <typename To, typename From, std::enable_if_t<is_com_interface_v<To>, int> = 0>
|
|
com_ref<To> as(From* ptr)
|
|
{
|
|
#ifdef WINRT_DIAGNOSTICS
|
|
get_diagnostics_info().add_query<To>();
|
|
#endif
|
|
|
|
if (!ptr)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
void* result{};
|
|
check_hresult(ptr->QueryInterface(guid_of<To>(), &result));
|
|
return wrap_as_result<To>(result);
|
|
}
|
|
|
|
// You must include <winrt/Windows.Foundation.h> to use this overload.
|
|
template <typename To, typename From, std::enable_if_t<!is_com_interface_v<To>, int> = 0>
|
|
auto try_as(From* ptr) noexcept;
|
|
|
|
template <typename To, typename From, std::enable_if_t<is_com_interface_v<To>, int> = 0>
|
|
com_ref<To> try_as(From* ptr) noexcept
|
|
{
|
|
#ifdef WINRT_DIAGNOSTICS
|
|
get_diagnostics_info().add_query<To>();
|
|
#endif
|
|
|
|
if (!ptr)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
void* result{};
|
|
hresult code = ptr->QueryInterface(guid_of<To>(), &result);
|
|
if (code < 0)
|
|
{
|
|
WINRT_IMPL_RoCaptureErrorContext(code);
|
|
}
|
|
return wrap_as_result<To>(result);
|
|
}
|
|
}
|
|
|
|
WINRT_EXPORT namespace winrt::Windows::Foundation
|
|
{
|
|
struct IUnknown
|
|
{
|
|
IUnknown() noexcept = default;
|
|
IUnknown(std::nullptr_t) noexcept {}
|
|
void* operator new(size_t) = delete;
|
|
|
|
IUnknown(void* ptr, take_ownership_from_abi_t) noexcept : m_ptr(static_cast<impl::unknown_abi*>(ptr))
|
|
{
|
|
}
|
|
|
|
IUnknown(IUnknown const& other) noexcept : m_ptr(other.m_ptr)
|
|
{
|
|
add_ref();
|
|
}
|
|
|
|
IUnknown(IUnknown&& other) noexcept : m_ptr(std::exchange(other.m_ptr, {}))
|
|
{
|
|
}
|
|
|
|
~IUnknown() noexcept
|
|
{
|
|
release_ref();
|
|
}
|
|
|
|
IUnknown& operator=(IUnknown const& other) noexcept
|
|
{
|
|
if (this != &other)
|
|
{
|
|
release_ref();
|
|
m_ptr = other.m_ptr;
|
|
add_ref();
|
|
}
|
|
|
|
return*this;
|
|
}
|
|
|
|
IUnknown& operator=(IUnknown&& other) noexcept
|
|
{
|
|
if (this != &other)
|
|
{
|
|
release_ref();
|
|
m_ptr = std::exchange(other.m_ptr, {});
|
|
}
|
|
|
|
return*this;
|
|
}
|
|
|
|
explicit operator bool() const noexcept
|
|
{
|
|
return nullptr != m_ptr;
|
|
}
|
|
|
|
IUnknown& operator=(std::nullptr_t) noexcept
|
|
{
|
|
release_ref();
|
|
return*this;
|
|
}
|
|
|
|
template <typename To>
|
|
auto as() const
|
|
{
|
|
return impl::as<To>(m_ptr);
|
|
}
|
|
|
|
template <typename To>
|
|
auto try_as() const noexcept
|
|
{
|
|
return impl::try_as<To>(m_ptr);
|
|
}
|
|
|
|
template <typename To>
|
|
void as(To& to) const
|
|
{
|
|
to = as<impl::wrapped_type_t<To>>();
|
|
}
|
|
|
|
template <typename To>
|
|
bool try_as(To& to) const noexcept
|
|
{
|
|
if constexpr (impl::is_com_interface_v<To> || !std::is_same_v<To, impl::wrapped_type_t<To>>)
|
|
{
|
|
to = try_as<impl::wrapped_type_t<To>>();
|
|
return static_cast<bool>(to);
|
|
}
|
|
else
|
|
{
|
|
auto result = try_as<To>();
|
|
to = result.has_value() ? result.value() : impl::empty_value<To>();
|
|
return result.has_value();
|
|
}
|
|
}
|
|
|
|
hresult as(guid const& id, void** result) const noexcept
|
|
{
|
|
return m_ptr->QueryInterface(id, result);
|
|
}
|
|
|
|
friend void swap(IUnknown& left, IUnknown& right) noexcept
|
|
{
|
|
std::swap(left.m_ptr, right.m_ptr);
|
|
}
|
|
|
|
private:
|
|
|
|
void add_ref() const noexcept
|
|
{
|
|
if (m_ptr)
|
|
{
|
|
m_ptr->AddRef();
|
|
}
|
|
}
|
|
|
|
void release_ref() noexcept
|
|
{
|
|
if (m_ptr)
|
|
{
|
|
unconditional_release_ref();
|
|
}
|
|
}
|
|
|
|
WINRT_IMPL_NOINLINE void unconditional_release_ref() noexcept
|
|
{
|
|
std::exchange(m_ptr, {})->Release();
|
|
}
|
|
|
|
impl::unknown_abi* m_ptr{};
|
|
};
|
|
}
|
|
|
|
WINRT_EXPORT namespace winrt
|
|
{
|
|
template <typename T, std::enable_if_t<!std::is_base_of_v<Windows::Foundation::IUnknown, T>, int> = 0>
|
|
auto get_abi(T const& object) noexcept
|
|
{
|
|
return reinterpret_cast<impl::abi_t<T> const&>(object);
|
|
}
|
|
|
|
template <typename T, std::enable_if_t<!std::is_base_of_v<Windows::Foundation::IUnknown, T>, int> = 0>
|
|
auto put_abi(T& object) noexcept
|
|
{
|
|
if constexpr (!std::is_trivially_destructible_v<T>)
|
|
{
|
|
object = {};
|
|
}
|
|
|
|
return reinterpret_cast<impl::abi_t<T>*>(&object);
|
|
}
|
|
|
|
template <typename T, typename V, std::enable_if_t<!std::is_base_of_v<Windows::Foundation::IUnknown, T>, int> = 0>
|
|
void copy_from_abi(T& object, V&& value)
|
|
{
|
|
object = reinterpret_cast<T const&>(value);
|
|
}
|
|
|
|
template <typename T, typename V, std::enable_if_t<!std::is_base_of_v<Windows::Foundation::IUnknown, T>, int> = 0>
|
|
void copy_to_abi(T const& object, V& value)
|
|
{
|
|
reinterpret_cast<T&>(value) = object;
|
|
}
|
|
|
|
template <typename T, std::enable_if_t<!std::is_base_of_v<Windows::Foundation::IUnknown, std::decay_t<T>> && !std::is_convertible_v<T, std::wstring_view>, int> = 0>
|
|
auto detach_abi(T&& object)
|
|
{
|
|
impl::abi_t<T> result{};
|
|
reinterpret_cast<T&>(result) = std::move(object);
|
|
return result;
|
|
}
|
|
|
|
inline void* get_abi(Windows::Foundation::IUnknown const& object) noexcept
|
|
{
|
|
return *(void**)(&object);
|
|
}
|
|
|
|
inline void** put_abi(Windows::Foundation::IUnknown& object) noexcept
|
|
{
|
|
object = nullptr;
|
|
return reinterpret_cast<void**>(&object);
|
|
}
|
|
|
|
inline void attach_abi(Windows::Foundation::IUnknown& object, void* value) noexcept
|
|
{
|
|
object = nullptr;
|
|
*put_abi(object) = value;
|
|
}
|
|
|
|
inline void* detach_abi(Windows::Foundation::IUnknown& object) noexcept
|
|
{
|
|
void* temp = get_abi(object);
|
|
*reinterpret_cast<void**>(&object) = nullptr;
|
|
return temp;
|
|
}
|
|
|
|
inline void* detach_abi(Windows::Foundation::IUnknown&& object) noexcept
|
|
{
|
|
void* temp = get_abi(object);
|
|
*reinterpret_cast<void**>(&object) = nullptr;
|
|
return temp;
|
|
}
|
|
|
|
constexpr void* detach_abi(std::nullptr_t) noexcept
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
inline void copy_from_abi(Windows::Foundation::IUnknown& object, void* value) noexcept
|
|
{
|
|
object = nullptr;
|
|
|
|
if (value)
|
|
{
|
|
static_cast<impl::unknown_abi*>(value)->AddRef();
|
|
*put_abi(object) = value;
|
|
}
|
|
}
|
|
|
|
inline void copy_to_abi(Windows::Foundation::IUnknown const& object, void*& value) noexcept
|
|
{
|
|
WINRT_ASSERT(value == nullptr);
|
|
value = get_abi(object);
|
|
|
|
if (value)
|
|
{
|
|
static_cast<impl::unknown_abi*>(value)->AddRef();
|
|
}
|
|
}
|
|
|
|
inline ::IUnknown* get_unknown(Windows::Foundation::IUnknown const& object) noexcept
|
|
{
|
|
return static_cast<::IUnknown*>(get_abi(object));
|
|
}
|
|
}
|
|
|
|
WINRT_EXPORT namespace winrt::Windows::Foundation
|
|
{
|
|
inline bool operator==(IUnknown const& left, IUnknown const& right) noexcept
|
|
{
|
|
if (get_abi(left) == get_abi(right))
|
|
{
|
|
return true;
|
|
}
|
|
if (!left || !right)
|
|
{
|
|
return false;
|
|
}
|
|
return get_abi(left.try_as<IUnknown>()) == get_abi(right.try_as<IUnknown>());
|
|
}
|
|
|
|
inline bool operator!=(IUnknown const& left, IUnknown const& right) noexcept
|
|
{
|
|
return !(left == right);
|
|
}
|
|
|
|
inline bool operator<(IUnknown const& left, IUnknown const& right) noexcept
|
|
{
|
|
if (get_abi(left) == get_abi(right))
|
|
{
|
|
return false;
|
|
}
|
|
if (!left || !right)
|
|
{
|
|
return get_abi(left) < get_abi(right);
|
|
}
|
|
return get_abi(left.try_as<IUnknown>()) < get_abi(right.try_as<IUnknown>());
|
|
}
|
|
|
|
inline bool operator>(IUnknown const& left, IUnknown const& right) noexcept
|
|
{
|
|
return right < left;
|
|
}
|
|
|
|
inline bool operator<=(IUnknown const& left, IUnknown const& right) noexcept
|
|
{
|
|
return !(right < left);
|
|
}
|
|
|
|
inline bool operator>=(IUnknown const& left, IUnknown const& right) noexcept
|
|
{
|
|
return !(left < right);
|
|
}
|
|
|
|
struct IInspectable : IUnknown
|
|
{
|
|
IInspectable(std::nullptr_t = nullptr) noexcept {}
|
|
IInspectable(void* ptr, take_ownership_from_abi_t) noexcept : IUnknown(ptr, take_ownership_from_abi) {}
|
|
};
|
|
}
|