Skip to main content

hatchery_node/
windows_process.rs

1//! Windows process-creation helpers for non-PTY children.
2//!
3//! PTY / ConPTY spawns must keep a console; everything else (ACP, app-server,
4//! m4a-agent, spawn profiles, probes) must not pop a visible window.
5
6/// `CREATE_NO_WINDOW` (0x08000000). Safe to OR with other creation flags.
7pub const CREATE_NO_WINDOW: u32 = 0x0800_0000;
8
9/// Apply [`CREATE_NO_WINDOW`] on Windows. No-op elsewhere. Does not touch
10/// program, args, env, cwd, or stdio. Call once: a second `creation_flags`
11/// replaces the previous value.
12pub fn hide_console(command: &mut std::process::Command) {
13    #[cfg(windows)]
14    {
15        use std::os::windows::process::CommandExt;
16        command.creation_flags(CREATE_NO_WINDOW);
17    }
18    #[cfg(not(windows))]
19    {
20        let _ = command;
21    }
22}
23
24/// Same for tokio's command (via `as_std_mut`).
25pub fn hide_console_tokio(command: &mut tokio::process::Command) {
26    #[cfg(windows)]
27    {
28        use std::os::windows::process::CommandExt;
29        command.as_std_mut().creation_flags(CREATE_NO_WINDOW);
30    }
31    #[cfg(not(windows))]
32    {
33        let _ = command;
34    }
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40
41    #[test]
42    fn hide_console_keeps_program_and_args() {
43        let mut c = std::process::Command::new("prog");
44        c.arg("a").arg("b");
45        hide_console(&mut c);
46        assert_eq!(c.get_program(), std::ffi::OsStr::new("prog"));
47        assert_eq!(c.get_args().collect::<Vec<_>>(), ["a", "b"]);
48    }
49
50    #[test]
51    fn create_no_window_constant() {
52        assert_eq!(CREATE_NO_WINDOW, 0x0800_0000);
53    }
54}