添加HVM项目配置文件,更新文件清理逻辑,增强文件强制替换功能
This commit is contained in:
81
CheckDown.hvmprj
Normal file
81
CheckDown.hvmprj
Normal file
@@ -0,0 +1,81 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<HVMProject version ="2">
|
||||
<Assemblies>
|
||||
<assembly>
|
||||
<path>.\bin\Debug\CheckDownload.exe</path>
|
||||
</assembly>
|
||||
</Assemblies>
|
||||
<Output>
|
||||
<path>.\bin\Debug_Protected</path>
|
||||
<runtime>HVMRuntm.dll</runtime>
|
||||
<runtime64>HVMRun64.dll</runtime64>
|
||||
<X64Optimize>true</X64Optimize>
|
||||
<LibMode>1</LibMode>
|
||||
<EmbedRuntime>0</EmbedRuntime>
|
||||
<shrink>true</shrink>
|
||||
<SingleEXE>true</SingleEXE>
|
||||
<EXE>
|
||||
<Main>CheckDownload.exe</Main>
|
||||
<PackType>1</PackType>
|
||||
<EntryType>0</EntryType>
|
||||
<LoadType>0</LoadType>
|
||||
<Assemblies>
|
||||
<assembly>
|
||||
<path>.\bin\Debug\7z.dll</path>
|
||||
<datafile>true</datafile>
|
||||
</assembly>
|
||||
<assembly>
|
||||
<path>.\bin\Debug\CheckDownload.exe.config</path>
|
||||
<datafile>true</datafile>
|
||||
</assembly>
|
||||
<assembly>
|
||||
<path>.\bin\Debug\CheckDownload.pdb</path>
|
||||
<datafile>true</datafile>
|
||||
</assembly>
|
||||
<SplashConfig>
|
||||
<Width>600</Width>
|
||||
<Height>400</Height>
|
||||
<iAutoClose>0</iAutoClose>
|
||||
<Image></Image>
|
||||
<msg1>Loading...</msg1>
|
||||
<msg2>Starting...</msg2>
|
||||
<title></title>
|
||||
</SplashConfig>
|
||||
</Assemblies>
|
||||
</EXE>
|
||||
</Output>
|
||||
<Settings>
|
||||
<EncryptComplierGen>true</EncryptComplierGen>
|
||||
<AntiDump>true</AntiDump>
|
||||
<EncryptNew>true</EncryptNew>
|
||||
<EncryptRes>true</EncryptRes>
|
||||
<EncryptBlob>true</EncryptBlob>
|
||||
<EncryptUS>true</EncryptUS>
|
||||
<HVM>true</HVM>
|
||||
<HVM2>true</HVM2>
|
||||
<HVMSig>true</HVMSig>
|
||||
<HVMEH>true</HVMEH>
|
||||
<HVMStr>true</HVMStr>
|
||||
<Level>4</Level>
|
||||
<Level2>3</Level2>
|
||||
<CompatLevel>15</CompatLevel>
|
||||
<AntiTrace>true</AntiTrace>
|
||||
<HVMAntiTrace>true</HVMAntiTrace>
|
||||
<HVMProxyMethod>true</HVMProxyMethod>
|
||||
<AnonymousProtection>2</AnonymousProtection>
|
||||
<StripConstantsString>true</StripConstantsString>
|
||||
</Settings>
|
||||
<Obfuscation>
|
||||
<AutoRename>true</AutoRename>
|
||||
<ObILCode>true</ObILCode>
|
||||
<ObMeta>true</ObMeta>
|
||||
<RenameMode>2</RenameMode>
|
||||
</Obfuscation>
|
||||
<TrialSettings>
|
||||
</TrialSettings>
|
||||
<LicenseSettings>
|
||||
<AddBiosID>true</AddBiosID>
|
||||
<AddMacID>true</AddMacID>
|
||||
<MasterKey></MasterKey>
|
||||
</LicenseSettings>
|
||||
</HVMProject>
|
495
Update.cs
495
Update.cs
@@ -252,7 +252,7 @@ namespace CheckDownload
|
||||
try
|
||||
{
|
||||
InitializeTempDirectory();
|
||||
CleanupNewFiles();
|
||||
CleanupOldFiles();
|
||||
UpdateStatus("下载在线MD5文件并读取...");
|
||||
UpdateCount("");
|
||||
UpdateSize("");
|
||||
@@ -366,16 +366,35 @@ namespace CheckDownload
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理旧的更新文件,删除所有.new后缀的临时文件
|
||||
/// 清理旧的更新文件,删除备份文件和临时文件
|
||||
/// </summary>
|
||||
private void CleanupNewFiles()
|
||||
private void CleanupOldFiles()
|
||||
{
|
||||
try
|
||||
{
|
||||
var newFiles = Directory.GetFiles(_baseDirectory, "*.new", SearchOption.AllDirectories);
|
||||
if (newFiles.Length > 0)
|
||||
// 清理备份文件
|
||||
var backupFiles = Directory.GetFiles(_baseDirectory, "*.bak_*", SearchOption.AllDirectories);
|
||||
if (backupFiles.Length > 0)
|
||||
{
|
||||
UpdateStatus("正在清理旧的更新文件...");
|
||||
UpdateStatus("正在清理备份文件...");
|
||||
foreach (var file in backupFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 只清理超过1小时的备份文件
|
||||
if (File.GetCreationTime(file) < DateTime.Now.AddHours(-1))
|
||||
{
|
||||
File.Delete(file);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 清理旧的 .new 文件(如果还有遗留的)
|
||||
var newFiles = Directory.GetFiles(_baseDirectory, "*.new", SearchOption.AllDirectories);
|
||||
foreach (var file in newFiles)
|
||||
{
|
||||
try
|
||||
@@ -387,7 +406,6 @@ namespace CheckDownload
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
@@ -914,7 +932,7 @@ namespace CheckDownload
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证所有下载文件的MD5完整性并保存到目标位置,处理文件占用情况
|
||||
/// 验证所有下载文件的MD5完整性并保存到目标位置,强制替换占用的文件
|
||||
/// </summary>
|
||||
private async Task VerifyAndSaveAllFiles()
|
||||
{
|
||||
@@ -922,11 +940,7 @@ namespace CheckDownload
|
||||
UpdateCount("");
|
||||
UpdateSize("");
|
||||
|
||||
// 新增:在开始校验前创建临时文件备份
|
||||
//await CreateTempFileBackup();
|
||||
|
||||
var failedFiles = new ConcurrentBag<string>();
|
||||
var filesForScripting = new ConcurrentBag<(string original, string newFile)>();
|
||||
|
||||
int totalFiles = _downloadedFiles.Count;
|
||||
int completed = 0;
|
||||
@@ -941,18 +955,17 @@ namespace CheckDownload
|
||||
string expectedMd5 = item.Value;
|
||||
string tempFilePath = Path.Combine(_tempDirectory, relativePath);
|
||||
|
||||
// 添加调试信息:检查临时文件是否存在
|
||||
// 检查临时文件是否存在
|
||||
if (!File.Exists(tempFilePath))
|
||||
{
|
||||
//UpdateStatus($"[调试] 临时文件在校验前消失: {relativePath}");
|
||||
failedFiles.Add(relativePath);
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证MD5
|
||||
string actualMd5 = CalculateMD5FromFile(tempFilePath);
|
||||
if (actualMd5 != expectedMd5.ToLower())
|
||||
{
|
||||
//UpdateStatus($"[调试] 文件MD5校验失败: {relativePath}");
|
||||
failedFiles.Add(relativePath);
|
||||
return;
|
||||
}
|
||||
@@ -964,23 +977,11 @@ namespace CheckDownload
|
||||
Directory.CreateDirectory(localDir);
|
||||
}
|
||||
|
||||
//UpdateStatus($"[调试] 开始复制文件: {relativePath}");
|
||||
if (!await TryCopyFileAsync(tempFilePath, localPath)) // 改为使用复制方法
|
||||
// 使用强制替换方法
|
||||
if (!await ForceReplaceFileAsync(tempFilePath, localPath))
|
||||
{
|
||||
//UpdateStatus($"[调试] 直接复制失败,创建.new文件: {relativePath}");
|
||||
string backupPath = localPath + ".new";
|
||||
File.Copy(tempFilePath, backupPath, true); // 复制而非移动
|
||||
filesForScripting.Add((localPath, backupPath));
|
||||
}
|
||||
else
|
||||
{
|
||||
//UpdateStatus($"[调试] 文件复制成功: {relativePath}");
|
||||
}
|
||||
|
||||
// 复制后再次检查临时文件是否还存在
|
||||
if (!File.Exists(tempFilePath))
|
||||
{
|
||||
//UpdateStatus($"[调试] 警告:文件复制后临时文件消失: {relativePath}");
|
||||
failedFiles.Add(relativePath);
|
||||
return;
|
||||
}
|
||||
}
|
||||
finally
|
||||
@@ -994,11 +995,6 @@ namespace CheckDownload
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
|
||||
if (filesForScripting.Any())
|
||||
{
|
||||
CreateReplaceScriptForAll(filesForScripting.ToList());
|
||||
}
|
||||
|
||||
foreach (var failed in failedFiles)
|
||||
{
|
||||
_downloadedFiles.Remove(failed);
|
||||
@@ -1019,178 +1015,9 @@ namespace CheckDownload
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试将文件从临时位置移动到目标位置(异步),若文件被占用则等待一秒后重试一次
|
||||
/// </summary>
|
||||
/// <param name="sourcePath">源文件的完整路径</param>
|
||||
/// <param name="targetPath">目标文件的完整路径</param>
|
||||
/// <returns>移动成功返回true,失败返回false</returns>
|
||||
private async Task<bool> TryMoveFileAsync(string sourcePath, string targetPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Move(sourcePath, targetPath);
|
||||
return true;
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
UpdateStatus($"文件被占用,尝试解锁...");
|
||||
|
||||
try
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
|
||||
File.Move(sourcePath, targetPath);
|
||||
UpdateStatus($"文件解锁成功并已更新");
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
UpdateStatus($"文件仍被占用,无法移动");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UpdateStatus($"移动文件时发生错误: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 为被占用文件创建批处理脚本,在程序退出后自动完成文件替换
|
||||
/// </summary>
|
||||
/// <param name="files">包含原始文件路径和新文件路径的元组列表</param>
|
||||
private void CreateReplaceScriptForAll(List<(string original, string newFile)> files)
|
||||
{
|
||||
if (!files.Any()) return;
|
||||
|
||||
try
|
||||
{
|
||||
string batchFilePath = Path.Combine(_baseDirectory, "update_files.bat");
|
||||
string processId = Process.GetCurrentProcess().Id.ToString();
|
||||
string processName = Process.GetCurrentProcess().ProcessName;
|
||||
|
||||
// 创建锁文件,程序退出前会删除它
|
||||
File.WriteAllText(_updateLockFilePath, processId);
|
||||
|
||||
var batchContent = new StringBuilder();
|
||||
batchContent.AppendLine("@echo off");
|
||||
batchContent.AppendLine("title Update Process");
|
||||
|
||||
// 简化的等待逻辑,避免复杂的计数器
|
||||
batchContent.AppendLine("echo 等待程序退出...");
|
||||
batchContent.AppendLine(":wait_loop");
|
||||
|
||||
// 优先检查锁文件
|
||||
batchContent.AppendLine($"if not exist \"{_updateLockFilePath}\" goto process_check");
|
||||
|
||||
// 等待0.5秒
|
||||
batchContent.AppendLine("ping 127.0.0.1 -n 1 -w 500 >nul");
|
||||
batchContent.AppendLine("goto wait_loop");
|
||||
|
||||
batchContent.AppendLine(":process_check");
|
||||
// 再次确认进程已退出
|
||||
batchContent.AppendLine($"tasklist /FI \"PID eq {processId}\" 2>nul | find /I \"{processId}\" >nul");
|
||||
batchContent.AppendLine("if %ERRORLEVEL% equ 0 (");
|
||||
batchContent.AppendLine(" ping 127.0.0.1 -n 1 -w 500 >nul");
|
||||
batchContent.AppendLine(" goto process_check");
|
||||
batchContent.AppendLine(")");
|
||||
|
||||
// 额外等待确保完全退出
|
||||
batchContent.AppendLine("ping 127.0.0.1 -n 1 -w 1000 >nul");
|
||||
batchContent.AppendLine("echo 开始更新文件...");
|
||||
|
||||
// 简化的文件处理逻辑,避免复杂的标签
|
||||
int fileIndex = 0;
|
||||
foreach (var file in files)
|
||||
{
|
||||
string fileName = Path.GetFileName(file.original);
|
||||
batchContent.AppendLine($"echo 处理文件: {fileName}");
|
||||
|
||||
// 检查新文件是否存在
|
||||
batchContent.AppendLine($"if not exist \"{file.newFile}\" (");
|
||||
batchContent.AppendLine($" echo 错误: 新文件不存在 - {fileName}");
|
||||
batchContent.AppendLine($" goto file_{fileIndex}_end");
|
||||
batchContent.AppendLine($")");
|
||||
|
||||
// 删除原文件(如果存在)
|
||||
batchContent.AppendLine($"if exist \"{file.original}\" (");
|
||||
batchContent.AppendLine($" echo 删除原文件: {fileName}");
|
||||
batchContent.AppendLine($" del \"{file.original}\" /f /q");
|
||||
batchContent.AppendLine($")");
|
||||
|
||||
// 复制新文件
|
||||
batchContent.AppendLine($"echo 复制新文件: {fileName}");
|
||||
batchContent.AppendLine($"copy /Y \"{file.newFile}\" \"{file.original}\"");
|
||||
|
||||
// 验证复制是否成功
|
||||
batchContent.AppendLine($"if exist \"{file.original}\" (");
|
||||
batchContent.AppendLine($" echo 成功更新: {fileName}");
|
||||
batchContent.AppendLine($" del \"{file.newFile}\" /f /q");
|
||||
batchContent.AppendLine($") else (");
|
||||
batchContent.AppendLine($" echo 失败: 无法创建 {fileName}");
|
||||
batchContent.AppendLine($")");
|
||||
|
||||
batchContent.AppendLine($":file_{fileIndex}_end");
|
||||
fileIndex++;
|
||||
}
|
||||
|
||||
// 清理工作
|
||||
batchContent.AppendLine("echo 清理临时文件...");
|
||||
|
||||
// 删除锁文件
|
||||
batchContent.AppendLine($"if exist \"{_updateLockFilePath}\" del \"{_updateLockFilePath}\" /f /q");
|
||||
|
||||
// 简化的清理逻辑
|
||||
batchContent.AppendLine($"cd /d \"{_baseDirectory}\"");
|
||||
batchContent.AppendLine("for %%f in (*.new) do del \"%%f\" /f /q");
|
||||
batchContent.AppendLine("for %%f in (*.bak) do del \"%%f\" /f /q");
|
||||
|
||||
batchContent.AppendLine("echo 更新完成");
|
||||
batchContent.AppendLine("ping 127.0.0.1 -n 1 -w 2000 >nul");
|
||||
|
||||
// 删除批处理脚本自身
|
||||
batchContent.AppendLine("del \"%~f0\" /f /q");
|
||||
|
||||
File.WriteAllText(batchFilePath, batchContent.ToString(), new UTF8Encoding(false));
|
||||
|
||||
// 使用Win7兼容的启动方式
|
||||
var startInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = batchFilePath,
|
||||
CreateNoWindow = false, // Win7下设为false更稳定
|
||||
UseShellExecute = true, // Win7下必须使用Shell执行
|
||||
WindowStyle = ProcessWindowStyle.Minimized,
|
||||
WorkingDirectory = _baseDirectory
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
Process.Start(startInfo);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// 如果上面的方式失败,尝试直接用cmd执行
|
||||
var fallbackStartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = "cmd.exe",
|
||||
Arguments = $"/c \"{batchFilePath}\"",
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = true,
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
WorkingDirectory = _baseDirectory
|
||||
};
|
||||
Process.Start(fallbackStartInfo);
|
||||
}
|
||||
|
||||
UpdateStatus("已创建更新脚本,程序退出后将自动完成更新");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleError("创建文件替换脚本 (CreateReplaceScriptForAll)", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化程序使用的临时目录,用于存储下载过程中的临时文件
|
||||
@@ -1864,18 +1691,64 @@ namespace CheckDownload
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试将文件从源位置复制到目标位置
|
||||
/// 强制替换文件,检查占用进程并强制杀掉
|
||||
/// </summary>
|
||||
private async Task<bool> TryCopyFileAsync(string sourcePath, string targetPath)
|
||||
/// <param name="sourcePath">源文件路径</param>
|
||||
/// <param name="targetPath">目标文件路径</param>
|
||||
/// <returns>成功返回true,失败返回false</returns>
|
||||
private async Task<bool> ForceReplaceFileAsync(string sourcePath, string targetPath)
|
||||
{
|
||||
string fileName = Path.GetFileName(targetPath);
|
||||
|
||||
try
|
||||
{
|
||||
// 第一次尝试直接替换
|
||||
if (await TryDirectReplaceAsync(sourcePath, targetPath))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// 如果失败,检查并强制杀掉占用的进程
|
||||
UpdateStatus($"文件被占用,正在强制终止相关进程: {fileName}");
|
||||
|
||||
// 强制杀掉可能占用文件的进程
|
||||
await ForceKillProcessesUsingFileAsync(targetPath);
|
||||
|
||||
// 等待进程完全退出
|
||||
await Task.Delay(2000);
|
||||
|
||||
// 再次尝试替换
|
||||
if (await TryDirectReplaceAsync(sourcePath, targetPath))
|
||||
{
|
||||
UpdateStatus($"强制替换成功: {fileName}");
|
||||
return true;
|
||||
}
|
||||
|
||||
// 如果还是失败,尝试使用系统工具强制解锁
|
||||
UpdateStatus($"尝试解锁文件: {fileName}");
|
||||
if (await ForceUnlockAndReplaceAsync(sourcePath, targetPath))
|
||||
{
|
||||
UpdateStatus($"解锁并替换成功: {fileName}");
|
||||
return true;
|
||||
}
|
||||
|
||||
UpdateStatus($"强制替换失败: {fileName}");
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UpdateStatus($"强制替换异常: {fileName} - {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试直接替换文件
|
||||
/// </summary>
|
||||
private async Task<bool> TryDirectReplaceAsync(string sourcePath, string targetPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 如果目标文件是.exe文件,先检查并kill掉可能正在运行的进程
|
||||
if (Path.GetExtension(targetPath).Equals(".exe", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
KillProcessIfRunning(targetPath);
|
||||
}
|
||||
|
||||
// 确保目标目录存在
|
||||
string targetDir = Path.GetDirectoryName(targetPath);
|
||||
if (!Directory.Exists(targetDir))
|
||||
@@ -1883,25 +1756,199 @@ namespace CheckDownload
|
||||
Directory.CreateDirectory(targetDir);
|
||||
}
|
||||
|
||||
// 执行复制操作
|
||||
File.Copy(sourcePath, targetPath, true);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 文件可能被占用,稍后重试
|
||||
try
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
// 直接复制覆盖
|
||||
File.Copy(sourcePath, targetPath, true);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
UpdateStatus($"文件复制失败: {Path.GetFileName(targetPath)}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 强制杀掉占用指定文件的进程
|
||||
/// </summary>
|
||||
private async Task ForceKillProcessesUsingFileAsync(string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
string fileName = Path.GetFileNameWithoutExtension(filePath);
|
||||
string fileDirectory = Path.GetDirectoryName(filePath);
|
||||
|
||||
// 1. 杀掉同名的进程
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var processes = Process.GetProcessesByName(fileName);
|
||||
foreach (var proc in processes)
|
||||
{
|
||||
if (proc.Id == _currentProcessId) continue;
|
||||
|
||||
try
|
||||
{
|
||||
// 检查进程是否在同一目录下
|
||||
string procPath = proc.MainModule?.FileName;
|
||||
if (!string.IsNullOrEmpty(procPath))
|
||||
{
|
||||
string procDir = Path.GetDirectoryName(procPath);
|
||||
if (string.Equals(procDir, fileDirectory, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
UpdateStatus($"强制终止进程: {proc.ProcessName} (PID: {proc.Id})");
|
||||
proc.Kill();
|
||||
proc.WaitForExit(3000);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 忽略无法访问的进程
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 2. 使用 taskkill 强制终止
|
||||
await Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var startInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = "taskkill",
|
||||
Arguments = $"/F /IM {fileName}.exe",
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true
|
||||
};
|
||||
|
||||
using (var process = Process.Start(startInfo))
|
||||
{
|
||||
process?.WaitForExit(5000);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 忽略 taskkill 失败
|
||||
}
|
||||
});
|
||||
|
||||
// 3. 如果是 DLL 文件,尝试卸载相关进程
|
||||
if (Path.GetExtension(filePath).Equals(".dll", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
await ForceKillProcessesUsingDllAsync(filePath);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 忽略杀进程过程中的错误
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 强制杀掉可能使用指定DLL的进程
|
||||
/// </summary>
|
||||
private async Task ForceKillProcessesUsingDllAsync(string dllPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
string dllName = Path.GetFileName(dllPath);
|
||||
string baseDir = _baseDirectory.ToLowerInvariant();
|
||||
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var allProcesses = Process.GetProcesses();
|
||||
foreach (var proc in allProcesses)
|
||||
{
|
||||
if (proc.Id == _currentProcessId) continue;
|
||||
|
||||
try
|
||||
{
|
||||
string procPath = proc.MainModule?.FileName;
|
||||
if (!string.IsNullOrEmpty(procPath) &&
|
||||
procPath.ToLowerInvariant().StartsWith(baseDir))
|
||||
{
|
||||
UpdateStatus($"终止可能使用DLL的进程: {proc.ProcessName} (PID: {proc.Id})");
|
||||
proc.Kill();
|
||||
proc.WaitForExit(3000);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 忽略无法访问的进程
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 忽略错误
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用系统工具强制解锁并替换文件
|
||||
/// </summary>
|
||||
private async Task<bool> ForceUnlockAndReplaceAsync(string sourcePath, string targetPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 尝试使用 handle.exe 或其他系统工具来解锁文件
|
||||
// 这里先尝试简单的重命名删除方法
|
||||
string backupPath = targetPath + ".bak_" + DateTime.Now.Ticks;
|
||||
|
||||
// 尝试重命名原文件
|
||||
if (File.Exists(targetPath))
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Move(targetPath, backupPath);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 如果重命名失败,尝试设置文件属性
|
||||
try
|
||||
{
|
||||
File.SetAttributes(targetPath, FileAttributes.Normal);
|
||||
await Task.Delay(500);
|
||||
File.Move(targetPath, backupPath);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 复制新文件
|
||||
File.Copy(sourcePath, targetPath, true);
|
||||
|
||||
// 删除备份文件
|
||||
try
|
||||
{
|
||||
if (File.Exists(backupPath))
|
||||
{
|
||||
File.Delete(backupPath);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 忽略备份文件删除失败
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试将文件从源位置复制到目标位置(保留原方法用于兼容性)
|
||||
/// </summary>
|
||||
private async Task<bool> TryCopyFileAsync(string sourcePath, string targetPath)
|
||||
{
|
||||
return await ForceReplaceFileAsync(sourcePath, targetPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
Reference in New Issue
Block a user