// 进程管理:启进程、关闭窗口、强杀 use std::path::Path; use windows_sys::Win32::Foundation::HWND; use windows_sys::Win32::System::Threading::{ OpenProcess, TerminateProcess, WaitForSingleObject, PROCESS_TERMINATE, PROCESS_VM_READ, }; use windows_sys::Win32::UI::WindowsAndMessaging::{ EnumWindows, GetWindowThreadProcessId, PostMessageW, WM_CLOSE, }; use std::cell::RefCell; thread_local! { static ENUM_RESULT: RefCell = RefCell::new(EnumResult { hwnd: std::ptr::null_mut(), pid: 0 }); } struct EnumResult { hwnd: HWND, pid: u32 } unsafe extern "system" fn enum_callback(hwnd: HWND, _lparam: isize) -> i32 { let mut proc_id: u32 = 0; GetWindowThreadProcessId(hwnd, &mut proc_id); ENUM_RESULT.with(|r| { *r.borrow_mut() = EnumResult { hwnd, pid: proc_id }; }); 1 // continue } /// 启动的子进程 pub struct Child { pub pid: u32, pub _handle: Option, } unsafe impl Send for Child {} unsafe impl Sync for Child {} /// 启动外部进程 pub fn spawn(exe: &Path, args: &str) -> anyhow::Result { let mut cmd = std::process::Command::new(exe); for arg in args.split_whitespace() { cmd.arg(arg.trim_matches('"')); } let child = cmd.spawn().map_err(|e| anyhow::anyhow!("启动 {:?} 失败:{}", exe, e))?; Ok(Child { pid: child.id(), _handle: Some(child) }) } /// 通过 PID 找到主窗口 HWND pub fn find_hwnd_by_pid(pid: u32) -> Option { unsafe { let _ = EnumWindows(Some(enum_callback), 0); } let r = ENUM_RESULT.with(|r| r.borrow().hwnd); let p = ENUM_RESULT.with(|r| r.borrow().pid); if p == pid && !r.is_null() { Some(r) } else { None } } /// 优雅关闭:PostMessage WM_CLOSE 给主窗口 → 等待 → taskkill pub fn close(child: &Child, cfg: &crate::config::ViewerSettings) -> anyhow::Result<()> { if let Some(hwnd) = find_hwnd_by_pid(child.pid) { unsafe { PostMessageW(hwnd, WM_CLOSE, 0, 0); } std::thread::sleep(std::time::Duration::from_millis(cfg.close_wait_ms)); } if is_running(child.pid) { kill(child.pid); } Ok(()) } /// 进程是否仍在运行 pub fn is_running(pid: u32) -> bool { unsafe { let h = OpenProcess(PROCESS_VM_READ, 0, pid); if h.is_null() { return false; } let r = WaitForSingleObject(h, 0); windows_sys::Win32::Foundation::CloseHandle(h); r != 0 } } /// 强杀 pub fn kill(pid: u32) { unsafe { let h = OpenProcess(PROCESS_TERMINATE, 0, pid); if !h.is_null() { TerminateProcess(h, 1); windows_sys::Win32::Foundation::CloseHandle(h); } let _ = std::process::Command::new("taskkill") .arg("/F").arg("/PID").arg(pid.to_string()).arg("/T") .output(); } }