mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-01-29 00:35:38 +08:00
refactor: replace shell command check with WinAPI call
This commit is contained in:
@@ -94,6 +94,8 @@ winapi = { version = "0.3.9", features = [
|
|||||||
"errhandlingapi",
|
"errhandlingapi",
|
||||||
"minwindef",
|
"minwindef",
|
||||||
"winerror",
|
"winerror",
|
||||||
|
"tlhelp32",
|
||||||
|
"processthreadsapi",
|
||||||
] }
|
] }
|
||||||
|
|
||||||
[target.'cfg(target_os = "linux")'.dependencies]
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
|
|||||||
@@ -514,70 +514,102 @@ impl CoreManager {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 根据进程名查找进程PID列表
|
/// 根据进程名查找进程PID列
|
||||||
async fn find_processes_by_name(
|
async fn find_processes_by_name(
|
||||||
&self,
|
&self,
|
||||||
process_name: String,
|
process_name: String,
|
||||||
_target: &str,
|
_target: &str,
|
||||||
) -> Result<(Vec<u32>, String)> {
|
) -> Result<(Vec<u32>, String)> {
|
||||||
let output = if cfg!(windows) {
|
#[cfg(windows)]
|
||||||
tokio::process::Command::new("tasklist")
|
{
|
||||||
.args([
|
use std::mem;
|
||||||
"/FI",
|
use winapi::um::handleapi::CloseHandle;
|
||||||
&format!("IMAGENAME eq {}", process_name),
|
use winapi::um::tlhelp32::{
|
||||||
"/FO",
|
CreateToolhelp32Snapshot, Process32FirstW, Process32NextW, PROCESSENTRY32W,
|
||||||
"CSV",
|
TH32CS_SNAPPROCESS,
|
||||||
"/NH",
|
};
|
||||||
])
|
use winapi::um::winnt::HANDLE;
|
||||||
.output()
|
|
||||||
.await?
|
|
||||||
} else if cfg!(target_os = "macos") {
|
|
||||||
tokio::process::Command::new("pgrep")
|
|
||||||
.arg(&process_name)
|
|
||||||
.output()
|
|
||||||
.await?
|
|
||||||
} else {
|
|
||||||
// Linux
|
|
||||||
tokio::process::Command::new("pidof")
|
|
||||||
.arg(&process_name)
|
|
||||||
.output()
|
|
||||||
.await?
|
|
||||||
};
|
|
||||||
|
|
||||||
if !output.status.success() {
|
let process_name_clone = process_name.clone();
|
||||||
return Ok((Vec::new(), process_name));
|
let pids = tokio::task::spawn_blocking(move || -> Result<Vec<u32>> {
|
||||||
}
|
let mut pids = Vec::new();
|
||||||
|
|
||||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
unsafe {
|
||||||
let mut pids = Vec::new();
|
// 创建进程快照
|
||||||
|
let snapshot: HANDLE = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||||
|
if snapshot == winapi::um::handleapi::INVALID_HANDLE_VALUE {
|
||||||
|
return Err(anyhow::anyhow!("Failed to create process snapshot"));
|
||||||
|
}
|
||||||
|
|
||||||
if cfg!(windows) {
|
let mut pe32: PROCESSENTRY32W = mem::zeroed();
|
||||||
// 解析CSV格式输出: "进程名","PID","会话名","会话#","内存使用"
|
pe32.dwSize = mem::size_of::<PROCESSENTRY32W>() as u32;
|
||||||
for line in stdout.lines() {
|
|
||||||
if !line.is_empty() && line.contains(&process_name) {
|
// 获取第一个进程
|
||||||
let fields: Vec<&str> = line.split(',').collect();
|
if Process32FirstW(snapshot, &mut pe32) != 0 {
|
||||||
if fields.len() >= 2 {
|
loop {
|
||||||
// 移除引号并解析PID
|
// 将宽字符转换为String
|
||||||
let pid_str = fields[1].trim_matches('"');
|
let end_pos = pe32
|
||||||
if let Ok(pid) = pid_str.parse::<u32>() {
|
.szExeFile
|
||||||
pids.push(pid);
|
.iter()
|
||||||
|
.position(|&x| x == 0)
|
||||||
|
.unwrap_or(pe32.szExeFile.len());
|
||||||
|
let exe_file = String::from_utf16_lossy(&pe32.szExeFile[..end_pos]);
|
||||||
|
|
||||||
|
// 检查进程名是否匹配
|
||||||
|
if exe_file.eq_ignore_ascii_case(&process_name_clone) {
|
||||||
|
pids.push(pe32.th32ProcessID);
|
||||||
|
}
|
||||||
|
if Process32NextW(snapshot, &mut pe32) == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 关闭句柄
|
||||||
|
CloseHandle(snapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(pids)
|
||||||
|
})
|
||||||
|
.await??;
|
||||||
|
|
||||||
|
Ok((pids, process_name))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
{
|
||||||
|
let output = if cfg!(target_os = "macos") {
|
||||||
|
tokio::process::Command::new("pgrep")
|
||||||
|
.arg(&process_name)
|
||||||
|
.output()
|
||||||
|
.await?
|
||||||
|
} else {
|
||||||
|
// Linux
|
||||||
|
tokio::process::Command::new("pidof")
|
||||||
|
.arg(&process_name)
|
||||||
|
.output()
|
||||||
|
.await?
|
||||||
|
};
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
return Ok((Vec::new(), process_name));
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||||
|
let mut pids = Vec::new();
|
||||||
|
|
||||||
// Unix系统直接解析PID列表
|
// Unix系统直接解析PID列表
|
||||||
for pid_str in stdout.split_whitespace() {
|
for pid_str in stdout.split_whitespace() {
|
||||||
if let Ok(pid) = pid_str.parse::<u32>() {
|
if let Ok(pid) = pid_str.parse::<u32>() {
|
||||||
pids.push(pid);
|
pids.push(pid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Ok((pids, process_name))
|
Ok((pids, process_name))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 终止进程并验证结果
|
/// 终止进程并验证结果 - 使用Windows API直接终止,更优雅高效
|
||||||
async fn kill_process_with_verification(&self, pid: u32, process_name: String) -> bool {
|
async fn kill_process_with_verification(&self, pid: u32, process_name: String) -> bool {
|
||||||
logging!(
|
logging!(
|
||||||
info,
|
info,
|
||||||
@@ -588,14 +620,30 @@ impl CoreManager {
|
|||||||
pid
|
pid
|
||||||
);
|
);
|
||||||
|
|
||||||
let success = if cfg!(windows) {
|
#[cfg(windows)]
|
||||||
tokio::process::Command::new("taskkill")
|
let success = {
|
||||||
.args(["/F", "/PID", &pid.to_string()])
|
use winapi::um::handleapi::CloseHandle;
|
||||||
.output()
|
use winapi::um::processthreadsapi::{OpenProcess, TerminateProcess};
|
||||||
.await
|
use winapi::um::winnt::{HANDLE, PROCESS_TERMINATE};
|
||||||
.map(|output| output.status.success())
|
|
||||||
.unwrap_or(false)
|
tokio::task::spawn_blocking(move || -> bool {
|
||||||
} else {
|
unsafe {
|
||||||
|
let process_handle: HANDLE = OpenProcess(PROCESS_TERMINATE, 0, pid);
|
||||||
|
if process_handle.is_null() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let result = TerminateProcess(process_handle, 1);
|
||||||
|
CloseHandle(process_handle);
|
||||||
|
|
||||||
|
result != 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap_or(false)
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
let success = {
|
||||||
tokio::process::Command::new("kill")
|
tokio::process::Command::new("kill")
|
||||||
.args(["-9", &pid.to_string()])
|
.args(["-9", &pid.to_string()])
|
||||||
.output()
|
.output()
|
||||||
@@ -643,34 +691,49 @@ impl CoreManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 检查进程是否仍在运行
|
/// Windows API检查进程
|
||||||
async fn is_process_running(&self, pid: u32) -> Result<bool> {
|
async fn is_process_running(&self, pid: u32) -> Result<bool> {
|
||||||
let output = if cfg!(windows) {
|
#[cfg(windows)]
|
||||||
tokio::process::Command::new("tasklist")
|
{
|
||||||
.args(["/FI", &format!("PID eq {}", pid), "/FO", "CSV", "/NH"])
|
use winapi::shared::minwindef::DWORD;
|
||||||
.output()
|
use winapi::um::handleapi::CloseHandle;
|
||||||
.await?
|
use winapi::um::processthreadsapi::GetExitCodeProcess;
|
||||||
} else {
|
use winapi::um::processthreadsapi::OpenProcess;
|
||||||
tokio::process::Command::new("ps")
|
use winapi::um::winnt::{HANDLE, PROCESS_QUERY_INFORMATION};
|
||||||
|
|
||||||
|
let result = tokio::task::spawn_blocking(move || -> Result<bool> {
|
||||||
|
unsafe {
|
||||||
|
let process_handle: HANDLE = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid);
|
||||||
|
if process_handle.is_null() {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
let mut exit_code: DWORD = 0;
|
||||||
|
let result = GetExitCodeProcess(process_handle, &mut exit_code);
|
||||||
|
CloseHandle(process_handle);
|
||||||
|
|
||||||
|
if result == 0 {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
Ok(exit_code == 259)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
{
|
||||||
|
let output = tokio::process::Command::new("ps")
|
||||||
.args(["-p", &pid.to_string()])
|
.args(["-p", &pid.to_string()])
|
||||||
.output()
|
.output()
|
||||||
.await?
|
.await?;
|
||||||
};
|
|
||||||
|
|
||||||
Ok(output.status.success() && !output.stdout.is_empty())
|
Ok(output.status.success() && !output.stdout.is_empty())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn start_core_by_sidecar(&self) -> Result<()> {
|
async fn start_core_by_sidecar(&self) -> Result<()> {
|
||||||
if let Err(e) = self.cleanup_orphaned_mihomo_processes().await {
|
|
||||||
logging!(
|
|
||||||
warn,
|
|
||||||
Type::Core,
|
|
||||||
true,
|
|
||||||
"清理多余 mihomo 进程时发生错误: {}",
|
|
||||||
e
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
logging!(trace, Type::Core, true, "Running core by sidecar");
|
logging!(trace, Type::Core, true, "Running core by sidecar");
|
||||||
let config_file = &Config::generate_file(ConfigType::Run)?;
|
let config_file = &Config::generate_file(ConfigType::Run)?;
|
||||||
let app_handle = handle::Handle::global()
|
let app_handle = handle::Handle::global()
|
||||||
@@ -1033,17 +1096,6 @@ impl CoreManager {
|
|||||||
pub async fn restart_core(&self) -> Result<()> {
|
pub async fn restart_core(&self) -> Result<()> {
|
||||||
self.stop_core().await?;
|
self.stop_core().await?;
|
||||||
|
|
||||||
// 在重启时也清理多余的 mihomo 进程
|
|
||||||
if let Err(e) = self.cleanup_orphaned_mihomo_processes().await {
|
|
||||||
logging!(
|
|
||||||
warn,
|
|
||||||
Type::Core,
|
|
||||||
true,
|
|
||||||
"重启时清理多余 mihomo 进程失败: {}",
|
|
||||||
e
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.start_core().await?;
|
self.start_core().await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user