From d055b415fa28b3ffe32050772b7bc73b9b4ab242 Mon Sep 17 00:00:00 2001 From: chenshoulin Date: Sun, 1 Nov 2026 20:17:56 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=BC=BA=E4=BE=BF=E6=90=BA?= =?UTF-8?q?=E7=89=88=E6=94=AF=E6=8C=81=E4=B8=8E=E9=85=8D=E7=BD=AE=E7=AE=A1?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 更新 .gitignore 文件,添加便携版分发目录和 Fody 生成的配置文件。 - 修改 README.md,详细说明便携版的构建与分发流程,强调单文件分发的优势。 - 在 Config.cs 中实现便携配置管理,优先使用 exe 同目录的 config.json,提升用户体验。 - 更新 ExcelService.cs,优化默认模板的导出逻辑,支持现场替换模板文件。 - 在 MainForm.cs 中加载应用图标,提升界面一致性。 - 调整 Program.cs,确保在单文件分发时正确加载 native DLL。 --- .gitignore | 6 + README.md | 43 +++- TfsExcelImporter/AppIcon.cs | 46 ++++ TfsExcelImporter/Config.cs | 46 +++- TfsExcelImporter/ExcelService.cs | 31 ++- TfsExcelImporter/FodyWeavers.xml | 3 + TfsExcelImporter/MainForm.cs | 8 +- TfsExcelImporter/MainFormUi.cs | 27 +- TfsExcelImporter/NativeLibraryLoader.cs | 83 ++++++ TfsExcelImporter/Program.cs | 3 + TfsExcelImporter/TfsExcelImporter.csproj | 30 ++- TfsExcelImporter/app.ico | Bin 0 -> 123112 bytes debug.log | 2 + tools/icon_preview.png | Bin 0 -> 51640 bytes tools/make_icon.py | 305 +++++++++++++++++++++++ tools/pe_icon.py | 140 +++++++++++ tools/win_screenshot.py | 212 ++++++++++++++++ 17 files changed, 965 insertions(+), 20 deletions(-) create mode 100644 TfsExcelImporter/AppIcon.cs create mode 100644 TfsExcelImporter/FodyWeavers.xml create mode 100644 TfsExcelImporter/NativeLibraryLoader.cs create mode 100644 TfsExcelImporter/app.ico create mode 100644 tools/icon_preview.png create mode 100644 tools/make_icon.py create mode 100644 tools/pe_icon.py create mode 100644 tools/win_screenshot.py diff --git a/.gitignore b/.gitignore index 57dcc3e..f56a046 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,12 @@ obj/ *.user *.suo +# 便携版分发目录(dotnet build 后把单文件 exe 拷进来) +dist/ + +# Fody(Costura)构建时自动生成 +TfsExcelImporter/FodyWeavers.xsd + # Python __pycache__/ *.py[cod] diff --git a/README.md b/README.md index 71e177f..8ca3c99 100644 --- a/README.md +++ b/README.md @@ -33,9 +33,17 @@ TFSImport/ ├── data/ │ └── work_items.example.csv # 列结构与示例行(UTF-8 BOM);真实台账不入库 ├── templates/ -│ └── TFS导入模板.xlsx # 默认模板:csproj 随构建拷到 exe 目录,「导出Excel模板」原样复制它 +│ └── TFS导入模板.xlsx # 默认模板:构建时嵌入 exe,「导出Excel模板」原样导出 +├── tools/ +│ ├── make_icon.py # 生成 app.ico(9 个尺寸帧,纯标准库 SDF 栅格化 + 手写 PNG/ICO) +│ ├── pe_icon.py # 解析 exe 的 PE 图标资源,导出某帧 PNG(换图标后核对用) +│ └── win_screenshot.py # 冒烟截图:拉起 exe、PrintWindow 抓窗、导出标题栏图标(ctypes) └── TfsExcelImporter/ # C# WinForms 桌面版(主用) ├── TfsExcelImporter.csproj # net48 + ClosedXML + TFS ExtendedClient 14.* + ├── FodyWeavers.xml # Costura 单文件打包配置(便携版) + ├── NativeLibraryLoader.cs # 释放并预加载内嵌的 TFS native DLL + ├── AppIcon.cs # 从内嵌 app.ico 取 Form.Icon(窗口/任务栏) + ├── app.ico # 应用图标(16~256 共 9 档,tools/make_icon.py 生成) ├── MainForm.cs # 导入 / 修 Area / 补挂父项流程 ├── MainFormUi.cs # 界面外壳:步骤卡片布局、手风琴折叠、状态呈现 ├── Theme.cs # 设计 token(颜色/字号/间距/缩放)与自绘控件 @@ -56,7 +64,14 @@ dotnet build TfsExcelImporter.sln -c Release TfsExcelImporter\bin\Release\net48\TfsExcelImporter.exe ``` -「导出Excel模板」复制的是 exe 同目录的 `TFS导入模板.xlsx`(构建时自动拷过去);单独分发 exe 时要带上这个文件,否则该按钮会报「未找到默认模板文件」。 +「导出Excel模板」优先用 exe 同目录的 `TFS导入模板.xlsx`(现场可替换),没有则从 exe 内嵌资源导出——**分发时只带一个 exe 就够,不用再附带模板文件**。 + +应用图标是 `TfsExcelImporter/app.ico`(蓝色渐变圆角底 + 白色上升箭头),csproj 里 `ApplicationIcon` 写进 exe 的 Win32 图标资源,同时以托管资源再嵌一份给 `Form.Icon` 用(多尺寸帧,高 DPI 下不糊)。要改设计就改 `tools/make_icon.py` 后重跑,覆盖 `app.ico` 再编译: + +```powershell +python tools/make_icon.py # 重新生成 app.ico,并出预览图 tools/icon_preview.png +python tools/win_screenshot.py TfsExcelImporter\bin\Release\net48\TfsExcelImporter.exe tools\_win.png +``` 界面按 4 步排:顶部状态条常驻显示服务器/项目/类型与连接状态,四张卡片一次只展开一张(展开一张会把其它收成一行摘要),预览表格永远占满剩余高度。 @@ -68,6 +83,28 @@ TfsExcelImporter\bin\Release\net48\TfsExcelImporter.exe 桌面版按 System DPI 感知实现,界面尺寸随 Windows 显示缩放换算;**改了显示缩放比例要重启程序**才生效。 +### 便携版(单 exe,免安装) + +构建产物只有一个文件:`TfsExcelImporter\bin\Release\net48\TfsExcelImporter.exe`(约 9.3 MB)。依赖和资源全部内嵌: + +| 内容 | 打包方式 | +| --- | --- | +| 58 个托管 DLL(ClosedXML / OpenXml / TFS Client OM …) | `Costura.Fody` 内嵌,运行时经 `AssemblyResolve` 从内存加载,不落盘 | +| `Microsoft.WITDataStore32/64.dll`(纯 win32,TFS OM 用) | 独立内嵌,启动时按进程位数释放到 `%TEMP%\TfsExcelImporter\native\{内容hash}` 并 `LoadLibrary` 预加载 | +| 默认模板 `TFS导入模板.xlsx` | 内嵌资源,「导出Excel模板」时释放;exe 同目录放同名文件则优先用它 | +| `config.json` | 首次保存时写到 exe 同目录(便携);目录只读时回退 `%AppData%\TfsExcelImporter\config.json` | + +分发: + +```powershell +mkdir dist +copy TfsExcelImporter\bin\Release\net48\TfsExcelImporter.exe dist\ +``` + +把 `dist\TfsExcelImporter.exe` 拷到任意目录双击即用。想连配置一起带走,就把 exe 同目录的 `config.json` 一起拷。 + +前提:目标机需有 .NET Framework 4.8(Win10 1903+ / Win11 系统自带,一般无需额外安装)。`FodyWeavers.xml` 是 Costura 的打包配置,删掉它或用 `-p:FodyDisable=true` 构建即回到「exe + 一堆 DLL」的普通输出。 + ### Python 版 ```powershell @@ -84,6 +121,8 @@ python tfs_import.py --input other.csv --limit 5 ## 配置说明 +桌面版的配置落在 exe 同目录的 `config.json`(界面改动后自动写回);exe 目录不可写时回退到 `%AppData%\TfsExcelImporter\config.json`。 + 配置的语义、留空字段如何解析见 [tfs_import.py:49](tfs_import.py#L49) 与 [Config.cs](TfsExcelImporter/Config.cs),关键字段: | 键 | 说明 | diff --git a/TfsExcelImporter/AppIcon.cs b/TfsExcelImporter/AppIcon.cs new file mode 100644 index 0000000..164eca3 --- /dev/null +++ b/TfsExcelImporter/AppIcon.cs @@ -0,0 +1,46 @@ +using System; +using System.Drawing; +using System.IO; +using System.Reflection; +using System.Windows.Forms; + +namespace TfsExcelImporter +{ + /// + /// 应用图标。exe 的 Win32 图标资源由 csproj 的 ApplicationIcon 提供, + /// 这里负责窗口标题栏/任务栏用的 Form.Icon:从内嵌的 app.ico(9 个尺寸帧) + /// 直接构造,系统按 DPI 取 16/32/48;取不到再退回提取 exe 自身图标。 + /// + internal static class AppIcon + { + private static Icon _cached; + private static bool _tried; + + public static Icon Load() + { + if (_tried) return _cached; + _tried = true; + + try + { + using (Stream s = Assembly.GetExecutingAssembly() + .GetManifestResourceStream("app.ico")) + { + if (s != null) _cached = new Icon(s); + } + } + catch + { + // 内嵌 ICO 解析失败(例如只认 BMP 帧的极端情况):忽略,走下面的兜底 + _cached = null; + } + + if (_cached == null) + { + try { _cached = Icon.ExtractAssociatedIcon(Application.ExecutablePath); } + catch { } + } + return _cached; + } + } +} diff --git a/TfsExcelImporter/Config.cs b/TfsExcelImporter/Config.cs index e11c842..b120770 100644 --- a/TfsExcelImporter/Config.cs +++ b/TfsExcelImporter/Config.cs @@ -44,11 +44,39 @@ namespace TfsExcelImporter // 父 Product Backlog Item:所有 Task 默认挂接的 PBI Id(如 219975);Excel 每行 PBI Id 列可覆盖 public string ParentPbiId { get; set; } = ""; - private static string ConfigPath + // 便携优先:配置写在 exe 同目录(拷走 exe 即可带走配置); + // exe 目录只读(如放在 Program Files)时回退到 %AppData%\TfsExcelImporter。 + private static string PortableConfigPath { get { return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config.json"); } } + private static string RoamingConfigPath + { + get + { + return Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), + "TfsExcelImporter", "config.json"); + } + } + + private static string ConfigPath + { + get + { + if (File.Exists(PortableConfigPath)) return PortableConfigPath; + if (File.Exists(RoamingConfigPath)) return RoamingConfigPath; + return PortableConfigPath; + } + } + + /// 当前实际使用的配置文件路径(界面提示用)。 + public static string ConfigLocation + { + get { return ConfigPath; } + } + public static AppConfig Load() { try @@ -68,14 +96,28 @@ namespace TfsExcelImporter public void Save() { + var json = JsonConvert.SerializeObject(this, Formatting.Indented); try { - File.WriteAllText(ConfigPath, JsonConvert.SerializeObject(this, Formatting.Indented)); + File.WriteAllText(ConfigPath, json); + return; } catch (Exception ex) { System.Diagnostics.Debug.WriteLine("写入 config.json 失败: " + ex.Message); } + + // exe 目录不可写(只读介质 / Program Files)时落到用户配置目录 + try + { + var fallback = RoamingConfigPath; + Directory.CreateDirectory(Path.GetDirectoryName(fallback)); + File.WriteAllText(fallback, json); + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine("写入用户配置目录失败: " + ex.Message); + } } } } diff --git a/TfsExcelImporter/ExcelService.cs b/TfsExcelImporter/ExcelService.cs index 2faecb0..e3ceb9d 100644 --- a/TfsExcelImporter/ExcelService.cs +++ b/TfsExcelImporter/ExcelService.cs @@ -22,7 +22,8 @@ namespace TfsExcelImporter /// /// Excel 读取与默认模板。模板内容(列宽、示例行、样式)只在 - /// templates\TFS导入模板.xlsx 里维护,随构建复制到 exe 目录后原样导出。 + /// templates\TFS导入模板.xlsx 里维护,构建时作为嵌入资源打进 exe; + /// 若 exe 同目录存在同名文件则优先用它(现场可替换模板而不用重编译)。 /// 列: Title | State | Assigned To | FinancialProject | Completed | LogDate | PBI Id | Description /// public static class ExcelService @@ -44,13 +45,33 @@ namespace TfsExcelImporter // --------------------------------------------------------- 默认模板 - /// 把随程序发布的默认模板原样复制到目标路径。 + /// + /// 把默认模板原样复制到目标路径。优先用 exe 同目录的同名文件(可由现场替换), + /// 没有则从 exe 内嵌资源释放——单文件便携分发时无需附带模板。 + /// public static void CopyTemplate(string path) { var src = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, TemplateFileName); - if (!File.Exists(src)) - throw new FileNotFoundException("未找到默认模板文件: " + src, src); - File.Copy(src, path, true); + if (File.Exists(src)) + { + File.Copy(src, path, true); + return; + } + + var asm = typeof(ExcelService).Assembly; + // 嵌入名取决于 Link 名:默认 .<文件名> + var name = asm.GetManifestResourceNames() + .FirstOrDefault(n => n.EndsWith(TemplateFileName, StringComparison.OrdinalIgnoreCase)); + if (name == null) + throw new FileNotFoundException( + "未找到默认模板:exe 内嵌资源与同目录 " + TemplateFileName + " 均缺失", src); + + using (var input = asm.GetManifestResourceStream(name)) + { + if (input == null) throw new FileNotFoundException("无法读取内嵌模板资源: " + name, src); + using (var output = File.Create(path)) + input.CopyTo(output); + } } // --------------------------------------------------------- 读取数据 diff --git a/TfsExcelImporter/FodyWeavers.xml b/TfsExcelImporter/FodyWeavers.xml new file mode 100644 index 0000000..758c089 --- /dev/null +++ b/TfsExcelImporter/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + diff --git a/TfsExcelImporter/MainForm.cs b/TfsExcelImporter/MainForm.cs index ee72fff..e34a31f 100644 --- a/TfsExcelImporter/MainForm.cs +++ b/TfsExcelImporter/MainForm.cs @@ -23,6 +23,7 @@ namespace TfsExcelImporter using (var g = Graphics.FromHwnd(IntPtr.Zero)) Theme.Scale = g.DpiX / 96f; _cfg = AppConfig.Load(); + Icon = AppIcon.Load(); BuildUi(); LoadConfigToUi(); WireEvents(); @@ -306,7 +307,7 @@ namespace TfsExcelImporter 标题 = r.Title, 状态 = r.State, 指派 = r.AssignedTo, - 财务项目 = r.FinancialProject, + 项目 = r.FinancialProject, 完成量 = r.Completed, 日期 = r.LogDate, 父PBI = r.PbiId, @@ -588,10 +589,9 @@ namespace TfsExcelImporter } catch (Exception ex) { Log("写报告失败: " + FirstLine(ex.Message)); } _pbar.Value = _pbar.Maximum; + // 成功/跳过/失败的分布已在右侧三个胶囊里,这里只补胶囊没有的「总数」,明细仍写日志 _lblStatus.Text = $"完成 {ok + skip + fail}/{_rows.Count}"; - var summary = $"汇总: 成功 {ok} / 跳过 {skip} / 失败 {fail}"; - _lblStatus.Text = summary; - Log(summary); + Log($"汇总: 成功 {ok} / 跳过 {skip} / 失败 {fail}"); SetChips(ok, skip, fail, false); RefreshSummaries(); if (fail == 0 && ok > 0) OpenDetail(_cardLog); diff --git a/TfsExcelImporter/MainFormUi.cs b/TfsExcelImporter/MainFormUi.cs index ad77a36..02c9d8a 100644 --- a/TfsExcelImporter/MainFormUi.cs +++ b/TfsExcelImporter/MainFormUi.cs @@ -341,7 +341,8 @@ namespace TfsExcelImporter // 透明背景会让父容器改画自己的 BackColor(灰),这里直接给成操作条的白 _badgeRun = new StepBadge { BackColor = Theme.Card }; _btnPreview = NewButton("预览数据", BtnKind.Secondary, IconKind.Table, 120); - _btnImport = NewButton("开始导入 TFS", BtnKind.Primary, IconKind.ArrowUp, 176); + // 148 已够图标+文字(实际量出约 130),省下的宽度留给右侧状态文字与进度条 + _btnImport = NewButton("开始导入 TFS", BtnKind.Primary, IconKind.ArrowUp, 148); // 主/次按钮同高(层级靠主色表达,不再用 38px 拔高),避免操作条里两个按钮大小不齐 _pbar = new ProgressTrack { @@ -390,13 +391,33 @@ namespace TfsExcelImporter _chipFail.SetBounds(_actionBar.Width - _chipFail.Width - M - Theme.Px(2), cy, _chipFail.Width, _chipFail.Height); _chipSkip.SetBounds(_chipFail.Left - G - _chipSkip.Width, cy, _chipSkip.Width, _chipSkip.Height); _chipOk.SetBounds(_chipSkip.Left - G - _chipOk.Width, cy, _chipOk.Width, _chipOk.Height); - int statW = Theme.Px(160); - _lblStatus.SetBounds(_chipOk.Left - statW - G, 0, statW, _actionBar.Height); + // 状态文字按最长常规文案实测给宽,且只给一行的高度: + // 宽度够了不折行,万一更长的文案也只省略尾巴,不会把计数拆到第二行。 + int statW = StatusLabelWidth(); + int statH = Theme.Caption.Height + Theme.Px(4); + _lblStatus.SetBounds(_chipOk.Left - statW - G, (_actionBar.Height - statH) / 2, statW, statH); int left = _btnImport.Right + Theme.S16; int barW = Math.Max(Theme.Px(40), _lblStatus.Left - G - left); _pbar.SetBounds(left, (_actionBar.Height - _pbar.Height) / 2, barW, _pbar.Height); } + /// + /// 操作条右侧状态文字的最大显示宽度:取各操作最长文案的实测宽度(160~280 之间夹取), + /// 保证常规状态既不折行、也不省略尾部计数。更长的文案(如「Area 修正完成…(详见日志)」) + /// 只省略尾巴——它们的数字在开头,不受影响。 + /// + private static int StatusLabelWidth() + { + string[] samples = + { + "完成 999/999", // 导入结束:只报总数,分布交给右侧胶囊 + "补挂完成: 挂接 99 / 已有父跳过 99 / 失败 0" // 补挂父项:最长的一条常规状态 + }; + int w = 0; + foreach (var s in samples) w = Math.Max(w, Theme.TextWidth(s, Theme.Caption)); + return Math.Min(Theme.Px(280), Math.Max(Theme.Px(160), w + Theme.Px(8))); + } + // --- 日志抽屉 --- private void BuildCardLog() { diff --git a/TfsExcelImporter/NativeLibraryLoader.cs b/TfsExcelImporter/NativeLibraryLoader.cs new file mode 100644 index 0000000..292100e --- /dev/null +++ b/TfsExcelImporter/NativeLibraryLoader.cs @@ -0,0 +1,83 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; +using System.Security.Cryptography; + +namespace TfsExcelImporter +{ + /// + /// TFS Client OM 除托管程序集外还依赖两个纯 win32 DLL + /// (Microsoft.WITDataStore32/64.dll)。托管程序集由 Costura 内嵌并从内存加载, + /// native DLL 只能落盘后 LoadLibrary,所以单文件分发时: + /// 启动阶段把内嵌的 native DLL 释放到 %TEMP%\TfsExcelImporter\native\{内容hash}, + /// 再 LoadLibrary 预加载 —— 之后 TFS 内部的 DllImport 会直接命中已加载模块。 + /// 目录名带 DLL 内容 hash,升级后不会残留旧版本。 + /// exe 同目录存在同名 DLL(开发机 bin 目录、绿色解压版)时不做任何处理。 + /// + internal static class NativeLibraryLoader + { + [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "LoadLibraryW")] + private static extern IntPtr LoadLibrary(string path); + + public static void EnsureLoaded() + { + var fileName = Environment.Is64BitProcess + ? "Microsoft.WITDataStore64.dll" + : "Microsoft.WITDataStore32.dll"; + + if (File.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName))) + return; + + try + { + var asm = typeof(NativeLibraryLoader).Assembly; + var resourceName = "native." + fileName; + using (var stream = asm.GetManifestResourceStream(resourceName)) + { + if (stream == null) + { + Debug.WriteLine("未找到内嵌 native 资源: " + resourceName); + return; + } + + byte[] bytes; + using (var buffer = new MemoryStream()) + { + stream.CopyTo(buffer); + bytes = buffer.ToArray(); + } + + var target = Path.Combine(NativeDir(bytes), fileName); + Directory.CreateDirectory(Path.GetDirectoryName(target)); + if (!File.Exists(target)) + { + try { File.WriteAllBytes(target, bytes); } + catch (IOException) + { + // 同 hash 目录已被另一实例写住,内容等价,直接用 + if (!File.Exists(target)) throw; + } + } + + if (LoadLibrary(target) == IntPtr.Zero) + Debug.WriteLine("LoadLibrary 失败(" + Marshal.GetLastWin32Error() + "): " + target); + } + } + catch (Exception ex) + { + // 释放失败不阻断启动:TFS 连接时会自行报 DllNotFound,提示仍是可读的 + Debug.WriteLine("释放 native DLL 失败: " + ex.Message); + } + } + + private static string NativeDir(byte[] bytes) + { + byte[] hash; + using (var sha = SHA256.Create()) + hash = sha.ComputeHash(bytes); + var stamp = BitConverter.ToString(hash, 0, 4).Replace("-", ""); + return Path.Combine(Path.GetTempPath(), "TfsExcelImporter", "native", stamp); + } + } +} diff --git a/TfsExcelImporter/Program.cs b/TfsExcelImporter/Program.cs index a417a71..7f2e240 100644 --- a/TfsExcelImporter/Program.cs +++ b/TfsExcelImporter/Program.cs @@ -8,6 +8,9 @@ namespace TfsExcelImporter [STAThread] private static void Main() { + // 单文件分发时 native DLL 从内嵌资源释放并预加载(TFS Client OM 需要) + NativeLibraryLoader.EnsureLoaded(); + Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new MainForm()); diff --git a/TfsExcelImporter/TfsExcelImporter.csproj b/TfsExcelImporter/TfsExcelImporter.csproj index bf66a2e..85dc59d 100644 --- a/TfsExcelImporter/TfsExcelImporter.csproj +++ b/TfsExcelImporter/TfsExcelImporter.csproj @@ -11,6 +11,10 @@ true app.manifest + + app.ico + + en @@ -22,16 +26,34 @@ + + + PreserveNewest - - - PreserveNewest - + + + + + + + native.Microsoft.WITDataStore64.dll + + + native.Microsoft.WITDataStore32.dll + diff --git a/TfsExcelImporter/app.ico b/TfsExcelImporter/app.ico new file mode 100644 index 0000000000000000000000000000000000000000..ad5af13c29c55cebd19e82f73665c94d96db6fff GIT binary patch literal 123112 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

