Skip to content

Commit 42d4d07

Browse files
squeek502andrewrk
authored andcommitted
start: Make wWinMain nCmdShow setting match Windows better
It won't match perfectly; see #17808
1 parent d892665 commit 42d4d07

File tree

1 file changed

+24
-3
lines changed

1 file changed

+24
-3
lines changed

lib/std/start.zig

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -603,13 +603,34 @@ pub fn callMain() u8 {
603603
}
604604

605605
pub fn call_wWinMain() std.os.windows.INT {
606+
const peb = std.os.windows.peb();
606607
const MAIN_HINSTANCE = @typeInfo(@TypeOf(root.wWinMain)).Fn.params[0].type.?;
607608
const hInstance = @as(MAIN_HINSTANCE, @ptrCast(std.os.windows.kernel32.GetModuleHandleW(null).?));
608609
const lpCmdLine = std.os.windows.kernel32.GetCommandLineW();
609610

610-
// There's no (documented) way to get the nCmdShow parameter, so we're
611-
// using this fairly standard default.
612-
const nCmdShow = 5;
611+
// There are various types used for the 'show window' variable through the Win32 APIs:
612+
// - u16 in STARTUPINFOA.wShowWindow / STARTUPINFOW.wShowWindow
613+
// - c_int in ShowWindow
614+
// - u32 in PEB.ProcessParameters.dwShowWindow
615+
// Since STARTUPINFO is the bottleneck for the allowed values, we use `u16` as the
616+
// type which can coerce into i32/c_int/u32 depending on how the user defines their wWinMain
617+
// (the Win32 docs show wWinMain with `int` as the type for nCmdShow).
618+
const nCmdShow: u16 = nCmdShow: {
619+
// This makes Zig match the nCmdShow behavior of a C program with a WinMain symbol:
620+
// - With STARTF_USESHOWWINDOW set in STARTUPINFO.dwFlags of the CreateProcess call:
621+
// - Compiled with subsystem:console -> nCmdShow is always SW_SHOWDEFAULT
622+
// - Compiled with subsystem:windows -> nCmdShow is STARTUPINFO.wShowWindow from
623+
// the parent CreateProcess call
624+
// - With STARTF_USESHOWWINDOW unset:
625+
// - nCmdShow is always SW_SHOWDEFAULT
626+
const SW_SHOWDEFAULT = 10;
627+
const STARTF_USESHOWWINDOW = 1;
628+
// root having a wWinMain means that std.builtin.subsystem will always have a non-null value.
629+
if (std.builtin.subsystem.? == .Windows and peb.ProcessParameters.dwFlags & STARTF_USESHOWWINDOW != 0) {
630+
break :nCmdShow @truncate(peb.ProcessParameters.dwShowWindow);
631+
}
632+
break :nCmdShow SW_SHOWDEFAULT;
633+
};
613634

614635
// second parameter hPrevInstance, MSDN: "This parameter is always NULL"
615636
return root.wWinMain(hInstance, null, lpCmdLine, nCmdShow);

0 commit comments

Comments
 (0)