How to stop my program from opening the console on windows at startup?

What it says in the title. At startup my program always opens a console too. How do I prevent that from happening?

Chatgpt claims that it depends on how you compile the binary (as a console program or windows application or smth) but I couldnt find any resources on how to do so with zig

see this thread: New terminal opens when running program

1 Like

In build.zig:

exe.subsystem = .Windows;

On the command line:

zig build-exe --subsystem windows
4 Likes

Thats what I was looking for, thank you!

Man I hate windows…

1 Like

Yeah this requirement to declare whether you’re a console or GUI executable is a source of pain. I’d love to be able to have a “.exe” file that can do both, but I’m not sure if there’s a way to perfectly emulate both without having to have 2 separate executables.

If you declare yourself a console app then opening the exe from the explorer application causes it to create and show a new terminal. If you declare yourself a GUI app then running the program from the CMD.exe process doesn’t seem to pass you the STDOUT/STDERR streams…

1 Like

Thats even worse than I thought lol

Here’s a rather silly workaround I came across while working on this post:

1 Like

I think you’re looking for AttachConsole.

const std = @import("std");
const win = std.os.windows;

pub extern "kernel32" fn AttachConsole(dwProcessId: win.DWORD) callconv(win.WINAPI) win.BOOL;
const ATTACH_PARENT_PROCESS = ~@as(win.DWORD, 0);

pub fn main() !void {
    _ = AttachConsole(ATTACH_PARENT_PROCESS);
    std.debug.print("Hello, world!", .{});
}
6 Likes

Yes, a single EXE can work both ways, but it’s a lot of work to get right. It would be marked as a Windows program, then as needed, AllocConsole to create a console.

Easier way I’ve seen is to create a console stub program that spawns the Windows EXE with flags and uses pipes for the console IO. Your stub would be foo.COM and the Windows one foo.EXE, because the console shell will prefer a .COM over the .EXE when running foo.

Visual Studio does this. If you have VS, look at your install folder and see that there is a devenv.com (12k) and a devenv.exe (1000K).

4 Likes

Yes, a single EXE can work both ways, but it’s a lot of work to get right. It would be marked as a Windows program, then as needed, AllocConsole to create a console.

This mechanism doesn’t seem to work. If the exe is marked as a “windows program”, then running it from the console doesn’t seem to block the console from printing and starting the next prompt. You could run start /wait myapp.exe, however, doesn’t seem like there’s any way for myapp.exe to perfectly behave like either one depending on the context? Any ideas on ways to solve this?

I believe this problem is what the workaround I linked in How to stop my program from opening the console on windows at startup? - #7 by squeek502 is meant to solve.

It’s used with AttachConsole in Rufus here. You can download Rufus and run it from the command line to see if it works how you’d like it to.

1 Like

yeah – AttachConsole - I misremembered the API name. And to do IO you have to get the stdio handles GetStdHandle(STD_OUTPUT_HANDLE), and if you want the command line, GetCommandLine(), etc.

Ends up being a lot less work to make a .COM and a .EXE with the same file stem.

Ah yes the thread continues; I have a new problem. How do I suppress the opening of a console from another process that I launched? I have no control over that processes code.

If you are running windowed and launching a console program, there’s nothing you can do about that. Windows will create the console as expected for any executable marked as a console program. You’re really limited what you can do to control another arbitrary process - they always have a way of bypassing or ignoring what you might be trying to do. This is a typical arms race that occurs when programs insist they must be the one on top, for example.

1 Like

AAAA okay thank you very much

I will say it again. I hate windows.

1 Like

viewed 73k