From fa9b81b5ce3690b733be5b1e5316b66d5a20ef7a Mon Sep 17 00:00:00 2001 From: Ryan Liptak Date: Tue, 31 Oct 2023 01:26:50 -0700 Subject: [PATCH] start: Make wWinMain nCmdShow setting match Windows better It won't match perfectly; see https://github.com/ziglang/zig/issues/17808 --- lib/std/start.zig | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/lib/std/start.zig b/lib/std/start.zig index 4bb85f4eb9fc..7ed59a467590 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -603,13 +603,34 @@ pub fn callMain() u8 { } pub fn call_wWinMain() std.os.windows.INT { + const peb = std.os.windows.peb(); const MAIN_HINSTANCE = @typeInfo(@TypeOf(root.wWinMain)).Fn.params[0].type.?; const hInstance = @as(MAIN_HINSTANCE, @ptrCast(std.os.windows.kernel32.GetModuleHandleW(null).?)); const lpCmdLine = std.os.windows.kernel32.GetCommandLineW(); - // There's no (documented) way to get the nCmdShow parameter, so we're - // using this fairly standard default. - const nCmdShow = 5; + // There are various types used for the 'show window' variable through the Win32 APIs: + // - u16 in STARTUPINFOA.wShowWindow / STARTUPINFOW.wShowWindow + // - c_int in ShowWindow + // - u32 in PEB.ProcessParameters.dwShowWindow + // Since STARTUPINFO is the bottleneck for the allowed values, we use `u16` as the + // type which can coerce into i32/c_int/u32 depending on how the user defines their wWinMain + // (the Win32 docs show wWinMain with `int` as the type for nCmdShow). + const nCmdShow: u16 = nCmdShow: { + // This makes Zig match the nCmdShow behavior of a C program with a WinMain symbol: + // - With STARTF_USESHOWWINDOW set in STARTUPINFO.dwFlags of the CreateProcess call: + // - Compiled with subsystem:console -> nCmdShow is always SW_SHOWDEFAULT + // - Compiled with subsystem:windows -> nCmdShow is STARTUPINFO.wShowWindow from + // the parent CreateProcess call + // - With STARTF_USESHOWWINDOW unset: + // - nCmdShow is always SW_SHOWDEFAULT + const SW_SHOWDEFAULT = 10; + const STARTF_USESHOWWINDOW = 1; + // root having a wWinMain means that std.builtin.subsystem will always have a non-null value. + if (std.builtin.subsystem.? == .Windows and peb.ProcessParameters.dwFlags & STARTF_USESHOWWINDOW != 0) { + break :nCmdShow @truncate(peb.ProcessParameters.dwShowWindow); + } + break :nCmdShow SW_SHOWDEFAULT; + }; // second parameter hPrevInstance, MSDN: "This parameter is always NULL" return root.wWinMain(hInstance, null, lpCmdLine, nCmdShow);