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.exe(fs::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::(&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_CONSOLE:Updater 获得独立的新终端窗口 /// - debug_mode = false → DETACHED_PROCESS:Updater 完全后台运行,无控制台 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(¤t_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)); } }