microsoft / microsoft-ui-xaml

Windows UI Library: the latest Windows 10 native controls and Fluent styles for your applications
MIT License
6.16k stars 666 forks source link

Support WinUI3 resource load from win32's traditional resource(rc) file. #9135

Open TeslaKang opened 7 months ago

TeslaKang commented 7 months ago

I'm using WinUI3(use DesktopWindowXamlSource ) for only certain parts of an existing MFC App. In most cases, it works well and there are no major problems. However, I want to use compiled XAML rather than XAML source code.

1) Is there a way to compile XAML in an MFC project? If project type is Window Store project, can compile XAML.. But cannot compile XAML in an MFC project.

2) Similar to number 1, IDL cannot be compiled, so Runtime Type cannot be used. If there is a way, I would appreciate it if you could let me know.

3) When using Windows::UI::Xaml::Application::LoadComponent, etc., is there a way to use Windows' traditional resource file as Uri?

4) After using the DesktopWindowXamlSource function in Windows 10, if close DesktopWindowXamlSource , it is not completely close and "DesktopWindowXamlSource" is displayed on the taskbar. Is there a way to completely remove DesktopWindowXamlSource?

5) There are two types of WinUI3: those that start with "Microsoft ::UI::Xaml::" and those that start with "Windows.::UI::Xaml::". It seems that anything that starts with Microsoft can be used only after using bootstrap and initializing it as an Application. Anything that starts with Windows can be used without any special restrictions as long as it is a specific version of Windows 10 or higher.

Are there any differences between the two UI libraries?

DarranRowe commented 7 months ago
  1. The Xaml compiler is enabled if the project identifies itself as a Windows Store project type. The traditional Win32/Windows API projects don't do this. The sample for WinUI 3 does this by adding something to the .vcxproj. This changes some subtle settings in the project, so I'm not sure how it would interact with an MFC project type. This should also work in a DLL project too. Maybe it would be possible to separate the Xaml Islands functionality into a separate library. There are some extra problems if you are trying to use the Xaml compiler for DesktopWindowXamlSource in the Windows root namespace though.
  2. In general, all MIDL needs is the /winrt command line option to make it compile for the Windows Runtime. Using C++/WinRT is more recommended because it also handles the metadata. This package changes the defaults for MIDL though, so again, I have no idea how it interacts with MFC projects though. Especially if it uses COM.
  3. I have only ever seen Application.LoadComponent target a .xaml file.
  4. First, DesktopWindowXamlSource is not a function. It is more akin to a COM CoClass. However, the projections usually wrap it up as a class. What you would be seeing is the equivalent of a constructor call. Both the system version of DesktopWindowXamlSource and the WinUI 3 version of DesktopWindowXamlSource document this in the same way. Secondly, it is always intended for the DesktopWindowXamlSource to be set as a child window to a parent Window. The system version of DesktopWindowXamlSource implements the IDesktopWindowXamlSourceNative(2) interfaces. This gives three very important members, AttachToWindow which allows you to set the parent window of the DesktopWindowXamlSource. Then there is get_WindowHandle, which provides you with the native window handle (HWND) of the DesktopWindowXamlSource. This allows you to interact with the underlying window itself. Finally, there is PreTranslateMessage. The WinUI 3 version of DesktopWindowXamlSource doesn't implement these interfaces. However, the same functionality is exposed in other ways. It takes advantage of the fact that the Windows App SDK exposes the WindowId type that represents a HWND in the Windows Runtime type system. You would use GetWindowIdFromWindow and GetWindowFromWindowId to convert between the WindowId and a HWND. Anyway, the WinUI 3 version of DesktopWindowXamlSource uses the Initialize member to set the parent window. The handle for the island itself can be obtained by using the SiteBridge property. This gives you a reference to the DesktopChildSiteBridge associated with the island. This site bridge then has the WindowId property. This gives you the native handle to the underlying HWND. Finally, there is ContentPreTranslateMessage.
  5. Xaml under Windows.UI.Xaml can be referred to as WinUI (or retroactively WinUI 1). WinUI 2 is a package of extra controls and styles that only works with the system Xaml, or WinUI 1. This is worth noting because these controls are in the Microsoft.UI.Xaml.Controls namespace. It is only the Xaml that comes packaged with the Windows App SDK that is known as WinUI 3. In general, you would want to prefer using WinUI 3 from the Windows App SDK.
TeslaKang commented 7 months ago

3. https://www.codeproject.com/Articles/5359576/WinUI3-in-Existing-Win32-Applications Looking at the sample here, since Application::LoadComponent cannot be done directly from Windows resources, a temporary file is created and the Uri is specified as ms-appx://local/ before loading. So I don't want to create temporary files, and I think we should support reading directly from resources, or at least reading from memory.

4. I don't think you quite understood what I said. There is no problem at all in using it. The problem is that when you close WINUI after finishing using it, "DesktopWindowXamlSource" appears and remains on the task bar. My main program is an MFC program and displays the WinUI screen as a modal when necessary. When the modal is closed, "DesktopWindowXamlSource" appears in the task bar. Currently, I am temporarily solving the problem by finding and hiding the window with the title "DesktopWindowXamlSource", but I am wondering if there is a way to solve the problem fundamentally.

5. ok... So is there a way to use it without using Application in WinUI 3? WinUI3 can be used after initializing it as an application, but I am curious about how to use it without an application. The reason is that because Application has a message loop function, it conflicts with MFC's message loop, making it difficult to use with MFC.

DarranRowe commented 6 months ago
  1. Do you want to know the interesting thing? Not using temporary files as a concept already exists. The big difference is that the WinUI 3 project types normally embed these files into the .pri file. The functionality exists, just not in the way you are asking for this. Yes, the compiled Xaml binary files will be embedded in the application's or package's .pri file. The Xaml runtime will also read these directly out of the .pri file. If you want to add even the .pri file to the application's resources, then unfortunately, MRT Core has no means of reading the resources from anywhere but off of the filesystem. Also, that codeproject sample was written before WinUI 3's version of Xaml Islands was released, and it seems to be trying to work with an actual Xaml application itself. I wouldn't say that it is a good source.
  2. I understood completely what you wrote. But to be blunt, a Xaml Island window will always have WS_CHILD set, this means that the lifetime of that child window will always be controlled by the parent window. This means that if you are seeing this DesktopWindowXamlSource window appear, then, unfortunately, you are mishandling the Xaml Island window somehow. I would guess that the window has ghosted due to not receiving messages. It is also possible that you running the Island window as modal is a major problem. When you use a modal dialog, the modal window uses its own message loop. Who knows what kind of filtering happens in this message loop. What's more, the sample application calls ContentPreTranslateMessage to handle the Xaml Island message, you can't control the message loop to that extent with a modal dialog.
  3. Look carefully at the main function for the sample Xaml Islands application. It uses an instance of Application, but it also uses its own message loop. It also never calls Application.Start. As the documentation states, the message pump/message loop only runs if you call Application.Start. You never call this in a Xaml Islands application since you want to control the message loop.