Skip to content

Commit 953d65c

Browse files
authored
Register event handlers with shared_ptr and weak_ptr (#1330)
1 parent 297454e commit 953d65c

File tree

4 files changed

+180
-3
lines changed

4 files changed

+180
-3
lines changed

cppwinrt/code_writers.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2446,6 +2446,8 @@ struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable<T, D, %>
24462446
template <typename O, typename M> %(O* object, M method);
24472447
template <typename O, typename M> %(com_ptr<O>&& object, M method);
24482448
template <typename O, typename M> %(weak_ref<O>&& object, M method);
2449+
template <typename O, typename M> %(std::shared_ptr<O>&& object, M method);
2450+
template <typename O, typename M> %(std::weak_ptr<O>&& object, M method);
24492451
auto operator()(%) const;
24502452
};
24512453
)";
@@ -2462,6 +2464,8 @@ struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable<T, D, %>
24622464
type_name,
24632465
type_name,
24642466
type_name,
2467+
type_name,
2468+
type_name,
24652469
bind<write_consume_params>(signature));
24662470
}
24672471

@@ -2523,6 +2527,14 @@ struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable<T, D, %>
25232527
%([o = std::move(object), method](auto&&... args) { if (auto s = o.get()) { ((*s).*(method))(args...); } })
25242528
{
25252529
}
2530+
template <%> template <typename O, typename M> %<%>::%(std::shared_ptr<O>&& object, M method) :
2531+
%([o = std::move(object), method](auto&&... args) { return ((*o).*(method))(args...); })
2532+
{
2533+
}
2534+
template <%> template <typename O, typename M> %<%>::%(std::weak_ptr<O>&& object, M method) :
2535+
%([o = std::move(object), method](auto&&... args) { if (auto s = o.lock()) { ((*s).*(method))(args...); } })
2536+
{
2537+
}
25262538
template <%> auto %<%>::operator()(%) const
25272539
{%
25282540
check_hresult((*(impl::abi_t<%<%>>**)this)->Invoke(%));%
@@ -2562,6 +2574,16 @@ struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable<T, D, %>
25622574
bind<write_generic_typenames>(generics),
25632575
type_name,
25642576
bind_list(", ", generics),
2577+
type_name,
2578+
type_name,
2579+
bind<write_generic_typenames>(generics),
2580+
type_name,
2581+
bind_list(", ", generics),
2582+
type_name,
2583+
type_name,
2584+
bind<write_generic_typenames>(generics),
2585+
type_name,
2586+
bind_list(", ", generics),
25652587
bind<write_consume_params>(signature),
25662588
bind<write_consume_return_type>(signature, true),
25672589
type_name,
@@ -2591,6 +2613,14 @@ struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable<T, D, %>
25912613
%([o = std::move(object), method](auto&&... args) { if (auto s = o.get()) { ((*s).*(method))(args...); } })
25922614
{
25932615
}
2616+
template <typename O, typename M> %::%(std::shared_ptr<O>&& object, M method) :
2617+
%([o = std::move(object), method](auto&&... args) { return ((*o).*(method))(args...); })
2618+
{
2619+
}
2620+
template <typename O, typename M> %::%(std::weak_ptr<O>&& object, M method) :
2621+
%([o = std::move(object), method](auto&&... args) { if (auto s = o.lock()) { ((*s).*(method))(args...); } })
2622+
{
2623+
}
25942624
inline auto %::operator()(%) const
25952625
{%
25962626
check_hresult((*(impl::abi_t<%>**)this)->Invoke(%));%
@@ -2615,6 +2645,12 @@ struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable<T, D, %>
26152645
type_name,
26162646
type_name,
26172647
type_name,
2648+
type_name,
2649+
type_name,
2650+
type_name,
2651+
type_name,
2652+
type_name,
2653+
type_name,
26182654
bind<write_consume_params>(signature),
26192655
bind<write_consume_return_type>(signature, true),
26202656
type_name,

strings/base_delegate.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,16 @@ namespace winrt::impl
179179
{
180180
}
181181

182+
template <typename O, typename M> delegate_base(std::shared_ptr<O>&& object, M method) :
183+
delegate_base([o = std::move(object), method](auto&& ... args) { return ((*o).*(method))(args...); })
184+
{
185+
}
186+
187+
template <typename O, typename M> delegate_base(std::weak_ptr<O>&& object, M method) :
188+
delegate_base([o = std::move(object), method](auto&& ... args) { if (auto s = o.lock()) { ((*s).*(method))(args...); } })
189+
{
190+
}
191+
182192
auto operator()(Args const& ... args) const
183193
{
184194
return (*(variadic_delegate_abi<R, Args...> * *)this)->invoke(args...);

test/old_tests/UnitTests/delegate_weak_strong.cpp

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,25 @@ namespace
3131
}
3232
};
3333

34+
template <typename Sender, typename Args>
35+
struct ObjectStd : std::enable_shared_from_this<ObjectStd<Sender, Args>>
36+
{
37+
~ObjectStd()
38+
{
39+
destroyed = true;
40+
}
41+
42+
void StrongHandler(Sender const&, Args const&)
43+
{
44+
++strong_count;
45+
}
46+
47+
void WeakHandler(Sender const&, Args const&)
48+
{
49+
++weak_count;
50+
}
51+
};
52+
3453
struct ReturnObject : implements<ReturnObject, IInspectable>
3554
{
3655
~ReturnObject()
@@ -44,8 +63,21 @@ namespace
4463
}
4564
};
4665

