aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-07-12 03:00:59 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-07-12 03:01:45 +0300
commit749e85e0fb5443488c5a96752afa7dd6cb040143 (patch)
tree2b8e79e51d6cec4cc657b442b6df73b75f3523c3 /src
parente418e4a4f95c27654b21fc4fb3349629e58d3656 (diff)
fix: detach windows server from host terminal
refs #1329
Diffstat (limited to 'src')
-rw-r--r--src/platform/windows.rs60
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())