Skip to content

Commit 6fb1dbd

Browse files
DanielJumpCopilot
andcommitted
Use a checked cast where the ABI type is a real base
The previous change assumed every ABI type derives from unknown_abi, which is false for classic COM interfaces: they derive from ::IUnknown and are layout compatible but unrelated, so a static_cast does not compile. That broke the test projects, which implement ICapture and IMoreDerived. impl::abi_cast picks static_cast when a conversion exists and falls back to reinterpret_cast otherwise. C4946 only fires for related classes, so the fallback is silent and the warning is still gone. Applied to both to_abi overloads as well, which have the same problem in reverse: producer derives from the interface for classic COM but holds its vtable by value for WinRT. Also brace the name_v terminator array, which only compiles on that path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b396c800-f1bf-4ba4-a50f-a7f91d4d4f94 Hostname: ManJump9
1 parent 334e525 commit 6fb1dbd

2 files changed

Lines changed: 22 additions & 4 deletions

File tree

‎strings/base_identity.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ WINRT_EXPORT namespace winrt::impl
468468
combine
469469
(
470470
to_array<wchar_t>(guid_of<T>()),
471-
std::array<wchar_t, 1>{ L'\0' }
471+
std::array<wchar_t, 1>{{ L'\0' }}
472472
)
473473
};
474474

‎strings/base_implements.h‎

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,24 @@ WINRT_EXPORT namespace winrt::impl
232232
std::memset(ptr, 0, sizeof(T));
233233
}
234234
}
235+
236+
// Converts between an implementation type and the ABI type it is layout compatible with.
237+
// Classic COM interfaces derive from ::IUnknown rather than from unknown_abi, and producer
238+
// holds its vtable by value for WinRT interfaces, so the two types are often unrelated and
239+
// only a reinterpret_cast will do. Where they are related, a reinterpret_cast is both
240+
// unnecessary and reported as C4946, so prefer the checked conversion when one exists.
241+
template <typename To, typename From>
242+
To* abi_cast(From* from) noexcept
243+
{
244+
if constexpr (std::is_convertible_v<From*, To*>)
245+
{
246+
return static_cast<To*>(from);
247+
}
248+
else
249+
{
250+
return reinterpret_cast<To*>(from);
251+
}
252+
}
235253
}
236254

237255
WINRT_EXPORT namespace winrt
@@ -257,13 +275,13 @@ WINRT_EXPORT namespace winrt
257275
template <typename I, typename D>
258276
impl::abi_t<I>* to_abi(impl::producer<D, I> const* from) noexcept
259277
{
260-
return reinterpret_cast<impl::abi_t<I>*>(const_cast<impl::producer<D, I>*>(from));
278+
return impl::abi_cast<impl::abi_t<I>>(const_cast<impl::producer<D, I>*>(from));
261279
}
262280

263281
template <typename I, typename D>
264282
impl::abi_t<I>* to_abi(impl::producer_convert<D, I> const* from) noexcept
265283
{
266-
return reinterpret_cast<impl::abi_t<I>*>((impl::producer<D, default_interface<I>>*)from);
284+
return impl::abi_cast<impl::abi_t<I>>(const_cast<impl::producer<D, default_interface<I>>*>(static_cast<impl::producer<D, default_interface<I>> const*>(from)));
267285
}
268286
}
269287

@@ -1568,7 +1586,7 @@ WINRT_EXPORT namespace winrt
15681586

15691587
impl::unknown_abi* get_unknown() const noexcept override
15701588
{
1571-
return static_cast<impl::unknown_abi*>(to_abi<typename impl::implements_default_interface<D>::type>(this));
1589+
return impl::abi_cast<impl::unknown_abi>(to_abi<typename impl::implements_default_interface<D>::type>(this));
15721590
}
15731591

15741592
hstring GetRuntimeClassName() const override

0 commit comments

Comments
 (0)