using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Management; using System.Threading.Tasks; using System.Text.RegularExpressions; using System.Net.Http; using System.Text.Json; using System.Text; using System.Timers; namespace VHDMounter { public class VHDManager : IDisposable { private const string TARGET_DRIVE = "M:"; private readonly string[] TARGET_KEYWORDS = { "SDEZ", "SDHD", "SDDT" }; private readonly string[] PROCESS_KEYWORDS = { "sinmai", "chusanapp", "mu3" }; public event Action StatusChanged; private static readonly HttpClient httpClient = new HttpClient(); private string configFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "vhdmonter_config.ini"); // 保护检查相关字段 private Timer protectionTimer; private string machineId; private bool isProtectionCheckEnabled; private string protectionCheckUrl; private int protectionCheckInterval; // 构造函数 public VHDManager() { InitializeProtectionCheck(); } // 初始化保护检查功能 private void InitializeProtectionCheck() { try { var config = ReadConfig(); // 读取Machine ID machineId = config.TryGetValue("MachineId", out var id) ? id : "MACHINE_001"; // 读取保护检查配置 isProtectionCheckEnabled = config.TryGetValue("EnableProtectionCheck", out var enableCheck) && bool.TryParse(enableCheck, out var enabled) && enabled; protectionCheckUrl = config.TryGetValue("ProtectionCheckUrl", out var url) ? url : "http://localhost:8080/api/protect"; protectionCheckInterval = config.TryGetValue("ProtectionCheckInterval", out var interval) && int.TryParse(interval, out var intervalMs) ? intervalMs : 500; if (isProtectionCheckEnabled) { StartProtectionCheck(); StatusChanged?.Invoke($"保护检查已启用 - Machine ID: {machineId}, 检查间隔: {protectionCheckInterval}ms"); } else { StatusChanged?.Invoke("保护检查功能已禁用"); } } catch (Exception ex) { StatusChanged?.Invoke($"初始化保护检查失败: {ex.Message}"); } } // 启动保护检查定时器 private void StartProtectionCheck() { if (protectionTimer != null) { protectionTimer.Stop(); protectionTimer.Dispose(); } protectionTimer = new Timer(protectionCheckInterval); protectionTimer.Elapsed += async (sender, e) => await CheckProtectionStatus(); protectionTimer.AutoReset = true; protectionTimer.Start(); } // 检查保护状态 private async Task CheckProtectionStatus() { try { if (!isProtectionCheckEnabled || string.IsNullOrWhiteSpace(protectionCheckUrl)) return; var requestUrl = $"{protectionCheckUrl}?machineId={Uri.EscapeDataString(machineId)}"; var response = await httpClient.GetAsync(requestUrl); if (response.IsSuccessStatusCode) { var jsonContent = await response.Content.ReadAsStringAsync(); var jsonDoc = JsonDocument.Parse(jsonContent); if (jsonDoc.RootElement.TryGetProperty("protected", out var protectedElement) && protectedElement.GetBoolean()) { StatusChanged?.Invoke($"收到保护信号 - Machine ID: {machineId},正在执行自动关机..."); await ExecuteShutdown(); } } } catch (Exception ex) { Debug.WriteLine($"保护状态检查失败: {ex.Message}"); } } // 执行自动关机 private async Task ExecuteShutdown() { try { StatusChanged?.Invoke("正在执行自动关机..."); // 停止保护检查定时器 if (protectionTimer != null) { protectionTimer.Stop(); protectionTimer.Dispose(); protectionTimer = null; } // 执行关机命令 var process = new Process { StartInfo = new ProcessStartInfo { FileName = "shutdown", Arguments = "/s /t 0", UseShellExecute = false, CreateNoWindow = true } }; process.Start(); await process.WaitForExitAsync(); } catch (Exception ex) { StatusChanged?.Invoke($"自动关机执行失败: {ex.Message}"); } } // 停止保护检查 public void StopProtectionCheck() { if (protectionTimer != null) { protectionTimer.Stop(); protectionTimer.Dispose(); protectionTimer = null; } } // 调试方法:检查特定文件是否符合条件 public bool IsVHDFileValid(string filePath) { try { if (!File.Exists(filePath)) { Debug.WriteLine($"文件不存在: {filePath}"); return false; } var fileName = Path.GetFileName(filePath).ToUpper(); var isValid = TARGET_KEYWORDS.Any(keyword => fileName.Contains(keyword)); Debug.WriteLine($"检查文件: {filePath}"); Debug.WriteLine($"文件名: {fileName}"); Debug.WriteLine($"是否包含关键词: {isValid}"); Debug.WriteLine($"关键词: {string.Join(", ", TARGET_KEYWORDS)}"); return isValid; } catch (Exception ex) { Debug.WriteLine($"检查文件时出错: {ex.Message}"); return false; } } // 检查是否存在卷标为NX_INS的USB设备 public DriveInfo FindNXInsUSBDrive() { try { var usbDrives = DriveInfo.GetDrives().Where(d => d.IsReady && d.DriveType == DriveType.Removable); foreach (var drive in usbDrives) { try { if (drive.VolumeLabel == "NX_INS") { StatusChanged?.Invoke($"找到NX_INS USB设备: {drive.Name}"); return drive; } } catch (Exception ex) { Debug.WriteLine($"读取驱动器 {drive.Name} 卷标时出错: {ex.Message}"); } } return null; } catch (Exception ex) { Debug.WriteLine($"查找NX_INS USB设备时出错: {ex.Message}"); return null; } } // 从USB设备中扫描VHD文件 public List ScanUSBForVHDFiles(DriveInfo usbDrive) { StatusChanged?.Invoke($"正在扫描USB设备 {usbDrive.Name} 中的VHD文件..."); var vhdFiles = new List(); try { var rootFiles = Directory.GetFiles(usbDrive.RootDirectory.FullName, "*.vhd", SearchOption.TopDirectoryOnly) .Where(f => TARGET_KEYWORDS.Any(keyword => Path.GetFileName(f).ToUpper().Contains(keyword))) .ToList(); vhdFiles.AddRange(rootFiles); StatusChanged?.Invoke($"在USB设备中找到 {vhdFiles.Count} 个VHD文件"); foreach (var file in vhdFiles) { Debug.WriteLine($"USB中找到VHD文件: {file}"); } } catch (Exception ex) { Debug.WriteLine($"扫描USB设备 {usbDrive.Name} 时出错: {ex.Message}"); StatusChanged?.Invoke($"扫描USB设备时出错: {ex.Message}"); } return vhdFiles; } // 替换本地VHD文件 public async Task ReplaceLocalVHDFiles(List usbVhdFiles, List localVhdFiles) { if (usbVhdFiles.Count == 0 || localVhdFiles.Count == 0) return false; // Win11兼容性诊断 DiagnoseWin11Issues(); bool anyReplaced = false; StatusChanged?.Invoke("正在替换本地VHD文件..."); foreach (var usbFile in usbVhdFiles) { string usbFileName = Path.GetFileName(usbFile); string usbKeyword = ExtractKeyword(usbFileName); if (string.IsNullOrEmpty(usbKeyword)) continue; // 查找对应关键词的本地文件 var matchingLocalFiles = localVhdFiles.Where(f => ExtractKeyword(Path.GetFileName(f)) == usbKeyword).ToList(); if (matchingLocalFiles.Count > 0) { foreach (var localFile in matchingLocalFiles) { try { // Win11兼容性检查和准备 StatusChanged?.Invoke($"检查Win11兼容性: {Path.GetFileName(localFile)}"); var localFileInfo = new FileInfo(localFile); var usbFileInfo = new FileInfo(usbFile); // 记录文件属性用于诊断 Debug.WriteLine($"本地文件属性: {localFileInfo.Attributes}, 只读: {localFileInfo.IsReadOnly}"); Debug.WriteLine($"USB文件属性: {usbFileInfo.Attributes}, 大小: {usbFileInfo.Length} bytes"); Debug.WriteLine($"操作系统版本: {Environment.OSVersion}"); // 检查文件是否被占用 if (IsFileInUse(localFile)) { StatusChanged?.Invoke($"文件被占用,无法删除: {Path.GetFileName(localFile)}"); Debug.WriteLine($"文件被占用: {localFile}"); continue; } // Win11兼容性处理 if (!PrepareFileForReplacement(localFile)) { StatusChanged?.Invoke($"无法准备文件进行替换: {Path.GetFileName(localFile)}"); continue; } // 直接删除本地文件 StatusChanged?.Invoke($"正在删除本地文件: {Path.GetFileName(localFile)}"); if (File.Exists(localFile)) File.Delete(localFile); // 等待文件系统完成删除操作 int retryCount = 0; while (File.Exists(localFile) && retryCount < 10) { await Task.Delay(100); retryCount++; } if (File.Exists(localFile)) { StatusChanged?.Invoke($"删除文件失败,文件仍然存在: {Path.GetFileName(localFile)}"); continue; } // 复制USB文件到本地 StatusChanged?.Invoke($"正在用 {Path.GetFileName(usbFile)} 替换 {Path.GetFileName(localFile)}"); File.Copy(usbFile, localFile); // 验证复制结果 var newFileInfo = new FileInfo(localFile); if (newFileInfo.Length != usbFileInfo.Length) { StatusChanged?.Invoke($"警告: 文件大小不匹配 - 原始: {usbFileInfo.Length}, 复制后: {newFileInfo.Length}"); } anyReplaced = true; StatusChanged?.Invoke($"替换完成: {Path.GetFileName(localFile)}"); } catch (UnauthorizedAccessException ex) { StatusChanged?.Invoke($"权限不足,无法替换文件: {Path.GetFileName(localFile)} - {ex.Message}"); Debug.WriteLine($"权限错误: {ex}"); } catch (IOException ex) { StatusChanged?.Invoke($"文件IO错误: {Path.GetFileName(localFile)} - {ex.Message}"); Debug.WriteLine($"IO错误: {ex}"); } catch (Exception ex) { StatusChanged?.Invoke($"替换文件时出错: {Path.GetFileName(localFile)} - {ex.Message}"); Debug.WriteLine($"替换文件时出错: {ex}"); } } } } return anyReplaced; } // 提取VHD文件名中的关键词部分 private string ExtractKeyword(string fileName) { foreach (var keyword in TARGET_KEYWORDS) { if (fileName.ToUpper().Contains(keyword)) return keyword; } return string.Empty; } // 检查文件是否被占用 private bool IsFileInUse(string filePath) { try { using (FileStream stream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None)) { return false; } } catch (IOException) { return true; } catch (UnauthorizedAccessException) { return true; } } // Win11兼容性检查和修复 private bool PrepareFileForReplacement(string filePath) { try { var fileInfo = new FileInfo(filePath); // 检查文件是否存在 if (!fileInfo.Exists) return true; // 移除只读属性 if (fileInfo.IsReadOnly) { StatusChanged?.Invoke($"移除只读属性: {fileInfo.Name}"); fileInfo.IsReadOnly = false; } // 移除隐藏和系统属性(Win11可能设置这些属性) if ((fileInfo.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden) { StatusChanged?.Invoke($"移除隐藏属性: {fileInfo.Name}"); fileInfo.Attributes &= ~FileAttributes.Hidden; } if ((fileInfo.Attributes & FileAttributes.System) == FileAttributes.System) { StatusChanged?.Invoke($"移除系统属性: {fileInfo.Name}"); fileInfo.Attributes &= ~FileAttributes.System; } // 检查是否有写入权限 try { using (var stream = File.OpenWrite(filePath)) { // 如果能打开写入流,说明有权限 } } catch (UnauthorizedAccessException) { StatusChanged?.Invoke($"权限不足,无法写入文件: {fileInfo.Name}"); return false; } return true; } catch (Exception ex) { StatusChanged?.Invoke($"准备文件时出错: {ex.Message}"); Debug.WriteLine($"PrepareFileForReplacement错误: {ex}"); return false; } } // 检测Win11并提供诊断信息 private void DiagnoseWin11Issues() { try { var osVersion = Environment.OSVersion; var isWin11 = osVersion.Version.Major >= 10 && osVersion.Version.Build >= 22000; StatusChanged?.Invoke($"操作系统: {osVersion.VersionString}"); Debug.WriteLine($"操作系统详细信息: {osVersion}"); Debug.WriteLine($"是否为Win11: {isWin11}"); if (isWin11) { StatusChanged?.Invoke("检测到Windows 11,启用兼容性模式"); // 检查UAC状态 try { var principal = new System.Security.Principal.WindowsPrincipal(System.Security.Principal.WindowsIdentity.GetCurrent()); bool isAdmin = principal.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator); StatusChanged?.Invoke($"管理员权限: {(isAdmin ? "是" : "否")}"); Debug.WriteLine($"当前进程是否以管理员身份运行: {isAdmin}"); if (!isAdmin) { StatusChanged?.Invoke("建议:以管理员身份运行程序以避免权限问题"); } } catch (Exception ex) { Debug.WriteLine($"检查管理员权限时出错: {ex}"); } } } catch (Exception ex) { Debug.WriteLine($"Win11诊断时出错: {ex}"); } } // 读取配置文件 private Dictionary ReadConfig() { var config = new Dictionary(); try { if (!File.Exists(configFilePath)) { StatusChanged?.Invoke("配置文件不存在,使用默认设置"); return config; } var lines = File.ReadAllLines(configFilePath); foreach (var line in lines) { if (string.IsNullOrWhiteSpace(line) || line.StartsWith(";") || line.StartsWith("[")) continue; var parts = line.Split('=', 2); if (parts.Length == 2) { config[parts[0].Trim()] = parts[1].Trim(); } } } catch (Exception ex) { StatusChanged?.Invoke($"读取配置文件失败: {ex.Message}"); } return config; } // 远程获取VHD选择 public async Task GetRemoteVHDSelection() { try { var config = ReadConfig(); if (!config.TryGetValue("EnableRemoteSelection", out var enableRemote) || !bool.TryParse(enableRemote, out var isEnabled) || !isEnabled) { StatusChanged?.Invoke("远程VHD选择功能已禁用"); return null; } if (!config.TryGetValue("BootImageSelectUrl", out var url) || string.IsNullOrWhiteSpace(url)) { StatusChanged?.Invoke("未配置BootImageSelectUrl"); return null; } // 添加Machine ID参数 var requestUrl = $"{url}?machineId={Uri.EscapeDataString(machineId)}"; StatusChanged?.Invoke($"正在从远程获取VHD选择: {requestUrl}"); var response = await httpClient.GetAsync(requestUrl); if (!response.IsSuccessStatusCode) { StatusChanged?.Invoke($"远程请求失败: {response.StatusCode}"); return null; } var jsonContent = await response.Content.ReadAsStringAsync(); var jsonDoc = JsonDocument.Parse(jsonContent); if (jsonDoc.RootElement.TryGetProperty("BootImageSelected", out var bootImageElement)) { var selectedKeyword = bootImageElement.GetString(); StatusChanged?.Invoke($"远程选择的VHD关键词: {selectedKeyword} (Machine ID: {machineId})"); return selectedKeyword; } else { StatusChanged?.Invoke("远程响应中未找到BootImageSelected字段"); return null; } } catch (Exception ex) { StatusChanged?.Invoke($"远程获取VHD选择失败: {ex.Message}"); return null; } } // 根据关键词查找对应的VHD文件 public string FindVHDByKeyword(List vhdFiles, string keyword) { if (string.IsNullOrWhiteSpace(keyword) || vhdFiles == null || vhdFiles.Count == 0) return null; var matchingFile = vhdFiles.FirstOrDefault(f => ExtractKeyword(Path.GetFileName(f)).Equals(keyword, StringComparison.OrdinalIgnoreCase)); if (matchingFile != null) { StatusChanged?.Invoke($"找到匹配关键词 '{keyword}' 的VHD文件: {Path.GetFileName(matchingFile)}"); } else { StatusChanged?.Invoke($"未找到匹配关键词 '{keyword}' 的VHD文件"); } return matchingFile; } public async Task> ScanForVHDFiles() { StatusChanged?.Invoke("正在扫描VHD文件..."); var vhdFiles = new List(); await Task.Run(() => { var drives = DriveInfo.GetDrives().Where(d => d.IsReady && d.DriveType == DriveType.Fixed); foreach (var drive in drives) { try { StatusChanged?.Invoke($"正在扫描驱动器 {drive.Name} 根目录..."); // 只扫描根目录 var rootFiles = Directory.GetFiles(drive.RootDirectory.FullName, "*.vhd", SearchOption.TopDirectoryOnly) .Where(f => TARGET_KEYWORDS.Any(keyword => Path.GetFileName(f).ToUpper().Contains(keyword))) .ToList(); vhdFiles.AddRange(rootFiles); Debug.WriteLine($"在 {drive.Name} 根目录找到 {rootFiles.Count} 个符合条件的VHD文件"); foreach (var file in rootFiles) { Debug.WriteLine($" 找到: {Path.GetFileName(file)}"); } } catch (Exception ex) { Debug.WriteLine($"扫描驱动器 {drive.Name} 时出错: {ex.Message}"); StatusChanged?.Invoke($"扫描驱动器 {drive.Name} 时出错: {ex.Message}"); } } StatusChanged?.Invoke($"扫描完成,共找到 {vhdFiles.Count} 个VHD文件"); foreach (var file in vhdFiles) { Debug.WriteLine($"找到VHD文件: {file}"); } }); return vhdFiles; } public async Task MountVHD(string vhdPath) { StatusChanged?.Invoke($"正在挂载VHD文件: {Path.GetFileName(vhdPath)}"); try { // 基本校验:文件必须存在 if (string.IsNullOrWhiteSpace(vhdPath) || !File.Exists(vhdPath)) { StatusChanged?.Invoke("挂载失败: VHD文件不存在或路径无效"); return false; } // 先清理盘符并分离可能已挂载的VHD,避免冲突 await UnmountDrive(); await UnmountVHD(); // 第一步:仅挂载VHD,不分配盘符 StatusChanged?.Invoke("步骤1: 挂载VHD文件..."); var attachScript = $@"select vdisk file=""{vhdPath}"" attach vdisk exit"; var tempScript = Path.GetTempFileName(); await File.WriteAllTextAsync(tempScript, attachScript); var process = new Process { StartInfo = new ProcessStartInfo { FileName = "diskpart", Arguments = $"/s \"{tempScript}\"", UseShellExecute = false, CreateNoWindow = true, RedirectStandardOutput = true, RedirectStandardError = true } }; process.Start(); // 设定挂载超时(60秒),防止卡死 var waitTask = process.WaitForExitAsync(); var timeoutTask = Task.Delay(60000); var completed = await Task.WhenAny(waitTask, timeoutTask); if (completed == timeoutTask) { try { process.Kill(); } catch { } StatusChanged?.Invoke("VHD挂载超时(超过60秒),已中止diskpart进程"); if (File.Exists(tempScript)) File.Delete(tempScript); return false; } string attachOutput = await process.StandardOutput.ReadToEndAsync(); string attachError = await process.StandardError.ReadToEndAsync(); if (File.Exists(tempScript)) File.Delete(tempScript); if (process.ExitCode != 0) { StatusChanged?.Invoke($"VHD挂载失败: {attachError.Trim()}"); Debug.WriteLine($"VHD挂载输出: {attachOutput}"); Debug.WriteLine($"VHD挂载错误: {attachError}"); return false; } StatusChanged?.Invoke("VHD挂载成功,等待系统识别分区..."); await Task.Delay(3000); // 等待系统识别分区 // 第二步:为第一个分区分配盘符 StatusChanged?.Invoke("步骤2: 为第一个分区分配盘符M..."); // 容错检查:如果M盘已经存在,先删除再重新分配 if (Directory.Exists(TARGET_DRIVE)) { StatusChanged?.Invoke("检测到M盘已存在,正在删除原有盘符..."); bool removed = await RemoveExistingDriveLetter(vhdPath); if (!removed) { StatusChanged?.Invoke("删除原有盘符失败,但继续尝试重新分配"); } else { StatusChanged?.Invoke("原有盘符删除成功"); } await Task.Delay(2000); // 等待系统更新 } bool driveAssigned = await AssignDriveLetterToFirstPartition(vhdPath); if (!driveAssigned) { StatusChanged?.Invoke("分配盘符失败,尝试备用方法..."); // 备用方法:直接尝试分配盘符 driveAssigned = await AssignDriveLetterDirect(); } if (driveAssigned) { StatusChanged?.Invoke("VHD挂载和盘符分配完成"); return true; } else { StatusChanged?.Invoke("盘符分配失败,但VHD已挂载"); return false; } } catch (Exception ex) { StatusChanged?.Invoke($"挂载失败: {ex.Message}"); Debug.WriteLine($"MountVHD异常: {ex}"); return false; } } public async Task UnmountDrive() { try { if (!Directory.Exists(TARGET_DRIVE)) { StatusChanged?.Invoke("M盘符已不存在,无需移除"); return true; } StatusChanged?.Invoke("正在移除M盘符..."); var diskpartScript = "select volume M\nremove\nexit"; var tempScript = Path.GetTempFileName(); await File.WriteAllTextAsync(tempScript, diskpartScript); var process = new Process { StartInfo = new ProcessStartInfo { FileName = "diskpart", Arguments = $"/s \"{tempScript}\"", UseShellExecute = false, CreateNoWindow = true, RedirectStandardOutput = true, RedirectStandardError = true } }; process.Start(); // 添加超时机制 var waitTask = process.WaitForExitAsync(); var timeoutTask = Task.Delay(20000); // 20秒超时 var completed = await Task.WhenAny(waitTask, timeoutTask); if (completed == timeoutTask) { try { process.Kill(); } catch { } StatusChanged?.Invoke("移除M盘符超时,已中止diskpart进程"); if (File.Exists(tempScript)) File.Delete(tempScript); return false; } if (File.Exists(tempScript)) File.Delete(tempScript); StatusChanged?.Invoke("M盘符移除完成"); return true; } catch (Exception ex) { StatusChanged?.Invoke($"移除M盘符失败: {ex.Message}"); Debug.WriteLine($"UnmountDrive异常: {ex}"); return false; } } public async Task FindFolder(string folderName) { StatusChanged?.Invoke($"正在搜索{folderName}文件夹..."); if (!Directory.Exists(TARGET_DRIVE)) { StatusChanged?.Invoke($"目标驱动器 {TARGET_DRIVE} 不存在"); return null; } return await Task.Run(() => { try { StatusChanged?.Invoke($"开始在 {TARGET_DRIVE} 中搜索{folderName}文件夹..."); // 首先检查根目录 var rootDirs = Directory.GetDirectories(TARGET_DRIVE) .Select(d => new { Path = d, Name = Path.GetFileName(d) }) .ToList(); StatusChanged?.Invoke($"根目录下找到 {rootDirs.Count} 个文件夹:"); foreach (var dir in rootDirs) { StatusChanged?.Invoke($" - {dir.Name}"); Debug.WriteLine($"根目录文件夹: {dir.Name}"); } // 检查根目录中是否有目标文件夹(不区分大小写) var targetInRoot = rootDirs.FirstOrDefault(d => string.Equals(d.Name, folderName, StringComparison.OrdinalIgnoreCase)); if (targetInRoot != null) { StatusChanged?.Invoke($"在根目录找到{folderName}文件夹: {targetInRoot.Path}"); return targetInRoot.Path; } // 如果根目录没有,递归搜索所有子目录(不区分大小写) StatusChanged?.Invoke($"根目录未找到{folderName}文件夹,开始递归搜索..."); var allDirectories = Directory.GetDirectories(TARGET_DRIVE, "*", SearchOption.AllDirectories) .Where(d => string.Equals(Path.GetFileName(d), folderName, StringComparison.OrdinalIgnoreCase)) .ToList(); StatusChanged?.Invoke($"递归搜索找到 {allDirectories.Count} 个{folderName}文件夹"); foreach (var dir in allDirectories) { StatusChanged?.Invoke($" 找到: {dir}"); Debug.WriteLine($"找到{folderName}文件夹: {dir}"); } return allDirectories.FirstOrDefault(); } catch (Exception ex) { StatusChanged?.Invoke($"搜索{folderName}文件夹时出错: {ex.Message}"); Debug.WriteLine($"FindFolder错误: {ex}"); return null; } }); } public async Task FindPackageFolder() { return await FindFolder("package"); } public Task StartBatchFile(string packagePath) { var startBatPath = Path.Combine(packagePath, "start.bat"); if (!File.Exists(startBatPath)) { StatusChanged?.Invoke("未找到start.bat文件"); return Task.FromResult(false); } StatusChanged?.Invoke("正在启动start.bat..."); try { var process = new Process { StartInfo = new ProcessStartInfo { FileName = startBatPath, WorkingDirectory = packagePath, UseShellExecute = true, CreateNoWindow = false } }; process.Start(); return Task.FromResult(true); } catch (Exception ex) { StatusChanged?.Invoke($"启动失败: {ex.Message}"); return Task.FromResult(false); } } public bool IsTargetProcessRunning() { try { var processes = Process.GetProcesses(); return processes.Any(p => PROCESS_KEYWORDS.Any(keyword => p.ProcessName.ToLower().Contains(keyword.ToLower()))); } catch { return false; } } public async Task MonitorAndRestart(string packagePath) { StatusChanged?.Invoke("等待15秒后开始监控进程..."); await Task.Delay(15000); // 等待15秒 StatusChanged?.Invoke("开始监控目标进程..."); while (true) { if (!IsTargetProcessRunning()) { StatusChanged?.Invoke("目标进程未运行,重新启动start.bat..."); await StartBatchFile(packagePath); await Task.Delay(15000); // 重启后等待15秒 } await Task.Delay(1000); // 每秒检查一次 } } /// /// 删除VHD第一个分区的现有盘符 /// private async Task RemoveExistingDriveLetter(string vhdPath) { try { StatusChanged?.Invoke("正在删除VHD第一个分区的现有盘符..."); // 使用diskpart删除第一个分区的盘符 var removeScript = $@"select vdisk file=""{vhdPath}"" list partition select partition 1 remove letter=M exit"; var tempScript = Path.GetTempFileName(); await File.WriteAllTextAsync(tempScript, removeScript); var process = new Process { StartInfo = new ProcessStartInfo { FileName = "diskpart", Arguments = $"/s \"{tempScript}\"", UseShellExecute = false, CreateNoWindow = true, RedirectStandardOutput = true, RedirectStandardError = true } }; process.Start(); var waitTask = process.WaitForExitAsync(); var timeoutTask = Task.Delay(30000); var completed = await Task.WhenAny(waitTask, timeoutTask); if (completed == timeoutTask) { try { process.Kill(); } catch { } StatusChanged?.Invoke("删除盘符超时"); if (File.Exists(tempScript)) File.Delete(tempScript); return false; } string output = await process.StandardOutput.ReadToEndAsync(); string error = await process.StandardError.ReadToEndAsync(); if (File.Exists(tempScript)) File.Delete(tempScript); Debug.WriteLine($"删除盘符输出: {output}"); if (!string.IsNullOrWhiteSpace(error)) { Debug.WriteLine($"删除盘符错误: {error}"); } // 等待盘符删除完成 await Task.Delay(2000); // 验证M盘是否已被删除 bool driveRemoved = !Directory.Exists(TARGET_DRIVE); if (driveRemoved) { StatusChanged?.Invoke("盘符M删除成功"); } else { StatusChanged?.Invoke("盘符M可能仍然存在,但继续处理"); } return driveRemoved; } catch (Exception ex) { StatusChanged?.Invoke($"删除盘符异常: {ex.Message}"); Debug.WriteLine($"RemoveExistingDriveLetter异常: {ex}"); return false; } } /// /// 为VHD的第一个分区分配盘符M /// private async Task AssignDriveLetterToFirstPartition(string vhdPath) { try { // 使用diskpart列出VHD的分区并为第一个分区分配盘符 var listScript = $@"select vdisk file=""{vhdPath}"" list partition select partition 1 assign letter=M exit"; var tempScript = Path.GetTempFileName(); await File.WriteAllTextAsync(tempScript, listScript); var process = new Process { StartInfo = new ProcessStartInfo { FileName = "diskpart", Arguments = $"/s \"{tempScript}\"", UseShellExecute = false, CreateNoWindow = true, RedirectStandardOutput = true, RedirectStandardError = true } }; process.Start(); var waitTask = process.WaitForExitAsync(); var timeoutTask = Task.Delay(30000); var completed = await Task.WhenAny(waitTask, timeoutTask); if (completed == timeoutTask) { try { process.Kill(); } catch { } StatusChanged?.Invoke("分配盘符超时"); if (File.Exists(tempScript)) File.Delete(tempScript); return false; } string output = await process.StandardOutput.ReadToEndAsync(); string error = await process.StandardError.ReadToEndAsync(); if (File.Exists(tempScript)) File.Delete(tempScript); Debug.WriteLine($"分区盘符分配输出: {output}"); if (!string.IsNullOrWhiteSpace(error)) { Debug.WriteLine($"分区盘符分配错误: {error}"); } // 等待盘符分配完成 await Task.Delay(2000); bool driveExists = Directory.Exists(TARGET_DRIVE); if (driveExists) { StatusChanged?.Invoke("盘符M分配成功"); } else { StatusChanged?.Invoke("盘符M分配失败,M盘不存在"); } return driveExists; } catch (Exception ex) { StatusChanged?.Invoke($"分配盘符异常: {ex.Message}"); Debug.WriteLine($"AssignDriveLetterToFirstPartition异常: {ex}"); return false; } } /// /// 备用方法:直接尝试分配盘符(适用于单分区VHD) /// private async Task AssignDriveLetterDirect() { try { StatusChanged?.Invoke("尝试备用盘符分配方法..."); // 尝试为最后挂载的磁盘分配盘符 var assignScript = @"list disk select disk 1 list partition select partition 1 assign letter=M exit"; var tempScript = Path.GetTempFileName(); await File.WriteAllTextAsync(tempScript, assignScript); var process = new Process { StartInfo = new ProcessStartInfo { FileName = "diskpart", Arguments = $"/s \"{tempScript}\"", UseShellExecute = false, CreateNoWindow = true, RedirectStandardOutput = true, RedirectStandardError = true } }; process.Start(); var waitTask = process.WaitForExitAsync(); var timeoutTask = Task.Delay(30000); var completed = await Task.WhenAny(waitTask, timeoutTask); if (completed == timeoutTask) { try { process.Kill(); } catch { } StatusChanged?.Invoke("备用盘符分配超时"); if (File.Exists(tempScript)) File.Delete(tempScript); return false; } string output = await process.StandardOutput.ReadToEndAsync(); string error = await process.StandardError.ReadToEndAsync(); if (File.Exists(tempScript)) File.Delete(tempScript); Debug.WriteLine($"备用盘符分配输出: {output}"); if (!string.IsNullOrWhiteSpace(error)) { Debug.WriteLine($"备用盘符分配错误: {error}"); } // 等待盘符分配完成 await Task.Delay(2000); bool driveExists = Directory.Exists(TARGET_DRIVE); if (driveExists) { StatusChanged?.Invoke("备用方法盘符M分配成功"); } else { StatusChanged?.Invoke("备用方法盘符M分配也失败"); } return driveExists; } catch (Exception ex) { StatusChanged?.Invoke($"备用盘符分配异常: {ex.Message}"); Debug.WriteLine($"AssignDriveLetterDirect异常: {ex}"); return false; } } public async Task UnmountVHD() { StatusChanged?.Invoke("正在解除VHD挂载..."); try { // 直接分离VHD文件,不移除驱动器字母 var diskpartScript = "select vdisk file=*\ndetach vdisk\nexit"; var tempScript = Path.GetTempFileName(); await File.WriteAllTextAsync(tempScript, diskpartScript); StatusChanged?.Invoke("正在执行VHD解除挂载脚本..."); var process = new Process { StartInfo = new ProcessStartInfo { FileName = "diskpart", Arguments = $"/s \"{tempScript}\"", UseShellExecute = false, CreateNoWindow = true, RedirectStandardOutput = true, RedirectStandardError = true } }; process.Start(); // 添加超时机制,防止解除挂载时卡住 var waitTask = process.WaitForExitAsync(); var timeoutTask = Task.Delay(30000); // 30秒超时 var completed = await Task.WhenAny(waitTask, timeoutTask); if (completed == timeoutTask) { try { process.Kill(); } catch { } StatusChanged?.Invoke("解除VHD挂载超时(超过30秒),已中止diskpart进程"); if (File.Exists(tempScript)) File.Delete(tempScript); return false; } // 获取进程输出用于调试 string output = ""; string error = ""; try { output = await process.StandardOutput.ReadToEndAsync(); error = await process.StandardError.ReadToEndAsync(); } catch { } if (File.Exists(tempScript)) File.Delete(tempScript); if (process.ExitCode != 0 && !string.IsNullOrWhiteSpace(error)) { StatusChanged?.Invoke($"解除VHD挂载警告: {error.Trim()}"); Debug.WriteLine($"UnmountVHD输出: {output}"); Debug.WriteLine($"UnmountVHD错误: {error}"); } StatusChanged?.Invoke("VHD解除挂载完成"); return true; } catch (Exception ex) { StatusChanged?.Invoke($"解除VHD挂载失败: {ex.Message}"); Debug.WriteLine($"UnmountVHD异常: {ex}"); return false; } } // IDisposable实现 public void Dispose() { StopProtectionCheck(); httpClient?.Dispose(); } // 析构函数 ~VHDManager() { Dispose(); } } }