feat(VHDManager): 添加Win11兼容性检查和文件处理逻辑

- 移除未使用的VHDFilesFound事件及相关代码
- 新增Win11兼容性诊断功能,检查操作系统版本和管理员权限
- 添加文件占用检测和属性修复功能
- 改进文件替换流程,增加错误处理和状态报告
- 添加详细的诊断日志记录
- 新增Win11故障排除文档
This commit is contained in:
Lannamokia
2025-10-20 03:35:23 +08:00
parent 6b5a6854cb
commit 358fb4ce14
3 changed files with 275 additions and 16 deletions
+1 -9
View File
@@ -19,7 +19,6 @@ namespace VHDMounter
InitializeComponent();
vhdManager = new VHDManager();
vhdManager.StatusChanged += OnStatusChanged;
vhdManager.VHDFilesFound += OnVHDFilesFound;
// 注册关机事件监听
SystemEvents.SessionEnding += OnSessionEnding;
@@ -36,14 +35,7 @@ namespace VHDMounter
});
}
private void OnVHDFilesFound(List<string> vhdFiles)
{
Dispatcher.Invoke(() =>
{
availableVHDs = vhdFiles;
ShowVHDSelector(vhdFiles);
});
}
private async Task StartMainProcessWithDelay()
{
+182 -7
View File
@@ -19,7 +19,6 @@ namespace VHDMounter
private readonly string[] PROCESS_KEYWORDS = { "sinmai", "chusanapp", "mu3" };
public event Action<string> StatusChanged;
public event Action<List<string>> VHDFilesFound;
private static readonly HttpClient httpClient = new HttpClient();
private string configFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "vhdmonter_config.ini");
@@ -117,6 +116,9 @@ namespace VHDMounter
if (usbVhdFiles.Count == 0 || localVhdFiles.Count == 0)
return false;
// Win11兼容性诊断
DiagnoseWin11Issues();
bool anyReplaced = false;
StatusChanged?.Invoke("正在替换本地VHD文件...");
@@ -138,22 +140,78 @@ namespace VHDMounter
{
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($"替换文件时出错: {ex.Message}");
Debug.WriteLine($"替换文件时出错: {ex.Message}");
StatusChanged?.Invoke($"替换文件时出错: {Path.GetFileName(localFile)} - {ex.Message}");
Debug.WriteLine($"替换文件时出错: {ex}");
}
}
}
@@ -173,6 +231,123 @@ namespace VHDMounter
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<string, string> ReadConfig()
{
@@ -536,14 +711,14 @@ exit";
return await FindFolder("package");
}
public async Task<bool> StartBatchFile(string packagePath)
public Task<bool> StartBatchFile(string packagePath)
{
var startBatPath = Path.Combine(packagePath, "start.bat");
if (!File.Exists(startBatPath))
{
StatusChanged?.Invoke("未找到start.bat文件");
return false;
return Task.FromResult(false);
}
StatusChanged?.Invoke("正在启动start.bat...");
@@ -562,12 +737,12 @@ exit";
};
process.Start();
return true;
return Task.FromResult(true);
}
catch (Exception ex)
{
StatusChanged?.Invoke($"启动失败: {ex.Message}");
return false;
return Task.FromResult(false);
}
}
+92
View File
@@ -0,0 +1,92 @@
# 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文件