Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 25 additions & 18 deletions strings/base_weak_ref.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,17 @@ WINRT_EXPORT namespace winrt
{
weak_ref(std::nullptr_t = nullptr) noexcept {}

weak_ref(impl::com_ref<T> const& object)
template<typename U = impl::com_ref<T> const&, typename = std::enable_if_t<std::is_convertible_v<U&&, impl::com_ref<T> const&>>>
weak_ref(U&& object)
{
if (object)
{
if constexpr(impl::is_implements_v<T>)
{
m_ref = std::move(object->get_weak().m_ref);
}
else
{
// An access violation (crash) on the following line means that the object does not support weak references.
// Avoid using weak_ref/auto_revoke with such objects.
check_hresult(object.template try_as<impl::IWeakReferenceSource>()->GetWeakReference(m_ref.put()));
}
}
from_com_ref(static_cast<impl::com_ref<T> const&>(object));
}

[[nodiscard]] impl::com_ref<T> get() const noexcept
[[nodiscard]] auto get() const noexcept
{
if (!m_ref)
{
return nullptr;
return impl::com_ref<T>{ nullptr };
}

if constexpr(impl::is_implements_v<T>)
Expand All @@ -36,13 +25,13 @@ WINRT_EXPORT namespace winrt
m_ref->Resolve(guid_of<T>(), put_abi(temp));
void* result = get_self<T>(temp);
detach_abi(temp);
return { result, take_ownership_from_abi };
return impl::com_ref<T>{ result, take_ownership_from_abi };
}
else
{
void* result{};
m_ref->Resolve(guid_of<T>(), &result);
return { result, take_ownership_from_abi };
return impl::com_ref<T>{ result, take_ownership_from_abi };
}
}

Expand All @@ -58,6 +47,24 @@ WINRT_EXPORT namespace winrt

private:

template<typename U>
void from_com_ref(U&& object)
{
if (object)
{
if constexpr (impl::is_implements_v<T>)
{
m_ref = std::move(object->get_weak().m_ref);
}
else
{
// An access violation (crash) on the following line means that the object does not support weak references.
// Avoid using weak_ref/auto_revoke with such objects.
check_hresult(object.template try_as<impl::IWeakReferenceSource>()->GetWeakReference(m_ref.put()));
}
}
}

com_ptr<impl::IWeakReference> m_ref;
};

Expand Down
69 changes: 69 additions & 0 deletions test/old_tests/UnitTests/weak.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,25 @@ namespace
return L"WeakNoModuleLock";
}
};

struct WeakWithSelfReference : implements<WeakWithSelfReference, IStringable>
{
winrt::weak_ref<WeakWithSelfReference> weak_self = get_weak();

hstring ToString()
{
// Verify that the weak reference works as long as the object is alive.
REQUIRE(weak_self.get().get() == this);

return L"WeakWithSelfReference";
}

~WeakWithSelfReference()
{
// Verify that the weak reference cannot be resolved once destruction begins.
REQUIRE(weak_self.get() == nullptr);
}
};
}

TEST_CASE("weak,source")
Expand Down Expand Up @@ -313,6 +332,49 @@ TEST_CASE("weak,comparison")
REQUIRE(refA1 != refNothing);
}

TEST_CASE("weak,assignment")
{
IStringable object = make<Weak>();
weak_ref<IStringable> ref1 = object;

// Move constructor
weak_ref<IStringable> ref2 = std::move(ref1);
REQUIRE(ref1 == nullptr);

// Copy constructor
weak_ref<IStringable> ref3 = ref2;
REQUIRE(ref2 == ref3);

// Copy assignment
ref1 = ref2;
REQUIRE(ref1 == ref2);
REQUIRE(ref1 == ref3);

// Move assignment
ref1 = std::move(ref2);
REQUIRE(ref2 == nullptr);
REQUIRE(ref1 == ref3);

// Copy assignment from const
ref2 = static_cast<weak_ref<IStringable> const&>(ref1);
REQUIRE(ref1 == ref2);

// Move assignment from const
ref1 = static_cast<weak_ref<IStringable> const&&>(ref2);
REQUIRE(ref1 == ref2);

// Constructed from com_ref<T> braced constructor
weak_ref<IStringable> yikes{ { nullptr, take_ownership_from_abi } };

// Not constructible from L"" (because Uri constructor is explicit)
static_assert(!std::is_constructible_v<weak_ref<Uri>, const wchar_t*>);

// Constructible from com_ptr<Derived> because com_ptr<Derived> is
// implicitly convertible to com_ptr<Base>.
struct Derived : WeakWithSelfReference {};
weak_ref<WeakWithSelfReference> decay{ winrt::com_ptr<Derived>{nullptr} };
}

TEST_CASE("weak,module_lock")
{
uint32_t object_count = get_module_lock();
Expand Down Expand Up @@ -344,3 +406,10 @@ TEST_CASE("weak,no_module_lock")
REQUIRE(get_module_lock() == object_count);
}

TEST_CASE("weak,self")
{
// The REQUIRE statements are in the WeakWithSelfReference class itself.
IStringable a = make<WeakWithSelfReference>();
a.ToString();
a = nullptr;
}