66+
struct ReturnObjectStd : std::enable_shared_from_this<ReturnObjectStd>
67+
{
68+
~ReturnObjectStd()
69+
{
70+
destroyed = true;
71+
}
72+
73+
int Handler(int a, int b)
74+
{
75+
return a + b;
76+
}
77+
};
78+
4779
template <typename Delegate, typename Sender, typename Args>
48-
void test_delegate()
80+
void test_delegate_winrt()
4981
{
5082
auto object = make_self<Object<Sender, Args>>();
5183

@@ -81,6 +113,51 @@ namespace
81113
weak({}, {});
82114
REQUIRE(weak_count == 2);
83115
}
116+
117+
template <typename Delegate, typename Sender, typename Args>
118+
void test_delegate_std()
119+
{
120+
auto object = std::make_shared<ObjectStd<Sender, Args>>();
121+
122+
Delegate strong{ object->shared_from_this(), &ObjectStd<Sender, Args>::StrongHandler };
123+
Delegate weak{ object->weak_from_this(), &ObjectStd<Sender, Args>::WeakHandler };
124+
125+
destroyed = false;
126+
strong_count = 0;
127+
weak_count = 0;
128+
129+
// Both weak and strong handlers
130+
strong({}, {});
131+
weak({}, {});
132+
REQUIRE(strong_count == 1);
133+
REQUIRE(weak_count == 1);
134+
135+
// Local 'object' strong reference is released
136+
object = nullptr;
137+
138+
// Still both since strong handler keeps object alive
139+
strong({}, {});
140+
weak({}, {});
141+
REQUIRE(strong_count == 2);
142+
REQUIRE(weak_count == 2);
143+
144+
// ~Object is called since the strong delegate is destroyed
145+
REQUIRE(!destroyed);
146+
strong = nullptr;
147+
REQUIRE(destroyed);
148+
149+
// Weak delegate remains but no longer fires
150+
REQUIRE(weak_count == 2);
151+
weak({}, {});
152+
REQUIRE(weak_count == 2);
153+
}
154+
155+
template <typename Delegate, typename Sender, typename Args>
156+
void test_delegate()
157+
{
158+
test_delegate_winrt<Delegate, Sender, Args>();
159+
test_delegate_std<Delegate, Sender, Args>();
160+
}
84161
}
85162

86163
TEST_CASE("delegate_weak_strong")
@@ -111,8 +188,10 @@ TEST_CASE("delegate_weak_strong")
111188
// scenarios such as callbacks so weak support isn't interesting anyway, but it does work with get_strong.
112189

113190
auto object = make_self<ReturnObject>();
114-
115191
Component::TwoArgDelegateReturn strong{ object->get_strong(), &ReturnObject::Handler };
116-
117192
REQUIRE(5 == strong(2, 3));
193+
194+
auto objectStd = std::make_shared<ReturnObjectStd>();
195+
Component::TwoArgDelegateReturn strongStd{ objectStd->shared_from_this(), &ReturnObjectStd::Handler };
196+
REQUIRE(5 == strongStd(2, 3));
118197
}

test/test/variadic_delegate.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,20 @@ namespace
4040
return L"Object";
4141
}
4242
};
43+
44+
struct ObjectStd : std::enable_shared_from_this<ObjectStd>
45+
{
46+
int& m_count;
47+
48+
ObjectStd(int& count) : m_count(count)
49+
{
50+
}
51+
52+
void Callback()
53+
{
54+
++m_count;
55+
}
56+
};
4357
}
4458

4559
TEST_CASE("variadic_delegate")
@@ -100,6 +114,44 @@ TEST_CASE("variadic_delegate")
100114
REQUIRE(count == 2); // Unchanged
101115
}
102116

117+
// shared_from_this
118+
{
119+
int count{};
120+
auto object = std::make_shared<ObjectStd>(count);
121+
122+
delegate<> up{ object->shared_from_this(), &ObjectStd::Callback };
123+
124+
REQUIRE(count == 0);
125+
up();
126+
REQUIRE(count == 1);
127+
up();
128+
REQUIRE(count == 2);
129+
130+
object = nullptr;
131+
132+
up();
133+
REQUIRE(count == 3);
134+
}
135+
136+
// weak_from_this
137+
{
138+
int count{};
139+
auto object = std::make_shared<ObjectStd>(count);
140+
141+
delegate<> up{ object->weak_from_this(), &ObjectStd::Callback };
142+
143+
REQUIRE(count == 0);
144+
up();
145+
REQUIRE(count == 1);
146+
up();
147+
REQUIRE(count == 2);
148+
149+
object = nullptr;
150+
151+
up();
152+
REQUIRE(count == 2); // Unchanged
153+
}
154+
103155
// Mixed arguments
104156
{
105157
int count{};

0 commit comments

Comments
 (0)