Compare commits

...

30 Commits

Author SHA1 Message Date
zsyg
a777991b8c 添加ClamAV图标 2025-07-05 19:34:02 +08:00
zsyg
e2c6c52b32 Add files via upload 2025-07-05 19:33:25 +08:00
zsyg
33089c39b6 Update features.html 2025-07-05 19:15:03 +08:00
zsyg
45805178cc 修改版本号 2025-07-05 19:09:08 +08:00
zsyg
08a11f025a 修复bug和扩展功能 2025-07-05 19:08:44 +08:00
zsyg
5bb3886bc5 添加乌班图的图标 2025-07-05 17:58:10 +08:00
zsyg
ce5f964776 添加应用卡片 2025-07-05 17:57:27 +08:00
zsyg
f52c7908d7 添加应用卡片图标 2025-07-05 17:32:23 +08:00
zsyg
abcbf06493 添加应用卡片图标 2025-07-05 17:32:04 +08:00
zsyg
f56bcb3627 添加应用卡片图标 2025-07-05 17:31:40 +08:00
zsyg
f789c7904a 修改版本号 2025-07-05 17:30:57 +08:00
zsyg
e04709637c 修改版本号 2025-07-05 17:30:38 +08:00
zsyg
e39f976607 添加更多应用卡片 2025-07-05 17:30:18 +08:00
zsyg
0d9ec0ad44 修改版本号 2025-07-05 16:44:38 +08:00
zsyg
122ada92d9 修改版本号 2025-07-05 16:44:11 +08:00
zsyg
d571729c89 修改版本号 2025-07-05 16:43:38 +08:00
zsyg
351e1e97c3 修改布局 2025-07-05 16:43:14 +08:00
zsyg
cff4c39e8c 添加版本号 2025-07-05 14:42:42 +08:00
zsyg
5f41f57e8d Add files via upload 2025-07-05 14:41:38 +08:00
zsyg
f2756ddbd8 添加图标 2025-07-05 14:40:40 +08:00
zsyg
d7a90ca422 添加notepad--图标 2025-07-05 14:30:46 +08:00
zsyg
7404bdfb5d 添加notepad-- 2025-07-05 14:28:40 +08:00
zsyg
5e8de310df 添加图标提取器图标 2025-07-05 14:17:32 +08:00
zsyg
f3cca9b3a1 添加图标提取器代码 2025-07-05 14:16:38 +08:00
zsyg
2154f465b7 Add files via upload 2025-07-05 14:16:00 +08:00
zsyg
99bbda4668 添加版本号 2025-07-05 10:24:08 +08:00
zsyg
d1d69da3e3 Add files via upload 2025-07-05 10:22:19 +08:00
zsyg
4c8cb807d9 添加ollama 2025-07-05 10:20:04 +08:00
zsyg
1ad64feab9 添加ollama 2025-07-05 10:19:19 +08:00
zsyg
ef7c582c50 删除视频压缩工具 2025-07-02 20:14:29 +08:00
29 changed files with 1239 additions and 611 deletions

View File

@@ -57,7 +57,7 @@ namespace AppStore
// 初始化并添加应用信息 // 初始化并添加应用信息
infoLabel = new Label(); infoLabel = new Label();
infoLabel.Text = "kortapp-z\n版本: 1.1.4\n作者: zs-yg\n一个简单、开源的应用商店\nkortapp-z是完全免费\n基于.NET8和C/C++的软件"; infoLabel.Text = "kortapp-z\n版本: 1.2.4\n作者: zs-yg\n一个简单、开源的应用商店\nkortapp-z是完全免费\n基于.NET8和C/C++的软件";
infoLabel.Font = new Font("Microsoft YaHei", 12); infoLabel.Font = new Font("Microsoft YaHei", 12);
infoLabel.AutoSize = false; infoLabel.AutoSize = false;
infoLabel.Width = 300; infoLabel.Width = 300;

View File

