Skip to content

Commit 5e08314

Browse files
committed
Improve process termination logic with graceful shutdown attempt and delayed force-kill
1 parent 012a4e0 commit 5e08314

File tree

2 files changed

+62
-12
lines changed

2 files changed

+62
-12
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "wallpaper-controller"
3-
version = "0.2.0"
3+
version = "0.2.1"
44
edition = "2021"
55
description = "A utility to control Wallpaper Engine based on desktop visibility"
66

src/main.rs

Lines changed: 61 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use tracing_subscriber::util::SubscriberInitExt;
1818
use sentry::integrations::tracing::EventFilter;
1919
use sentry::ClientInitGuard;
2020
use windows::Win32::System::Console::AllocConsole;
21-
use windows::Win32::System::Console::AttachConsole;
21+
use windows::Win32::System::Console::{AttachConsole};
2222
use single_instance::SingleInstance;
2323
use windows_elevate::{check_elevated, elevate};
2424

@@ -202,34 +202,84 @@ fn kill_other_instances() -> Result<(), Box<dyn std::error::Error>> {
202202
}
203203

204204
let stdout = String::from_utf8_lossy(&output.stdout);
205-
let mut killed_any = false;
206205

206+
// Collect target PIDs (excluding self)
207+
let mut target_pids: Vec<u32> = Vec::new();
207208
for (i, line) in stdout.lines().enumerate() {
208209
if i == 0 { continue; } // skip header
209210
let trimmed = line.trim();
210211
if trimmed.is_empty() { continue; }
211212
// CSV fields quoted, expect: "Image Name","PID","Session Name","Session#","Mem Usage"
212-
// We'll split commas and trim surrounding quotes.
213213
let parts: Vec<String> = trimmed.split(',')
214214
.map(|s| s.trim().trim_matches('"').to_string())
215215
.collect();
216216
if parts.len() < 2 { continue; }
217-
let pid_str = &parts[1];
218-
if let Ok(pid) = pid_str.parse::<u32>() {
219-
if pid == this_pid {
220-
continue; // skip self
217+
if let Ok(pid) = parts[1].parse::<u32>() {
218+
if pid != this_pid { target_pids.push(pid); }
219+
}
220+
}
221+
222+
if target_pids.is_empty() {
223+
return Ok(());
224+
}
225+
226+
// First, try a graceful termination using taskkill without /F (no console tricks)
227+
for pid in &target_pids {
228+
let res = Command::new("taskkill")
229+
.args(["/PID", &pid.to_string()])
230+
.output();
231+
match res {
232+
Ok(out) => {
233+
if out.status.success() {
234+
info!("Requested graceful termination for PID {} ({})", pid, image_name);
235+
} else {
236+
let stderr = String::from_utf8_lossy(&out.stderr);
237+
warn!("Graceful taskkill failed for PID {}: {}", pid, stderr);
238+
}
221239
}
222-
// Attempt to kill this PID
240+
Err(e) => warn!("taskkill (graceful) failed for PID {}: {}", pid, e),
241+
}
242+
}
243+
244+
// Wait 2.5 seconds to allow graceful shutdown
245+
thread::sleep(Duration::from_millis(2500));
246+
247+
// Force-kill any remaining instances
248+
let output2 = Command::new("tasklist")
249+
.args(["/FI", &format!("IMAGENAME eq {}", image_name), "/FO", "CSV"])
250+
.output()?;
251+
252+
if !output2.status.success() {
253+
let stderr = String::from_utf8_lossy(&output2.stderr);
254+
warn!("tasklist failed while verifying remaining instances: {}", stderr);
255+
return Ok(());
256+
}
257+
258+
let stdout2 = String::from_utf8_lossy(&output2.stdout);
259+
let mut killed_any = false;
260+
261+
for (i, line) in stdout2.lines().enumerate() {
262+
if i == 0 { continue; }
263+
let trimmed = line.trim();
264+
if trimmed.is_empty() { continue; }
265+
let parts: Vec<String> = trimmed
266+
.split(',')
267+
.map(|s| s.trim().trim_matches('"').to_string())
268+
.collect();
269+
if parts.len() < 2 { continue; }
270+
if let Ok(pid) = parts[1].parse::<u32>() {
271+
if pid == this_pid { continue; }
272+
if !target_pids.contains(&pid) { continue; } // only those we targeted
273+
223274
let kill = Command::new("taskkill").args(["/PID", &pid.to_string(), "/F"]).output();
224275
match kill {
225276
Ok(res) => {
226277
if res.status.success() {
227-
info!("Terminated process PID {} ({})", pid, image_name);
278+
info!("Force terminated process PID {} ({})", pid, image_name);
228279
killed_any = true;
229280
} else {
230281
let stderr = String::from_utf8_lossy(&res.stderr);
231-
// If the process exited between list and kill, ignore the error.
232-
warn!("Failed to terminate PID {}: {}", pid, stderr);
282+
warn!("Failed to force terminate PID {}: {}", pid, stderr);
233283
}
234284
}
235285
Err(e) => warn!("taskkill failed for PID {}: {}", pid, e),

0 commit comments

Comments
 (0)