发送升级消息
This commit is contained in:
@@ -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); // 始终打印通知详情
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user