发送升级消息

This commit is contained in:
zqm
2026-04-13 09:35:43 +08:00
parent 1c385306cb
commit 6e58857074

View File

@@ -237,7 +237,7 @@ fn start_named_pipe_server(
use windows::Win32::Storage::FileSystem::PIPE_ACCESS_DUPLEX;
use windows::Win32::System::Pipes::{
ConnectNamedPipe, CreateNamedPipeW, DisconnectNamedPipe,
PIPE_READMODE_MESSAGE, PIPE_TYPE_MESSAGE, PIPE_WAIT,
PIPE_READMODE_BYTE, PIPE_TYPE_BYTE, PIPE_WAIT,
};
use windows::core::PCWSTR;
@@ -246,7 +246,7 @@ fn start_named_pipe_server(
CreateNamedPipeW(
PCWSTR::from_raw(name.as_ptr()),
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
1, // nMaxInstances
65536, // nOutBufferSize
65536, // nInBufferSize
@@ -1383,14 +1383,14 @@ fn send_get_all_file(
// ===================== 向应用发送升级确认 =====================
/// 向指定应用发送升级确认消息
/// 向指定应用发送升级确认消息(修复版:直接用 Win32 API 连接管道,不再用 PowerShell
/// 消息格式:{"Type":"UpgradeConfirm","Data":{"AppName":"xxx","CurrentVer":"1.0.0","LatestVer":"1.1.0"}}
fn notify_app_upgrade(app_name: &str, current_ver: &str, latest_ver: &str, debug: bool) {
fn notify_app_upgrade(app_name: &str, current_ver: &str, latest_ver: &str, _debug: bool) {
#[cfg(windows)]
{
use std::process::Command;
// 查找运行中的进程,获取 PID(使用 PowerShell Get-Process 更可靠)
// 1. 获取所有运行中的进程 PID
let ps_script = format!(
"(Get-Process -Name '{}' -ErrorAction SilentlyContinue).Id",
app_name
@@ -1399,75 +1399,40 @@ fn notify_app_upgrade(app_name: &str, current_ver: &str, latest_ver: &str, debug
.args(["-NoProfile", "-NonInteractive", "-Command", &ps_script])
.output();
let output_bytes = match output {
Ok(o) => o.stdout,
let pids: Vec<u32> = match output {
Ok(o) => {
let s = String::from_utf8_lossy(&o.stdout);
s.lines().filter_map(|l| l.trim().parse().ok()).collect()
}
Err(_) => return,
};
let output_str = String::from_utf8_lossy(&output_bytes);
// 解析 PID 列表(每行一个 PID
let mut pids: Vec<u32> = Vec::new();
for line in output_str.lines() {
let line = line.trim();
if !line.is_empty() && line != "0" {
if let Ok(pid) = line.parse::<u32>() {
// 排除 Updater 自己
let current_pid = std::process::id();
if pid != current_pid {
pids.push(pid);
}
}
}
}
if pids.is_empty() {
if debug {
let ts = chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.3f");
log_print!("{} [升级确认] {} 未运行,跳过通知", ts, app_name);
}
let ts = chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.3f");
log_print!("{} [升级确认] {} 未运行,跳过通知", ts, app_name);
return;
}
// 向每个运行中的进程发送升级确认
// 管道名称格式EasyTest_{pid}(与 EasyTest 启动的命名管道一致)
// 2. 构造消息
let msg = format!(
r#"{{"Type":"UpgradeConfirm","Data":{{"AppName":"{}","CurrentVer":"{}","LatestVer":"{}"}}}}"#,
app_name, current_ver, latest_ver
);
// 3. 对每个 PID 直接用 Win32 命名管道发送(不再用 PowerShell
for pid in pids {
let pipe_name = format!("\\\\.\\pipe\\EasyTest_{}", pid);
let msg = format!(
r#"{{"Type":"UpgradeConfirm","Data":{{"AppName":"{}","CurrentVer":"{}","LatestVer":"{}"}}}}"#,
app_name, current_ver, latest_ver
);
// 使用 PowerShell 连接命名管道并发送消息
let pipe_server = pipe_name.replace("\\\\.\\pipe\\", "");
let ps_script = format!(
r#"
$pipe = [System.IO.Pipes.NamedPipeClientStream]::new(".", "{}", [System.IO.Pipes.PipeDirection]::InOut)
try {{
$pipe.Connect(3000)
$writer = [System.IO.StreamWriter]::new($pipe)
$writer.AutoFlush = $true
$writer.WriteLine("{}")
$pipe.WaitForPipeDrain()
}} catch {{
Write-Error $_.Exception.Message
}} finally {{
$pipe.Close()
}}
"#,
pipe_server,
msg
);
let result = Command::new("powershell")
.args(["-NoProfile", "-NonInteractive", "-Command", &ps_script])
.output();
let ts = chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.3f");
if result.is_ok() {
log_print!("{} [升级确认] 连接到 {} (PID={})", ts, pipe_name, pid);
// 直接用 windows-rs Win32 API 连接命名管道
let pipe_result = connect_named_pipe_byte(&pipe_name, &msg);
if pipe_result {
log_print!("{} [升级确认] 已通知 {} (PID={}): {} -> {}",
ts, app_name, pid, current_ver, latest_ver);
} else {
log_print!("{} [升级确认] 通知 {} (PID={}) 失败", ts, app_name, pid);
log_print!("{} [升级确认] 连接 {} (PID={}) 失败", ts, app_name, pid);
}
}
}
@@ -1479,22 +1444,82 @@ fn notify_app_upgrade(app_name: &str, current_ver: &str, latest_ver: &str, debug
}
}
/// 用 Win32 API 连接命名管道并发送字节数据(字节模式)
fn connect_named_pipe_byte(pipe_name: &str, msg: &str) -> bool {
use windows::Win32::Foundation::{CloseHandle, INVALID_HANDLE_VALUE};
use windows::Win32::Storage::FileSystem::{CreateFileW, WriteFile, FILE_ATTRIBUTE_NORMAL};
use windows::core::PCWSTR;
// Windows API 常量(跨版本稳定)
use windows::Win32::Storage::FileSystem::{FILE_SHARE_MODE, FILE_CREATION_DISPOSITION};
const GENERIC_WRITE: u32 = 0x40000000u32;
const FILE_SHARE_NONE: u32 = 0u32;
const OPEN_EXISTING: u32 = 3u32;
// 将管道名转换为宽字符串
let wide_name: Vec<u16> = pipe_name.encode_utf16().chain(std::iter::once(0)).collect();
// 用 CreateFileW 打开命名管道(写模式,字节模式)
let pipe = unsafe {
CreateFileW(
PCWSTR::from_raw(wide_name.as_ptr()),
GENERIC_WRITE,
FILE_SHARE_MODE(FILE_SHARE_NONE),
None,
FILE_CREATION_DISPOSITION(OPEN_EXISTING),
FILE_ATTRIBUTE_NORMAL,
None,
)
};
// CreateFileW 返回 Result需要 unwrap
let pipe = match pipe {
Ok(h) => h,
Err(e) => {
eprintln!("[Pipe] CreateFileW failed: {:?}", e);
return false;
}
};
// 检查是否成功打开
if pipe == INVALID_HANDLE_VALUE {
return false;
}
// 写入消息 + 换行C# 端用 StreamReader.ReadLine 读取)
let mut msg_with_newline = msg.to_string();
msg_with_newline.push_str("\r\n");
let data = msg_with_newline.as_bytes();
let mut written: u32 = 0;
let success = unsafe {
WriteFile(
pipe,
Some(data),
Some(&mut written),
None,
)
};
let _ = unsafe { CloseHandle(pipe) };
success.is_ok() && written > 0
}
/// 通知所有升级了的应用EasyTest 等)
/// app_upgrades: Vec<(app_name, current_ver, latest_ver)>
fn notify_all_app_upgrades(app_upgrades: &[(String, String, String)], debug: bool) {
fn notify_all_app_upgrades(app_upgrades: &[(String, String, String)], _debug: bool) {
let ts = chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.3f");
if app_upgrades.is_empty() {
if debug {
log_print!("{} [升级确认] 没有应用需要升级通知", ts);
}
log_print!("{} [升级确认] 没有应用需要升级通知upgraded_apps 为空)", ts);
return;
}
log_print!("{} [升级确认] 准备通知 {} 个应用", ts, app_upgrades.len());
log_print!("{} [升级确认] 准备通知 {} 个应用: {:?}", ts, app_upgrades.len(), app_upgrades);
for (app_name, current_ver, latest_ver) in app_upgrades {
notify_app_upgrade(app_name, current_ver, latest_ver, debug);
notify_app_upgrade(app_name, current_ver, latest_ver, true); // 始终打印通知详情
}
}