Files
ctbjrj/.agents/skills/winforms-designer-package/SKILL.md
T

17 KiB
Raw Blame History

name, description
name description
winforms-designer-package 把编译好的 .NET Framework 4.8 WinForms 项目(exe + 依赖 DLL + 图标)用 Inno Setup 6 打包成可分发的单文件安装包(setup.exe)。当用户说"打包""安装包""setup""发布""做成安装程序""Inno Setup""生成 setup.exe""打安装包""做成 exe 安装包""封装发布""更新包",或要求把 F:\pycode\wpf\src\WinFormsDesigner.Fx48 下 Samples\COOO\scr<项目名> 里编译好的 exe 打包成安装包,或对"成套报价软件"项目发版打包(含版本号递增/Gitea Release/更新包的完整 8 步发版链,见文末专章)时,必须使用本技能。即使用户没说"Inno Setup",只要是要把编译产物做成可分发/可安装的形式就触发。涵盖:识别要打包的文件、写 setup.iss 脚本、中文语言包安装、编译安装包、图标嵌入、Program Files 权限处理、卸载清理等完整发布流程。

WinForms 设计器项目打包器

把 winforms-designer-compile 技能编译出的 <项目名>.exe + 依赖 DLL + 图标,用 Inno Setup 6 打包成一个单文件 setup.exe 安装包,带中文安装向导、开始菜单/桌面快捷方式、控制面板卸载项。

本技能流程在 GCS 铜排壳体计算项目中完整实战验证过,每个步骤都真实跑通。

⛔ 铁律:不做测试安装,直接交付正式版(用户强制,2026-09-24)

禁止 AI 自己做任何安装测试——包括但不限于:

  • 编译"测试变体"安装包(降权限 PrivilegesRequired=lowest / 改临时目录)再静默安装验证
  • 把 setup.exe 装到本机临时目录、虚拟机去验证启动/卸载
  • 安装后自动运行程序验证功能

正确做法:按需求直接编译正式版 setup.exe(含正确的默认安装目录、权限、快捷方式),立即交付给用户,由用户本人安装和测试。测试中发现的任何问题由用户反馈后在下轮修复。

原因(xuanxing 项目实测教训):AI 侧测试变体要在用户桌面弹 UAC/错误框(如降权限后写公共桌面快捷方式报 IPersistFile::Save 失败 0x80070005 拒绝访问)、留残留目录和卸载表项,还要反复等待静默安装——比用户直接装一遍正式版更慢更吵。打包环节唯一要"验证"的只有 ISCC 编译输出 Successful compile 和产物存在。

前提:这是编译之后的环节

本技能接在 winforms-designer-compile 之后。进本技能前,scr\<项目名>\ 目录里应该已经有:

  • <项目名>.exe(csc 编译产物)
  • 第三方 .dll(如 AdvancedDataGridView.dll)
  • 可选 app.ico(程序图标)

如果还没有 exe,先去用 winforms-designer-compile 技能编译。

触发前提

  • Inno Setup 6 已安装(默认在 C:\Program Files (x86)\Inno Setup 6\)。没装的话提示用户先装。
  • 项目目录约定在 F:\pycode\wpf\src\WinFormsDesigner.Fx48\bin\Debug\net48\Samples\COOO\scr\<项目名>\。

📋 完整打包流程(5 步)

第 1 步:识别需要打包的文件

进项目目录 scr\<项目名>\,按下表分类:

文件类型 来源 是否打包
<项目名>.exe csc 编译产物 ✅ 必需
第三方 .dll(如 AdvancedDataGridView.dll) 设计器/代码依赖 ✅ 必需(缺了程序跑不起来)
app.ico(若有) 自制图标 ✅ 建议带(用于快捷方式)
.cs / .ui.cs / .xml 源码 — ❌ 不打包
build.bat / build.rsp / *.log — ❌ 不打包
单价.cfg / *.cfg 配置 运行时生成 ⚠️ 一般不打包(程序用默认值重建)

判断要打包哪些 DLL:读 <窗体名>.dependencies.txt(设计器生成的权威清单),或直接 ls *.dll 看项目里实际存在的 DLL。

第 2 步:建发布目录 + 复制运行时文件

在 Samples\COOO\ 下建 release\<项目名>\,只复制运行时必需文件(源码和构建文件不进):

mkdir -p 'F:\pycode\wpf\src\WinFormsDesigner.Fx48\bin\Debug\net48\Samples\COOO\release\<项目名>'
cp 'F:\...\scr\<项目名>\<项目名>.exe'           'F:\...\release\<项目名>\/'
cp 'F:\...\scr\<项目名>\AdvancedDataGridView.dll' 'F:\...\release\<项目名>\/'   # 按实际依赖
cp 'F:\...\scr\<项目名>\app.ico'                 'F:\...\release\<项目名>\/'   # 若有图标

