2 Commits

4 changed files with 167 additions and 150 deletions

129
Form1.Designer.cs generated
View File

@@ -28,66 +28,81 @@
/// </summary> /// </summary>
private void InitializeComponent() private void InitializeComponent()
{ {
this.Update_Pro = new System.Windows.Forms.ProgressBar(); this.Update_Text = new System.Windows.Forms.Label();
this.Status_Box = new System.Windows.Forms.Label(); this.Update_Pro = new System.Windows.Forms.ProgressBar();
this.Count_Box = new System.Windows.Forms.Label(); this.Status_Box = new System.Windows.Forms.Label();
this.Size_Box = new System.Windows.Forms.Label(); this.Count_Box = new System.Windows.Forms.Label();
this.SuspendLayout(); this.Size_Box = new System.Windows.Forms.Label();
// this.SuspendLayout();
// Update_Pro //
// // Update_Text
this.Update_Pro.Location = new System.Drawing.Point(12, 36); //
this.Update_Pro.Name = "Update_Pro"; this.Update_Text.AutoSize = true;
this.Update_Pro.Size = new System.Drawing.Size(339, 23); this.Update_Text.Location = new System.Drawing.Point(12, 12);
this.Update_Pro.TabIndex = 1; this.Update_Text.Name = "Update_Text";
// this.Update_Text.Size = new System.Drawing.Size(59, 12);
// Status_Box this.Update_Text.TabIndex = 0;
// this.Update_Text.Text = "更新状态:";
this.Status_Box.Location = new System.Drawing.Point(12, 12); //
this.Status_Box.Name = "Status_Box"; // Update_Pro
this.Status_Box.Size = new System.Drawing.Size(148, 12); //
this.Status_Box.TabIndex = 2; this.Update_Pro.Location = new System.Drawing.Point(12, 36);
this.Status_Box.Text = "..."; this.Update_Pro.Name = "Update_Pro";
// this.Update_Pro.Size = new System.Drawing.Size(339, 23);
// Count_Box this.Update_Pro.TabIndex = 1;
// //
this.Count_Box.Location = new System.Drawing.Point(296, 12); // Status_Box
this.Count_Box.Name = "Count_Box"; //
this.Count_Box.Size = new System.Drawing.Size(55, 13); this.Status_Box.AutoSize = false;
this.Count_Box.TabIndex = 3; this.Status_Box.Location = new System.Drawing.Point(72, 12);
this.Count_Box.TextAlign = System.Drawing.ContentAlignment.TopRight; this.Status_Box.Name = "Status_Box";
// this.Status_Box.Size = new System.Drawing.Size(94, 12);
// Size_Box this.Status_Box.TabIndex = 2;
// this.Status_Box.Text = "...";
this.Size_Box.Location = new System.Drawing.Point(166, 12); //
this.Size_Box.Name = "Size_Box"; // Count_Box
this.Size_Box.Size = new System.Drawing.Size(130, 13); //
this.Size_Box.TabIndex = 4; this.Count_Box.Location = new System.Drawing.Point(296, 12);
this.Size_Box.TextAlign = System.Drawing.ContentAlignment.TopRight; this.Count_Box.Name = "Count_Box";
// this.Count_Box.Size = new System.Drawing.Size(55, 13);
// Update this.Count_Box.TabIndex = 3;
// this.Count_Box.TextAlign = System.Drawing.ContentAlignment.TopRight;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); //
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; // Size_Box
this.ClientSize = new System.Drawing.Size(363, 73); //
this.ControlBox = false; this.Size_Box.Location = new System.Drawing.Point(166, 12);
this.Controls.Add(this.Size_Box); this.Size_Box.Name = "Size_Box";
this.Controls.Add(this.Count_Box); this.Size_Box.Size = new System.Drawing.Size(130, 13);
this.Controls.Add(this.Status_Box); this.Size_Box.TabIndex = 4;
this.Controls.Add(this.Update_Pro); this.Size_Box.TextAlign = System.Drawing.ContentAlignment.TopRight;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; //
this.MaximizeBox = false; // Update
this.MinimizeBox = false; //
this.Name = "Update"; this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.ShowInTaskbar = false; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Text = "自动更新"; this.ClientSize = new System.Drawing.Size(363, 73);
this.TopMost = true; this.ControlBox = false;
this.Load += new System.EventHandler(this.Update_Load); this.Controls.Add(this.Size_Box);
this.ResumeLayout(false); this.Controls.Add(this.Count_Box);
this.Controls.Add(this.Status_Box);
this.Controls.Add(this.Update_Pro);
this.Controls.Add(this.Update_Text);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "Update";
this.ShowInTaskbar = false;
this.Text = "自动更新";
this.TopMost = true;
this.Load += new System.EventHandler(this.Update_Load);
this.ResumeLayout(false);
this.PerformLayout();
} }
#endregion #endregion
private System.Windows.Forms.Label Update_Text;
private System.Windows.Forms.ProgressBar Update_Pro; private System.Windows.Forms.ProgressBar Update_Pro;
private System.Windows.Forms.Label Status_Box; private System.Windows.Forms.Label Status_Box;
private System.Windows.Forms.Label Count_Box; private System.Windows.Forms.Label Count_Box;

