I've got a Windows application with a GUI written in Rust and winapi. Despite its GUI, it behaves like a console application. When the exe
file is started, a Command Prompt
window pops up, and the application is run from it. This is not what I want; a main window should open instead, as in all real desktop apps. How can I achieve this goal in Rust with winapi?
I've investigated some options. You can develop Windows desktop applications using Tauri or gtk-rs, but both of these techniques have drawbacks when used for Windows apps. More options may be found here. I've also tried the windows-rs samples available on the internet, but they're all console apps with a graphical user interface, which isn't what I'm looking for.
I also note that C desktop applications use the function int APIENTRY wWinMain(...)
as the entry point while console applications use int main(...)
, and wWinMain
doesn't seem available in rust winapi.
CodePudding user response:
Whether the system allocates a console for a newly created process is controlled by the Subsystem
field in the Windows-specific optional PE header. The field is populated through the linker's /SUBSYSTEM
command line option. The only relevant arguments for desktop applications are CONSOLE
and WINDOWS
. The former instructs the system to allocate a console on launch, whereas the latter won't.
You can instruct the linker to target the WINDOWS
subsystem from Rust code by placing the per-module
#![windows_subsystem = "windows"]
attribute (see windows-subsystem) inside the main module of your application.
You'll find an example of this in the core_app sample of the windows
crate.
This is the most convenient way to target the WINDOWS
subsystem. You can also explicitly pass the linker flag along, e.g. by placing the following override into .cargo/config.toml:
[build]
rustflags = [
"-C", "link-arg=/SUBSYSTEM:WINDOWS",
]
This may or may not work, depending on the linker you happen to be using. Since the linker isn't part of the Rust toolchain, making sure that this works and has the intended effect is on you.
A note on the entry point's function name: It is irrelevant as far as the OS loader is concerned. It never even makes it into the final executable image anyway. The PE image only stores the (image-base-relative) AddressOfEntryPoint
, and that symbol could have been named anything.
The concrete name is only relevant to the build tools involved in generating the respective linker input.
More info here: WinMain is just the conventional name for the Win32 process entry point. The underlying principles apply to Rust just the same, particularly the aspect that the user-defined entry point (fn main()
) isn't actually the executable's entry point.