Skip to content
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

Proposal: A ThousandIslands Window for Easy Interoperability and Migration #10050

Open
softworkz opened this issue Oct 10, 2024 · 9 comments
Open
Labels
feature proposal New feature proposal needs-triage Issue needs to be triaged by the area owners

Comments

@softworkz
Copy link

softworkz commented Oct 10, 2024

Proposal: ThousandIslands Window

TL/DR

This is about hosting Win32 Islands like WinForms, WPF, ActiveX, ATL, MFC inside a WinUI3 application.

Primer

About "Modernize your applications with WinUI3"

This tag line can be found on many different places these days and I'm inclined to say that - per se - it's a good one.
But once you follow, you always get to the same kind of suggestions, which are about using XAML islands for integrating newly developed WinUI3 content/controls in existing applications. Each time I come across those topics, it appears kind of alienating to me, because it doesn't quite match reality. There are basically two ways for migrating to a new UI framework:

  1. Switch to the new framework and include legacy elements (until migrated)
    🡆 The typical mainstream way
  2. Stick to the legacy framework and include some elements done in the new framework
    🡆 Makes sense for niche cases only

I won't elaborate further on this classification for now, other than this: "modernizing" usually implies getting a fresh new look and this cannot only be achieved with (1), not with (2). When you put effort into some migration effort, you typically want some visual advancements and with (2), you just create visual weirdness.

Developer Acceptance and Adoption

I can only wonder why the focus on migration paths is so strongly fixated on (2).
Surely, XAML Islands are a good thing and also a useful building block for (1). but as of now, I am seeing ZERO effort on enabling (1) in any way.

And that's weird, because I think this is among the top blockers (if not THE top blocking reason) for delopers migrating to WinUI3:

"Can we integrate our existing UI components (win32, WinForms, WPF) when we migrate to WinUI3?"

As long as the answer is "no", I don't think that WinUI3 will ever achieve a level of adoption that is even close to the other frameworks.

 

The Current Situation

Many developers have tried to include Win32 windows in WinUI3 applications already - and failed. At least eventually at the point where it comes to input processing: it's possible to show something in a child window but it's not possible to get input working properly (keyboard, mouse, pointer).

Why is that so?

First, we need to understand how XAML islands are working: A XAML Island is basically a Win32 window in which the XAML content is sited. To build a XAML Island, you create a Win32 window first and then you use DesktopWindowXamlSource to have your XAML rendered (and available for interaction) inside that Win32 window.
This allows to host one or more XAML Islands inside another application - in a way that it's cooperative with regards to input focus management and input processing. You can switch input focus back and forther between non-WinUI3 XAML content, XAML content and from one to another XAML content. This functionality already exists (InputFocusController.

So what's wrong, why can't we use that to embed arbitrary Win32 controls in our WinUI3 app?

The Culprit: Microsoft.UI.Xaml.Window

When we create a default plain WinUI3 application (as of WASDK 1.6), we get the following window hierarchy:

image

A WinUI3 window forms a ContentIsland itself (you can retrieve it like this: ContentIsland.FindAllForCompositor(this.Compositor).First()).
And as we have learned: A content island consists of a hWnd window and a DesktopChildSiteBridge as a child. And that's the important part:

The DesktopChildSiteBridge IS NOT the XAML island.
The XAML island is the top-level window itself (WinUIDesktopWin32WindowClass).

And here it becomes clear why all those attempts of adding custom Win32 windows as children of the window never worked out well:

This way, you are essentially putting content INSIDE an existing island and hence it's no wonder that none of the interoperability mechanisms is working.

The Proposal: Microsoft.UI.Xaml.MultiIslandWindow

The MultiIslandWindow class should be very similar to the existing Window class, just with some important differences:

  • The XAML desktop island is not rooted directly to the AppWindow
    Instead, there's an intermediate Win32 window (direct child of the AppWindow, same size) for hosting the XAML content
  • Large parts of the subclassing (window message processing) that JupiterWindow is currently performing on the AppWindow is performed on the intermediate Win32 window instead, so that the AppWindow will no longer block input messages flowing to (non-WinUI3) child windows
    (I say "large parts", because certain processing like activation, closing, non-client messages might need to remain to be done on the AppWindow directly)