第 3 步:检查 Inno Setup 环境 + 中文语言包

检查 Inno Setup:

ls 'C:\Program Files (x86)\Inno Setup 6\ISCC.exe' 2>&1 && echo 'Inno Setup 已安装' || echo '未安装,需先装 Inno Setup 6'

中文语言包:Inno Setup 6 默认不带中文简体语言包。要做中文界面必须下载 ChineseSimplified.isl 放到 C:\Program Files (x86)\Inno Setup 6\Languages\(需管理员权限)。下载用 kira-96 社区维护版(已验证可用):

# 1. 下载到可写位置
curl -sL -o ChineseSimplified.isl 'https://raw.githubusercontent.com/kira-96/Inno-Setup-Chinese-Simplified-Translation/main/ChineseSimplified.isl'

# 2. 需管理员权限复制到 Program Files
powershell -NoProfile -Command "Start-Process cmd -ArgumentList '/c copy /Y ChineseSimplified.isl \"C:\Program Files (x86)\Inno Setup 6\Languages\\\"' -Verb RunAs -Wait"

# 3. 验证
ls 'C:\Program Files (x86)\Inno Setup 6\Languages\ChineseSimplified.isl'

⚠️ 下载的语言包必须带 UTF-8 BOM。下载后检查,没有 BOM 就补一个,否则中文界面会乱码:

python -c "
import os
p=r'C:\Program Files (x86)\Inno Setup 6\Languages\ChineseSimplified.isl'
d=open(p,'rb').read()
if d[:3]!=b'\xef\xbb\xbf': open(p,'wb').write(b'\xef\xbb\xbf'+d); print('已补 BOM')
"

(Program Files 需要管理员权限写入,可能要提权 PowerShell 跑。)

第 4 步:编写 setup.iss 脚本

在 release\<项目名>\ 目录下建 setup.iss。下面是实战验证过的完整模板(GCS 铜排壳体计算项目),按需替换 <...> 占位:

; ============================================================
; <项目名> 安装包脚本 — Inno Setup 6
; 文件必须保存为 UTF-8 with BOM 编码(中文才能正确显示)
; ============================================================

[Setup]
AppName=<项目显示名>
AppVersion=1.0
AppPublisher=<作者或公司>
DefaultDirName=C:\<项目目录名>
DefaultGroupName=<项目显示名>
DisableProgramGroupPage=yes
OutputDir=Output
OutputBaseFilename=<项目名>_Setup
Compression=lzma2
SolidCompression=yes
WizardStyle=modern
ArchitecturesAllowed=x64
ArchitecturesInstallIn64BitMode=x64
PrivilegesRequired=admin

; 安装包自身图标(用程序的 app.ico)
SetupIconFile=app.ico
UninstallDisplayIcon={app}\app.ico
UninstallDisplayName=<项目显示名>

[Languages]
Name: "chinesesimp"; MessagesFile: "compiler:Languages\ChineseSimplified.isl"

[Tasks]
Name: "desktopicon"; Description: "创建桌面快捷方式(&D)"; GroupDescription: "附加图标:"

[Files]
Source: "<项目名>.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "<第三方DLL>.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "app.ico"; DestDir: "{app}"; Flags: ignoreversion

[Icons]
; 开始菜单快捷方式
Name: "{group}\<项目显示名>"; Filename: "{app}\<项目名>.exe"; IconFilename: "{app}\app.ico"; Comment: "<项目描述>"
Name: "{group}\卸载 <项目显示名>"; Filename: "{uninstallexe}"
; 桌面快捷方式
Name: "{commondesktop}\<项目显示名>"; Filename: "{app}\<项目名>.exe"; IconFilename: "{app}\app.ico"; Tasks: desktopicon

[Run]
; 安装完成可选启动
Filename: "{app}\<项目名>.exe"; Description: "立即启动 <项目显示名>"; Flags: nowait postinstall skipifsilent

[UninstallDelete]
; 卸载时彻底清理 {app} 目录
Type: filesandordirs; Name: "{app}"

setup.iss 段语法说明

段 作用
[Setup] 安装包基本信息、压缩、平台、权限。DefaultDirName = 默认安装位置({pf} = Program Files,或直接写 C:\xxx)
[Languages] 界面语言。中文用 chinesesimp + ChineseSimplified.isl
[Tasks] 可勾选任务。桌面快捷方式任务默认勾选(不要加 Flags: checked,新版不认)
[Files] 要打包的文件。Flags: ignoreversion = 不比对版本直接覆盖
[Icons] 快捷方式。{group} = 开始菜单文件夹,{app} = 安装目录,{commondesktop} = 公共桌面
[Run] 安装后动作。postinstall = 勾选"立即启动",skipifsilent = 静默安装时不启动
[UninstallDelete] 卸载时额外删除。filesandordirs 删整个目录及内容

