Skip to content

Commit 0ba1c4a

Browse files
committed
support more process creation options on Windows
Adds a CreateProcessFlags packed struct for all the possible flags to CreateProcessW on windows. In addition, propagates the existing `start_suspended` option in std.process.Child which was previously only used on Darwin. Also adds a `create_no_window` option to std.process.Child which is a commonly used flag for launching console executables on windows without causing a new console window to "pop up".
1 parent 0367d68 commit 0ba1c4a

File tree

3 files changed

+55
-8
lines changed

3 files changed

+55
-8
lines changed

lib/std/os/windows.zig

+36-1
Original file line numberDiff line numberDiff line change
@@ -1886,13 +1886,48 @@ pub const CreateProcessError = error{
18861886
Unexpected,
18871887
};
18881888

1889+
pub const CreateProcessFlags = packed struct(u32) {
1890+
debug_process: bool = false,
1891+
debug_only_this_process: bool = false,
1892+
create_suspended: bool = false,
1893+
detached_process: bool = false,
1894+
create_new_console: bool = false,
1895+
normal_priority_class: bool = false,
1896+
idle_priority_class: bool = false,
1897+
high_priority_class: bool = false,
1898+
realtime_priority_class: bool = false,
1899+
create_new_process_group: bool = false,
1900+
create_unicode_environment: bool = false,
1901+
create_separate_wow_vdm: bool = false,
1902+
create_shared_wow_vdm: bool = false,
1903+
create_forcedos: bool = false,
1904+
below_normal_priority_class: bool = false,
1905+
above_normal_priority_class: bool = false,
1906+
inherit_parent_affinity: bool = false,
1907+
inherit_caller_priority: bool = false,
1908+
create_protected_process: bool = false,
1909+
extended_startupinfo_present: bool = false,
1910+
process_mode_background_begin: bool = false,
1911+
process_mode_background_end: bool = false,
1912+
create_secure_process: bool = false,
1913+
reserved: bool = false,
1914+
create_breakaway_from_job: bool = false,
1915+
create_preserve_code_authz_level: bool = false,
1916+
create_default_error_mode: bool = false,
1917+
create_no_window: bool = false,
1918+
profile_user: bool = false,
1919+
profile_kernel: bool = false,
1920+
profile_server: bool = false,
1921+
create_ignore_system_default: bool = false,
1922+
};
1923+
18891924
pub fn CreateProcessW(
18901925
lpApplicationName: ?LPCWSTR,
18911926
lpCommandLine: ?LPWSTR,
18921927
lpProcessAttributes: ?*SECURITY_ATTRIBUTES,
18931928
lpThreadAttributes: ?*SECURITY_ATTRIBUTES,
18941929
bInheritHandles: BOOL,
1895-
dwCreationFlags: DWORD,
1930+
dwCreationFlags: CreateProcessFlags,
18961931
lpEnvironment: ?*anyopaque,
18971932
lpCurrentDirectory: ?LPCWSTR,
18981933
lpStartupInfo: *STARTUPINFOW,

lib/std/os/windows/kernel32.zig

+1-1
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ pub extern "kernel32" fn CreateProcessW(
314314
lpProcessAttributes: ?*SECURITY_ATTRIBUTES,
315315
lpThreadAttributes: ?*SECURITY_ATTRIBUTES,
316316
bInheritHandles: BOOL,
317-
dwCreationFlags: DWORD,
317+
dwCreationFlags: windows.CreateProcessFlags,
318318
lpEnvironment: ?LPVOID,
319319
lpCurrentDirectory: ?LPCWSTR,
320320
lpStartupInfo: *STARTUPINFOW,

lib/std/process/Child.zig

+18-6
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,13 @@ expand_arg0: Arg0Expand,
8080
/// Darwin-only. Disable ASLR for the child process.
8181
disable_aslr: bool = false,
8282

83-
/// Darwin-only. Start child process in suspended state as if SIGSTOP was sent.
83+
/// Darwin and Windows only. Start child process in suspended state. For Darwin it's started
84+
/// as if SIGSTOP was sent.
8485
start_suspended: bool = false,
8586

87+
/// Windows-only. Sets the CREATE_NO_WINDOW flag in CreateProcess.
88+
create_no_window: bool = false,
89+
8690
/// Set to true to obtain rusage information for the child process.
8791
/// Depending on the target platform and implementation status, the
8892
/// requested statistics may or may not be available. If they are
@@ -854,6 +858,12 @@ fn spawnWindows(self: *ChildProcess) SpawnError!void {
854858
const app_name_w = try unicode.wtf8ToWtf16LeAllocZ(self.allocator, app_basename_wtf8);
855859
defer self.allocator.free(app_name_w);
856860

861+
const flags: windows.CreateProcessFlags = .{
862+
.create_suspended = self.start_suspended,
863+
.create_unicode_environment = true,
864+
.create_no_window = self.create_no_window,
865+
};
866+
857867
run: {
858868
const PATH: [:0]const u16 = process.getenvW(unicode.utf8ToUtf16LeStringLiteral("PATH")) orelse &[_:0]u16{};
859869
const PATHEXT: [:0]const u16 = process.getenvW(unicode.utf8ToUtf16LeStringLiteral("PATHEXT")) orelse &[_:0]u16{};
@@ -889,7 +899,7 @@ fn spawnWindows(self: *ChildProcess) SpawnError!void {
889899
dir_buf.shrinkRetainingCapacity(normalized_len);
890900
}
891901

892-
windowsCreateProcessPathExt(self.allocator, &dir_buf, &app_buf, PATHEXT, &cmd_line_cache, envp_ptr, cwd_w_ptr, &siStartInfo, &piProcInfo) catch |no_path_err| {
902+
windowsCreateProcessPathExt(self.allocator, &dir_buf, &app_buf, PATHEXT, &cmd_line_cache, envp_ptr, cwd_w_ptr, flags, &siStartInfo, &piProcInfo) catch |no_path_err| {
893903
const original_err = switch (no_path_err) {
894904
// argv[0] contains unsupported characters that will never resolve to a valid exe.
895905
error.InvalidArg0 => return error.FileNotFound,
@@ -917,7 +927,7 @@ fn spawnWindows(self: *ChildProcess) SpawnError!void {
917927
const normalized_len = windows.normalizePath(u16, dir_buf.items) catch continue;
918928
dir_buf.shrinkRetainingCapacity(normalized_len);
919929

920-
if (windowsCreateProcessPathExt(self.allocator, &dir_buf, &app_buf, PATHEXT, &cmd_line_cache, envp_ptr, cwd_w_ptr, &siStartInfo, &piProcInfo)) {
930+
if (windowsCreateProcessPathExt(self.allocator, &dir_buf, &app_buf, PATHEXT, &cmd_line_cache, envp_ptr, cwd_w_ptr, flags, &siStartInfo, &piProcInfo)) {
921931
break :run;
922932
} else |err| switch (err) {
923933
// argv[0] contains unsupported characters that will never resolve to a valid exe.
@@ -1016,6 +1026,7 @@ fn windowsCreateProcessPathExt(
10161026
cmd_line_cache: *WindowsCommandLineCache,
10171027
envp_ptr: ?[*]u16,
10181028
cwd_ptr: ?[*:0]u16,
1029+
flags: windows.CreateProcessFlags,
10191030
lpStartupInfo: *windows.STARTUPINFOW,
10201031
lpProcessInformation: *windows.PROCESS_INFORMATION,
10211032
) !void {
@@ -1166,7 +1177,7 @@ fn windowsCreateProcessPathExt(
11661177
else
11671178
full_app_name;
11681179

1169-
if (windowsCreateProcess(app_name_w.ptr, cmd_line_w.ptr, envp_ptr, cwd_ptr, lpStartupInfo, lpProcessInformation)) |_| {
1180+
if (windowsCreateProcess(app_name_w.ptr, cmd_line_w.ptr, envp_ptr, cwd_ptr, flags, lpStartupInfo, lpProcessInformation)) |_| {
11701181
return;
11711182
} else |err| switch (err) {
11721183
error.FileNotFound,
@@ -1221,7 +1232,7 @@ fn windowsCreateProcessPathExt(
12211232
else
12221233
full_app_name;
12231234

1224-
if (windowsCreateProcess(app_name_w.ptr, cmd_line_w.ptr, envp_ptr, cwd_ptr, lpStartupInfo, lpProcessInformation)) |_| {
1235+
if (windowsCreateProcess(app_name_w.ptr, cmd_line_w.ptr, envp_ptr, cwd_ptr, flags, lpStartupInfo, lpProcessInformation)) |_| {
12251236
return;
12261237
} else |err| switch (err) {
12271238
error.FileNotFound => continue,
@@ -1247,6 +1258,7 @@ fn windowsCreateProcess(
12471258
cmd_line: [*:0]u16,
12481259
envp_ptr: ?[*]u16,
12491260
cwd_ptr: ?[*:0]u16,
1261+
flags: windows.CreateProcessFlags,
12501262
lpStartupInfo: *windows.STARTUPINFOW,
12511263
lpProcessInformation: *windows.PROCESS_INFORMATION,
12521264
) !void {
@@ -1273,7 +1285,7 @@ fn windowsCreateProcess(
12731285
null,
12741286
null,
12751287
windows.TRUE,
1276-
windows.CREATE_UNICODE_ENVIRONMENT,
1288+
flags,
12771289
@as(?*anyopaque, @ptrCast(envp_ptr)),
12781290
cwd_ptr,
12791291
lpStartupInfo,

0 commit comments

Comments
 (0)