diff --git a/AppCard.cs b/AppCard.cs
new file mode 100644
index 0000000..f23574e
--- /dev/null
+++ b/AppCard.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace AppStore
+{
+ public class AppCard : UserControl
+ {
+ private PictureBox iconBox;
+ private Label nameLabel;
+ private Button downloadBtn;
+
+ public string AppName { get; set; } = string.Empty;
+ public Image AppIcon { get; set; } = SystemIcons.Application.ToBitmap();
+ public string DownloadUrl { get; set; } = string.Empty;
+
+ public AppCard()
+ {
+ iconBox = new PictureBox();
+ nameLabel = new Label();
+ downloadBtn = new Button();
+ InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ this.Size = new Size(200, 120);
+ this.BackColor = Color.White;
+ this.BorderStyle = BorderStyle.FixedSingle;
+
+ // 应用图标
+ iconBox = new PictureBox();
+ iconBox.Size = new Size(64, 64);
+ iconBox.Location = new Point(10, 10);
+ iconBox.SizeMode = PictureBoxSizeMode.StretchImage;
+ this.Controls.Add(iconBox);
+
+ // 应用名称
+ nameLabel = new Label();
+ nameLabel.AutoSize = true;
+ nameLabel.Location = new Point(80, 15);
+ nameLabel.Font = new Font("Microsoft YaHei", 10, FontStyle.Bold);
+ this.Controls.Add(nameLabel);
+
+ // 下载按钮
+ downloadBtn = new Button();
+ downloadBtn.Text = "下载";
+ downloadBtn.Size = new Size(80, 30);
+ downloadBtn.Location = new Point(60, 80);
+ downloadBtn.BackColor = Color.FromArgb(0, 120, 215);
+ downloadBtn.ForeColor = Color.White;
+ downloadBtn.FlatStyle = FlatStyle.Flat;
+ downloadBtn.FlatAppearance.BorderSize = 0;
+ downloadBtn.Click += DownloadBtn_Click;
+ this.Controls.Add(downloadBtn);
+ }
+
+ public void UpdateDisplay()
+ {
+ nameLabel.Text = AppName;
+ iconBox.Image = AppIcon;
+ }
+
+ private void DownloadBtn_Click(object sender, EventArgs e)
+ {
+ if (sender == null || e == null) return;
+ if (!string.IsNullOrEmpty(DownloadUrl))
+ {
+ try
+ {
+ string fileName = $"{AppName.Replace(" ", "_")}.exe";
+ DownloadManager.Instance.StartDownload(fileName, DownloadUrl);
+ MessageBox.Show($"已开始下载: {AppName}", "下载中", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show($"下载失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+ }
+ }
+ }
+}
diff --git a/AppStore.csproj b/AppStore.csproj
new file mode 100644
index 0000000..f8301fd
--- /dev/null
+++ b/AppStore.csproj
@@ -0,0 +1,30 @@
+
+
+ CS8622
+
+
+
+ WinExe
+ net8.0-windows
+ enable
+ true
+ enable
+ CS8618
+ img\ico\icon.ico
+ x86;x64
+
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
+
diff --git a/DownloadItem.cs b/DownloadItem.cs
new file mode 100644
index 0000000..6882f11
--- /dev/null
+++ b/DownloadItem.cs
@@ -0,0 +1,92 @@
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace AppStore
+{
+ public class DownloadItem : UserControl
+ {
+ private Label nameLabel;
+ private ProgressBar progressBar;
+ private Label statusLabel;
+ private Button cancelBtn;
+
+ public string FileName { get; set; } = string.Empty;
+ public int Progress { get; set; }
+ public string Status { get; set; } = string.Empty;
+
+ public DownloadItem()
+ {
+ nameLabel = new Label();
+ progressBar = new ProgressBar();
+ statusLabel = new Label();
+ cancelBtn = new Button();
+
+ InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ this.Size = new Size(400, 60);
+ this.BackColor = Color.White;
+ this.BorderStyle = BorderStyle.FixedSingle;
+
+ // 文件名标签
+ nameLabel = new Label();
+ nameLabel.AutoSize = true;
+ nameLabel.Location = new Point(10, 10);
+ nameLabel.Font = new Font("Microsoft YaHei", 9, FontStyle.Bold);
+ this.Controls.Add(nameLabel);
+
+ // 进度条
+ progressBar = new ProgressBar();
+ progressBar.Size = new Size(200, 20);
+ progressBar.Location = new Point(10, 30);
+ this.Controls.Add(progressBar);
+
+ // 状态标签
+ statusLabel = new Label();
+ statusLabel.AutoSize = true;
+ statusLabel.Location = new Point(220, 30);
+ statusLabel.Font = new Font("Microsoft YaHei", 8);
+ this.Controls.Add(statusLabel);
+
+ // 取消按钮
+ cancelBtn = new Button();
+ cancelBtn.Text = "取消";
+ cancelBtn.Size = new Size(60, 25);
+ cancelBtn.Location = new Point(320, 30);
+ cancelBtn.Click += CancelBtn_Click;
+ this.Controls.Add(cancelBtn);
+ }
+
+ public void UpdateDisplay()
+ {
+ nameLabel.Text = FileName;
+ progressBar.Value = Progress;
+ statusLabel.Text = Status;
+ }
+
+ private void CancelBtn_Click(object sender, EventArgs e)
+ {
+ if (sender == null || e == null) return;
+ if (InvokeRequired)
+ {
+ Invoke(new EventHandler(CancelBtn_Click), sender, e);
+ return;
+ }
+
+ try
+ {
+ DownloadManager.Instance.CancelDownload(this);
+ Status = "已取消";
+ UpdateDisplay();
+ }
+ catch (Exception ex)
+ {
+ Status = $"取消失败: {ex.Message}";
+ UpdateDisplay();
+ }
+ }
+ }
+}
diff --git a/DownloadManager.cs b/DownloadManager.cs
new file mode 100644
index 0000000..fbe7f39
--- /dev/null
+++ b/DownloadManager.cs
@@ -0,0 +1,306 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace AppStore
+{
+ public class DownloadManager
+ {
+ private static DownloadManager instance = null!;
+ public static DownloadManager Instance => instance ??= new DownloadManager();
+
+ private Process? currentProcess;
+ public List DownloadItems { get; } = new List();
+
+ public event Action DownloadAdded = delegate { };
+ public event Action DownloadProgressChanged = delegate { };
+ public event Action DownloadCompleted = delegate { };
+
+ // 内部类封装进程结果
+ private class ProcessResult
+ {
+ public int ExitCode { get; set; } = -1;
+ public bool HasExited { get; set; }
+ }
+
+ // 安全获取进程结果
+ private ProcessResult GetProcessResult(Process? process)
+ {
+ var result = new ProcessResult();
+ if (process == null) return result;
+
+ try
+ {
+ if (!process.HasExited)
+ {
+ process.WaitForExit(5000);
+ }
+
+ result.HasExited = process.HasExited;
+ if (result.HasExited)
+ {
+ result.ExitCode = process.ExitCode;
+ }
+ }
+ catch
+ {
+ // 忽略所有异常,使用默认值
+ }
+
+ return result;
+ }
+
+ public void StartDownload(string fileName, string url)
+ {
+ var downloadItem = new DownloadItem
+ {
+ FileName = fileName,
+ Progress = 0,
+ Status = "准备下载"
+ };
+
+ DownloadItems.Add(downloadItem);
+ DownloadAdded?.Invoke(downloadItem);
+
+ Task.Run(() => DownloadFile(downloadItem, fileName, url));
+ }
+
+ private void DownloadFile(DownloadItem downloadItem, string fileName, string url)
+ {
+ try
+ {
+ // 设置下载目录为用户文件夹中的Downloads
+ var downloadsDir = Path.Combine(
+ Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
+ "Downloads");
+ Directory.CreateDirectory(downloadsDir);
+
+ // 构建aria2c路径
+ var aria2cPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "resource", "aria2c.exe");
+
+ if (!File.Exists(aria2cPath))
+ {
+ throw new FileNotFoundException($"找不到aria2c.exe: {aria2cPath}");
+ }
+
+ // 设置线程数为16并添加详细日志
+ var arguments = $"--out={fileName} --dir=\"{downloadsDir}\" --split=16 --max-connection-per-server=16 {url}";
+ Console.WriteLine($"下载目录: {downloadsDir}");
+
+ currentProcess = new Process
+ {
+ StartInfo = new ProcessStartInfo
+ {
+ FileName = aria2cPath,
+ Arguments = arguments,
+ WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory,
+ UseShellExecute = false,
+ CreateNoWindow = true,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true
+ }
+ };
+
+ // 获取目标文件路径
+ string downloadPath = Path.Combine(
+ Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
+ "Downloads",
+ fileName);
+
+ long totalSize = 0;
+
+ // 添加进度检测超时机制
+ var progressTimer = new System.Timers.Timer(5000); // 5秒无更新视为完成
+ progressTimer.Elapsed += (s, e) => {
+ progressTimer.Stop();
+ if (downloadItem.Progress < 100) {
+ downloadItem.Progress = 100;
+ downloadItem.Status = "下载完成 (100%)";
+ DownloadProgressChanged?.Invoke(downloadItem);
+ }
+ };
+
+ currentProcess.OutputDataReceived += (sender, e) =>
+ {
+ if (!string.IsNullOrEmpty(e.Data))
+ {
+ Console.WriteLine($"输出: {e.Data}");
+
+ // 重置超时计时器
+ progressTimer.Stop();
+ progressTimer.Start();
+
+ // 解析总大小
+ if (e.Data.Contains("Length:"))
+ {
+ var sizeStr = e.Data.Split(new[]{"Length:"}, StringSplitOptions.RemoveEmptyEntries)[1]
+ .Split('(')[0].Trim();
+ if (long.TryParse(sizeStr, out totalSize))
+ {
+ Console.WriteLine($"检测到文件总大小: {totalSize} bytes");
+ }
+ }
+
+ // 解析进度百分比
+ if (e.Data.Contains("%)"))
+ {
+ var start = e.Data.IndexOf("(") + 1;
+ var end = e.Data.IndexOf("%)");
+ if (start > 0 && end > start)
+ {
+ var progressStr = e.Data.Substring(start, end - start);
+ if (int.TryParse(progressStr, out int progress))
+ {
+ progress = Math.Min(progress, 100);
+ downloadItem.Progress = progress;
+ downloadItem.Status = $"下载中({progress}%)";
+ DownloadProgressChanged?.Invoke(downloadItem);
+ }
+ }
+ }
+ }
+ };
+
+ currentProcess.ErrorDataReceived += (sender, e) =>
+ {
+ if (!string.IsNullOrEmpty(e.Data))
+ {
+ Console.WriteLine($"错误: {e.Data}");
+ downloadItem.Status = $"错误: {e.Data}";
+ DownloadProgressChanged?.Invoke(downloadItem);
+ }
+ };
+
+ currentProcess.Exited += (sender, e) =>
+ {
+ var process = currentProcess;
+ if (process == null) return;
+
+ var result = GetProcessResult(process);
+
+ if (result.ExitCode == 0)
+ {
+ // 最终状态强制更新
+ downloadItem.Progress = 100;
+ downloadItem.Status = "下载完成 (100%)";
+
+ // 验证文件完整性
+ string downloadPath = Path.Combine(
+ Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
+ "Downloads",
+ downloadItem.FileName);
+
+ if (File.Exists(downloadPath))
+ {
+ Console.WriteLine($"文件下载完成: {downloadPath}");
+ }
+ else
+ {
+ Console.WriteLine("警告: 下载完成但文件不存在");
+ }
+
+ // 触发界面更新
+ DownloadProgressChanged?.Invoke(downloadItem);
+ DownloadCompleted?.Invoke(downloadItem);
+ downloadItem.UpdateDisplay();
+
+ try
+ {
+ // 双重确保在主线程显示提示
+ if (Application.OpenForms.Count > 0)
+ {
+ var mainForm = Application.OpenForms[0];
+ mainForm.Invoke((MethodInvoker)delegate {
+ MessageBox.Show(mainForm,
+ $"文件 {downloadItem.FileName} 已成功下载到:\n{Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Downloads", downloadItem.FileName)}",
+ "下载完成",
+ MessageBoxButtons.OK,
+ MessageBoxIcon.Information);
+ });
+ }
+ else
+ {
+ Console.WriteLine("下载完成提示:无法找到主窗体");
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"显示下载完成提示时出错:{ex}");
+ }
+ }
+ else
+ {
+ downloadItem.Status = $"下载失败 (代码: {result.ExitCode})";
+ MessageBox.Show($"文件 {downloadItem.FileName} 下载失败", "下载失败",
+ MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+
+ DownloadCompleted?.Invoke(downloadItem);
+
+ try
+ {
+ process?.Dispose();
+ }
+ finally
+ {
+ if (process != null)
+ {
+ currentProcess = null;
+ }
+ }
+
+ // 强制更新显示
+ downloadItem.UpdateDisplay();
+ };
+
+ Console.WriteLine($"启动aria2c: {aria2cPath}");
+ Console.WriteLine($"参数: {arguments}");
+
+ if (!currentProcess.Start())
+ {
+ throw new Exception("进程启动失败");
+ }
+
+ currentProcess.BeginOutputReadLine();
+ currentProcess.BeginErrorReadLine();
+ progressTimer.Start();
+ }
+ catch (Exception ex)
+ {
+ downloadItem.Status = $"下载错误: {ex.Message}";
+ Console.WriteLine($"下载错误: {ex}");
+ DownloadCompleted?.Invoke(downloadItem);
+ }
+ }
+
+ public void CancelDownload(DownloadItem item)
+ {
+ try
+ {
+ var process = currentProcess;
+ if (process == null || process.HasExited || process.StartInfo == null)
+ {
+ item.Status = "已取消";
+ DownloadProgressChanged?.Invoke(item);
+ return;
+ }
+
+ process.Kill();
+ process.Dispose();
+ currentProcess = null;
+
+ item.Status = "已取消";
+ DownloadProgressChanged?.Invoke(item);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"取消下载时出错: {ex}");
+ item.Status = $"取消失败: {ex.Message}";
+ DownloadProgressChanged?.Invoke(item);
+ }
+ }
+ }
+}
diff --git a/MainForm.cs b/MainForm.cs
new file mode 100644
index 0000000..e7ef59a
--- /dev/null
+++ b/MainForm.cs
@@ -0,0 +1,158 @@
+#nullable enable
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace AppStore
+{
+ public class MainForm : Form
+ {
+ private Button btnApps = null!;
+ private Button btnDownloads = null!;
+ private Panel contentPanel = null!;
+
+ private void InitializeComponent()
+ {
+ // 窗体基本设置
+ this.Text = "应用商店";
+ this.Size = new Size(800, 600);
+ this.StartPosition = FormStartPosition.CenterScreen;
+ this.Icon = new Icon("img/ico/icon.ico");
+
+ // 顶部按钮面板
+ Panel buttonPanel = new Panel();
+ buttonPanel.Dock = DockStyle.Top;
+ buttonPanel.Height = 50;
+ buttonPanel.BackColor = Color.LightGray;
+
+ // 软件下载按钮
+ btnApps = new Button();
+ btnApps.Text = "软件下载";
+ btnApps.Size = new Size(100, 30);
+ btnApps.Location = new Point(20, 10);
+ btnApps.Font = new Font("Microsoft YaHei", 9);
+ btnApps.Click += (s, e) => ShowAppsView();
+ buttonPanel.Controls.Add(btnApps);
+
+ // 下载进度按钮
+ btnDownloads = new Button();
+ btnDownloads.Text = "下载进度";
+ btnDownloads.Size = new Size(100, 30);
+ btnDownloads.Location = new Point(140, 10);
+ btnDownloads.Font = new Font("Microsoft YaHei", 9);
+ btnDownloads.Click += (s, e) => ShowDownloadsView();
+ buttonPanel.Controls.Add(btnDownloads);
+
+ this.Controls.Add(buttonPanel);
+
+ // 内容区域
+ contentPanel = new Panel();
+ contentPanel.Dock = DockStyle.Fill;
+ contentPanel.Padding = new Padding(20);
+ this.Controls.Add(contentPanel);
+
+ // 默认显示软件下载视图
+ ShowAppsView();
+ }
+
+ private void ShowAppsView()
+ {
+ contentPanel.Controls.Clear();
+
+ // 使用FlowLayoutPanel来组织应用卡片
+ // 使用FlowLayoutPanel实现自动流式布局
+ FlowLayoutPanel flowPanel = new FlowLayoutPanel();
+ flowPanel.Dock = DockStyle.Fill;
+ flowPanel.AutoScroll = true;
+ flowPanel.Padding = new Padding(10, 30, 10, 10); // 增加顶部间距
+ flowPanel.WrapContents = true;
+ contentPanel.Controls.Add(flowPanel);
+
+ // 创建WindowsCleaner应用卡片
+ AppCard windowsCleanerCard = new AppCard();
+ windowsCleanerCard.AppName = "WindowsCleaner";
+ windowsCleanerCard.DownloadUrl = "https://ghproxy.net/https://github.com/darkmatter2048/WindowsCleaner/releases/download/v5.0.8/windowscleaner_v5.0.8_amd64_x64_setup.exe";
+
+ try
+ {
+ // 加载应用图标
+ windowsCleanerCard.AppIcon = Image.FromFile("img/png/WindowsCleaner.png");
+ }
+ catch
+ {
+ // 如果图标加载失败,使用默认图标
+ windowsCleanerCard.AppIcon = SystemIcons.Application.ToBitmap();
+ }
+
+ windowsCleanerCard.UpdateDisplay();
+ // 添加卡片到流式布局
+ flowPanel.Controls.Add(windowsCleanerCard);
+ }
+
+ private FlowLayoutPanel downloadsFlowPanel = new FlowLayoutPanel();
+ private List downloadItems = new List();
+
+ public MainForm()
+ {
+ InitializeComponent();
+ // 订阅下载管理器事件
+ DownloadManager.Instance.DownloadAdded += OnDownloadAdded;
+ DownloadManager.Instance.DownloadProgressChanged += OnDownloadProgressChanged;
+ DownloadManager.Instance.DownloadCompleted += OnDownloadCompleted;
+ }
+
+ private void ShowDownloadsView()
+ {
+ contentPanel.Controls.Clear();
+
+ // 使用FlowLayoutPanel组织下载项
+ downloadsFlowPanel = new FlowLayoutPanel();
+ downloadsFlowPanel.Dock = DockStyle.Fill;
+ downloadsFlowPanel.AutoScroll = true;
+ downloadsFlowPanel.Padding = new Padding(10, 30, 10, 10); // 增加顶部间距
+ downloadsFlowPanel.FlowDirection = FlowDirection.TopDown;
+ downloadsFlowPanel.WrapContents = false;
+ contentPanel.Controls.Add(downloadsFlowPanel);
+
+ // 显示所有下载项
+ foreach (var item in DownloadManager.Instance.DownloadItems)
+ {
+ downloadsFlowPanel.Controls.Add(item);
+ }
+ }
+
+ private void OnDownloadAdded(DownloadItem item)
+ {
+ if (InvokeRequired)
+ {
+ Invoke(new Action(OnDownloadAdded), item);
+ return;
+ }
+
+ downloadItems.Add(item);
+ downloadsFlowPanel?.Controls.Add(item);
+ }
+
+ private void OnDownloadProgressChanged(DownloadItem item)
+ {
+ if (InvokeRequired)
+ {
+ Invoke(new Action(OnDownloadProgressChanged), item);
+ return;
+ }
+
+ item.UpdateDisplay();
+ }
+
+ private void OnDownloadCompleted(DownloadItem item)
+ {
+ if (InvokeRequired)
+ {
+ Invoke(new Action(OnDownloadCompleted), item);
+ return;
+ }
+
+ item.UpdateDisplay();
+ }
+ }
+}
diff --git a/Program.cs b/Program.cs
new file mode 100644
index 0000000..9ce17df
--- /dev/null
+++ b/Program.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Windows.Forms;
+
+namespace AppStore
+{
+ static class Program
+ {
+ [STAThread]
+ static void Main()
+ {
+ Application.EnableVisualStyles();
+ Application.SetCompatibleTextRenderingDefault(false);
+ Application.Run(new MainForm());
+ }
+ }
+}
diff --git a/img/ico/icon.ico b/img/ico/icon.ico
new file mode 100644
index 0000000..d973473
Binary files /dev/null and b/img/ico/icon.ico differ
diff --git a/img/png/WindowsCleaner.png b/img/png/WindowsCleaner.png
new file mode 100644
index 0000000..5d9e8a5
Binary files /dev/null and b/img/png/WindowsCleaner.png differ
diff --git a/img/png/kortapp-z.png b/img/png/kortapp-z.png
new file mode 100644
index 0000000..f92a09a
Binary files /dev/null and b/img/png/kortapp-z.png differ
diff --git a/resource/aria2c.exe b/resource/aria2c.exe
new file mode 100644
index 0000000..5004e10
Binary files /dev/null and b/resource/aria2c.exe differ