diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-07-12 03:00:59 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-07-12 03:01:45 +0300 |
| commit | 749e85e0fb5443488c5a96752afa7dd6cb040143 (patch) | |
| tree | 2b8e79e51d6cec4cc657b442b6df73b75f3523c3 /src/platform | |
| parent | e418e4a4f95c27654b21fc4fb3349629e58d3656 (diff) | |
fix: detach windows server from host terminal
refs #1329
Diffstat (limited to 'src/platform')
| -rw-r--r-- | src/platform/windows.rs | 60 |
1 files changed, 56 insertions, 4 deletions
diff --git a/src/platform/windows.rs b/src/platform/windows.rs index a44ebafd..209ec6d6 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -23,11 +23,13 @@ use windows_sys::{ TH32CS_SNAPPROCESS, }, }, + JobObjects::IsProcessInJob, Memory::{GlobalAlloc, GlobalLock, GlobalUnlock, GMEM_MOVEABLE}, Ole::CF_UNICODETEXT, Threading::{ - GetExitCodeProcess, OpenProcess, TerminateProcess, PROCESS_BASIC_INFORMATION, - PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_VM_READ, + GetCurrentProcess, GetExitCodeProcess, OpenProcess, TerminateProcess, + DETACHED_PROCESS, PROCESS_BASIC_INFORMATION, PROCESS_QUERY_LIMITED_INFORMATION, + PROCESS_VM_READ, }, }, UI::Shell::{CommandLineToArgvW, ShellExecuteW}, @@ -127,10 +129,19 @@ fn scrollback_editor_argv_with_env( Ok(argv) } -pub fn detach_server_daemon_command(_command: &mut std::process::Command) {} +pub fn detach_server_daemon_command(command: &mut std::process::Command) { + use std::os::windows::process::CommandExt; + + command.creation_flags(DETACHED_PROCESS); +} pub fn current_process_is_detached_server_daemon() -> bool { - false + if !unsafe { GetConsoleWindow() }.is_null() { + return false; + } + + let mut in_job = 0; + unsafe { IsProcessInJob(GetCurrentProcess(), null_mut(), &mut in_job) != 0 && in_job == 0 } } pub fn foreground_job(child_pid: u32) -> Option<ForegroundJob> { @@ -649,6 +660,47 @@ mod tests { time::{Duration, Instant}, }; + use windows_sys::Win32::System::Console::{AllocConsole, FreeConsole, GetConsoleWindow}; + + const DETACHED_CONSOLE_TEST_CHILD_ENV: &str = "HERDR_TEST_DETACHED_CONSOLE_CHILD"; + + #[test] + fn server_daemon_command_does_not_inherit_console() { + if std::env::var_os(DETACHED_CONSOLE_TEST_CHILD_ENV).is_some() { + assert!(unsafe { GetConsoleWindow() }.is_null()); + return; + } + + let allocated_console = if unsafe { GetConsoleWindow() }.is_null() { + assert_ne!(unsafe { AllocConsole() }, 0, "allocate test console"); + true + } else { + false + }; + + let test_exe = std::env::current_exe().expect("resolve test executable"); + let mut child = Command::new(test_exe); + child + .arg("server_daemon_command_does_not_inherit_console") + .env(DETACHED_CONSOLE_TEST_CHILD_ENV, "1") + .stdin(Stdio::null()) + .stdout(Stdio::null()) + .stderr(Stdio::null()); + super::detach_server_daemon_command(&mut child); + + let status = child.status().expect("spawn detached test child"); + if allocated_console { + unsafe { + FreeConsole(); + } + } + + assert!( + status.success(), + "detached child inherited the test console" + ); + } + fn argv_strings(argv: &[std::ffi::OsString]) -> Vec<String> { argv.into_iter() .map(|arg| arg.to_string_lossy().into_owned()) |