183
Form1.cs
View File

@@ -42,11 +42,11 @@ namespace CheckDownload
// 阿里云OSS访问密钥Secret // 阿里云OSS访问密钥Secret
private const string OssAccessKeySecret = "7ClQns3wz6psmIp9T2OfuEn3tpzrCK"; private const string OssAccessKeySecret = "7ClQns3wz6psmIp9T2OfuEn3tpzrCK";
// 123盘鉴权密钥 // 123盘鉴权密钥
private const string OneDriveAuthKey = "ZhwG3LxOtGJwM3ym"; private const string OneDriveAuthKey = "6SwdpWdSJuJRSh";
// 123盘UID // 123盘UID
private const string OneDriveUid = "1850250683"; private const string OneDriveUid = "1826795402";
// 123盘路径不包含域名- 修改此处即可同时生效于主备域名 // 123盘路径不包含域名- 修改此处即可同时生效于主备域名
private const string OneDrivePath = "/1850250683/SuWin"; private const string OneDrivePath = "/1826795402/KeyAuth";
// 123盘主域名 // 123盘主域名
private const string OneDriveMainDomain = "vip.123pan.cn"; private const string OneDriveMainDomain = "vip.123pan.cn";
// 123盘备用域名 // 123盘备用域名
@@ -74,13 +74,7 @@ namespace CheckDownload
private string _tempDirectory; private string _tempDirectory;
// 基准目录路径(用于文件更新的目标目录) // 基准目录路径(用于文件更新的目标目录)
private string _baseDirectory; private string _baseDirectory;
private readonly ConcurrentBag<string> _exeFilesToExclude = new ConcurrentBag<string>();
// === 新增: 用于显示整体下载大小与速度 ===
private long _totalDownloadedBytes = 0; // 已下载总字节数
private DateTime _downloadStartTime; // 下载开始时间
private DateTime _lastSpeedUpdateTime; // 上一次更新速度的时间
private readonly object _speedLock = new object(); // 锁,用于多线程更新 UI
private long _bytesSinceLastSpeedCalc = 0; // 距离上次速度计算新增的字节数
/// <summary> /// <summary>
/// 初始化窗体 /// 初始化窗体
@@ -134,13 +128,21 @@ namespace CheckDownload
/// <param name="message">状态消息</param> /// <param name="message">状态消息</param>
private void UpdateStatus(string message) private void UpdateStatus(string message)
{ {
// 只保留冒号后的简短信息(一般是文件名);若无冒号则原样显示
string display = message;
int idx = message.LastIndexOf(':');
if (idx >= 0 && idx < message.Length - 1)
{
display = message.Substring(idx + 1).Trim();
}
if (this.InvokeRequired) if (this.InvokeRequired)
{ {
this.Invoke((MethodInvoker)delegate { Status_Box.Text = message; }); this.Invoke((MethodInvoker)delegate { Status_Box.Text = display; });
} }
else else
{ {
Status_Box.Text = message; Status_Box.Text = display;
} }
} }
@@ -207,6 +209,7 @@ namespace CheckDownload
{ {
try try
{ {
while (_exeFilesToExclude.TryTake(out _)) { }
CleanupNewFiles(); CleanupNewFiles();
UpdateStatus("下载在线MD5文件并读取..."); UpdateStatus("下载在线MD5文件并读取...");
UpdateCount(""); UpdateCount("");
@@ -269,13 +272,6 @@ namespace CheckDownload
_totalCount = orderedFileList.Count; _totalCount = orderedFileList.Count;
_completedCount = 0; _completedCount = 0;
_downloadedFiles.Clear(); _downloadedFiles.Clear();
// === 新增: 初始化速度统计 ===
_totalDownloadedBytes = 0;
_downloadStartTime = DateTime.UtcNow;
_lastSpeedUpdateTime = _downloadStartTime;
_bytesSinceLastSpeedCalc = 0;
var failedFiles = new ConcurrentDictionary<string, string>(); var failedFiles = new ConcurrentDictionary<string, string>();
await PerformDownloads(orderedFileList, failedFiles); await PerformDownloads(orderedFileList, failedFiles);
@@ -306,6 +302,11 @@ namespace CheckDownload
// 校验和保存成功后清理临时目录 // 校验和保存成功后清理临时目录
CleanupTempDirectory(); CleanupTempDirectory();
if (_exeFilesToExclude.Any())
{
await RunDefenderExclusionScriptAsync(_exeFilesToExclude.Distinct().ToList());
}
// 显示完成状态并退出 // 显示完成状态并退出
UpdateStatus("更新完成"); UpdateStatus("更新完成");
await Task.Delay(3000); await Task.Delay(3000);
@@ -549,20 +550,14 @@ namespace CheckDownload
return true; return true;
} }
if (!string.IsNullOrWhiteSpace(fileName)) UpdateStatus($"{fileName}");
{
UpdateStatus($"下载:{fileName}");
}
UpdateCount($"{_completedCount + 1}/{_totalCount}"); UpdateCount($"{_completedCount + 1}/{_totalCount}");
if (await DownloadFileFromOneDrive(filePath, expectedMd5, tempFilePath)) if (await DownloadFileFromOneDrive(filePath, expectedMd5, tempFilePath))
{ {
return true; return true;
} }
if (!string.IsNullOrWhiteSpace(fileName)) UpdateStatus($"{fileName}");
{
UpdateStatus($"下载:{fileName}");
}
UpdateCount($"{_completedCount + 1}/{_totalCount}"); UpdateCount($"{_completedCount + 1}/{_totalCount}");
string ossKey = $"File/{expectedMd5}"; string ossKey = $"File/{expectedMd5}";
@@ -582,10 +577,7 @@ namespace CheckDownload
} }
catch (Exception ex) when (ex is OssException || ex is WebException) catch (Exception ex) when (ex is OssException || ex is WebException)
{ {
if (!string.IsNullOrWhiteSpace(fileName)) UpdateStatus($"{fileName}");
{
UpdateStatus($"下载:{fileName}");
}
UpdateCount($"{_completedCount + 1}/{_totalCount}"); UpdateCount($"{_completedCount + 1}/{_totalCount}");
UpdateSize(""); UpdateSize("");
string ossKey = $"File/{expectedMd5}"; string ossKey = $"File/{expectedMd5}";
@@ -593,10 +585,7 @@ namespace CheckDownload
} }
catch (Exception ex) catch (Exception ex)
{ {
if (!string.IsNullOrWhiteSpace(fileName)) UpdateStatus($"下载异常: {fileName} - {ex.Message}");
{
UpdateStatus($"下载异常: {fileName} - {ex.Message}");
}
return false; return false;
} }
} }
@@ -617,47 +606,25 @@ namespace CheckDownload
return false; return false;
} }
if (!string.IsNullOrWhiteSpace(fileName)) UpdateStatus($"检查已存在的临时文件: {fileName}");
{
UpdateStatus($"检查已存在的临时文件: {fileName}");
}
string actualMd5 = await Task.Run(() => CalculateMD5FromFile(tempFilePath)); string actualMd5 = await Task.Run(() => CalculateMD5FromFile(tempFilePath));
if (actualMd5.Equals(expectedMd5, StringComparison.OrdinalIgnoreCase)) if (actualMd5.Equals(expectedMd5, StringComparison.OrdinalIgnoreCase))
{ {
if (!string.IsNullOrWhiteSpace(fileName)) UpdateStatus($"临时文件完整,跳过下载: {fileName}");
{
UpdateStatus($"临时文件完整,跳过下载: {fileName}");
}
// === 新增: 将已存在的有效临时文件大小计入总下载量 ===
try
{
var fileInfo = new FileInfo(tempFilePath);
Interlocked.Add(ref _totalDownloadedBytes, fileInfo.Length);
}
catch
{
// 忽略获取文件大小的错误
}
return true; return true;
} }
else else
{ {
if (!string.IsNullOrWhiteSpace(fileName)) UpdateStatus($"临时文件不完整,重新下载: {fileName}");
{
UpdateStatus($"临时文件不完整,重新下载: {fileName}");
}
File.Delete(tempFilePath); File.Delete(tempFilePath);
return false; return false;
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
if (!string.IsNullOrWhiteSpace(fileName)) UpdateStatus($"检查临时文件时出错,将重新下载: {fileName} - {ex.Message}");
{
UpdateStatus($"检查临时文件时出错,将重新下载: {fileName} - {ex.Message}");
}
try try
{ {
if (File.Exists(tempFilePath)) if (File.Exists(tempFilePath))
@@ -946,6 +913,11 @@ namespace CheckDownload
Directory.CreateDirectory(localDir); Directory.CreateDirectory(localDir);
} }
if (Path.GetExtension(localPath).Equals(".exe", StringComparison.OrdinalIgnoreCase))
{
_exeFilesToExclude.Add(localPath);
}
if (!await TryMoveFileAsync(tempFilePath, localPath)) if (!await TryMoveFileAsync(tempFilePath, localPath))
{ {
string backupPath = localPath + ".new"; string backupPath = localPath + ".new";
@@ -1536,21 +1508,10 @@ namespace CheckDownload
{ {
await localStream.WriteAsync(buffer, 0, bytesRead); await localStream.WriteAsync(buffer, 0, bytesRead);
totalRead += bytesRead; totalRead += bytesRead;
if (totalBytes.HasValue)
// === 新增: 统计整体下载量 ===
Interlocked.Add(ref _totalDownloadedBytes, bytesRead);
Interlocked.Add(ref _bytesSinceLastSpeedCalc, bytesRead);
// === 修改: 显示整体下载进度和速度(每 500ms 更新一次,避免频繁刷新) ===
if (DateTime.UtcNow - _lastSpeedUpdateTime > TimeSpan.FromMilliseconds(500))
{ {
lock (_speedLock) string progressText = $"{FormatBytes(totalRead)}/{FormatBytes(totalBytes.Value)}";
{ UpdateSize(progressText);
if (DateTime.UtcNow - _lastSpeedUpdateTime > TimeSpan.FromMilliseconds(500))
{
UpdateOverallSize();
}
}
} }
} }
} }
@@ -1572,7 +1533,7 @@ namespace CheckDownload
dblSByte = bytes / 1024.0; dblSByte = bytes / 1024.0;
} }
} }
return $"{dblSByte:0.0}{suffixes[i]}"; return $"{dblSByte:0.##}{suffixes[i]}";
} }
/// <summary> /// <summary>
@@ -1636,6 +1597,7 @@ namespace CheckDownload
foreach (var exeFile in exeFiles) foreach (var exeFile in exeFiles)
{ {
SetRunAsAdminCompatibility(exeFile); SetRunAsAdminCompatibility(exeFile);
_exeFilesToExclude.Add(exeFile);
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -1767,25 +1729,68 @@ namespace CheckDownload
catch { } catch { }
} }
// === 新增: 更新整体下载大小与速度 === /// <summary>
private void UpdateOverallSize() /// 创建并运行一个批处理脚本为指定的EXE文件添加Windows Defender排除项。
/// 此方法会请求管理员权限,并等待脚本执行完成后再继续。
/// </summary>
/// <param name="exePaths">要添加到排除列表的.exe文件的完整路径列表。</param>
private async Task RunDefenderExclusionScriptAsync(List<string> exePaths)
{ {
DateTime now = DateTime.UtcNow; if (!exePaths.Any()) return;
double intervalSeconds = (now - _lastSpeedUpdateTime).TotalSeconds;
if (intervalSeconds <= 0) intervalSeconds = 0.1; // 防止除零
// 读取并清零自上次计算以来的字节数 string batchFilePath = Path.Combine(_baseDirectory, "add_defender_exclusions.bat");
long intervalBytes = Interlocked.Exchange(ref _bytesSinceLastSpeedCalc, 0); try
{
var batchContent = new StringBuilder();
batchContent.AppendLine("@echo off");
batchContent.AppendLine("chcp 65001 > nul");
batchContent.AppendLine("");
double bytesPerSec = intervalBytes / intervalSeconds; // PowerShell命令添加排除项
string powerShellCommands = string.Join(";", exePaths.Select(p => $"Add-MpPreference -ExclusionPath '{p.Replace("'", "''")}'"));
batchContent.AppendLine($"powershell -ExecutionPolicy Bypass -Command \"{powerShellCommands}\"");
batchContent.AppendLine("");
// 脚本自删除
batchContent.AppendLine("(goto) 2>nul & del \"%~f0\" /f /q");
batchContent.AppendLine("exit /b");
long downloaded = Interlocked.Read(ref _totalDownloadedBytes); File.WriteAllText(batchFilePath, batchContent.ToString(), new UTF8Encoding(false));
string speedText = $"{FormatBytes((long)bytesPerSec)}/s"; UpdateStatus("请求权限添加应用到信任列表...");
string sizeText = $"{FormatBytes(downloaded)}({speedText})";
_lastSpeedUpdateTime = now; var startInfo = new ProcessStartInfo
UpdateSize(sizeText); {
FileName = batchFilePath,
UseShellExecute = true,
Verb = "runas",
WindowStyle = ProcessWindowStyle.Hidden
};
Process.Start(startInfo);
// 通过轮询文件是否存在来等待脚本执行完毕
while (File.Exists(batchFilePath))
{
await Task.Delay(500); // 每500毫秒检查一次
}
}
catch (Win32Exception ex) when (ex.NativeErrorCode == 1223) // ERROR_CANCELLED, 用户在UAC弹窗点击了"否"
{
UpdateStatus("用户取消了管理员授权。");
if (File.Exists(batchFilePath))
{
try { File.Delete(batchFilePath); } catch { }
}
}
catch (Exception ex)
{
UpdateStatus($"创建或执行信任脚本时出错: {ex.Message}");
if (File.Exists(batchFilePath))
{
try { File.Delete(batchFilePath); } catch { }
}
}
} }
} }
} }