@@ -54,9 +54,23 @@ namespace AppStore
this.Padding = new Padding(10); this.Padding = new Padding(10);
// 异步初始化卡片路径和边框 // 异步初始化卡片路径和边框
// 预加载边框路径
Task.Run(() => { Task.Run(() => {
InitializeCardPath(); InitializeCardPath();
InitializeBorder(); InitializeBorder();
// 确保在主线程注册事件
this.Invoke((MethodInvoker)(() => {
this.Paint += (sender, e) => {
if (BorderCache.IsEmpty)
{
Task.Run(() => {
InitializeBorder();
this.Invoke((MethodInvoker)(() => this.Invalidate()));
});
}
};
}));
}); });
// 应用图标 - 添加null检查 // 应用图标 - 添加null检查
@@ -187,52 +201,58 @@ namespace AppStore
// 使用卡片尺寸作为缓存键 // 使用卡片尺寸作为缓存键
string cacheKey = $"{Width}_{Height}_10"; string cacheKey = $"{Width}_{Height}_10";
// 检查缓存中是否已有路径 // 双重检查锁模式确保线程安全
if (!BorderCache.TryGetValue(cacheKey, out var borderPath)) if (!BorderCache.TryGetValue(cacheKey, out var borderPath))
{ {
// 创建临时文件存储路径数据 lock (BorderCache)
string tempFile = Path.GetTempFileName();
try
{ {
// 配置C++程序启动参数 if (!BorderCache.TryGetValue(cacheKey, out borderPath))
ProcessStartInfo startInfo = new ProcessStartInfo
{ {
FileName = Path.Combine(Application.StartupPath, "resource", "border_renderer.exe"), // 创建临时文件存储路径数据
Arguments = $"{Width} {Height} 10 \"{tempFile}\"", // 传递宽高和圆角半径 string tempFile = Path.GetTempFileName();
UseShellExecute = false, // 不显示命令行窗口 try
CreateNoWindow = true // 静默运行
};
// 启动C++程序计算路径
using (var process = Process.Start(startInfo))
{
process.WaitForExit();
// 检查计算结果
if (process.ExitCode == 0 && File.Exists(tempFile))
{ {
// 读取C++程序生成的路径点 // 配置C++程序启动参数
var lines = File.ReadAllLines(tempFile); ProcessStartInfo startInfo = new ProcessStartInfo
PointF[] points = lines.Select(line => { {
var parts = line.Split(','); // 解析坐标点 FileName = Path.Combine(Application.StartupPath, "resource", "border_renderer.exe"),
return new PointF(float.Parse(parts[0]), float.Parse(parts[1])); Arguments = $"{Width} {Height} 10 \"{tempFile}\"", // 传递宽高和圆角半径
}).ToArray(); UseShellExecute = false, // 不显示命令行窗口
CreateNoWindow = true // 静默运行
};
// 创建GraphicsPath对象 // 启动C++程序计算路径
borderPath = new System.Drawing.Drawing2D.GraphicsPath(); using (var process = Process.Start(startInfo))
borderPath.AddLines(points); // 添加路径点 {
process.WaitForExit();
// 缓存路径对象 // 检查计算结果
BorderCache.TryAdd(cacheKey, borderPath); if (process.ExitCode == 0 && File.Exists(tempFile))
{
// 读取C++程序生成的路径点
var lines = File.ReadAllLines(tempFile);
PointF[] points = lines.Select(line => {
var parts = line.Split(','); // 解析坐标点
return new PointF(float.Parse(parts[0]), float.Parse(parts[1]));
}).ToArray();
// 创建GraphicsPath对象
borderPath = new System.Drawing.Drawing2D.GraphicsPath();
borderPath.AddLines(points); // 添加路径点
// 缓存路径对象
BorderCache.TryAdd(cacheKey, borderPath);
}
}
}
finally
{
// 确保临时文件被删除
if (File.Exists(tempFile))
{
File.Delete(tempFile);
}
} }
}
}
finally
{
// 确保临时文件被删除
if (File.Exists(tempFile))
{
File.Delete(tempFile);
} }
} }
} }
@@ -243,6 +263,12 @@ namespace AppStore
{ {
base.OnPaint(e); base.OnPaint(e);
// 确保边框已初始化
if (BorderCache.IsEmpty)
{
InitializeBorder();
}
// 绘制背景 // 绘制背景
using (var brush = new SolidBrush(this.BackColor)) { using (var brush = new SolidBrush(this.BackColor)) {
e.Graphics.FillRectangle(brush, this.ClientRectangle); e.Graphics.FillRectangle(brush, this.ClientRectangle);

View File

@@ -48,7 +48,7 @@ namespace AppStore
private ProcessResult GetProcessResult(Process? process) private ProcessResult GetProcessResult(Process? process)
{ {
var result = new ProcessResult(); var result = new ProcessResult();
if (process == null) return result; if (process == null || process.StartInfo == null) return result;
try try
{ {
@@ -363,6 +363,7 @@ namespace AppStore
private string GetDownloadPath() private string GetDownloadPath()
{ {
string fallbackPath = string.Empty;
// 1. 优先读取用户设置的下载路径 // 1. 优先读取用户设置的下载路径
try try
{ {
@@ -481,9 +482,18 @@ namespace AppStore
// 3. 最终回退到相对路径 ~/Downloads // 3. 最终回退到相对路径 ~/Downloads
string relativePath = "~/Downloads"; string relativePath = "~/Downloads";
string userProfile = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) ?? string.Empty; string userProfile = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) ??
string fallbackPath = relativePath.Replace("~", userProfile); Environment.GetFolderPath(Environment.SpecialFolder.Desktop) ??
fallbackPath = Path.GetFullPath(fallbackPath); AppDomain.CurrentDomain.BaseDirectory;
if (!string.IsNullOrEmpty(userProfile))
{
fallbackPath = relativePath.Replace("~", userProfile);
if (!string.IsNullOrEmpty(fallbackPath))
{
fallbackPath = Path.GetFullPath(fallbackPath);
}
}
try { try {
Directory.CreateDirectory(fallbackPath); Directory.CreateDirectory(fallbackPath);

View File

@@ -248,6 +248,7 @@ namespace AppStore
contentPanel.Dock = DockStyle.Fill; contentPanel.Dock = DockStyle.Fill;
contentPanel.BackColor = ThemeManager.BackgroundColor; contentPanel.BackColor = ThemeManager.BackgroundColor;
contentPanel.Padding = new Padding(20); contentPanel.Padding = new Padding(20);
contentPanel.AutoScroll = true;
this.Controls.Add(contentPanel); this.Controls.Add(contentPanel);
// 添加分隔线 // 添加分隔线
@@ -464,44 +465,6 @@ namespace AppStore
}; };
flowPanel.Controls.Add(systemInfoCard); flowPanel.Controls.Add(systemInfoCard);
// 视频压缩工具卡片
var videoCompressorCard = new ToolCard();
videoCompressorCard.ToolName = "视频压缩工具";
try
{
string iconPath = Path.Combine(Application.StartupPath, "img", "resource", "png", "video_compressor.png");
if (File.Exists(iconPath))
{
videoCompressorCard.ToolIcon = Image.FromFile(iconPath);
}
else
{
videoCompressorCard.ToolIcon = SystemIcons.Shield.ToBitmap();
}
}
catch
{
videoCompressorCard.ToolIcon = SystemIcons.Shield.ToBitmap();
}
videoCompressorCard.UpdateDisplay();
videoCompressorCard.ToolCardClicked += (s, e) => {
try {
string toolPath = Path.Combine(Application.StartupPath, "resource", "video_compressor.exe");
if (File.Exists(toolPath)) {
Process.Start(toolPath);
} else {
MessageBox.Show("视频压缩工具未找到,请确保已正确安装", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
} catch (Exception ex) {
MessageBox.Show($"启动视频压缩工具失败: {ex.Message}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
};
flowPanel.Controls.Add(videoCompressorCard);
// 计算器工具卡片 // 计算器工具卡片
var calculatorCard = new CalculatorToolCard(); var calculatorCard = new CalculatorToolCard();
try try
@@ -589,6 +552,23 @@ namespace AppStore
} }
flowPanel.Controls.Add(selfStartingManagerCard); flowPanel.Controls.Add(selfStartingManagerCard);
// 图标提取器工具卡片
var iconExtractorCard = new AppStore.Tools.IconExtractor.IconExtractorToolCard();
try
{
string iconPath = Path.Combine(Application.StartupPath, "img", "resource", "png", "ico_extractor.png");
if (File.Exists(iconPath))
{
iconExtractorCard.ToolIcon = Image.FromFile(iconPath);
}
iconExtractorCard.UpdateDisplay();
}
catch (Exception ex)
{
Logger.LogError("加载图标提取器图标失败", ex);
}
flowPanel.Controls.Add(iconExtractorCard);
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -656,11 +636,11 @@ namespace AppStore
flowPanel.Dock = DockStyle.Fill; flowPanel.Dock = DockStyle.Fill;
flowPanel.AutoScroll = true; flowPanel.AutoScroll = true;
flowPanel.Padding = new Padding(15, 15, 15, 15); flowPanel.Padding = new Padding(15, 15, 15, 15);
flowPanel.WrapContents = true; flowPanel.WrapContents = false;
flowPanel.Margin = new Padding(0); flowPanel.Margin = new Padding(0);
flowPanel.AutoSize = true; flowPanel.AutoSize = true;
flowPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; flowPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink;
flowPanel.AutoScrollMinSize = new Size(0, 3350); flowPanel.AutoScrollMinSize = new Size(0, 5000);
// 创建搜索框 // 创建搜索框
TextBox searchBox = new TextBox(); TextBox searchBox = new TextBox();
@@ -688,11 +668,11 @@ namespace AppStore
flowPanel.Dock = DockStyle.Fill; flowPanel.Dock = DockStyle.Fill;
flowPanel.AutoScroll = true; flowPanel.AutoScroll = true;
flowPanel.Padding = new Padding(15, 60, 15, 15); flowPanel.Padding = new Padding(15, 60, 15, 15);
flowPanel.WrapContents = true; flowPanel.WrapContents = false;
flowPanel.Margin = new Padding(0); flowPanel.Margin = new Padding(0);
flowPanel.AutoSize = true; flowPanel.AutoSize = true;
flowPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; flowPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink;
flowPanel.AutoScrollMinSize = new Size(0, 3350); flowPanel.AutoScrollMinSize = new Size(0, 5000);
contentPanel.Controls.Add(flowPanel); contentPanel.Controls.Add(flowPanel);
// 添加窗体关闭事件处理 // 添加窗体关闭事件处理
@@ -730,7 +710,7 @@ namespace AppStore
flowPanel.Margin = new Padding(0); flowPanel.Margin = new Padding(0);
flowPanel.AutoSize = true; flowPanel.AutoSize = true;
flowPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; flowPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink;
flowPanel.AutoScrollMinSize = new Size(0, 3350); flowPanel.AutoScrollMinSize = new Size(0, 3800);//大概一行250像素
contentPanel.Controls.Add(flowPanel); contentPanel.Controls.Add(flowPanel);
// 添加所有应用卡片并恢复位置 // 添加所有应用卡片并恢复位置
@@ -806,6 +786,11 @@ namespace AppStore
"https://ghproxy.net/https://github.com/msys2/msys2-installer/releases/download/2025-02-21/msys2-x86_64-20250221.exe", "https://ghproxy.net/https://github.com/msys2/msys2-installer/releases/download/2025-02-21/msys2-x86_64-20250221.exe",
"img/png/MSYS2.png")); "img/png/MSYS2.png"));
flowPanel.Controls.Add(CreateAppCard(
"OpenJDK by Azul JDKs",
"https://cdn.azul.com/zulu/bin/zulu21.42.19-ca-jdk21.0.7-win_x64.msi",
"img/png/Azul_JDKs.png"));
flowPanel.Controls.Add(CreateAppCard( flowPanel.Controls.Add(CreateAppCard(
".NET SDK 8.0", ".NET SDK 8.0",
"https://dotnet.microsoft.com/zh-cn/download/dotnet/thank-you/sdk-8.0.411-windows-x64-installer", "https://dotnet.microsoft.com/zh-cn/download/dotnet/thank-you/sdk-8.0.411-windows-x64-installer",
@@ -841,6 +826,16 @@ namespace AppStore
"https://ghproxy.net/https://github.com/game1024/OpenSpeedy/releases/download/v1.7.1/OpenSpeedy-v1.7.1.zip", "https://ghproxy.net/https://github.com/game1024/OpenSpeedy/releases/download/v1.7.1/OpenSpeedy-v1.7.1.zip",
"img/png/openspeedy.png")); "img/png/openspeedy.png"));
flowPanel.Controls.Add(CreateAppCard(
"Final2x",
"https://ghproxy.net/https://github.com/Tohrusky/Final2x/releases/download/2024-12-14/Final2x-windows-x64-setup.exe",
"img/png/Final2x.png"));
flowPanel.Controls.Add(CreateAppCard(
"Pixpin",
"https://download.pixpin.cn/PixPin_2.0.0.3.exe",
"img/png/pixpin.png"));
flowPanel.Controls.Add(CreateAppCard( flowPanel.Controls.Add(CreateAppCard(
"QuickLook", "QuickLook",
"https://ghproxy.net/https://github.com/QL-Win/QuickLook/releases/download/4.0.2/QuickLook-4.0.2.exe", "https://ghproxy.net/https://github.com/QL-Win/QuickLook/releases/download/4.0.2/QuickLook-4.0.2.exe",
@@ -1027,6 +1022,11 @@ namespace AppStore
"https://ghproxy.net/https://github.com/vnotex/vnote/releases/download/v3.19.2/VNote-3.19.2-win64.zip", "https://ghproxy.net/https://github.com/vnotex/vnote/releases/download/v3.19.2/VNote-3.19.2-win64.zip",
"img/png/vnote.png")); "img/png/vnote.png"));
flowPanel.Controls.Add(CreateAppCard(
"notepad--",
"https://www.ghproxy.cn/https://github.com/cxasm/notepad--/releases/download/notepad-v3.3/Notepad--v3.3-plugin-Installer.exe",
"img/png/notepad--.png"));
flowPanel.Controls.Add(CreateAppCard( flowPanel.Controls.Add(CreateAppCard(
"PowerToys", "PowerToys",
"https://ghproxy.net/https://github.com/microsoft/PowerToys/releases/download/v0.91.1/PowerToysSetup-0.91.1-x64.exe", "https://ghproxy.net/https://github.com/microsoft/PowerToys/releases/download/v0.91.1/PowerToysSetup-0.91.1-x64.exe",
@@ -1037,6 +1037,21 @@ namespace AppStore
"https://ghproxy.net/https://github.com/microsoft/terminal/releases/download/v1.22.11141.0/Microsoft.WindowsTerminal_1.22.11141.0_x64.zip", "https://ghproxy.net/https://github.com/microsoft/terminal/releases/download/v1.22.11141.0/Microsoft.WindowsTerminal_1.22.11141.0_x64.zip",
"img/png/terminal.png")); "img/png/terminal.png"));
flowPanel.Controls.Add(CreateAppCard(
"github_cli",
"https://ghproxy.cn/https://github.com/cli/cli/releases/download/v2.74.2/gh_2.74.2_windows_arm64.msi",
"img/png/github_cli.png"));
flowPanel.Controls.Add(CreateAppCard(
"ReactOS",
"https://ghproxy.cn/https://github.com/reactos/reactos/releases/download/0.4.15-release/ReactOS-0.4.15-release-1-gdbb43bbaeb2-x86-iso.zip",
"img/png/ReactOS.png"));
flowPanel.Controls.Add(CreateAppCard(
"Ubuntu桌面发行版",
"https://releases.ubuntu.com/24.04/ubuntu-24.04.2-desktop-amd64.iso",
"img/png/Ubuntu.png"));
flowPanel.Controls.Add(CreateAppCard( flowPanel.Controls.Add(CreateAppCard(
"typescript", "typescript",
"https://ghproxy.net/https://github.com/microsoft/TypeScript/releases/download/v5.8.3/typescript-5.8.3.tgz", "https://ghproxy.net/https://github.com/microsoft/TypeScript/releases/download/v5.8.3/typescript-5.8.3.tgz",
@@ -1047,6 +1062,11 @@ namespace AppStore
"https://mirror.nju.edu.cn/gimp/gimp/v3.0/windows/gimp-3.0.4-setup.exe", "https://mirror.nju.edu.cn/gimp/gimp/v3.0/windows/gimp-3.0.4-setup.exe",
"img/jpg/Gimp.jpg")); "img/jpg/Gimp.jpg"));
flowPanel.Controls.Add(CreateAppCard(
"ClamAV",
"https://www.clamav.net/downloads/production/clamav-1.4.3.win.x64.msi",
"img/png/ClamAV.png"));
flowPanel.Controls.Add(CreateAppCard( flowPanel.Controls.Add(CreateAppCard(
"Shotcut", "Shotcut",
"https://sourceforge.net/projects/shotcut/files/v25.05.11/shotcut-win64-250511.exe/download", "https://sourceforge.net/projects/shotcut/files/v25.05.11/shotcut-win64-250511.exe/download",
@@ -1202,6 +1222,11 @@ namespace AppStore
"https://ghproxy.net/https://github.com/cloudreve/cloudreve/releases/download/3.8.3/cloudreve_3.8.3_windows_amd64.zip", "https://ghproxy.net/https://github.com/cloudreve/cloudreve/releases/download/3.8.3/cloudreve_3.8.3_windows_amd64.zip",
"img/png/cloudreve.png")); "img/png/cloudreve.png"));
flowPanel.Controls.Add(CreateAppCard(
"ollama",
"https://www.ghproxy.cn/https://github.com/ollama/ollama/releases/download/v0.9.5/OllamaSetup.exe",
"img/png/ollama.png"));
flowPanel.Controls.Add(CreateAppCard( flowPanel.Controls.Add(CreateAppCard(
"SeelenUI", "SeelenUI",
"https://ghproxy.net/https://github.com/eythaann/Seelen-UI/releases/download/v2.3.8/Seelen.UI_2.3.8_x64-setup.exe", "https://ghproxy.net/https://github.com/eythaann/Seelen-UI/releases/download/v2.3.8/Seelen.UI_2.3.8_x64-setup.exe",

View File

@@ -209,7 +209,7 @@ namespace AppStore
{ {
string jsonString = File.ReadAllText(jsonPath); string jsonString = File.ReadAllText(jsonPath);
var jsonData = JsonSerializer.Deserialize<JsonElement>(jsonString); var jsonData = JsonSerializer.Deserialize<JsonElement>(jsonString);
string customPath = jsonData.GetProperty("DownloadPath").GetString(); string customPath = jsonData.GetProperty("DownloadPath").GetString() ?? "";
// 如果自定义路径有效则显示,否则显示默认路径 // 如果自定义路径有效则显示,否则显示默认路径
txtBox.Text = !string.IsNullOrWhiteSpace(customPath) ? customPath : defaultPath; txtBox.Text = !string.IsNullOrWhiteSpace(customPath) ? customPath : defaultPath;

View File

@@ -76,6 +76,10 @@ namespace AppStore
private static readonly Color DarkText = Color.FromArgb(240, 240, 240); private static readonly Color DarkText = Color.FromArgb(240, 240, 240);
private static readonly Color DarkButtonHover = Color.FromArgb(60, 60, 60); private static readonly Color DarkButtonHover = Color.FromArgb(60, 60, 60);
private static readonly Color DarkButtonActive = Color.FromArgb(70, 70, 70); private static readonly Color DarkButtonActive = Color.FromArgb(70, 70, 70);
private static readonly Color DarkBorder = Color.FromArgb(80, 80, 80);
// 浅色主题边框颜色
private static readonly Color LightBorder = Color.FromArgb(180, 180, 180);
public static event Action<ThemeMode> ThemeChanged = delegate {}; public static event Action<ThemeMode> ThemeChanged = delegate {};
@@ -108,6 +112,9 @@ namespace AppStore
public static Color ButtonActiveColor => public static Color ButtonActiveColor =>
_currentTheme == ThemeMode.Light ? LightButtonActive : DarkButtonActive; _currentTheme == ThemeMode.Light ? LightButtonActive : DarkButtonActive;
public static Color BorderColor =>
_currentTheme == ThemeMode.Light ? LightBorder : DarkBorder;
public static void ApplyTheme(Control control) public static void ApplyTheme(Control control)
{ {
ApplyThemeToControl(control); ApplyThemeToControl(control);

View File

@@ -17,21 +17,7 @@
<h2>核心功能</h2> <h2>核心功能</h2>
<article class="feature"> <article class="feature">
<h3>应用程序管理</h3> <h3>目前没有什么东西,别看了,害羞(✿◡‿◡)
<p>批量安装、卸载(目前没有)和更新应用程序(目前没有),管理启动项(目前没有)。</p>
<p>优势:集中管理所有应用,节省时间,避免系统臃肿。</p>
</article>
<article class="feature">
<h3>资源监控(之后可能在内置工具里有)</h3>
<p>实时监控CPU、内存、磁盘和网络使用情况。</p>
<p>优势:直观的图表展示,及时发现资源瓶颈。</p>
</article>
<article class="feature">
<h3>文件管理(之后可能在内置工具里有)</h3>
<p>高级文件搜索、批量重命名和快速文件分类。</p>
<p>优势:提升文件管理效率,支持正则表达式搜索。</p>
</article> </article>
</section> </section>
</main> </main>

BIN
img/png/Azul_JDKs.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
img/png/ClamAV.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
img/png/Final2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
img/png/ReactOS.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

BIN
img/png/Ubuntu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 853 B

BIN
img/png/github_cli.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
img/png/notepad--.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

BIN
img/png/ollama.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

BIN
img/png/pixpin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 523 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 946 KiB

View File

@@ -2,7 +2,7 @@
; 有关创建 Inno Setup 脚本文件的详细信息,请参阅帮助文档! ; 有关创建 Inno Setup 脚本文件的详细信息,请参阅帮助文档!
#define MyAppName "kortapp-z" #define MyAppName "kortapp-z"
#define MyAppVersion "1.1.4" #define MyAppVersion "1.2.4"
#define MyAppPublisher "zsyg" #define MyAppPublisher "zsyg"
#define MyAppURL "https://github.com/zs-yg/kortapp-z" #define MyAppURL "https://github.com/zs-yg/kortapp-z"
#define MyAppExeName "kortapp-z.exe" #define MyAppExeName "kortapp-z.exe"

View File

@@ -2,7 +2,7 @@
; 有关创建 Inno Setup 脚本文件的详细信息,请参阅帮助文档! ; 有关创建 Inno Setup 脚本文件的详细信息,请参阅帮助文档!
#define MyAppName "kortapp-z" #define MyAppName "kortapp-z"
#define MyAppVersion "1.1.4" #define MyAppVersion "1.2.4"
#define MyAppPublisher "zsyg" #define MyAppPublisher "zsyg"
#define MyAppURL "https://github.com/zs-yg/kortapp-z" #define MyAppURL "https://github.com/zs-yg/kortapp-z"
#define MyAppExeName "kortapp-z.exe" #define MyAppExeName "kortapp-z.exe"

View File

@@ -75,5 +75,25 @@ namespace AppStore
} }
Log(warningMessage); Log(warningMessage);
} }
public static void LogDebug(string message, Exception? ex = null)
{
string debugMessage = $"DEBUG: {message}";
if (ex != null)
{
debugMessage += $"\nException: {ex}\nStackTrace: {ex.StackTrace}";
}
Log(debugMessage);
}
public static void LogTip(string message, Exception? ex = null)
{
string tipMessage = $"TIP: {message}";
if (ex != null)
{
tipMessage += $"\nException: {ex}\nStackTrace: {ex.StackTrace}";
}
Log(tipMessage);
}
} }
} }

Binary file not shown.

View File

@@ -131,29 +131,39 @@ namespace AppStore
{ {
foreach (var item in items) foreach (var item in items)
{ {
Image iconImage = null; Image? iconImage = null;
try try
{ {
if (!string.IsNullOrEmpty(item.Value) && System.IO.File.Exists(item.Value)) if (!string.IsNullOrEmpty(item.Value) && System.IO.File.Exists(item.Value))
{ {
using (Icon icon = Icon.ExtractAssociatedIcon(item.Value)) using (Icon icon = Icon.ExtractAssociatedIcon(item.Value))
{ {
iconImage = icon.ToBitmap(); iconImage = icon?.ToBitmap() ?? SystemIcons.Application.ToBitmap();
} }
} }
else else
{ {
// 使用默认图标 // 使用默认图标
iconImage = SystemIcons.Application.ToBitmap(); iconImage = SystemIcons.Application?.ToBitmap() ?? SystemIcons.WinLogo.ToBitmap();
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.LogWarning($"无法加载程序图标: {item.Value}", ex); Logger.LogWarning($"无法加载程序图标: {item.Value}", ex);
iconImage = SystemIcons.Warning.ToBitmap(); // 确保在任何情况下都有有效的图标
iconImage = SystemIcons.Warning?.ToBitmap()
?? SystemIcons.Error?.ToBitmap()
?? SystemIcons.Application?.ToBitmap()
?? SystemIcons.WinLogo?.ToBitmap()
?? SystemIcons.Shield?.ToBitmap()
?? new Bitmap(16, 16);
if (iconImage == null)
{
iconImage = new Bitmap(16, 16);
}
} }
dataGridView.Rows.Add(iconImage, item.Key, item.Value); dataGridView.Rows.Add(iconImage!, item.Key, item.Value);
} }
} }
} }

View File

@@ -0,0 +1,104 @@
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.IO;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
namespace AppStore.Tools.IconExtractor
{
public static class IconExtractor
{
/// <summary>
/// 获取ICO文件中的实际尺寸列表
/// </summary>
public static List<int> GetIconDimensions(string filePath)
{
var sizes = new List<int>();
try
{
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
using (var reader = new BinaryReader(fs))
{
// 读取ICO文件头
reader.ReadUInt16(); // 保留字段
ushort type = reader.ReadUInt16(); // 1=ICO, 2=CUR
ushort count = reader.ReadUInt16(); // 图像数量
if (type != 1) return sizes; // 不是ICO文件
// 读取每个图像目录项
for (int i = 0; i < count; i++)
{
byte width = reader.ReadByte();
byte height = reader.ReadByte();
reader.ReadBytes(14); // 跳过其他字段
// 宽度/高度为0表示256像素
int size = width == 0 ? 256 : width;
sizes.Add(size);
}
}
}
catch
{
// 忽略所有错误,返回空列表
}
return sizes;
}
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
private static extern int ExtractIconEx(
string lpszFile,
int nIconIndex,
[AllowNull] IntPtr[] phiconLarge,
[AllowNull] IntPtr[] phiconSmall,
int nIcons);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern bool DestroyIcon(IntPtr handle);
/// <summary>
/// 从文件中提取图标
/// </summary>
/// <param name="filePath">文件路径</param>
/// <param name="iconIndex">图标索引</param>
/// <param name="largeIcon">是否提取大图标</param>
/// <returns>提取的图标</returns>
public static Icon ExtractIconFromFile(string filePath, int iconIndex = 0)
{
IntPtr[] hIcons = new IntPtr[1];
int extractedCount = ExtractIconEx(filePath, iconIndex, hIcons, null, 1);
if (extractedCount <= 0 || hIcons[0] == IntPtr.Zero)
throw new FileNotFoundException("无法从文件中提取图标");
// 直接返回原始图标
Icon icon = (Icon)Icon.FromHandle(hIcons[0]).Clone();
DestroyIcon(hIcons[0]);
return icon;
}
/// <summary>
/// 将图标保存为文件
/// </summary>
/// <param name="icon">图标对象</param>
/// <param name="outputPath">输出路径</param>
public static void SaveIconToFile(Icon icon, string outputPath)
{
using (FileStream fs = new FileStream(outputPath, FileMode.Create))
{
icon.Save(fs);
}
}
/// <summary>
/// 获取文件中的图标数量
/// </summary>
/// <param name="filePath">文件路径</param>
/// <returns>图标数量</returns>
public static int GetIconCount(string filePath)
{
return ExtractIconEx(filePath, -1, null, null, 0);
}
}
}

View File

@@ -0,0 +1,19 @@
namespace AppStore.Tools.IconExtractor
{
public static class IconExtractorConstants
{
public const string FileFilter = "可执行文件|*.exe;*.dll;*.ocx;*.cpl|所有文件|*.*";
public const string SaveFilter = "图标文件|*.ico|位图文件|*.bmp|PNG文件|*.png";
public static readonly int[] SupportedSizes = { 16, 24, 32, 48, 64, 128, 256, 512 };
public static readonly int DefaultExtractSize = 256;
public const string ErrorNoIconsFound = "文件不包含任何图标";
public const string ErrorExtractionFailed = "图标提取失败";
public const string ErrorInvalidIndex = "无效的图标索引";
public const string ErrorFileNotFound = "文件未找到";
public const int MaxRecentFiles = 5;
public const int DefaultPreviewSize = 128;
}
}

View File

@@ -0,0 +1,186 @@
using System;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
using AppStore.Tools.IconExtractor;
namespace AppStore.Tools.IconExtractor
{
public class IconExtractorForm : Form
{
private Button btnBrowse = new Button();
private Button btnSave = new Button();
private NumericUpDown numIconIndex = new NumericUpDown();
private PictureBox picIcon = new PictureBox();
private Label lblStatus = new Label();
private TextBox txtFilePath = new TextBox();
private ComboBox cmbIconSize = new ComboBox();
private string currentFilePath = string.Empty;
public IconExtractorForm()
{
this.Text = "图标提取器";
this.Size = new Size(500, 550);
this.StartPosition = FormStartPosition.CenterScreen;
InitializeComponents();
}
private void InitializeComponents()
{
// 文件路径文本框
txtFilePath.Location = new Point(20, 20);
txtFilePath.Size = new Size(300, 25);
txtFilePath.ReadOnly = true;
this.Controls.Add(txtFilePath);
// 浏览按钮
btnBrowse.Text = "浏览...";
btnBrowse.Location = new Point(330, 20);
btnBrowse.Size = new Size(80, 25);
btnBrowse.Click += BtnBrowse_Click;
this.Controls.Add(btnBrowse);
// 图标索引标签
Label lblIndex = new Label();
lblIndex.Text = "图标索引:";
lblIndex.Location = new Point(20, 60);
lblIndex.Size = new Size(80, 20);
this.Controls.Add(lblIndex);
// 图标索引选择器
numIconIndex.Location = new Point(100, 60);
numIconIndex.Size = new Size(80, 20);
numIconIndex.Minimum = 0;
numIconIndex.ValueChanged += NumIconIndex_ValueChanged;
this.Controls.Add(numIconIndex);
// 图标预览区域
picIcon.Location = new Point(20, 100);
picIcon.Size = new Size(256, 256);
picIcon.SizeMode = PictureBoxSizeMode.Zoom;
picIcon.BorderStyle = BorderStyle.FixedSingle;
this.Controls.Add(picIcon);
// 索引说明
Label lblIndexHelp = new Label();
lblIndexHelp.Text = "索引号表示文件中的第几个图标从0开始";
lblIndexHelp.Location = new Point(20, 240);
lblIndexHelp.Size = new Size(300, 20);
this.Controls.Add(lblIndexHelp);
// 保存按钮
btnSave.Text = "保存图标";
btnSave.Location = new Point(20, 450);
btnSave.Size = new Size(100, 30);
btnSave.Click += BtnSave_Click;
this.Controls.Add(btnSave);
// 状态标签
lblStatus.Location = new Point(20, 490);
lblStatus.Size = new Size(400, 20);
lblStatus.Text = "请选择包含图标的文件";
this.Controls.Add(lblStatus);
}
private void BtnBrowse_Click(object sender, EventArgs e)
{
using (OpenFileDialog ofd = new OpenFileDialog())
{
ofd.Filter = "可执行文件|*.exe;*.dll;*.ocx;*.cpl|所有文件|*.*";
if (ofd.ShowDialog() == DialogResult.OK)
{
currentFilePath = ofd.FileName;
txtFilePath.Text = currentFilePath;
LoadIconInfo();
}
}
}
private void LoadIconInfo()
{
try
{
int iconCount = IconExtractor.GetIconCount(currentFilePath);
numIconIndex.Maximum = Math.Max(0, iconCount - 1);
// 如果是ICO文件获取实际包含的尺寸
if (currentFilePath.EndsWith(".ico", StringComparison.OrdinalIgnoreCase))
{
var sizes = IconExtractor.GetIconDimensions(currentFilePath);
if (sizes.Count > 0)
{
cmbIconSize.Items.Clear();
foreach (var size in sizes)
{
cmbIconSize.Items.Add($"{size}x{size}");
}
// 默认选择最接近256的尺寸
int closest = sizes.OrderBy(s => Math.Abs(s - 256)).First();
cmbIconSize.SelectedIndex = sizes.IndexOf(closest);
}
}
lblStatus.Text = $"找到 {iconCount} 个图标";
ExtractAndDisplayIcon();
}
catch (Exception ex)
{
lblStatus.Text = $"错误: {ex.Message}";
picIcon.Image = null;
}
}
private void NumIconIndex_ValueChanged(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(currentFilePath))
{
ExtractAndDisplayIcon();
}
}
private void ExtractAndDisplayIcon()
{
try
{
Icon icon = IconExtractor.ExtractIconFromFile(currentFilePath, (int)numIconIndex.Value);
picIcon.Image = icon.ToBitmap();
lblStatus.Text = $"显示原始图标 #{numIconIndex.Value}";
}
catch (Exception ex)
{
lblStatus.Text = $"提取图标失败: {ex.Message}";
picIcon.Image = null;
}
}
private void BtnSave_Click(object sender, EventArgs e)
{
if (picIcon.Image == null)
{
MessageBox.Show("没有可保存的图标", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
using (SaveFileDialog sfd = new SaveFileDialog())
{
sfd.Filter = "图标文件|*.ico|位图文件|*.bmp|PNG文件|*.png";
if (sfd.ShowDialog() == DialogResult.OK)
{
try
{
using (Icon icon = IconExtractor.ExtractIconFromFile(currentFilePath, (int)numIconIndex.Value))
{
IconExtractor.SaveIconToFile(icon, sfd.FileName);
lblStatus.Text = $"已保存原始图标到 {sfd.FileName}";
}
}
catch (Exception ex)
{
MessageBox.Show($"保存图标失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
}
}

View File

@@ -0,0 +1,73 @@
using System;
using System.Drawing;
using System.IO;
using System.Collections.Generic;
namespace AppStore.Tools.IconExtractor
{
public static class IconExtractorHelper
{
/// <summary>
/// 将图标转换为位图
/// </summary>
public static Bitmap ConvertIconToBitmap(Icon icon, Size size)
{
Bitmap bitmap = new Bitmap(size.Width, size.Height);
using (Graphics g = Graphics.FromImage(bitmap))
{
g.DrawIcon(icon, new Rectangle(0, 0, size.Width, size.Height));
}
return bitmap;
}
/// <summary>
/// 批量提取文件中的所有图标
/// </summary>
public static List<Icon> ExtractAllIcons(string filePath)
{
List<Icon> icons = new List<Icon>();
int count = IconExtractor.GetIconCount(filePath);
for (int i = 0; i < count; i++)
{
try
{
Icon icon = IconExtractor.ExtractIconFromFile(filePath, i);
icons.Add(icon);
}
catch
{
// 忽略提取失败的图标
}
}
return icons;
}
/// <summary>
/// 将图标保存为PNG格式
/// </summary>
public static void SaveIconAsPng(Icon icon, string outputPath)
{
using (Bitmap bitmap = icon.ToBitmap())
{
bitmap.Save(outputPath, System.Drawing.Imaging.ImageFormat.Png);
}
}
/// <summary>
/// 检查文件是否包含图标
/// </summary>
public static bool HasIcons(string filePath)
{
try
{
return IconExtractor.GetIconCount(filePath) > 0;
}
catch
{
return false;
}
}
}
}

View File

@@ -0,0 +1,123 @@
using System;
using System.IO;
using System.Text.Json;
namespace AppStore.Tools.IconExtractor
{
public static class IconExtractorSettings
{
private static readonly string SettingsPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"kortapp-z", "icon_extractor_settings.json");
public static SettingsData CurrentSettings { get; private set; } = new SettingsData();
public class SettingsData
{
public string LastUsedDirectory { get; set; } = string.Empty;
public string DefaultSaveFormat { get; set; } = "ico";
public int DefaultIconSize { get; set; } = 128;
public string[] RecentFiles { get; set; } = Array.Empty<string>();
}
/// <summary>
/// 加载设置
/// </summary>
public static void LoadSettings()
{
try
{
if (File.Exists(SettingsPath))
{
string json = File.ReadAllText(SettingsPath);
if (!string.IsNullOrWhiteSpace(json))
{
try
{
using (JsonDocument doc = JsonDocument.Parse(json))
{
var root = doc.RootElement;
CurrentSettings = new SettingsData
{
LastUsedDirectory = root.TryGetProperty("LastUsedDirectory", out var dir) ? dir.GetString() ?? string.Empty : string.Empty,
DefaultSaveFormat = root.TryGetProperty("DefaultSaveFormat", out var format) ? format.GetString() ?? "ico" : "ico",
DefaultIconSize = root.TryGetProperty("DefaultIconSize", out var size) ? size.GetInt32() : 128,
RecentFiles = root.TryGetProperty("RecentFiles", out var files) ?
JsonSerializer.Deserialize<string[]>(files.GetRawText()) ?? Array.Empty<string>() :
Array.Empty<string>()
};
}
}
catch
{
CurrentSettings = new SettingsData();
}
}
}
}
catch
{
// 加载失败时使用默认设置
CurrentSettings = new SettingsData();
}
}
/// <summary>
/// 保存设置
/// </summary>
public static void SaveSettings()
{
try
{
if (string.IsNullOrEmpty(SettingsPath))
return;
string directory = Path.GetDirectoryName(SettingsPath);
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
string json = JsonSerializer.Serialize(CurrentSettings);
File.WriteAllText(SettingsPath, json);
}
catch
{
// 忽略保存错误
}
}
/// <summary>
/// 添加最近使用的文件
/// </summary>
public static void AddRecentFile(string filePath)
{
if (CurrentSettings.RecentFiles.Length >= 5)
{
var list = new List<string>(CurrentSettings.RecentFiles);
list.RemoveAt(0);
CurrentSettings.RecentFiles = list.ToArray();
}
var newList = new List<string>(CurrentSettings.RecentFiles);
if (!newList.Contains(filePath))
{
newList.Add(filePath);
CurrentSettings.RecentFiles = newList.ToArray();
SaveSettings();
}
}
/// <summary>
/// 更新最后使用的目录
/// </summary>
public static void UpdateLastUsedDirectory(string directory)
{
if (Directory.Exists(directory) && CurrentSettings.LastUsedDirectory != directory)
{
CurrentSettings.LastUsedDirectory = directory;
SaveSettings();
}
}
}
}

View File

@@ -0,0 +1,39 @@
using System;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
namespace AppStore.Tools.IconExtractor
{
public class IconExtractorToolCard : ToolCard
{
public IconExtractorToolCard()
{
ToolName = "图标提取器";
try
{
string iconPath = Path.Combine(Application.StartupPath, "img", "resource", "png", "QRcode.png");
if (File.Exists(iconPath))
{
ToolIcon = Image.FromFile(iconPath);
}
else
{
ToolIcon = SystemIcons.Application.ToBitmap();
}
}
catch
{
ToolIcon = SystemIcons.Application.ToBitmap();
}
this.ToolCardClicked += OnIconExtractorCardClicked;
UpdateDisplay();
}
private void OnIconExtractorCardClicked(object sender, EventArgs e)
{
var iconExtractorForm = new IconExtractorForm();
iconExtractorForm.ShowDialog();
}
}
}