Allow classic COM interfaces with get_self (#1314)

* Allow classic COM interfaces with get_self

Fixes #1312

* Fix mingw builds

---------

Co-authored-by: Kenny Kerr <kenny@kennykerr.ca>
This commit is contained in:
Charles Milette 2023-06-27 12:40:35 -04:00 коммит произвёл GitHub
Родитель d3bb275464
Коммит 297454ee28
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
3 изменённых файлов: 58 добавлений и 0 удалений

Просмотреть файл

@ -242,6 +242,12 @@ WINRT_EXPORT namespace winrt
return &static_cast<impl::produce<D, default_interface<I>>*>(get_abi(from))->shim();
}
template <typename D, typename I>
D* get_self(com_ptr<I> const& from) noexcept
{
return static_cast<D*>(static_cast<impl::producer<D, I>*>(from.get()));
}
template <typename D, typename I>
[[deprecated]] D* from_abi(I const& from) noexcept
{

Просмотреть файл

@ -13,6 +13,9 @@ WINRT_EXPORT namespace winrt
template <typename T>
struct com_ptr;
template <typename D, typename I>
D* get_self(com_ptr<I> const& from) noexcept;
namespace param
{
template <typename T>

Просмотреть файл

@ -7,6 +7,10 @@ using namespace Windows::Foundation;
namespace
{
struct IClassicComInterface : ::IUnknown {};
struct ClassicCom : implements<ClassicCom, IClassicComInterface> {};
struct Stringable : implements<Stringable, IStringable>
{
Stringable(std::wstring_view const& value = L"Stringable") : m_value(value)
@ -30,8 +34,16 @@ namespace
object->AddRef();
return object->Release();
}
template <typename T>
uint32_t get_ref_count(com_ptr<T> const& object)
{
return get_ref_count(object.get());
}
}
template <> inline constexpr winrt::guid winrt::impl::guid_v<IClassicComInterface>{ 0xc136bb75, 0xbc03, 0x41a6, { 0xa5, 0xdc, 0x5e, 0xfa, 0x67, 0x92, 0x4e, 0xbf } };
TEST_CASE("interop")
{
uint32_t const before = get_module_lock();
@ -108,6 +120,43 @@ TEST_CASE("self")
REQUIRE(get_ref_count(object) == 1);
object = nullptr;
strong = weak.get();
REQUIRE(!strong);
}
TEST_CASE("self_classic_com")
{
com_ptr<ClassicCom> strong = make_self<ClassicCom>();
REQUIRE(get_ref_count(strong.get()) == 1);
com_ptr<IClassicComInterface> object = strong.as<IClassicComInterface>();
REQUIRE(get_ref_count(strong.get()) == 2);
ClassicCom* ptr = get_self<ClassicCom>(object);
REQUIRE(ptr == strong.get());
REQUIRE(get_ref_count(strong.get()) == 2);
strong = nullptr;
REQUIRE(get_ref_count(object) == 1);
strong = get_self<ClassicCom>(object)->get_strong();
REQUIRE(get_ref_count(object) == 2);
strong = nullptr;
REQUIRE(get_ref_count(object) == 1);
weak_ref<ClassicCom> weak = get_self<ClassicCom>(object)->get_weak();
REQUIRE(get_ref_count(object) == 1); // <-- still just one!
strong = weak.get();
REQUIRE(strong);
REQUIRE(get_ref_count(object) == 2);
strong = nullptr;
REQUIRE(get_ref_count(object) == 1);
object = nullptr;
strong = weak.get();
REQUIRE(!strong);
}