⚠️ setup.iss 的两个必做细节

细节 1:必须 UTF-8 with BOM 编码。中文(AppName、说明等)才能正确显示,否则装界面是乱码。写完 .iss 后检查并补 BOM:

python -c "
data = open('setup.iss','rb').read()
if data[:3] != b'\xef\xbb\xbf':
    open('setup.iss','wb').write(b'\xef\xbb\xbf' + data)
    print('已加 UTF-8 BOM')
"

细节 2:[Tasks] 桌面快捷方式不要写 Flags: checked。新版 Inno Setup 不认这个 flag,编译报 "Parameter Flags includes an unknown flag"。任务默认就是勾选的,直接省略 Flags。

第 5 步:编译安装包

cd 'F:\pycode\wpf\src\WinFormsDesigner.Fx48\bin\Debug\net48\Samples\COOO\release\<项目名>'
'C:\Program Files (x86)\Inno Setup 6\ISCC.exe' setup.iss 2>&1 | tail -5

成功标志:末尾输出 Successful compile,并在 Output\<项目名>_Setup.exe 生成安装包(通常 1~3 MB,LZMA2 压缩后远小于源文件总和)。

编译时 Warning: A message named "..." has not been defined for "chinesesimp" 是正常的——中文语言包版本与 Inno Setup 主程序版本不完全同步,缺失的消息自动用英文 Default.isl 回退,不影响功能。


发布目录最终结构

Samples\COOO\release\<项目名>\
├── <项目名>.exe              ← 编译产物
├── <第三方DLL>.dll           ← 依赖
├── app.ico                   ← 图标
├── setup.iss                 ← Inno Setup 脚本(源文件,留着方便改版重打包)
└── Output\
    └── <项目名>_Setup.exe     ← 最终交付的安装包

交付物就是 Output\<项目名>_Setup.exe 这一个文件,用户双击即可安装,自带中文向导、快捷方式、卸载项。


图标制作(可选,让 exe 有专属图标)

如果想给程序做专属图标嵌入 exe,详见 references/icon-generation.md(Pillow 纯 Python 绘制多尺寸 ICO 的完整模板,零原生依赖)。

简要流程:

  1. 用 Pillow 绘制 512×512 图标 → 存成多尺寸 app.ico
  2. 编译时在 build.rsp 加 /win32icon:app.ico
  3. 窗体构造函数加 LoadAppIcon()(Icon.ExtractAssociatedIcon),让窗口/任务栏也显示图标

图标嵌入 exe 是编译环节做的事(/win32icon 是 csc 参数),打包环节只是把已有的 app.ico 一起带进安装包用于快捷方式。两环节配合。


常见问题排查

现象 原因 解决
安装界面中文乱码 setup.iss 不是 UTF-8 BOM 编码 按第 4 步"细节 1"补 BOM 后重新编译
Couldn't open include file "...ChineseSimplified.isl" 没装中文语言包 按第 3 步下载 ChineseSimplified.isl 到 Inno Setup 的 Languages 目录
中文语言包装了还乱码 语言包 .isl 没 UTF-8 BOM 给 .isl 文件补 BOM(需管理员权限)
Parameter "Flags" includes an unknown flag [Tasks] 写了 Flags: checked 删掉 Flags: checked,任务默认就勾选
安装到 Program Files 后程序保存配置报错 exe 目录无写入权限 程序里配置文件改存 %APPDATA%\<项目名>\(用 Environment.SpecialFolder.ApplicationData),并在 [UninstallDelete] 加 {userappdata}\<项目名> 卸载时清理
装的 exe 双击没反应 缺少第三方 DLL 检查 [Files] 是否把所有依赖 DLL 都打包了
卸载后配置文件残留 [UninstallDelete] 没覆盖配置目录 加 Type: filesandordirs; Name: "{userappdata}\<项目名>"
error CS0016: 未能写入输出文件(重新编译 exe 时) exe 被安装包运行的进程占用 先关掉运行中的程序再重新编译

发布前的完整流程(汇总)

1. [编译] 改完 .cs → 用 winforms-designer-compile 编译出 exe
2. [识别] 读 dependencies.txt 确定依赖 DLL
3. [建目录] 建 release\<项目名>\,复制 exe + DLL + ico
4. [写脚本] 写 setup.iss(用模板,改占位)+ 确保有 UTF-8 BOM
5. [语言包] 确认装了中文语言包(没有就下载,记得带 BOM)
6. [编译包] ISCC.exe setup.iss → 生成 Output\<项目名>_Setup.exe
7. [交付] 不做任何测试安装(见顶部铁律)——把 Output\<项目名>_Setup.exe 直接交给用户,由用户自行安装测试