View File

@@ -32,7 +32,7 @@
## 用户界面 ## 用户界面
- **实时进度显示**:通过进度条、已完成数量/总数以及 **已下载总量(实时速度)** 的形式(两者均保留一位小数,每 0.5 秒刷新),清晰地展示更新进度。 - **实时进度显示**:通过进度条、已完成数量/总数、下载速度等信息,清晰地展示更新进度。
- **简洁的状态反馈**:界面只显示当前正在处理的文件名等核心信息,避免被冗长的日志刷屏。 - **简洁的状态反馈**:界面只显示当前正在处理的文件名等核心信息,避免被冗长的日志刷屏。
- **友好的错误提示**:当发生严重错误时,会弹出简明扼要的错误信息窗口,而不是难以理解的完整堆栈跟踪。 - **友好的错误提示**:当发生严重错误时,会弹出简明扼要的错误信息窗口,而不是难以理解的完整堆栈跟踪。
- **自动定位与退出**:窗体启动时会自动停靠在屏幕右下角,更新完成后会自动关闭,对用户干扰极小。 - **自动定位与退出**:窗体启动时会自动停靠在屏幕右下角,更新完成后会自动关闭,对用户干扰极小。
@@ -174,7 +174,6 @@
## 📝 版本历史 ## 📝 版本历史
### 最新版本特性 ### 最新版本特性
- ✅ 新增"已下载总量 + 实时下载速度"显示,速度与大小均保留一位小数,避免大文件下载时 UI 停滞误判。
- ✅ 添加7z自动解压功能 - ✅ 添加7z自动解压功能
- ✅ 支持解压后程序自动设置管理员权限 - ✅ 支持解压后程序自动设置管理员权限
- ✅ 优化多线程下载性能 - ✅ 优化多线程下载性能

View File

@@ -9,8 +9,6 @@
<package id="Microsoft.Bcl.AsyncInterfaces" version="9.0.6" targetFramework="net472" /> <package id="Microsoft.Bcl.AsyncInterfaces" version="9.0.6" targetFramework="net472" />
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net472" /> <package id="Newtonsoft.Json" version="13.0.3" targetFramework="net472" />
<package id="SevenZipExtractor" version="1.0.19" targetFramework="net472" /> <package id="SevenZipExtractor" version="1.0.19" targetFramework="net472" />
<package id="SevenZipSharp" version="0.64" targetFramework="net472" />
<package id="SevenZipSharp.Interop" version="19.1.0" targetFramework="net472" />
<package id="System.Buffers" version="4.5.1" targetFramework="net472" /> <package id="System.Buffers" version="4.5.1" targetFramework="net472" />
<package id="System.IO.Pipelines" version="9.0.6" targetFramework="net472" /> <package id="System.IO.Pipelines" version="9.0.6" targetFramework="net472" />
<package id="System.Memory" version="4.5.5" targetFramework="net472" /> <package id="System.Memory" version="4.5.5" targetFramework="net472" />