Skip to content

Commit dcea885

Browse files
authored
Add support for composed implementations of IComponentConnector (#1149)
* add support for composed implementations of IComponentConnector * document ComponentConnectorT helper * revert change for deriving without interfaces - creates other breaks and very atypical scenario * pr feedback * pr feedback * pr feedback * http://slashslash.info/petition/ compliance
1 parent 0058881 commit dcea885

File tree

7 files changed

+157
-29
lines changed

7 files changed

+157
-29
lines changed

cppwinrt/code_writers.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3270,6 +3270,14 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable<T, D, %>
32703270
{
32713271
w.write(strings::base_xaml_typename);
32723272
}
3273+
else if (namespace_name == "Windows.UI.Xaml.Markup")
3274+
{
3275+
w.write(strings::base_xaml_component_connector, "Windows");
3276+
}
3277+
else if (namespace_name == "Microsoft.UI.Xaml.Markup")
3278+
{
3279+
w.write(strings::base_xaml_component_connector, "Microsoft");
3280+
}
32733281
}
32743282

32753283
static void write_namespace_special_1(writer& w, std::string_view const& namespace_name)

cppwinrt/component_writers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,7 @@ catch (...) { return winrt::to_hresult(); }
797797
}
798798
else
799799
{
800+
composable_base_name = w.write_temp("using composable_base = B;");
800801
base_type_parameter = ", typename B";
801802
base_type_argument = ", B";
802803
no_module_lock = "no_module_lock, ";

cppwinrt/cppwinrt.vcxproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@
5454
<ClInclude Include="..\strings\base_com_ptr.h" />
5555
<ClInclude Include="..\strings\base_coroutine_foundation.h" />
5656
<ClInclude Include="..\strings\base_coroutine_system.h" />
57+
<ClInclude Include="..\strings\base_coroutine_system_winui.h" />
5758
<ClInclude Include="..\strings\base_coroutine_threadpool.h" />
5859
<ClInclude Include="..\strings\base_coroutine_ui_core.h" />
59-
<ClInclude Include="..\strings\base_coroutine_system_winui.h" />
6060
<ClInclude Include="..\strings\base_deferral.h" />
6161
<ClInclude Include="..\strings\base_delegate.h" />
6262
<ClInclude Include="..\strings\base_error.h" />
@@ -88,6 +88,7 @@
8888
<ClInclude Include="..\strings\base_version_odr.h" />
8989
<ClInclude Include="..\strings\base_weak_ref.h" />
9090
<ClInclude Include="..\strings\base_windows.h" />
91+
<ClInclude Include="..\strings\base_xaml_component_connector.h" />
9192
<ClInclude Include="..\strings\base_xaml_typename.h" />
9293
<ClInclude Include="cmd_reader.h" />
9394
<ClInclude Include="code_writers.h" />

cppwinrt/cppwinrt.vcxproj.filters

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,6 @@
6464
<ClInclude Include="..\strings\base_coroutine_foundation.h">
6565
<Filter>strings</Filter>
6666
</ClInclude>
67-
<ClInclude Include="..\strings\base_coroutine_system.h">
68-
<Filter>strings</Filter>
69-
</ClInclude>
7067
<ClInclude Include="..\strings\base_coroutine_threadpool.h">
7168
<Filter>strings</Filter>
7269
</ClInclude>
@@ -163,9 +160,6 @@
163160
<ClInclude Include="..\strings\base_includes.h">
164161
<Filter>strings</Filter>
165162
</ClInclude>
166-
<ClInclude Include="..\strings\base_coroutine_system_winui.h">
167-
<Filter>strings</Filter>
168-
</ClInclude>
169163
<ClInclude Include="..\strings\base_iterator.h">
170164
<Filter>strings</Filter>
171165
</ClInclude>
@@ -175,6 +169,15 @@
175169
<ClInclude Include="..\strings\base_stringable_format.h">
176170
<Filter>strings</Filter>
177171
</ClInclude>
172+
<ClInclude Include="..\strings\base_xaml_component_connector.h">
173+
<Filter>strings</Filter>
174+
</ClInclude>
175+
<ClInclude Include="..\strings\base_coroutine_system.h">
176+
<Filter>strings</Filter>
177+
</ClInclude>
178+
<ClInclude Include="..\strings\base_coroutine_system_winui.h">
179+
<Filter>strings</Filter>
180+
</ClInclude>
178181
</ItemGroup>
179182
<ItemGroup>
180183
<ResourceCompile Include="$(OutDir)version.rc" />

nuget/readme.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,14 @@ void MyComponent::InitializeComponent()
112112
}
113113
```
114114

115+
***[Windows|Microsoft]::UI::Xaml::Markup::ComponentConnectorT***
116+
117+
A consequence of calling InitializeComponent outside construction is that Xaml runtime callbacks to IComponentConnector::Connect and IComponentConnector2::GetBindingConnector are now dispatched to the most derived implementations. Previously, these calls were dispatched directly to the class under construction, as the vtable had yet to be initialized. For objects with markup that derive from composable base classes with markup, this is a breaking change. Derived classes must now implement IComponentConnector::Connect and IComponentConnector2::GetBindingConnector by explicitly calling into the base class. The ComponentConnectorT template provides a correct implemenation for these interfaces:
118+
119+
```cpp
120+
struct DerivedPage : winrt::Windows::UI::Xaml::Markup::ComponentConnectorT<DerivedPageT<DerivedPage>>
121+
```
122+
115123
## Troubleshooting
116124
117125
The msbuild verbosity level maps to msbuild message importance as follows:

strings/base_implements.h

Lines changed: 76 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -253,24 +253,24 @@ namespace winrt::impl
253253
template <>
254254
struct interface_list<>
255255
{
256-
template <typename T, typename Predicate>
257-
static constexpr void* find(const T*, const Predicate&) noexcept
256+
template <typename Traits>
257+
static constexpr auto find(Traits const& traits) noexcept
258258
{
259-
return nullptr;
259+
return traits.not_found();
260260
}
261261
};
262262

263263
template <typename First, typename ... Rest>
264264
struct interface_list<First, Rest...>
265265
{
266-
template <typename T, typename Predicate>
267-
static constexpr void* find(const T* obj, const Predicate& pred) noexcept
266+
template <typename Traits>
267+
static constexpr auto find(Traits const& traits) noexcept
268268
{
269-
if (pred.template test<First>())
269+
if (traits.template test<First>())
270270
{
271-
return to_abi<First>(obj);
271+
return traits.template found<First>();
272272
}
273-
return interface_list<Rest...>::find(obj, pred);
273+
return interface_list<Rest...>::find(traits);
274274
}
275275
using first_interface = First;
276276
};
@@ -362,34 +362,88 @@ namespace winrt::impl
362362
using type = typename implements_default_interface<T>::type;
363363
};
364364

365-
struct iid_finder
365+
template<typename T>
366+
struct find_iid_traits
366367
{
367-
const guid& m_guid;
368+
T const* m_object;
369+
guid const& m_guid;
368370

369371
template <typename I>
370372
constexpr bool test() const noexcept
371373
{
372374
return is_guid_of<typename default_interface<I>::type>(m_guid);
373375
}
376+
377+
template <typename I>
378+
constexpr void* found() const noexcept
379+
{
380+
return to_abi<I>(m_object);
381+
}
382+
383+
static constexpr void* not_found() noexcept
384+
{
385+
return nullptr;
386+
}
374387
};
375388

376389
template <typename T>
377-
auto find_iid(const T* obj, const guid& iid) noexcept
390+
auto find_iid(T const* obj, guid const& iid) noexcept
378391
{
379-
return static_cast<unknown_abi*>(implemented_interfaces<T>::find(obj, iid_finder{ iid }));
392+
return static_cast<unknown_abi*>(implemented_interfaces<T>::find(find_iid_traits<T>{ obj, iid }));
380393
}
381394

382-
struct inspectable_finder
395+
template <typename I>
396+
struct has_interface_traits
383397
{
398+
template <typename T>
399+
constexpr bool test() const noexcept
400+
{
401+
return std::is_same_v<T, I>;
402+
}
403+
404+
template <typename>
405+
static constexpr bool found() noexcept
406+
{
407+
return true;
408+
}
409+
410+
static constexpr bool not_found() noexcept
411+
{
412+
return false;
413+
}
414+
};
415+
416+
template <typename T, typename I>
417+
constexpr bool has_interface() noexcept
418+
{
419+
return impl::implemented_interfaces<T>::find(has_interface_traits<I>{});
420+
}
421+
422+
template<typename T>
423+
struct find_inspectable_traits
424+
{
425+
T const* m_object;
426+
384427
template <typename I>
385428
static constexpr bool test() noexcept
386429
{
387430
return std::is_base_of_v<inspectable_abi, abi_t<I>>;
388431
}
432+
433+
template <typename I>
434+
constexpr void* found() const noexcept
435+
{
436+
return to_abi<I>(m_object);
437+
}
438+
439+
static constexpr void* not_found() noexcept
440+
{
441+
return nullptr;
442+
}
389443
};
390444

391445
template <typename T>
392-
inspectable_abi* find_inspectable(const T* obj) noexcept
446+
inspectable_abi* find_inspectable(T const* obj) noexcept
393447
{
394448
using default_interface = typename implements_default_interface<T>::type;
395449

@@ -399,7 +453,7 @@ namespace winrt::impl
399453
}
400454
else
401455
{
402-
return static_cast<inspectable_abi*>(implemented_interfaces<T>::find(obj, inspectable_finder{}));
456+
return static_cast<inspectable_abi*>(implemented_interfaces<T>::find(find_inspectable_traits<T>{ obj }));
403457
}
404458
}
405459

@@ -502,7 +556,7 @@ namespace winrt::impl
502556
template <typename D>
503557
struct produce<D, INonDelegatingInspectable> : produce_base<D, INonDelegatingInspectable>
504558
{
505-
int32_t __stdcall QueryInterface(const guid& id, void** object) noexcept final
559+
int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final
506560
{
507561
return this->shim().NonDelegatingQueryInterface(id, object);
508562
}
@@ -910,7 +964,7 @@ namespace winrt::impl
910964
return target;
911965
}
912966

913-
int32_t __stdcall NonDelegatingQueryInterface(const guid& id, void** object) noexcept
967+
int32_t __stdcall NonDelegatingQueryInterface(guid const& id, void** object) noexcept
914968
{
915969
if (is_guid_of<Windows::Foundation::IInspectable>(id) || is_guid_of<Windows::Foundation::IUnknown>(id))
916970
{
@@ -932,13 +986,13 @@ namespace winrt::impl
932986

933987
int32_t __stdcall NonDelegatingGetIids(uint32_t* count, guid** array) noexcept
934988
{
935-
const auto& local_iids = static_cast<D*>(this)->get_local_iids();
936-
const uint32_t& local_count = local_iids.first;
989+
auto const& local_iids = static_cast<D*>(this)->get_local_iids();
990+
uint32_t const& local_count = local_iids.first;
937991
if constexpr (root_implements_type::is_composing)
938992
{
939993
if (local_count > 0)
940994
{
941-
const com_array<guid>& inner_iids = get_interfaces(root_implements_type::m_inner);
995+
com_array<guid> const& inner_iids = get_interfaces(root_implements_type::m_inner);
942996
*count = local_count + inner_iids.size();
943997
*array = static_cast<guid*>(WINRT_IMPL_CoTaskMemAlloc(sizeof(guid)*(*count)));
944998
if (*array == nullptr)
@@ -1189,7 +1243,7 @@ namespace winrt::impl
11891243
}
11901244

11911245
virtual unknown_abi* get_unknown() const noexcept = 0;
1192-
virtual std::pair<uint32_t, const guid*> get_local_iids() const noexcept = 0;
1246+
virtual std::pair<uint32_t, guid const*> get_local_iids() const noexcept = 0;
11931247
virtual hstring GetRuntimeClassName() const = 0;
11941248
virtual void* find_interface(guid const&) const noexcept = 0;
11951249
virtual inspectable_abi* find_inspectable() const noexcept = 0;
@@ -1450,7 +1504,7 @@ WINRT_EXPORT namespace winrt
14501504
return impl::find_inspectable(static_cast<const D*>(this));
14511505
}
14521506

1453-
std::pair<uint32_t, const guid*> get_local_iids() const noexcept override
1507+
std::pair<uint32_t, guid const*> get_local_iids() const noexcept override
14541508
{
14551509
using interfaces = impl::uncloaked_interfaces<D>;
14561510
using local_iids = impl::uncloaked_iids<interfaces>;
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
2+
WINRT_EXPORT namespace winrt::%::UI::Xaml::Markup
3+
{
4+
template <typename D>
5+
struct ComponentConnectorT : D
6+
{
7+
using composable_base = typename D::composable_base;
8+
9+
void InitializeComponent()
10+
{
11+
if constexpr (m_has_connectable_base)
12+
{
13+
m_dispatch_base = true;
14+
composable_base::InitializeComponent();
15+
m_dispatch_base = false;
16+
}
17+
D::InitializeComponent();
18+
}
19+
20+
void Connect(int32_t connectionId, Windows::Foundation::IInspectable const& target)
21+
{
22+
if constexpr (m_has_connectable_base)
23+
{
24+
if (m_dispatch_base)
25+
{
26+
composable_base::Connect(connectionId, target);
27+
return;
28+
}
29+
}
30+
D::Connect(connectionId, target);
31+
}
32+
33+
auto GetBindingConnector(int32_t connectionId, Windows::Foundation::IInspectable const& target)
34+
{
35+
if constexpr (m_has_connectable_base)
36+
{
37+
if (m_dispatch_base)
38+
{
39+
return composable_base::GetBindingConnector(connectionId, target);
40+
}
41+
}
42+
return D::GetBindingConnector(connectionId, target);
43+
}
44+
45+
private:
46+
static constexpr bool m_has_connectable_base{
47+
impl::has_initializer<composable_base>::value &&
48+
impl::has_interface<D, IComponentConnector>() &&
49+
impl::has_interface<D, IComponentConnector2>() };
50+
51+
bool m_dispatch_base{};
52+
};
53+
}

0 commit comments

Comments
 (0)