This will essentially allow developers to include ContentIslands from other sources and UI frameworks in a WinUI3 application.

 

Follow-Up Proposals

  • Extending APIs to manage ContentSites with non-xaml content
    for example with InputFocusController
  • Provide a HwndHost XAML control for easy integration in your XAML layouts
    (that content will just "fly above" the XAML content)
  • Possible derivatives of the HwndHost control:
    • WinFormsHost control
    • WpfContentHost control
  • Provide a XamlIslandHost XAML control for including a XamlIsland in a XAML layout
    (this will in turn allow to have XAML content "above" some other Hwnd content)
@castorix
Copy link

Many developers have tried to include Win32 windows in WinUI3 applications already - and failed. At least eventually at the point where it comes to input processing: it's possible to show something in a child window but it's not possible to get input working properly (keyboard, mouse, pointer).

Some people talked about Windows 11. On Windows 10, all Win32 controls I tested worked by hosting them with ATL (AtlAxWin)
For example, with a InkPicture control, the mouse works normally :

Image

@softworkz
Copy link
Author

Some people talked about Windows 11. On Windows 10, all Win32 controls I tested worked by hosting them with ATL (AtlAxWin)
For example, with a InkPicture control, the mouse works normally

Besides the fact that a "Win10-only" solution has little to no value anyway, how about touch input? That's what almost killed my strategy, nobody had ever even thought about testing it - until somebody came up with it in the public beta; now we have no solution to offer.

@castorix
Copy link

Besides the fact that a "Win10-only" solution has little to no value anyway, how about touch input?

It should theorically work on Windows 11, but I cannot test and people did not answer me about Windows 11...

@softworkz
Copy link
Author

I've spent five days, exploring all thinkable and unthinkable ways for getting pointer events (as plain window messages) inside the JupiterWindow, all kinds of hooks, subclassing reparenting, window styles and parameters. I've skimmed the APIs high and low, several times, I I have reviewed the source code in this repo - unfortunately the interesting bits are hidden inside CoreMessagingXP.dll, Microsoft.UI.Input.dll and Microsoft.InputStatemanager.dll, which are neither open source nor documented. I even partially disassembled and decompiled certain parts, but eventually it felt too insane and any such under-cover way I had hoped to find would essentially be rather worthless.
We need a solid and supposted method which we can rely on that it won't stop working all of a sudden - just like multi-threaded XAML islands (=one thread per island of course) are suddenly crashing on Windows 24H2 (no matter which appsdk version) - which is another major headache I have, but this topic is about getting a supported way for embedding non-xaml elements in a WinUI3 application.

@castorix
Copy link

castorix commented Oct 11, 2024

It shoud be fast to test if AtlAxWin works on Windows 11 (I used it in test samples like WinUI3_ActiveX_MSRDP (the hardcoded server I used has broken UI now (even with MSTSC), but mouse still works)
(ATL works since windows 95...)

@softworkz
Copy link
Author

Thanks, I've posted some new findings in your repo: castorix/WinUI3_ActiveX_MSRDP#2
Yet, that doesn't resolve or affect this proposal.

@castorix
Copy link

castorix commented Oct 12, 2024

Thanks, I've posted some new findings in your repo: castorix/WinUI3_ActiveX_MSRDP#2
Yet, that doesn't resolve or affect this proposal.

Thanks for having tested on Windows 11, because I only have Windows 10 (22H2) to do my tests, and everytime I ask people to test some code on other OS, they give up the thread 😕
(btw, I was also MVP SDK at same period, but now I'm not even "P" anymore 😏 (I'm disabled : impossible to find a job in my country (France))

@nikolayvpavlov
Copy link

Perhaps I am not getting your idea, but aren't you turning the table into hosting WinUI3 as an insland into a Win32 app?

@softworkz
Copy link
Author

softworkz commented Oct 14, 2024

Perhaps I am not getting your idea, but aren't you turning the table into hosting WinUI3 as an insland into a Win32 app?

It's about hosting Win32 Islands like WinForms, WPF, ActiveX, ATL, MFC inside a WinUI3 application.

Thanks for your comment, I have edited the original post to make this more clear.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature proposal New feature proposal needs-triage Issue needs to be triaged by the area owners
Projects
None yet
Development

No branches or pull requests

3 participants