diff --git a/VHDManager.cs b/VHDManager.cs index 6c916f7..8d3d3e3 100644 --- a/VHDManager.cs +++ b/VHDManager.cs @@ -574,12 +574,20 @@ exit"; // 第二步:为第一个分区分配盘符 StatusChanged?.Invoke("步骤2: 为第一个分区分配盘符M..."); - // 容错检查:如果M盘已经存在,可能是系统自动分配的 + // 容错检查:如果M盘已经存在,先删除再重新分配 if (Directory.Exists(TARGET_DRIVE)) { - StatusChanged?.Invoke("检测到M盘已自动分配,跳过手动分配步骤"); - StatusChanged?.Invoke("VHD挂载和盘符分配完成"); - return true; + StatusChanged?.Invoke("检测到M盘已存在,正在删除原有盘符..."); + bool removed = await RemoveExistingDriveLetter(vhdPath); + if (!removed) + { + StatusChanged?.Invoke("删除原有盘符失败,但继续尝试重新分配"); + } + else + { + StatusChanged?.Invoke("原有盘符删除成功"); + } + await Task.Delay(2000); // 等待系统更新 } bool driveAssigned = await AssignDriveLetterToFirstPartition(vhdPath); @@ -806,6 +814,89 @@ exit"; } } + /// + /// 删除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 /// @@ -813,14 +904,6 @@ exit"; { try { - // 容错机制:检查M盘是否已经存在 - if (Directory.Exists(TARGET_DRIVE)) - { - StatusChanged?.Invoke("检测到M盘已存在,跳过盘符分配"); - Debug.WriteLine("M盘已存在,无需重复分配"); - return true; - } - // 使用diskpart列出VHD的分区并为第一个分区分配盘符 var listScript = $@"select vdisk file=""{vhdPath}"" list partition @@ -901,14 +984,8 @@ exit"; { try { - // 容错机制:检查M盘是否已经存在 - if (Directory.Exists(TARGET_DRIVE)) - { - StatusChanged?.Invoke("备用方法检测到M盘已存在,跳过盘符分配"); - Debug.WriteLine("备用方法:M盘已存在,无需重复分配"); - return true; - } - + StatusChanged?.Invoke("尝试备用盘符分配方法..."); + // 尝试为最后挂载的磁盘分配盘符 var assignScript = @"list disk select disk 1 diff --git a/VHD_Mount_Fix_Guide.md b/VHD_Mount_Fix_Guide.md new file mode 100644 index 0000000..8d54f07 --- /dev/null +++ b/VHD_Mount_Fix_Guide.md @@ -0,0 +1,121 @@ +# VHD挂载修复测试指南 + +## 修复内容 + +本次修复解决了以下VHD挂载相关问题: + +1. **VHD解除挂载后程序卡住问题** + - 重写了`MountVHD`方法,采用两步式挂载流程 + - 先挂载VHD文件,再为第一个分区分配盘符M + - 添加了完善的错误处理和超时机制 + +2. **VHD挂载盘符处理兼容性问题** + - 新增`AssignDriveLetterToFirstPartition()`方法,专门处理分区盘符分配 + - 新增`AssignDriveLetterDirect()`备用方法,提供兼容性支持 + - 改进了diskpart脚本的执行和错误处理 + +3. **智能盘符重新分配机制** + - 新增`RemoveExistingDriveLetter()`方法,用于删除已有盘符 + - 当检测到M盘已存在时,先删除原有盘符,再重新分配 + - 确保盘符分配的一致性和可靠性,避免冲突 + +## 测试步骤 + +### 准备工作 +1. 确保有管理员权限(VHD挂载需要管理员权限) +2. 准备测试用的VHD文件 +3. 确保M盘符当前未被占用 + +### 测试1:本地VHD挂载测试 +1. 将VHD文件放在本地目录 +2. 运行程序,选择本地VHD文件 +3. 观察挂载过程的状态输出 +4. 验证M盘是否成功挂载并可访问 + +### 测试2:USB VHD替换测试 +1. 准备包含VHD文件的USB设备 +2. 插入USB设备 +3. 运行程序,让其自动检测并替换本地VHD +4. 验证替换和挂载过程是否正常 + +### 测试3:盘符冲突处理测试 +1. 手动创建一个M盘(可以是网络驱动器或其他) +2. 运行程序挂载VHD +3. 验证程序是否正确删除原有M盘并重新分配 + +### 测试4:多分区VHD兼容性测试 +1. 使用包含多个分区的VHD文件 +2. 验证程序是否正确为第一个分区分配M盘符 +3. 检查其他分区是否不受影响 + +## 预期输出示例 + +### 正常挂载流程 +``` +开始挂载VHD: C:\path\to\file.vhd +步骤1: 挂载VHD文件... +VHD挂载成功,等待系统识别分区... +步骤2: 为第一个分区分配盘符M... +正在为第一个分区分配盘符M... +盘符M分配成功 +VHD挂载和盘符分配完成 +``` + +### 盘符冲突处理流程 +``` +开始挂载VHD: C:\path\to\file.vhd +步骤1: 挂载VHD文件... +VHD挂载成功,等待系统识别分区... +步骤2: 为第一个分区分配盘符M... +检测到M盘已存在,正在删除原有盘符... +正在删除VHD第一个分区的现有盘符... +盘符M删除成功 +原有盘符删除成功 +正在为第一个分区分配盘符M... +盘符M分配成功 +VHD挂载和盘符分配完成 +``` + +### 备用方法触发 +``` +分配盘符失败,尝试备用方法... +尝试备用盘符分配方法... +备用方法:盘符M分配成功 +VHD挂载和盘符分配完成 +``` + +## 故障排除 + +### 常见问题 +1. **权限不足**:确保以管理员身份运行程序 +2. **VHD文件损坏**:检查VHD文件是否完整 +3. **盘符冲突**:程序会自动处理M盘冲突,删除原有盘符后重新分配 +4. **系统资源不足**:确保有足够的内存和磁盘空间 + +### 调试信息 +程序会在Debug输出中显示详细的操作信息,包括: +- diskpart命令的执行结果 +- 盘符分配的详细过程 +- 错误信息和异常堆栈 + +## 注意事项 + +1. **管理员权限**:VHD挂载操作需要管理员权限 +2. **盘符占用**:程序会自动处理M盘冲突,无需手动干预 +3. **系统兼容性**:支持Windows 10/11系统 +4. **VHD格式**:支持标准的VHD和VHDX格式文件 +5. **安全性**:程序会在操作完成后自动清理临时文件 + +## 技术细节 + +### 盘符重新分配流程 +1. 检测M盘是否已存在 +2. 如果存在,使用diskpart删除原有盘符 +3. 等待系统更新(2秒延迟) +4. 重新为VHD第一个分区分配M盘符 +5. 验证分配结果 + +### 容错机制 +- 删除盘符失败时,程序仍会尝试重新分配 +- 主要分配方法失败时,自动尝试备用方法 +- 所有操作都有超时保护,避免程序卡死 \ No newline at end of file