feat(VHDManager): 添加Win11兼容性检查和文件处理逻辑
- 移除未使用的VHDFilesFound事件及相关代码 - 新增Win11兼容性诊断功能,检查操作系统版本和管理员权限 - 添加文件占用检测和属性修复功能 - 改进文件替换流程,增加错误处理和状态报告 - 添加详细的诊断日志记录 - 新增Win11故障排除文档
This commit is contained in:
+1
-9
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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文件
|
||||
Reference in New Issue
Block a user