;(x$#?)WrbciG}5P#QOEh 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 0.0 else 0.0 + oy = dy if dy > 0.0 else 0.0 + inner = dx if dx > dy else dy + if inner > 0.0: + inner = 0.0 + return math.hypot(ox, oy) + inner - r + + +def sd_seg(x, y, ax, ay, bx, by): + pax, pay = x - ax, y - ay + bax, bay = bx - ax, by - ay + den = bax * bax + bay * bay + t = 0.0 if den == 0.0 else max(0.0, min(1.0, (pax * bax + pay * bay) / den)) + return math.hypot(pax - bax * t, pay - bay * t) + + +def clamp01(v): + return 0.0 if v < 0.0 else (1.0 if v > 1.0 else v) + + +def cov(d, size): + """距离场 -> 覆盖率(1px 过渡带)。""" + return clamp01(0.5 - d * size) + + +# ----------------------------------------------------------------- 单尺寸渲染 +def render(size, variant="tray"): + st = style(size) + # 只有箭头时没有「托盘」当配重,线条要更粗一点才站得住 + stroke = st["stroke"] + (0.016 if variant == "arrow" else 0.0) + grow = st["grow"] + arrow, tray, tray_w = glyph_capsules(stroke, variant) + gr = stroke / 2.0 + # 大尺寸下托盘描边略细于箭头:用「粗细」而不是「透明度」做主次(透明度压在深蓝上会发灰) + tray_k = tray_w * (1.0 if size <= 32 else 0.94) + tray_tone = 1.0 + + hw = 0.5 - TILE_MARGIN + rad = TILE_RADIUS + inner_shrink = 1.0 / size # 内描边宽度 = 1px + + buf = bytearray(size * size * 4) + span = 1.0 - 2.0 * TILE_MARGIN + + for py in range(size): + v = (py + 0.5) / size + # 字形整体缩放:把坐标拉回以 0.5 为心 + gv = 0.5 + (v - 0.5) / grow + row_off = py * size * 4 + for px in range(size): + u = (px + 0.5) / size + + a = cov(sd_round_rect(u, v, 0.5, 0.5, hw, hw, rad), size) + if a <= 0.0: + continue + + # 渐变(略偏对角线,避免纯竖条的死板) + t = clamp01(((v - TILE_MARGIN) * 0.82 + (u - TILE_MARGIN) * 0.18) / span) + cr = COLOR_TOP[0] + (COLOR_BOT[0] - COLOR_TOP[0]) * t + cg = COLOR_TOP[1] + (COLOR_BOT[1] - COLOR_TOP[1]) * t + cb = COLOR_TOP[2] + (COLOR_BOT[2] - COLOR_TOP[2]) * t + + # 顶部高光 + if st["gloss"] > 0.0: + g = st["gloss"] * clamp01(1.0 - (v - TILE_MARGIN) / 0.38) + cr += (255.0 - cr) * g + cg += (255.0 - cg) * g + cb += (255.0 - cb) * g + + # 1px 内描边(沿边缘的细亮线,让方块边界更挺) + if st["rim"] > 0.0: + d_in = sd_round_rect(u, v, 0.5, 0.5, hw - inner_shrink, + hw - inner_shrink, rad - inner_shrink) + band = a - cov(d_in, size) + if band > 0.0: + k = st["rim"] * band + cr += (255.0 - cr) * k + cg += (255.0 - cg) * k + cb += (255.0 - cb) * k + + # 字形:托盘(略细)+ 箭头(主调) + gu = 0.5 + (u - 0.5) / grow + for group, tone, k in ((tray, tray_tone, tray_k), (arrow, 1.0, 1.0)): + d = 1e9 + rg = gr * k + for (ax, ay, bx, by) in group: + dd = sd_seg(gu, gv, ax, ay, bx, by) - rg + if dd < d: + d = dd + ag = cov(d, size) * a * tone + if ag > 0.0: + cr += (WHITE[0] - cr) * ag + cg += (WHITE[1] - cg) * ag + cb += (WHITE[2] - cb) * ag + + i = row_off + px * 4 + buf[i] = int(cr + 0.5) + buf[i + 1] = int(cg + 0.5) + buf[i + 2] = int(cb + 0.5) + buf[i + 3] = int(a * 255.0 + 0.5) + return buf + + +# ----------------------------------------------------------------- PNG / ICO +def png_bytes(w, h, rgba): + raw = bytearray() + for y in range(h): + raw.append(0) + raw += rgba[y * w * 4:(y + 1) * w * 4] + + def chunk(tag, data): + return (struct.pack(">I", len(data)) + tag + data + + struct.pack(">I", zlib.crc32(tag + data) & 0xFFFFFFFF)) + + ihdr = struct.pack(">IIBBBBB", w, h, 8, 6, 0, 0, 0) + return (b"\x89PNG\r\n\x1a\n" + chunk(b"IHDR", ihdr) + + chunk(b"IDAT", zlib.compress(bytes(raw), 9)) + chunk(b"IEND", b"")) + + +def dib_bytes(w, h, rgba): + """32bpp 自下而上的 BMP(ICO 里的 DIB,含 AND 掩码)。""" + xor = bytearray() + for y in range(h - 1, -1, -1): + for x in range(w): + i = (y * w + x) * 4 + xor += bytes((rgba[i + 2], rgba[i + 1], rgba[i], rgba[i + 3])) + and_stride = ((w + 31) // 32) * 4 + and_mask = bytes(and_stride * h) + hdr = struct.pack("= 256 else size + out.append(struct.pack("= dh: + break + for x in range(sw * scale): + sx = x // scale + dx = ox + x + if dx >= dw: + break + si = (sy * sw + sx) * 4 + di = (dy * dw + dx) * 4 + dst[di:di + 4] = src[si:si + 4] + + +def preview(renders, path): + pad = 10 + big = renders[256] + strip = SIZES[:-1] # 16..128 + zoom = 4 + strip_w = sum(s * zoom + pad for s in strip) + w = max(256 + 2 * pad, strip_w + pad) + h = 256 + strip_w * 0 + 64 + 128 * zoom + 3 * pad + h = 256 + pad * 3 + 128 * zoom + canvas = bytearray(w * h * 4) + for i in range(w * h): + canvas[i * 4 + 0] = 0xF3 + canvas[i * 4 + 1] = 0xF4 + canvas[i * 4 + 2] = 0xF6 + canvas[i * 4 + 3] = 0xFF + blit(canvas, w, h, big, 256, 256, pad, pad, 1) + x = pad + y = 256 + pad * 2 + for s in strip: + blit(canvas, w, h, renders[s], s, s, x, y + (128 - s) * zoom, zoom) + x += s * zoom + pad + with open(path, "wb") as f: + f.write(png_bytes(w, h, canvas)) + return w, h + + +# ----------------------------------------------------------------- main +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--out", default="TfsExcelImporter/app.ico") + ap.add_argument("--preview", default="tools/icon_preview.png") + ap.add_argument("--only-preview", action="store_true") + ap.add_argument("--variant", default="arrow", choices=["arrow", "tray", "slot"]) + args = ap.parse_args() + + root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + out_ico = args.out if os.path.isabs(args.out) else os.path.join(root, args.out) + out_png = (args.preview if os.path.isabs(args.preview) + else os.path.join(root, args.preview)) + if args.variant != "arrow": + base, ext = os.path.splitext(out_png) + out_png = "%s_%s%s" % (base, args.variant, ext) + + renders = {} + for s in SIZES: + renders[s] = render(s, args.variant) + print("rendered %dx%d" % (s, s)) + + frames = [(s, png_bytes(s, s, renders[s]) if s >= 256 + else dib_bytes(s, s, renders[s])) for s in SIZES] + + if not args.only_preview: + with open(out_ico, "wb") as f: + f.write(ico_bytes(frames)) + print("wrote %s (%d bytes)" % (out_ico, os.path.getsize(out_ico))) + + with open(os.path.splitext(out_png)[0] + "_256.png", "wb") as f: + f.write(png_bytes(256, 256, renders[256])) + w, h = preview(renders, out_png) + print("wrote %s (%dx%d)" % (out_png, w, h)) + + +if __name__ == "__main__": + main() diff --git a/tools/pe_icon.py b/tools/pe_icon.py new file mode 100644 index 0000000..d3492ea --- /dev/null +++ b/tools/pe_icon.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python3 +"""查 exe 里到底嵌了哪套图标(PE 资源解析),可导出最大帧为 PNG 核对。 + +用途:换图标后 Windows 仍显示旧图标时,先确认「exe 里是新图标」还是「外壳图标缓存没刷」。 + + python tools/pe_icon.py dist/TfsExcelImporter.exe [out_256.png] +""" + +import struct +import sys +import zlib + + +def u16(d, o): + return struct.unpack_from("I", len(data)) + tag + data + + struct.pack(">I", zlib.crc32(tag + data) & 0xFFFFFFFF)) + + with open(path, "wb") as f: + f.write(b"\x89PNG\r\n\x1a\n" + + chunk(b"IHDR", struct.pack(">IIBBBBB", w, h, 8, 6, 0, 0, 0)) + + chunk(b"IDAT", zlib.compress(bytes(raw), 9)) + chunk(b"IEND", b"")) + + +def dib_to_rgba(payload): + bw, bh2 = struct.unpack_from(" 2 else None + res = parse_resources(exe) + + groups = [(p, b) for p, b in res if p[0] == 14] + icons = {(p[1] if len(p) > 1 else 0): b for p, b in res if p[0] == 3} + print("%s: RT_GROUP_ICON=%d RT_ICON=%d" % (exe, len(groups), len(icons))) + if not groups: + print("!! exe 里没有图标资源(会用系统默认 exe 图标)") + return + + for path_ids, b in groups: + cnt, = struct.unpack_from("", out_png) + return + for size, idx, sz in frames: + if size == 48: + w, h, rgba = dib_to_rgba(icons[idx]) + png_write(out_png, w, h, rgba) + print(" 已导出 48 DIB 帧 ->", out_png) + return + + +if __name__ == "__main__": + main() diff --git a/tools/win_screenshot.py b/tools/win_screenshot.py new file mode 100644 index 0000000..ec435da --- /dev/null +++ b/tools/win_screenshot.py @@ -0,0 +1,212 @@ +#!/usr/bin/env python3 +"""冒烟验证:直接拉起 Release exe,截取真实窗口(含标题栏图标),存 PNG。 + +用途:确认 ApplicationIcon 与 Form.Icon 都生效、且换图标后窗口能正常起来。 +纯标准库 + ctypes,不依赖任何第三方包。 +""" + +import ctypes +import os +import struct +import subprocess +import sys +import time +import zlib +from ctypes import wintypes as wt + +u32 = ctypes.WinDLL("user32", use_last_error=True) +g32 = ctypes.WinDLL("gdi32", use_last_error=True) +k32 = ctypes.WinDLL("kernel32", use_last_error=True) + +u32.PrintWindow.argtypes = [wt.HWND, wt.HDC, wt.UINT] +u32.GetWindowRect.argtypes = [wt.HWND, ctypes.POINTER(wt.RECT)] +u32.GetWindowDC.argtypes = [wt.HWND] +u32.GetWindowDC.restype = wt.HDC +u32.GetWindowTextW.argtypes = [wt.HWND, wt.LPWSTR, ctypes.c_int] +u32.GetWindowThreadProcessId.argtypes = [wt.HWND, ctypes.POINTER(wt.DWORD)] +u32.IsWindowVisible.argtypes = [wt.HWND] +u32.SendMessageW.argtypes = [wt.HWND, wt.UINT, wt.WPARAM, wt.LPARAM] +u32.SendMessageW.restype = ctypes.c_void_p +g32.CreateCompatibleDC.argtypes = [wt.HDC] +g32.CreateCompatibleDC.restype = wt.HDC +g32.CreateCompatibleBitmap.argtypes = [wt.HDC, ctypes.c_int, ctypes.c_int] +g32.CreateCompatibleBitmap.restype = wt.HBITMAP +g32.SelectObject.argtypes = [wt.HDC, wt.HGDIOBJ] +g32.SelectObject.restype = wt.HGDIOBJ +g32.GetDIBits.argtypes = [wt.HDC, wt.HBITMAP, wt.UINT, wt.UINT, ctypes.c_void_p, + ctypes.c_void_p, wt.UINT] +u32.ReleaseDC.argtypes = [wt.HWND, wt.HDC] +u32.ReleaseDC.restype = ctypes.c_int +u32.GetDC.argtypes = [wt.HWND] +u32.GetDC.restype = wt.HDC +u32.FillRect.argtypes = [wt.HDC, ctypes.POINTER(wt.RECT), wt.HBRUSH] +g32.DeleteObject.argtypes = [wt.HGDIOBJ] +g32.DeleteObject.restype = wt.BOOL +g32.DeleteDC.argtypes = [wt.HDC] +g32.DeleteDC.restype = wt.BOOL +g32.CreateSolidBrush.argtypes = [wt.DWORD] +g32.CreateSolidBrush.restype = wt.HBRUSH + + +class BITMAPINFOHEADER(ctypes.Structure): + _fields_ = [("biSize", wt.DWORD), ("biWidth", wt.LONG), ("biHeight", wt.LONG), + ("biPlanes", wt.WORD), ("biBitCount", wt.WORD), + ("biCompression", wt.DWORD), ("biSizeImage", wt.DWORD), + ("biXPelsPerMeter", wt.LONG), ("biYPelsPerMeter", wt.LONG), + ("biClrUsed", wt.DWORD), ("biClrImportant", wt.DWORD)] + + +def bgra_to_rgba(buf): + """GetDIBits 给的是 BGRA,PNG 要 RGBA。""" + out = bytearray(buf) + for i in range(0, len(out), 4): + out[i], out[i + 2] = out[i + 2], out[i] + return bytes(out) + + +def png(path, w, h, rgba): + raw = bytearray() + for y in range(h): + raw.append(0) + raw += rgba[y * w * 4:(y + 1) * w * 4] + + def chunk(tag, data): + return (struct.pack(">I", len(data)) + tag + data + + struct.pack(">I", zlib.crc32(tag + data) & 0xFFFFFFFF)) + + with open(path, "wb") as f: + f.write(b"\x89PNG\r\n\x1a\n" + + chunk(b"IHDR", struct.pack(">IIBBBBB", w, h, 8, 6, 0, 0, 0)) + + chunk(b"IDAT", zlib.compress(bytes(raw), 9)) + chunk(b"IEND", b"")) + + +def find_window(pid, timeout=25.0): + result = [] + + @ctypes.WINFUNCTYPE(wt.BOOL, wt.HWND, wt.LPARAM) + def cb(hwnd, _): + p = wt.DWORD() + u32.GetWindowThreadProcessId(hwnd, ctypes.byref(p)) + if p.value != pid or not u32.IsWindowVisible(hwnd): + return True + n = u32.GetWindowTextLengthW(hwnd) + if n <= 0: + return True + buf = ctypes.create_unicode_buffer(n + 2) + u32.GetWindowTextW(hwnd, buf, n + 2) + result.append((hwnd, buf.value)) + return False + + end = time.time() + timeout + while time.time() < end: + u32.EnumWindows(cb, 0) + if result: + return result[0] + time.sleep(0.3) + return None + + +def grab(hwnd, path): + r = wt.RECT() + u32.GetWindowRect(hwnd, ctypes.byref(r)) + w, h = r.right - r.left, r.bottom - r.top + if w <= 0 or h <= 0: + raise RuntimeError("window rect empty") + src = u32.GetWindowDC(hwnd) + mem = g32.CreateCompatibleDC(src) + bmp = g32.CreateCompatibleBitmap(src, w, h) + old = g32.SelectObject(mem, bmp) + ok = u32.PrintWindow(hwnd, mem, 2) # PW_RENDERFULLCONTENT + bi = BITMAPINFOHEADER() + bi.biSize = ctypes.sizeof(BITMAPINFOHEADER) + bi.biWidth, bi.biHeight = w, -h + bi.biPlanes, bi.biBitCount, bi.biCompression = 1, 32, 0 + buf = ctypes.create_string_buffer(w * h * 4) + lines = g32.GetDIBits(mem, bmp, 0, h, buf, ctypes.byref(bi), 0) + g32.SelectObject(mem, old) + g32.DeleteObject(bmp) + g32.DeleteDC(mem) + u32.ReleaseDC(hwnd, src) + rgba = bgra_to_rgba(buf.raw) + png(path, w, h, rgba) + return w, h, ok, lines, rgba + + +def crop_zoom(src_png_w, src_png_h, rgba, cw, ch, scale, path, ox=0, oy=0): + out_w, out_h = cw * scale, ch * scale + dst = bytearray(out_w * out_h * 4) + for y in range(out_h): + sy = oy + y // scale + for x in range(out_w): + sx = ox + x // scale + si = (sy * src_png_w + sx) * 4 + di = (y * out_w + x) * 4 + dst[di:di + 4] = rgba[si:si + 4] + png(path, out_w, out_h, dst) + + +def main(): + exe = sys.argv[1] + out = sys.argv[2] + icon_dump = sys.argv[3] if len(sys.argv) > 3 else None + + proc = subprocess.Popen([exe], cwd=os.path.dirname(exe)) + try: + got = find_window(proc.pid) + if not got: + print("FAIL: 没找到窗口(可能是启动崩溃),进程存活 =", proc.poll() is None) + if proc.poll() is None: + proc.terminate() + return 1 + hwnd, title = got + print("window title:", title) + + # WM_GETICON=0x7F, ICON_BIG=1 / ICON_SMALL=0 + big = u32.SendMessageW(hwnd, 0x7F, 1, 0) + small = u32.SendMessageW(hwnd, 0x7F, 0, 0) + print("WM_GETICON big=%#x small=%#x" % (big or 0, small or 0)) + + time.sleep(0.6) + w, h, ok, lines, pixels = grab(hwnd, out) + print("printed %dx%d ok=%s lines=%d -> %s" % (w, h, ok, lines, out)) + # 标题栏局部放大 4 倍,专门看图标 + crop_zoom(w, h, pixels, min(300, w), min(44, h), 4, + os.path.splitext(out)[0] + "_titlebar.png", 0, 0) + print("titlebar crop ->", os.path.splitext(out)[0] + "_titlebar.png") + + if icon_dump and big: + u32.DrawIconEx.argtypes = [wt.HDC, ctypes.c_int, ctypes.c_int, wt.HICON, + ctypes.c_int, ctypes.c_int, wt.UINT, + wt.HBRUSH, wt.UINT] + src = u32.GetDC(None) + mem = g32.CreateCompatibleDC(src) + size = 32 + bmp = g32.CreateCompatibleBitmap(src, size, size) + old = g32.SelectObject(mem, bmp) + # 白底,避免透明区域看不清 + brush = g32.CreateSolidBrush(0x00FFFFFF) + rect = wt.RECT(0, 0, size, size) + u32.FillRect(mem, ctypes.byref(rect), brush) + u32.DrawIconEx(mem, 0, 0, big, size, size, 0, None, 3) # DI_NORMAL + bi = BITMAPINFOHEADER() + bi.biSize = ctypes.sizeof(BITMAPINFOHEADER) + bi.biWidth, bi.biHeight = size, -size + bi.biPlanes, bi.biBitCount, bi.biCompression = 1, 32, 0 + buf2 = ctypes.create_string_buffer(size * size * 4) + g32.GetDIBits(mem, bmp, 0, size, buf2, ctypes.byref(bi), 0) + g32.SelectObject(mem, old) + g32.DeleteObject(bmp) + g32.DeleteObject(brush) + g32.DeleteDC(mem) + u32.ReleaseDC(None, src) + png(icon_dump, size, size, bgra_to_rgba(buf2.raw)) + print("icon dumped ->", icon_dump) + finally: + time.sleep(0.2) + if proc.poll() is None: + proc.terminate() + return 0 + + +if __name__ == "__main__": + sys.exit(main())