95 lines
2.9 KiB
Rust
95 lines
2.9 KiB
Rust
|
|
// 进程管理:启进程、关闭窗口、强杀
|
|||
|
|
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<EnumResult> = 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<std::process::Child>,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
unsafe impl Send for Child {}
|
|||
|
|
unsafe impl Sync for Child {}
|
|||
|
|
|
|||
|
|
/// 启动外部进程
|
|||
|
|
pub fn spawn(exe: &Path, args: &str) -> anyhow::Result<Child> {
|
|||
|
|
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<HWND> {
|
|||
|
|
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();
|
|||
|
|
}
|
|||
|
|
}
|