Revertron
Revertron

Reputation: 1352

How to make a program that does not display the console window?

I'm trying to develop a program that uses the sdl2 library. It works perfectly so far, but when I run the program I get two windows - the sdl2 window and the console window.

How can I hide or not create the console window? Maybe there is some sort of WinMain?

Upvotes: 43

Views: 28064

Answers (6)

vlad
vlad

Reputation: 51

After hours of searching, in case if anyone wonders how to detach a process from windows console, there's a console api which can be called via win32console.

The trick is to call freeconsole() method in the child process:

// Start the process from parent with Command::new()
// Send markings. For instance arguments to that process via args() associated function, in this case "hidden"
use win32console::console::WinConsole;
if args[1] == "hidden" {
   WinConsole::free_console().unwrap();
}

Upvotes: 0

Dave Horner
Dave Horner

Reputation: 423

How can I hide or not create the console window?

It may be that you can use a creation flag to indicate no window.

winapi = {version = "0.3.9", features = ["winbase"]}
use winapi::um::winbase::CREATE_NO_WINDOW;
let cmd = "run.bat";
Command::new(cmd).creation_flags(CREATE_NO_WINDOW).spawn().ok();

Is it possible to use the standard library to spawn a process without showing the console window in Windows?

Upvotes: 1

ArtemGr
ArtemGr

Reputation: 12547

Rust 1.18 introduced a Windows Subsystem attribute. Turn off the console with:

#![windows_subsystem = "windows"]

When the Rust binaries are linked with the GCC toolchain, to start a program without spawning a command line window we need to pass the -mwindows option to the linker.

Cargo has a cargo rustc mode which can be used to pass extra flags to rustc. Before that was introduced, there was no known way to pass an option to the compiler with Cargo.

When we can not affect the compilation or linking to the desired effect, one workaround is to hide the window after it has been created:

fn hide_console_window() {
    use std::ptr;
    use winapi::um::wincon::GetConsoleWindow;
    use winapi::um::winuser::{ShowWindow, SW_HIDE};

    let window = unsafe {GetConsoleWindow()};
    // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
    if window != ptr::null_mut() {
        unsafe {
            ShowWindow(window, SW_HIDE);
        }
    }
}

We'll need the following in Cargo.toml to compile the example:

[dependencies]
winapi = {version = "0.3", features = ["wincon", "winuser"]}

When we are running the program from an existing console or IDE:

fn hide_console_window() {
    unsafe { winapi::um::wincon::FreeConsole() };
}

This second method doesn't work if we're starting the application from a batch file, for the batch still owns the console and keeps its from disappearing.

Upvotes: 69

Revertron
Revertron

Reputation: 1352

After some time I've found a perfect answer! Cargo now has very useful subcommand - rustc.

The full build command is like this:

cargo rustc -- -Clink-args="-Wl,--subsystem,windows"

Now we can build debug builds with regular cargo build, and when we need to make a final build we can use this command:

cargo rustc --release -- -Clink-args="-Wl,--subsystem,windows"

Upvotes: 9

Steve Klabnik
Steve Klabnik

Reputation: 15529

Soon, https://github.com/rust-lang/rust/pull/37501 will land, which is an implementation of RFC 1665 and the correct answer will be

#![windows_subsystem = "windows"]

in your crate root.

Upvotes: 16

GhotiPhud
GhotiPhud

Reputation: 976

Adding to Roman Quick's answer if you're using the MSVC toolchain you'll want to pass MSVC linker args instead.

cargo rustc --release -- -Clink-args="/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup"

Upvotes: 12

Related Questions