-
Notifications
You must be signed in to change notification settings - Fork 660
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unable to implement classic COM interface on XAML component with C++/WinRT #3331
Comments
@kennykerr or @jevansaks I feel like we do this already, I think one of you two probably knows the answer. If not this sounds like a xaml compiler bug? @fabiant3 |
going with markup team for now. |
Yeah, it is a XAML compiler bug. Without XAML (a normal WinRT runtime component) it does work, but the XAML compiler's explicit specialization in .xaml.g.hpp is what breaks it. |
@RealTommyKlein - can you take a look? |
My workaround was implementing the functionality in a subclass that doesn't use the XAML compiler: TranslucentTB/TranslucentTB@8f68f3c |
Guessing that there's no workaround for this one? Just bit Terminal :/ |
There's 2 options:
|
@Scottj1s any chance someone from the Xaml compiler can take a look at this seemingly trivial bug? |
@sylveon There was a brief but real moment when I realized I was here because I was also implementing Why does the XAML generated header need to forcibly instantiate this template anyway? Does it not suffice to let the consumer do it? |
The XAML codegen does this because some members are forward declared in the |
Without this explicit instantiation, you get linker errors. |
This fixes the issue with the settings UI where clicking the browse buttons would cause an exception to be thrown when we tried to display a picker without an originating HWND. It turns out that pickers need a hosting/parent window, and Xaml Islands doesn't furnish us with a CoreWindow that's set up for that use case. Alas! Raymond Chen's [blog post on the matter] suggests that we should hand the HWND off through some classic COM interface. To do that properly, Terminal's various components need to implement that interface and propagate the HWND down where it's needed. Thanks to a [Xaml compiler issue], we can't actually do that. To work around that, we've begged and borrowed different methods for pushing HWNDs around: 1. Using IInitializeWithWindow in secret 2. A member that takes a uint64 3. An interface that offers a function that will "wire up" the HWND. I chose (1) because AppHost can implement IInitializeWithWindow, but TerminalPage cannot. We're just pretending that TerminalPage _can_. I chose (2) because none of the Xaml types in TerminalSettingsEditor can implement the interface thanks to the aforementioned compiler issue, but we don't have an escape hatch like AppHost that lives in the same module and can help us do the propagation. I chose (3) because I didn't want to commit the same sin as (2) _seven times_ for every different type of settings page that exists. (3) is backed by "IHostedInWindow", and anybody who knows they have to use IInitializeWithWindow to tie an HWND to an object can call IHostedInWindow.TryPropagateHostingWindow() on that object. House of cards. [Xaml compiler issue]: microsoft/microsoft-ui-xaml#3331 [blog post on the matter]: https://devblogs.microsoft.com/oldnewthing/20190412-00/?p=102413
This fixes the issue with the settings UI where clicking the browse buttons would cause an exception to be thrown when we tried to display a picker without an originating HWND. It turns out that pickers need a hosting/parent window, and Xaml Islands doesn't furnish us with a CoreWindow that's set up for that use case. Alas! Raymond Chen's [blog post on the matter] suggests that we should hand the HWND off through some classic COM interface. To do that properly, Terminal's various components need to implement that interface and propagate the HWND down where it's needed. Thanks to a [Xaml compiler issue], we can't actually do that. To work around that, we've begged and borrowed different methods for pushing HWNDs around: 1. Using IInitializeWithWindow in secret 2. A member that takes a uint64 3. An interface that offers a function that will "wire up" the HWND. I chose (1) because AppHost can implement IInitializeWithWindow, but TerminalPage cannot. We're just pretending that TerminalPage _can_. I chose (2) because none of the Xaml types in TerminalSettingsEditor can implement the interface thanks to the aforementioned compiler issue, but we don't have an escape hatch like AppHost that lives in the same module and can help us do the propagation. I chose (3) because I didn't want to commit the same sin as (2) _seven times_ for every different type of settings page that exists. (3) is backed by "IHostedInWindow", and anybody who knows they have to use IInitializeWithWindow to tie an HWND to an object can call IHostedInWindow.TryPropagateHostingWindow() on that object. House of cards. [Xaml compiler issue]: microsoft/microsoft-ui-xaml#3331 [blog post on the matter]: https://devblogs.microsoft.com/oldnewthing/20190412-00/?p=102413
This fixes the issue with the settings UI where clicking the browse buttons would cause an exception to be thrown when we tried to display a picker without an originating HWND. It turns out that pickers need a hosting/parent window, and Xaml Islands doesn't furnish us with a CoreWindow that's set up for that use case. Alas! Raymond Chen's [blog post on the matter] suggests that we should hand the HWND off through some classic COM interface. To do that properly, Terminal's various components need to implement that interface and propagate the HWND down where it's needed. Thanks to a [Xaml compiler issue], we can't actually do that. To work around that, we've begged and borrowed different methods for pushing HWNDs around: 1. Using IInitializeWithWindow in secret 2. A member that takes a uint64 3. An interface that offers a function that will "wire up" the HWND. I chose (1) because AppHost can implement IInitializeWithWindow, but TerminalPage cannot. We're just pretending that TerminalPage _can_. I chose (2) because none of the Xaml types in TerminalSettingsEditor can implement the interface thanks to the aforementioned compiler issue, but we don't have an escape hatch like AppHost that lives in the same module and can help us do the propagation. I chose (3) because I didn't want to commit the same sin as (2) _seven times_ for every different type of settings page that exists. (3) is backed by "IHostedInWindow", and anybody who knows they have to use IInitializeWithWindow to tie an HWND to an object can call IHostedInWindow.TryPropagateHostingWindow() on that object. House of cards. [Xaml compiler issue]: microsoft/microsoft-ui-xaml#3331 [blog post on the matter]: https://devblogs.microsoft.com/oldnewthing/20190412-00/?p=102413 (cherry picked from commit f9fc986)
Bump, still an issue |
This bug also prevents you from adding any additional arguments whatsoever to the base class template--not just COM interfaces, but also marker structs, etc. |
Describe the bug
When creating a XAML control/page, it's not possible to make it implement a classic COM interface (as C++/WinRT does it, by appending it to the base template arguments:
Something : SomethingT<Something, IMyClassicInterface>
) because the XAML compiler codegen does not account for this case.Steps to reproduce the bug
<windows.ui.xaml.media.dxinterop.h>
.struct MainPage : MainPageT<MainPage, ISwapChainPanelNative>
.IFACEMETHOD(SetSwapChain)(IDXGISwapChain*) noexcept;
to the struct members.Expected behavior
The app builds fine and a consumer is able to cast the XAML component to
ISwapChainPanelNative
and call the method provided by that interface.Screenshots
Version Info
NuGet package version:
[Microsoft.Windows.CppWinRT 2.0.200921.6]
Windows app type:
Additional context
I replied Yes to the app type being Win32 because this issue showed up in system XAML islands while implementing
IInitializeWithWindow
to pass on a window handle to MessageDialog from my hosting code to the XAML code. I'm using MessageDialog because of ContentDialog's limitation of one dialog open at a time per thread. Implementing threading proved to be a huge pain, so I've decided on using MessageDialog for now.The bug is caused by this line in MainPage.xaml.g.hpp:
It tries to specialize
MainPageT
using different parameters than what I used in my declaration, and since the class uses CRTP, it tries to castthis
back to MainPage, but because MainPage actually inherits from a different type (different template instantiations are effectively different types), the cast fails.The text was updated successfully, but these errors were encountered: