From 94e42e31ed3b3350bc1dabca42dd61acb89f5a04 Mon Sep 17 00:00:00 2001 From: Lannamokia Date: Mon, 20 Oct 2025 03:56:55 +0800 Subject: [PATCH] =?UTF-8?q?refactor(VHDManager):=20=E6=94=B9=E8=BF=9BVHD?= =?UTF-8?q?=E6=8C=82=E8=BD=BD=E6=B5=81=E7=A8=8B=E4=B8=BA=E4=B8=A4=E6=AD=A5?= =?UTF-8?q?=E6=93=8D=E4=BD=9C=E5=B9=B6=E5=A2=9E=E5=8A=A0=E5=AE=B9=E9=94=99?= =?UTF-8?q?=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将VHD挂载流程拆分为两步:先挂载VHD再分配盘符 增加对M盘已存在的检测和自动跳过功能 添加备用盘符分配方法以增强可靠性 删除过时的Windows 11故障排除文档 --- VHDManager.cs | 251 +++++++++++++++++++++++++++++++++++---- Win11_Troubleshooting.md | 92 -------------- 2 files changed, 227 insertions(+), 116 deletions(-) delete mode 100644 Win11_Troubleshooting.md diff --git a/VHDManager.cs b/VHDManager.cs index c8ccff7..6c916f7 100644 --- a/VHDManager.cs +++ b/VHDManager.cs @@ -516,13 +516,14 @@ namespace VHDMounter await UnmountDrive(); await UnmountVHD(); - var diskpartScript = $@"select vdisk file=""{vhdPath}"" + // 第一步:仅挂载VHD,不分配盘符 + StatusChanged?.Invoke("步骤1: 挂载VHD文件..."); + var attachScript = $@"select vdisk file=""{vhdPath}"" attach vdisk -assign letter=M exit"; var tempScript = Path.GetTempFileName(); - await File.WriteAllTextAsync(tempScript, diskpartScript); + await File.WriteAllTextAsync(tempScript, attachScript); var process = new Process { @@ -547,39 +548,64 @@ exit"; if (completed == timeoutTask) { try { process.Kill(); } catch { } - StatusChanged?.Invoke("挂载超时(超过60秒),已中止diskpart进程"); - File.Delete(tempScript); + StatusChanged?.Invoke("VHD挂载超时(超过60秒),已中止diskpart进程"); + if (File.Exists(tempScript)) + File.Delete(tempScript); return false; } - string output = await process.StandardOutput.ReadToEndAsync(); - string error = await process.StandardError.ReadToEndAsync(); + string attachOutput = await process.StandardOutput.ReadToEndAsync(); + string attachError = await process.StandardError.ReadToEndAsync(); - File.Delete(tempScript); + if (File.Exists(tempScript)) + File.Delete(tempScript); - // 等待系统完成卷挂载 - await Task.Delay(2000); - - bool mounted = Directory.Exists(TARGET_DRIVE); - if (!mounted) + if (process.ExitCode != 0) { - if (!string.IsNullOrWhiteSpace(error)) - { - StatusChanged?.Invoke($"挂载失败:{error.Trim()}"); - } - else - { - // 提供有限的DiskPart输出以辅助定位问题 - var trimmedOutput = output?.Length > 400 ? output.Substring(output.Length - 400) : output; - StatusChanged?.Invoke($"挂载失败:未检测到M盘。DiskPart输出片段:{trimmedOutput}"); - } + StatusChanged?.Invoke($"VHD挂载失败: {attachError.Trim()}"); + Debug.WriteLine($"VHD挂载输出: {attachOutput}"); + Debug.WriteLine($"VHD挂载错误: {attachError}"); + return false; } - return mounted; + StatusChanged?.Invoke("VHD挂载成功,等待系统识别分区..."); + await Task.Delay(3000); // 等待系统识别分区 + + // 第二步:为第一个分区分配盘符 + StatusChanged?.Invoke("步骤2: 为第一个分区分配盘符M..."); + + // 容错检查:如果M盘已经存在,可能是系统自动分配的 + if (Directory.Exists(TARGET_DRIVE)) + { + StatusChanged?.Invoke("检测到M盘已自动分配,跳过手动分配步骤"); + StatusChanged?.Invoke("VHD挂载和盘符分配完成"); + return true; + } + + 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; } } @@ -780,6 +806,183 @@ exit"; } } + /// + /// 为VHD的第一个分区分配盘符M + /// + private async Task AssignDriveLetterToFirstPartition(string vhdPath) + { + 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 +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 + { + // 容错机制:检查M盘是否已经存在 + if (Directory.Exists(TARGET_DRIVE)) + { + StatusChanged?.Invoke("备用方法检测到M盘已存在,跳过盘符分配"); + Debug.WriteLine("备用方法:M盘已存在,无需重复分配"); + return true; + } + + // 尝试为最后挂载的磁盘分配盘符 + 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挂载..."); diff --git a/Win11_Troubleshooting.md b/Win11_Troubleshooting.md deleted file mode 100644 index 4e8eade..0000000 --- a/Win11_Troubleshooting.md +++ /dev/null @@ -1,92 +0,0 @@ -# Windows 11 VHD替换故障排除指南 - -## 问题描述 -在Windows 11系统上,VHD文件替换可能会失败,这通常是由于Win11增强的安全策略和文件保护机制导致的。 - -## 常见错误原因 - -### 1. 权限问题 -- **症状**: 提示"权限不足,无法替换文件" -- **原因**: Win11的UAC(用户账户控制)更加严格 -- **解决方案**: - - 右键点击程序,选择"以管理员身份运行" - - 或者在程序属性中设置"始终以管理员身份运行" - -### 2. 文件属性问题 -- **症状**: 文件无法删除或替换 -- **原因**: Win11可能自动设置VHD文件为只读、隐藏或系统文件 -- **解决方案**: 程序现在会自动检测并移除这些属性 - -### 3. 文件被占用 -- **症状**: 提示"文件被占用,无法删除" -- **原因**: VHD文件可能被Windows资源管理器或其他程序占用 -- **解决方案**: - - 关闭所有文件资源管理器窗口 - - 确保没有其他程序正在访问VHD文件 - - 重启计算机后再尝试 - -### 4. Windows Defender实时保护 -- **症状**: 文件操作被阻止或延迟 -- **原因**: Windows Defender可能将VHD文件操作视为可疑行为 -- **解决方案**: - - 临时禁用实时保护 - - 或将VHD文件夹添加到排除列表 - -## 程序改进功能 - -### 新增的Win11兼容性检查 -程序现在包含以下改进: - -1. **自动检测Win11**: 程序会自动识别是否运行在Windows 11上 -2. **权限检查**: 检查程序是否以管理员身份运行 -3. **文件属性修复**: 自动移除只读、隐藏、系统等属性 -4. **文件占用检测**: 检查文件是否被其他程序占用 -5. **详细错误报告**: 提供更详细的错误信息和诊断数据 - -### 诊断信息 -程序会在状态栏显示以下信息: -- 操作系统版本 -- 管理员权限状态 -- 文件属性详情 -- 具体的错误原因 - -## 手动排除步骤 - -### 步骤1: 检查权限 -1. 右键点击VHDMounter.exe -2. 选择"属性" → "兼容性" -3. 勾选"以管理员身份运行此程序" -4. 点击"确定" - -### 步骤2: 检查文件属性 -1. 右键点击VHD文件 -2. 选择"属性" -3. 取消勾选"只读" -4. 在"高级"中取消勾选"隐藏"和"系统" - -### 步骤3: 检查Windows Defender -1. 打开Windows安全中心 -2. 转到"病毒和威胁防护" -3. 在"病毒和威胁防护设置"中点击"管理设置" -4. 临时关闭"实时保护"或添加排除项 - -### 步骤4: 检查磁盘空间 -确保目标磁盘有足够的空间存储VHD文件 - -### 步骤5: 重启服务 -如果问题持续,尝试重启以下服务: -- Windows资源管理器 (explorer.exe) -- 虚拟磁盘服务 (vds) - -## 联系支持 -如果以上步骤都无法解决问题,请提供以下信息: -1. 程序显示的具体错误消息 -2. Windows 11版本号 -3. VHD文件大小和位置 -4. 是否以管理员身份运行程序 - -## 预防措施 -1. 始终以管理员身份运行程序 -2. 定期检查VHD文件的属性设置 -3. 保持Windows 11系统更新 -4. 避免在系统保护的文件夹中存储VHD文件 \ No newline at end of file