Files
JoyD/Windows/CS/Framework4.0/BootLoader/src/main.rs
2026-04-07 13:02:22 +08:00

194 lines
6.7 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use std::fs;
use std::process::Command;
use std::thread::sleep;
use std::time::Duration;
fn main() {
// 检查是否已有多个 BootLoader 进程在运行
if is_process_running("BootLoader.exe") {
println!("Multiple BootLoader instances detected, exiting...");
return;
}
// 获取 BootLoader 启动目录所在盘的 AppData 目录
let appdata_dir = get_appdata_dir();
println!("AppData directory: {:?}", appdata_dir);
// 构建 Updater 相关文件路径
let updater_exe = appdata_dir.join("Updater.exe");
let updater_new_exe = appdata_dir.join("Updater.new.exe");
println!("Updater.exe path: {:?}", updater_exe);
println!("Updater.new.exe path: {:?}", updater_new_exe);
// 检查 Updater.new.exe 是否存在
if !updater_new_exe.exists() {
println!("Updater.new.exe does not exist, exiting...");
return;
}
// 等待 Updater 进程退出
println!("Waiting for Updater process to exit...");
if !wait_for_process_exit("Updater.exe") {
// 超时,退出 BootLoader
println!("BootLoader exiting due to timeout...");
return;
}
println!("Updater process exited");
// 直接覆盖 Updater.exefs::rename 在 Windows 上会自动替换已存在的文件)
println!("Renaming Updater.new.exe to Updater.exe...");
match fs::rename(&updater_new_exe, &updater_exe) {
Ok(_) => println!("Rename successful"),
Err(e) => println!("Rename failed: {:?}", e),
}
// 读取 Updater 的 debug_mode 配置,决定启动方式
let updater_debug_mode = load_updater_debug_mode(&appdata_dir);
println!("Updater debug_mode: {}", updater_debug_mode);
// 启动 Updater.exe
println!("Starting Updater.exe...");
let started = spawn_updater(&updater_exe, updater_debug_mode);
if started {
println!("Updater.exe started successfully");
// 等待一点时间,确保 Updater 有足够的时间启动
sleep(Duration::from_secs(1));
// 检查 Updater 进程是否仍在运行
if is_process_running("Updater.exe") {
println!("Updater.exe is running");
} else {
println!("Updater.exe may have exited immediately");
}
} else {
println!("Failed to start Updater.exe");
}
}
/// 读取 Updater 的配置文件,获取 debug_mode
fn load_updater_debug_mode(appdata_dir: &std::path::Path) -> bool {
let config_path = appdata_dir.join("Updater").join("config.json");
if let Ok(content) = fs::read_to_string(&config_path) {
if let Ok(json) = serde_json::from_str::<serde_json::Value>(&content) {
return json.get("debug_mode").and_then(|v| v.as_bool()).unwrap_or(false);
}
}
false
}
/// 根据 debug_mode 以不同方式启动 Updater.exe
/// - debug_mode = true → CREATE_NEW_CONSOLEUpdater 获得独立的新终端窗口
/// - debug_mode = false → DETACHED_PROCESSUpdater 完全后台运行,无控制台
fn spawn_updater(updater_exe: &std::path::Path, debug_mode: bool) -> bool {
use std::os::windows::process::CommandExt;
// Windows 进程创建标志
const CREATE_NEW_CONSOLE: u32 = 0x00000010;
const DETACHED_PROCESS: u32 = 0x00000008;
let creation_flags = if debug_mode {
CREATE_NEW_CONSOLE // 新建独立控制台窗口
} else {
DETACHED_PROCESS // 完全脱离控制台,后台静默运行
};
match Command::new(updater_exe)
.creation_flags(creation_flags)
.spawn()
{
Ok(child) => {
drop(child);
true
}
Err(e) => {
println!("Failed to start Updater.exe: {:?}", e);
false
}
}
}
fn is_process_running(process_name: &str) -> bool {
use std::process::id;
let current_pid = id().to_string();
let output = Command::new("tasklist")
.args(["/FI", &format!("IMAGENAME eq {}", process_name), "/FO", "CSV"])
.output()
.expect("Failed to execute tasklist");
let output_str = String::from_utf8_lossy(&output.stdout);
// 检查是否有其他同名进程
let lines: Vec<&str> = output_str.lines().collect();
let mut count = 0;
for line in lines {
if line.contains(&format!("\"{}\"", process_name)) && !line.contains(&current_pid) {
count += 1;
}
}
// 如果有其他同名进程,则返回 true
count > 0
}
fn get_appdata_dir() -> std::path::PathBuf {
let exe_path = std::env::current_exe().expect("Failed to get executable path");
println!("BootLoader executable path: {:?}", exe_path);
let drive = if let Some(parent) = exe_path.parent() {
println!("Parent directory: {:?}", parent);
let parent_str = parent.as_os_str().to_str().unwrap_or("C:/");
println!("Parent directory string: {:?}", parent_str);
let drive = parent_str.split('\\').next().unwrap_or("C:");
println!("Drive: {:?}", drive);
std::path::Path::new(&format!("{}/", drive)).to_path_buf()
} else {
std::path::Path::new("C:/").to_path_buf()
};
let appdata_dir = drive.join("AppData");
println!("Final AppData directory: {:?}", appdata_dir);
appdata_dir
}
fn wait_for_process_exit(process_name: &str) -> bool {
let mut attempts = 0;
let max_attempts = 300; // 30 seconds
loop {
// 使用 tasklist 命令检查进程是否存在,使用 CSV 格式以便更精确地匹配
let output = Command::new("tasklist")
.args(["/FI", &format!("IMAGENAME eq {}", process_name), "/FO", "CSV"])
.output()
.expect("Failed to execute tasklist");
let output_str = String::from_utf8_lossy(&output.stdout);
println!("Tasklist output for {}: {:?}", process_name, output_str);
// 检查是否有精确匹配的进程名
let mut process_found = false;
let lines: Vec<&str> = output_str.lines().collect();
for line in lines {
// 查找精确匹配的进程名
if line.contains(&format!("\"{}\"", process_name)) {
process_found = true;
break;
}
}
if !process_found {
println!("Process {} not found, continuing...", process_name);
return true; // 进程成功退出
}
attempts += 1;
if attempts > max_attempts {
println!("Timeout waiting for process {} to exit, exiting BootLoader...", process_name);
return false; // 超时,返回 false
}
// 等待 100 毫秒后再次检查
sleep(Duration::from_millis(100));
}
}