From 6290826c4d6e6ca05a06cb4bdc4774dee1397c6a Mon Sep 17 00:00:00 2001 From: DecDuck Date: Sun, 21 Jun 2026 15:11:25 +1000 Subject: [PATCH] Implement tree kill for Windows --- .../src-tauri/process/src/process_manager.rs | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/desktop/src-tauri/process/src/process_manager.rs b/desktop/src-tauri/process/src/process_manager.rs index 05050039..e7389dec 100644 --- a/desktop/src-tauri/process/src/process_manager.rs +++ b/desktop/src-tauri/process/src/process_manager.rs @@ -125,7 +125,7 @@ impl ProcessManager<'_> { match self.processes.get_mut(&game_id) { Some(process) => { process.manually_killed = true; - process.handle.kill()?; + kill_process_tree(&process.handle)?; let exit_status = process.handle.wait()?; info!("exit status: {:?}", exit_status); Ok(()) @@ -593,6 +593,30 @@ impl ProcessManager<'_> { } } +fn kill_process_tree(handle: &SharedChild) -> io::Result<()> { + #[cfg(target_os = "windows")] + { + // handle.kill() only terminates the launched process (often a cmd or + // powershell wrapper), orphaning the actual game. taskkill /T kills the + // whole process tree. + use std::os::windows::process::CommandExt; + const CREATE_NO_WINDOW: u32 = 0x08000000; + let pid = handle.id().to_string(); + let killed = Command::new("taskkill") + .args(["/F", "/T", "/PID", pid.as_str()]) + .creation_flags(CREATE_NO_WINDOW) + .stdout(std::process::Stdio::null()) + .stderr(std::process::Stdio::null()) + .status() + .map(|status| status.success()) + .unwrap_or(false); + if killed { + return Ok(()); + } + } + handle.kill() +} + pub trait ProcessHandler: Send + 'static { fn create_launch_process( &self,