Suggestion
Hi,
Let me start with the disclaimer: I do understand that this might be an uncommon scenario, but I hope that you'll be able to find some time to look into it nonetheless, and maybe share your experience.
Besides, I believe that generally, this should be a supported scenario.
Anyway, I've been toying with Windows App SDK and Rust, and I'm happy to say that I've managed to create a very simple app! I have essentially reimplemented this app: https://github.com/sotanakamura/winui3-without-xaml
My original research was into WinUI Islands. I must note that I believe that hosting WinUI components, even if from a C++ DLL, within a Win32 app written in Rust could be a valid scenario. I understand that XAML technology itself is very specific to C#, but some things (like the Islands host) are, from my knowledge, "usual" (non-XAML) components.
Anyway :) Here are a few things that I've noticed.
Composable classes with overridable methods
Probably the most important bit for this specific issue and for the future of windows-rs in general, currently windows-bindgen seems unable to generate bindings for unsealed classes with overridable methods.
To make the app run, I need to inherit from the Application class and override the OnLaunched method. For this, I need to call the factory's CreateInstance method with a pointer to my IApplicationOverrides implementation. However, windows-bindgen generates a simple new() function that doesn't accept any parameters. In the end, I had to write the constructor myself like this:
fn create_app() -> Result<Application> {
// App implements IApplicationOverrides
let app = App::new()?.into_object();
let app_unknown = app.as_interface::<IUnknown>();
ApplicationFactory(|this| unsafe {
let mut result__ = core::mem::zeroed();
(Interface::vtable(this).CreateInstance)(
Interface::as_raw(this),
Interface::as_raw(&*app_unknown),
&mut core::ptr::null_mut(),
&mut result__,
)
.and_then(|| Type::from_abi(result__))
})
Interesting behaviour of Drop
I'm not sure that this is a correct heading, but I experience a bit of an interesting behaviour with this constructor.
In reality, it does a bit more (see the linked project): it actually saves the resulting Application into a variable and then "inits" the App class with it as follows:
#[implement(IApplicationOverrides)]
struct App {
application: RefCell<Option<Application>>,
}
impl App {
fn init(&self, app: Application) {
self.application.borrow_mut().replace(app);
}
}
impl Drop for App {
fn drop(&mut self) {
log::debug!("App::drop");
}
}
The interesting thing is that, if I do pass the Application to my App class, the latter doesn't get dropped anymore, and the call to RoUninitialize at process exit causes a violating access error. And if I do manage to manually release it (by casting it to IUnknown and then using the vtable), the Drop gets called but I get an Object has been over-released panic at process exit.
I'm sure I'm doing something wrong here, but I can't quite figure it out. Application is a strange object that cannot be put into a ComObject, and cannot even be cast to IApplication. But I need to save it so I could later call its methods.
Usability of this repo as a dependency
I have to note that using this repo as a git dependency is quite sub-optimal. This is because I would like to use only the newer version of windows-bindgen that is capable of generating composable class constructors, but I end up checking out the whole multi-dozen-megabyte repository. I wish there was a new windows-bindgen release on crates.io.
The sample app
You can find the sample app I've built here: https://github.com/Alovchin91/rust-winui
Note that it uses Git LFS because WinAppSDK's bindings that do compile are ginormous 😅
There are also a couple of patches that I had to apply to the bindings: I couldn't find a good way to make WinAppSDK bindings use the Windows::UI::Xaml::Interop bindings so I do search and replace, and WebView2.Core's bindings generate two overloaded methods with the same name so I have to rename the last one manually.
You'll also have to put all the WinAppSDK's WinMDs into the winappsdk/winmd directory manually as I'm not sure if I can legally "redistribute" them.
Suggestion
Hi,
Let me start with the disclaimer: I do understand that this might be an uncommon scenario, but I hope that you'll be able to find some time to look into it nonetheless, and maybe share your experience.
Besides, I believe that generally, this should be a supported scenario.
Anyway, I've been toying with Windows App SDK and Rust, and I'm happy to say that I've managed to create a very simple app! I have essentially reimplemented this app: https://github.com/sotanakamura/winui3-without-xaml
My original research was into WinUI Islands. I must note that I believe that hosting WinUI components, even if from a C++ DLL, within a Win32 app written in Rust could be a valid scenario. I understand that XAML technology itself is very specific to C#, but some things (like the Islands host) are, from my knowledge, "usual" (non-XAML) components.
Anyway :) Here are a few things that I've noticed.
Composable classes with overridable methods
Probably the most important bit for this specific issue and for the future of windows-rs in general, currently windows-bindgen seems unable to generate bindings for unsealed classes with overridable methods.
To make the app run, I need to inherit from the
Applicationclass and override theOnLaunchedmethod. For this, I need to call the factory'sCreateInstancemethod with a pointer to myIApplicationOverridesimplementation. However, windows-bindgen generates a simplenew()function that doesn't accept any parameters. In the end, I had to write the constructor myself like this:Interesting behaviour of Drop
I'm not sure that this is a correct heading, but I experience a bit of an interesting behaviour with this constructor.
In reality, it does a bit more (see the linked project): it actually saves the resulting
Applicationinto a variable and then "inits" theAppclass with it as follows:The interesting thing is that, if I do pass the
Applicationto myAppclass, the latter doesn't get dropped anymore, and the call toRoUninitializeat process exit causes a violating access error. And if I do manage to manually release it (by casting it to IUnknown and then using the vtable), the Drop gets called but I get anObject has been over-releasedpanic at process exit.I'm sure I'm doing something wrong here, but I can't quite figure it out.
Applicationis a strange object that cannot be put into aComObject, and cannot even be cast toIApplication. But I need to save it so I could later call its methods.Usability of this repo as a dependency
I have to note that using this repo as a git dependency is quite sub-optimal. This is because I would like to use only the newer version of windows-bindgen that is capable of generating composable class constructors, but I end up checking out the whole multi-dozen-megabyte repository. I wish there was a new
windows-bindgenrelease on crates.io.The sample app
You can find the sample app I've built here: https://github.com/Alovchin91/rust-winui
Note that it uses Git LFS because WinAppSDK's bindings that do compile are ginormous 😅
There are also a couple of patches that I had to apply to the bindings: I couldn't find a good way to make WinAppSDK bindings use the
Windows::UI::Xaml::Interopbindings so I do search and replace, and WebView2.Core's bindings generate two overloaded methods with the same name so I have to rename the last one manually.You'll also have to put all the WinAppSDK's WinMDs into the
winappsdk/winmddirectory manually as I'm not sure if I can legally "redistribute" them.