diff --git a/cppwinrt/code_writers.h b/cppwinrt/code_writers.h index 7122e9541..e6122a514 100644 --- a/cppwinrt/code_writers.h +++ b/cppwinrt/code_writers.h @@ -3270,6 +3270,14 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable { w.write(strings::base_xaml_typename); } + else if (namespace_name == "Windows.UI.Xaml.Markup") + { + w.write(strings::base_xaml_component_connector, "Windows"); + } + else if (namespace_name == "Microsoft.UI.Xaml.Markup") + { + w.write(strings::base_xaml_component_connector, "Microsoft"); + } } static void write_namespace_special_1(writer& w, std::string_view const& namespace_name) diff --git a/cppwinrt/component_writers.h b/cppwinrt/component_writers.h index 98bc75720..8521a777e 100644 --- a/cppwinrt/component_writers.h +++ b/cppwinrt/component_writers.h @@ -797,6 +797,7 @@ catch (...) { return winrt::to_hresult(); } } else { + composable_base_name = w.write_temp("using composable_base = B;"); base_type_parameter = ", typename B"; base_type_argument = ", B"; no_module_lock = "no_module_lock, "; diff --git a/cppwinrt/cppwinrt.vcxproj b/cppwinrt/cppwinrt.vcxproj index 81b6703ef..391fda68f 100644 --- a/cppwinrt/cppwinrt.vcxproj +++ b/cppwinrt/cppwinrt.vcxproj @@ -54,9 +54,9 @@ + - @@ -88,6 +88,7 @@ + diff --git a/cppwinrt/cppwinrt.vcxproj.filters b/cppwinrt/cppwinrt.vcxproj.filters index dfe1488ee..9033a34a8 100644 --- a/cppwinrt/cppwinrt.vcxproj.filters +++ b/cppwinrt/cppwinrt.vcxproj.filters @@ -64,9 +64,6 @@ strings - - strings - strings @@ -163,9 +160,6 @@ strings - - strings - strings @@ -175,6 +169,15 @@ strings + + strings + + + strings + + + strings + diff --git a/nuget/readme.md b/nuget/readme.md index 4d925d06d..cc27391ec 100644 --- a/nuget/readme.md +++ b/nuget/readme.md @@ -112,6 +112,14 @@ void MyComponent::InitializeComponent() } ``` +***[Windows|Microsoft]::UI::Xaml::Markup::ComponentConnectorT*** + +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: + +```cpp + struct DerivedPage : winrt::Windows::UI::Xaml::Markup::ComponentConnectorT> +``` + ## Troubleshooting The msbuild verbosity level maps to msbuild message importance as follows: diff --git a/strings/base_implements.h b/strings/base_implements.h index 212f2ecf7..53826d6b6 100644 --- a/strings/base_implements.h +++ b/strings/base_implements.h @@ -253,24 +253,24 @@ namespace winrt::impl template <> struct interface_list<> { - template - static constexpr void* find(const T*, const Predicate&) noexcept + template + static constexpr auto find(Traits const& traits) noexcept { - return nullptr; + return traits.not_found(); } }; template struct interface_list { - template - static constexpr void* find(const T* obj, const Predicate& pred) noexcept + template + static constexpr auto find(Traits const& traits) noexcept { - if (pred.template test()) + if (traits.template test()) { - return to_abi(obj); + return traits.template found(); } - return interface_list::find(obj, pred); + return interface_list::find(traits); } using first_interface = First; }; @@ -362,34 +362,88 @@ namespace winrt::impl using type = typename implements_default_interface::type; }; - struct iid_finder + template + struct find_iid_traits { - const guid& m_guid; + T const* m_object; + guid const& m_guid; template constexpr bool test() const noexcept { return is_guid_of::type>(m_guid); } + + template + constexpr void* found() const noexcept + { + return to_abi(m_object); + } + + static constexpr void* not_found() noexcept + { + return nullptr; + } }; template - auto find_iid(const T* obj, const guid& iid) noexcept + auto find_iid(T const* obj, guid const& iid) noexcept { - return static_cast(implemented_interfaces::find(obj, iid_finder{ iid })); + return static_cast(implemented_interfaces::find(find_iid_traits{ obj, iid })); } - struct inspectable_finder + template + struct has_interface_traits { + template + constexpr bool test() const noexcept + { + return std::is_same_v; + } + + template + static constexpr bool found() noexcept + { + return true; + } + + static constexpr bool not_found() noexcept + { + return false; + } + }; + + template + constexpr bool has_interface() noexcept + { + return impl::implemented_interfaces::find(has_interface_traits{}); + } + + template + struct find_inspectable_traits + { + T const* m_object; + template static constexpr bool test() noexcept { return std::is_base_of_v>; } + + template + constexpr void* found() const noexcept + { + return to_abi(m_object); + } + + static constexpr void* not_found() noexcept + { + return nullptr; + } }; template - inspectable_abi* find_inspectable(const T* obj) noexcept + inspectable_abi* find_inspectable(T const* obj) noexcept { using default_interface = typename implements_default_interface::type; @@ -399,7 +453,7 @@ namespace winrt::impl } else { - return static_cast(implemented_interfaces::find(obj, inspectable_finder{})); + return static_cast(implemented_interfaces::find(find_inspectable_traits{ obj })); } } @@ -502,7 +556,7 @@ namespace winrt::impl template struct produce : produce_base { - int32_t __stdcall QueryInterface(const guid& id, void** object) noexcept final + int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final { return this->shim().NonDelegatingQueryInterface(id, object); } @@ -910,7 +964,7 @@ namespace winrt::impl return target; } - int32_t __stdcall NonDelegatingQueryInterface(const guid& id, void** object) noexcept + int32_t __stdcall NonDelegatingQueryInterface(guid const& id, void** object) noexcept { if (is_guid_of(id) || is_guid_of(id)) { @@ -932,13 +986,13 @@ namespace winrt::impl int32_t __stdcall NonDelegatingGetIids(uint32_t* count, guid** array) noexcept { - const auto& local_iids = static_cast(this)->get_local_iids(); - const uint32_t& local_count = local_iids.first; + auto const& local_iids = static_cast(this)->get_local_iids(); + uint32_t const& local_count = local_iids.first; if constexpr (root_implements_type::is_composing) { if (local_count > 0) { - const com_array& inner_iids = get_interfaces(root_implements_type::m_inner); + com_array const& inner_iids = get_interfaces(root_implements_type::m_inner); *count = local_count + inner_iids.size(); *array = static_cast(WINRT_IMPL_CoTaskMemAlloc(sizeof(guid)*(*count))); if (*array == nullptr) @@ -1189,7 +1243,7 @@ namespace winrt::impl } virtual unknown_abi* get_unknown() const noexcept = 0; - virtual std::pair get_local_iids() const noexcept = 0; + virtual std::pair get_local_iids() const noexcept = 0; virtual hstring GetRuntimeClassName() const = 0; virtual void* find_interface(guid const&) const noexcept = 0; virtual inspectable_abi* find_inspectable() const noexcept = 0; @@ -1450,7 +1504,7 @@ WINRT_EXPORT namespace winrt return impl::find_inspectable(static_cast(this)); } - std::pair get_local_iids() const noexcept override + std::pair get_local_iids() const noexcept override { using interfaces = impl::uncloaked_interfaces; using local_iids = impl::uncloaked_iids; diff --git a/strings/base_xaml_component_connector.h b/strings/base_xaml_component_connector.h new file mode 100644 index 000000000..ac2edf807 --- /dev/null +++ b/strings/base_xaml_component_connector.h @@ -0,0 +1,53 @@ + +WINRT_EXPORT namespace winrt::%::UI::Xaml::Markup +{ + template + struct ComponentConnectorT : D + { + using composable_base = typename D::composable_base; + + void InitializeComponent() + { + if constexpr (m_has_connectable_base) + { + m_dispatch_base = true; + composable_base::InitializeComponent(); + m_dispatch_base = false; + } + D::InitializeComponent(); + } + + void Connect(int32_t connectionId, Windows::Foundation::IInspectable const& target) + { + if constexpr (m_has_connectable_base) + { + if (m_dispatch_base) + { + composable_base::Connect(connectionId, target); + return; + } + } + D::Connect(connectionId, target); + } + + auto GetBindingConnector(int32_t connectionId, Windows::Foundation::IInspectable const& target) + { + if constexpr (m_has_connectable_base) + { + if (m_dispatch_base) + { + return composable_base::GetBindingConnector(connectionId, target); + } + } + return D::GetBindingConnector(connectionId, target); + } + + private: + static constexpr bool m_has_connectable_base{ + impl::has_initializer::value && + impl::has_interface() && + impl::has_interface() }; + + bool m_dispatch_base{}; + }; +}