🏭 项目专章:成套报价软件 完整发版体系(2026-10-01 定稿,用户强制)

仓库根:C:\Users\099978\Documents\SharpDevelop Projects\成套报价软件。 该项目发版不走上面的通用 5 步,走下面的 8 步固定链(多了版本号递增、更新包、git、Gitea Release 环节)。 用户说"打包/发版/上传到 git"针对本项目时,必须按本节执行,顺序不可换。

① 递增版本号 → ② 清进程+编译 → ③ make_package 组装 → ④ ISCC 安装包
→ ⑤ make_update_package 更新包 → ⑥ git 提交推送 → ⑦ Gitea Release → ⑧ 验收

① 递增版本号(版本号铁律:每次发版必须递增)

powershell -File tools\递增版本号.ps1          # 修订号+1;大版本: tools\递增版本号.ps1 1.1.0

唯一事实源 = 成套报价软件\Properties\AssemblyInfo.cs 的 AssemblyVersion(脚本同步 setup.iss 的 AppVersion 与安装包文件名)。关于软件页运行时自动读程序集版本。输出必须显示两处 [OK]。

② 清进程 + 编译

Get-Process | Where-Object { $_.Path -like '*成套报价软件*' -or $_.Path -like '*SharpDevelop Projects*' } | Stop-Process -Force
cd 成套报价软件   # ★ rsp 相对路径基于此子目录,在仓库根跑必报 CS2001
& "C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe" "@..\tools\verify_build.rsp" /warn:1

ExitCode=0 且无 warning 才继续(rsp 默认 /warn:0 压警告,排查必须 /warn:1)。

③ 组装发布目录

python tools\make_package.py    # 仓库根跑

核对输出:DLL 复制完成,缺失: 无;cadbt 段只有 node+CAD-Viewer(独立扒图 exe 已于 2026-10-01 退役);无 !! 警告。

④ ISCC 安装包

& "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" "release\成套报价软件\setup.iss"

lzma2 约 2 分钟;产物 release\成套报价软件\Output\成套报价软件_Setup_<版本>.exe(约 120MB);Successful compile 才算成。中文语言包已装(chinesesimp 消息缺失 Warning 属正常)。

⑤ 更新包

先改 tools\make_update_package.py 两处:PKG 目录名带版本(如 更新包_1.0.4)+ 说明 本期文案(只写用户可感知变化;使用方法写清覆盖哪个文件、怎么验证版本)。再跑 python tools\make_update_package.py。当前只含 成套报价软件.exe+使用说明(<1MB)。

⑥ git 提交推送

git add -A → git commit -m "发版 v<版本>:..." → git push(remote 已内嵌令牌)。

⑦ Gitea Release

tag=v<版本>(与 AssemblyInfo 一致)。PowerShell API 模式(令牌与仓库地址见 sd-enhanced-components 技能第 8 条或项目记忆):

  • 建 Release:Invoke-RestMethod -Method Post -Headers @{Authorization="token <令牌>"} -ContentType 'application/json; charset=utf-8' -Body ([Text.Encoding]::UTF8.GetBytes($body))——中文 body 必须 UTF8.GetBytes 否则乱码
  • 传附件:System.Net.Http.HttpClient + MultipartFormDataContent(字段名 attachment,PS5.1 无 -Form)
  • Release 说明与更新包说明同源

⑧ 验收

附件大小合理(Setup ~120MB、更新包 <1MB);提醒用户装机验证:关于软件页显示 v<版本>、CAD/PDF 扒图窗口可用。

故障速查(本项目专属)

现象 处置
组装/替换文件报"正在使用" ② 的进程没杀干净(查 node/AI 引擎/主程序)
编译报 CS2001 全部源文件找不到 工作目录错了——必须 成套报价软件\ 子目录
ISCC 报文件找不到 make_package 没跑或发布目录被清,回到 ③
Release 附件上传 401 令牌失效——请用户在 Gitea 设置→应用重新生成(git remote 和 API 同步换)
push 被拒 fetch first 用户网页传过文件——git pull --rebase 再 push,绝不 force push

配套技能

  • winforms-designer-compile:本技能的上游。先用它把 .cs + .ui.cs 编译成 exe,再交给本技能打包。
  • winforms-designer-xml:生成/校验窗体 XML 布局,是整个流水线(XML → 编译 → 打包)的起点。