ARTICLE · 1288165
我卸载了 VS,八天发了七个版本的桌面工具
第一人称实践记录。文中所有数字都能对着仓库和发行版页面核对,核对口径写在最后一节。
先说一件每天都在很多办公室里发生的事:一份二十页的合同扫描件要盖骑缝章,正经做法是整叠打出来,理齐,压到桌边,盖下去,再整叠塞回扫描仪,扫完还得逐页摆正、裁掉黑边。一个人干这套,二十分钟算手快的。
我做了个 Windows 小工具来吃这道工序:图片导进来,选纸张和章径,落章,导出整张效果图加逐页切片。中间那两次机器往返(打印和扫描)整段没了。
更有意思的是它是怎么被做出来的:八天,七个版本,我几乎没手写一行代码,机器上连 Visual Studio 都没有——早卸载了。而 AI 花得最久的地方也不是写代码,是证明它写的东西真能在别人的电脑上跑起来。后半截才是这篇想讲的东西。
先说结果
一个 Windows 桌面小工具(WordSealTool,文档盖章/转格式用的)到今天发了 11 个版本,工作方式在中间断成了两截。
前四版(1.0.0—1.0.2 在 6 月 27 日上午,1.0.3 在八天后的 7 月 5 日晚上)是豆包给代码、我在 Visual Studio 里手工拼出来的,每个窗体的动作都是一个一个对出来的。后七版(1.0.4 → 1.1.0,10 月 24 日到 31 日这八天)是另一个样子:我几乎没有手写一行代码,也没有打开过任何 IDE——Visual Studio 在那之前就卸载了,编译走命令行,验收走断言。
这两截的差别,就是这篇文章想讲的东西。
这八天里真正值得说的不是"AI 写得快"。快是廉价的,一天生成十个版本谁都能做到。值得说的是它交付的每一版都带着证据:最后一次发版前,它跑了 727 条断言,做了安装/卸载往返冒烟,并且主动指出我桌面上那个快捷方式是被上一版升级流程删掉的——那个 bug 是我报给它的,但根因、修复、回归断言,是它找齐的。
它替谁省下哪道工序
先把话说清楚:这工具吃的不是"设计"这道工序,是打印—盖章—扫描—摆正—裁边这一整套物理往返。它只处理图片(PNG/JPG/BMP/TIFF),不直接吃 PDF,也不是"电子签章"那套身份认证。所以别指望它替你把关,它只是替你省手。
按人群分一下,能替的是这些:
- 财务/会计
(回单、对账单、审计附件):原来打印→盖章→再扫描回电子档→裁边;现在导入扫描件、选章径、在预览上点一下落章、导出。省掉一次打印、一次扫描、一遍裁边。 - 行政/文印
(通知、公示、证明):原来同上,扫描完还得逐页摆正;现在同上。省掉一次打印、一次扫描、一遍摆正。 - 跑投标、签合同的
:原来二十页理齐、压边盖一枚骑缝章,对齐理半天;现在按顺序导入 N 页、落章、导出整张效果图,要装订就导出逐页切片(按原顺序拼回去章是完整的)。最狠的一项就是这里——整叠物理对齐没了。 - HR/异地用工
:原来在职证明盖完拍照发过去,清晰度像偷拍的;现在盖章后导出 300DPI,或直接把图拖出去转格式。省的是观感和来回返工。 - 只要转格式的
:手机拍的纸想变成"扫描件既视感",原来得打开修图软件;现在不盖章直接拖出,原像素原 DPI 只换封装,要白底就开"打印效果"(文档去色、章保持彩色)。不用为了换格式去开 Photoshop。
时间上我不吹实测,工序步数是硬的,分钟数是软的。拿二十页骑缝章举例,实体流程要走"打印一次、理纸压边、盖章、扫描一次、扫描完逐页摆正裁边";程序流程是"按顺序导入、选参数、落章、导出"。中间那两段机器往返——打印和扫描——是整段消失的。按我这台设备掐表,前者十八到二十分钟,后者三分钟左右。你的打印机和扫描仪未必是这个数,请用自己的设备换掉这两个数字。
再往下换算就是纯算术了:每月 200 份这类文件、每份省 15 分钟,是 50 小时;哪怕只有 50 份、每份省 5 分钟,也有四个多小时。这笔账只有你自己算得准,因为量在你的工作里,不在我的工具里。
起点:前四版是"AI 给代码 + Visual Studio 手工拼"
1.0.0、1.0.1、1.0.2 是 6 月 27 日上午发出去的,发行记录上的时间分别是 10:43、11:34、12:12;1.0.3 隔了八天,7 月 5 日 20:07 发出去,走的是同一套方式。那一段的工作方式和后来完全不同:我把需求讲给豆包,它回给我一段代码,我复制进 Visual Studio 的工程,编译、运行,发现某个窗体的某个动作不对,再回去问、再改。
1.0.3 干了什么,现在还能从仓库里翻出来:预览区支持把外部图片拖进来导入、也支持拖出去导出成品,导入手机拍的大公章时按物理英寸设上限,不再被 DPI 校正无限放大。那一版留下的代码里有个 region 标题直接写着「优化1+3」——那就是我手里攥着一份编了号的优化清单,一条一条复制进 IDE 的痕迹。也是从这一版起,仓库里才出现 Visual Studio 自动生成的那套脚手架(Properties/AssemblyInfo.cs、Resources.Designer.cs、Settings.Designer.cs),版本号还是硬写在一个常量里的。
那个阶段真正耗时间的不是"写",是对。每一个窗体的动作都要一个一个对出来:按钮点了有没有反应、下拉选中的值有没有落到配置里、导出的尺寸对不对、换一台机器还起不起来。对的方式是人眼加人手,一次一个动作。所以那三个版本的功能面很窄——因为每加一个功能,验收成本就线性往上加,而验收完全长在我身上。
后来能一天发两版,我认为关键不是"换了个更聪明的模型",而是验收这件事从人身上搬走了:编译变成一条命令,点界面变成反射调用私有方法,看效果变成量像素,装没装对变成注册表与快捷方式的断言。前两件事(AI 写代码、人对着看)2024 年就能做,第三件事才是这八天的新东西。
我到底让它做了什么
先给个可量化的轮廓(截至 1.1.0):
项目 数值
发行版 11 个(前 4 个是手工拼那段,后 7 个在这八天)
提交 17 次
源码 16 个 C# 文件,6421 行(其中 982 行是 Designer 生成的布局)
离线断言 727 条,全绿才允许打包
任务清单 77 项,每项一个可验证的完成条件
落笔的人 17 次提交全部由 AI 写;我负责提要求、拍板、验收
这八天,七个版本分别改了什么
- 1.0.4
(10-24 22:32):自制 exe 安装/卸载程序;两种安装范围;Program Files 下只给数据目录放开普通用户写权限。 - 1.0.5
(10-25 17:55):骑缝章(多图)窗体——世界坐标模型,整齐并排/扇形展开/错位叠放,效果图 + 逐页切片双导出。 - 1.0.6
(10-29 20:44):裁边自适应底色,不再把魔棒残留算进章径;导出可选打印效果/全彩效果。 - 1.0.7
(10-29 23:16):修 JPG 公章导入后在下拉里看不见;导出可选 PNG/JPG 并记住选择。 - 1.0.8
(10-31 11:33):提示新版本改为直接下载安装(原来只能跳网页自己找);未盖章时拖出即按原图转格式。 - 1.0.9
(10-31 14:27):用途边界写进 README/关于/首次启动确认;盖章成品默认叠半透明「副本」斜纹水印。 - 1.1.0
(10-31 16:00):两个窗体的参数区重排成两列;升级不再删桌面快捷方式。
(再往前那四版 1.0.0—1.0.3 是豆包 + Visual Studio 手工拼的那段,见上一节,没有留下过程截图。)
第一件事:它得先解决"没有 IDE 怎么编译"
我的机器上没有 Visual Studio,只有一个 .NET Framework。正常思路是"那你去装个 VS 吧"——这是最省事也最没用的建议。它给出的方案是用框架自带的 MSBuild 编译老式 csproj,但那个自带的编译器太老,不支持 C# 7.3,于是单独拉了一份独立 Roslyn,通过 CscToolPath 指给 MSBuild:
MSBuild.exe WordSealTool.csproj -p:CscToolPath=<独立 Roslyn>\tools -p:CscToolExe=csc.exe
这条命令写进了打包脚本,从此"编译 → 断言 → 打包 → 冒烟"是一根线拉到底的。这一步看起来是环境琐事,但它决定了后面所有事情能不能自动化:只要编译还需要人打开一个图形界面,验证就永远是我自己做。
第二件事:断言跑在"发布出去的那个 exe"上,不是跑在测试工程里
这是我这次最意外的收获。它写了一个独立的验证程序,用反射直接加载打包出来的 WordSealTool.exe,调用里面的私有方法做断言:版本比较、裁边算法、DPI 定标、导出格式、水印只挂在盖章这条路径上……
界面也能这么验。它用 TextRenderer.MeasureText 按程序真实字体量每个下拉框最长选项的像素宽度,然后断言:
字段宽度 ≥ 量出来的文字宽度(下拉另加 20px 箭头位)——不许出现"选项被截断成 A4 210×…" 标签不被截字、标签在字段左边 同一行控件垂直居中对齐误差 ≤2px、同行等高 同一列左边界对齐、矩形互不相交、行距 ≥24px 所有控件落在客户区内
这次把主窗体六个下拉从一列改成三行两列、把骑缝章窗体重排,就是靠这组几何断言兜底的。如果我人眼验收,我说不出"标签和字段中心差了 1.5 像素",我大概会说"看着还行"。"看着还行"是界面 bug 的温床,而像素阈值是可以每天重跑一遍的东西。
改之前(1.0.9):右侧参数一列排到底,导出那一行把 DPI/效果/格式/水印四个下拉挤在一起,标签和字段都只剩最小可用宽度。
图 1|1.0.9 主窗体(页面上的斜纹是 1.0.9 起的默认「副本」水印,那枚红圆是程序自带的假章,不是任何真实印章)

改之后(1.1.0):三行两列,标签右对齐、字段等宽,最长选项按真实字体量出来不被截断。
图 2|1.1.0 主窗体(纸张/章径、导出/效果、格式/水印)

骑缝章窗体用的是同一套列规则。之前:
图 3|旧版骑缝章窗体(纸张、章径、印章、排列、页间距、扇形角、章面角、导出各占一行,一路排到底)

之后——「印章」仍然独占一行,因为印章文件名长度不定,挤进半行一定被截断:
图 4|1.1.0 骑缝章窗体(成对排列,两个按钮并排)

顺带说一句骑缝章本身(1.0.5 加的功能):多页文档按页序排开,章可以整齐并排、绕左下角扇形展开、或者错位叠放,最后同时导出"一张整体效果图 + 每页各一张真骑缝章"。下面这张是扇形展开的渲染结果。
图 5|骑缝章扇形展开渲染

它还会自己截图。这一步踩了个很典型的坑:Graphics.CopyFromScreen 截到的是屏幕区域,窗口被别的窗口挡住就截了个背景;对没 Show() 过的窗体调 DrawToBitmap 会得到一张空白图。最后它换了 PrintWindow(hwnd, hdc, 2) 去抓真实窗体,才拿到能看的图。
第三件事:一个我自己都没法接受的 bug——升级把我的桌面图标删了
1.0.9 装完之后,桌面上那个"文件盖章"快捷方式不见了。我报给它的只有一句现象。
它翻出来的根因是安装器里的这段逻辑:安装函数收到"要不要建桌面快捷方式"的参数,而自动升级走的静默路径从来不提这个要求——于是"没提要求"被实现成了"要求删除",它就把用户自己放到桌面的图标删掉了。修法是引入三态而不是布尔:没提要求=保持原样,显式要求=创建,只有卸载=删除。
图 6|安装向导(1.0.4 起;那个「在桌面创建快捷方式」勾选框就是这次的开关——勾了才建,静默升级不带这个参数,以前恰恰是"不带参数"被当成了"要删除")

然后它给打包脚本补了三条回归断言:
静默安装(不带桌面参数)不得凭空造图标 静默安装不得改写它没被要求动的图标 带参数时图标照旧创建,卸载时照旧清走
跑完前两条就绿了。但真正让我对它改观的是下一步:它发现自己写的冒烟脚本有危险。脚本要验证"升级不删图标",就得先放一个测试图标在桌面上,而它假定桌面是干净的、并且会在收尾时删掉那个图标——那个位置正是我真实在用的快捷方式。于是它改成:先按字节备份、测完原样还回去,并且只在"这个图标指向测试目录"时才允许删除。
这件事的普适结论是:AI 补的测试本身也需要被审。它写的第一版验证逻辑,差点成为下一个删我图标的代码。
最难的不是写代码,是"证明它真的能跑"
自动升级那条链(发现新版本 → 下载安装包 → 校验 SHA256 → 等主程序退出 → 静默安装 → 重新拉起)没法在真发布源上反复试。它的做法是起一个只监听本地回环的裸 TcpListener 假发布源,在临时目录里造一个 9.9.8 的沙箱,让它真的升到 9.9.9,全程不碰真安装目录、不碰代码托管平台。
图 7|1.0.8 之前的更新提示(只能三选一:打开发布页自己下载/跳过这个版本/下次再问。1.0.8 把第一条换成了"直接下载并安装",用户参与的环节从"打开网页—找到包—运行—点 UAC"缩到一次确认)

水印那个功能的验收也是用像素说话的:拿一张 A4 扫描件,文字全放在页面下半部,同一枚章导两次,只统计上半部空白带的非白像素——带水印 2477 个墨点、最暗像素 221(半透明,不遮挡内容),切"无"之后 0 个墨点,两张成品的尺寸与 DPI 完全相同。
还有一类是外部平台的坑,只能实测出来。比如这个代码托管平台的发行版编辑页,那个"更新"按钮点了会跳成功页,但正文和附件经常根本没落库(前端的文件上传队列是手动处理的,提交时还没生成附件 id)。最后它放弃了网页,直接按接口序列走:上传拿附件 id → 先删同名旧附件(不删就报"不能上传同名文件")→ PATCH 发行版,而且必须把正文原样读回来一起提交,否则没传的字段有被清空的风险。改完一律用匿名下载比 SHA256 收尾——发行版详情页有渲染缓存,看网页会骗人。
它主动给我泼的冷水
这个工具是"往文档上盖一个章的图"。它在我还没想到的时候,先给了我一页风险清单:这类工具的边界在哪、会不会被用来伪造、发布出去我要不要负责。
结论不是"那别发了",而是把边界写进产品里,一共四处,随 1.0.9 上线:
README 开头就是用途边界:只导入您本单位所有、且已获得明确用印授权的印章图片;不导入、不截取、不仿制其他主体的印章。 首次启动一次性确认这段约定,点"不同意,退出"就退出且什么都不写;发布出去的配置文件刻意不带确认标记,所以每个新用户都会被问到。 盖章成品默认叠半透明"副本"斜纹水印(可关,选择会记住)。 明确写清它不是电子签章:不做身份认证、不加时间戳、不防篡改,成品不具备《电子签名法》意义上可靠电子签名的效力。
图 8|首次启动弹出的一次性确认(点"不同意,退出"直接退出且什么都不写,下次照样再问;这份文案同时常驻在「使用须知与关于」里,就是图 9)

图 9|「使用须知与关于」窗口(右下角版本行从"点击检查更新"变成"检查更新 | 使用须知与关于")

另外它给自己下了两条硬约束,我觉得这两条比任何功能都重要:发行文案、README、关于框里不许出现"具有法律效力/同等效力/代替实体章/无需授权"式表述;程序自带的示例章永远是虚构的("某某专用章 001678001678"),并且每次断言都全文扫一遍确认没有越界措辞。
还有一个决定我改了它的建议。它最初把新版本号定成 1.0.10,理由是"第三位一直加就好了"。我反问了一句:那以后要加到 1.0.100、1.0.1000 吗?于是有了现在写进版本号唯一出处(AssemblyInfo.cs)注释里的规矩:
第三位=只修 bug,界面和功能都没变 第二位=用户一打开就看得见的变化 第一位=老数据不兼容
所以那天的发版是 1.1.0 而不是 1.0.10。规矩要写在代码里,不要写在聊天记录里——聊天记录下次就找不到了。
它真实犯过的错(都不是"幻觉"那种段子)
- PowerShell 脚本里写中文注释
:无 BOM 的 UTF-8 会让一条语句"消失",脚本执行成功、退出码 0,但少干了一件事。这种错最阴险,因为它看起来是全绿的。之后的纪律是脚本一律 ASCII。 - Shell 变量被吃掉
:把带 $_ 的 PowerShell 片段塞进命令行传参,$_ 被外层 shell 展开成别的东西,报错信息像天书。同一份逻辑挪进 .ps1 文件就好了。 - 差点把真实公章打包
:这台机器的印章缓存目录里是我实际在用的多家单位公章图片。它写的所有打包脚本都必须是白名单列文件,绝不能整目录递归压缩。这条是纪律,不是运气。 - 一个会毁掉真实安装的开关
:打包脚本有个"装给所有用户"的冒烟开关,开头会把机器范围安装目录整个 rmdir /s /q——而那个目录正是我在用的安装,里面有 7 枚真实公章。发现之后我把它写成了禁止项:任何能删真实数据的脚本开关,都要在注释里标清它会动什么。
哪些决定我没有交给它
分工其实很清楚,而且不是我强加的:
要不要提交、要不要推送、要不要发版——每一次都要我点头,包括这次 1.1.0。 装到"所有用户"还是"仅当前用户"、默认要不要加水印、版本号进哪一位——这些是产品判断和风险偏好,它给方案和实测数据,我拍板。 任何会动到线上发行版和我本机真实安装的操作,先说清楚会动什么再动手。
反过来,它不该问我也不要问我的是:断言够不够、这一版和上一版字节差在哪、这个包哈希对不对。
想试就下,顺便一句丑话
仓库和发行版都在 gitee:仓库 https://gitee.com/tdcn/word-seal-tool,下载页 https://gitee.com/tdcn/word-seal-tool/releases(当前是 1.1.0)。
- 装到机器上
:下载 WordSealTool-Setup-v1.1.0.exe 双击。两种范围任选——"所有用户"装进 Program Files,要确认一次 UAC;"仅当前用户"装在自己目录下,不要管理员权限。 - 不想装
:下载 WordSealTool_v1.1.0.zip,解压后双击里面的 exe 就能跑,绿色免安装。 - 环境
:Windows 7 SP1 及以上,装了 .NET Framework 4.8 即可。盖章全程离线,断网也能用。唯一的联网只有两件事:启动时和点"检查更新"时去 gitee 看一眼版本号、有新版就把安装包下下来并校验——不传你的文档,也不传你的章。你要彻底断网,把 config.ini 里的更新地址改成内网镜像即可。
丑话说在前面,这不是客套:
- 只盖你自己单位、且你已经拿到明确用印授权的章。
别人的章不要截、不要抠、不要仿。这条没有弹性。 - 它盖出来的不是实体章原件。
对方要不要纸质原件、认不认电子件,先问清楚再发出去。 - 盖章即用印。
该审批审批、该登记登记。程序不记录谁在哪个文件上盖了章,出了事它替你证明不了任何东西。 成品默认叠半透明"副本"斜纹水印,就是给上面三条留的技术兜底;确实要干净成品,把界面上的"水印"切到"无",选择会记住。
第一次启动会把这套约定弹出来要你确认,点"不同意,退出"就直接退出,什么都不写、下次还问。你要是觉得这几条烦,那说明这工具现在还不适合你。
还有一件在排队的,正好是上面流程里唯一还得绕出去的一步:把文档直接转成图片。现在你手上如果是 PDF 或 Word,得先在别的地方转成图再导进来,这一步我不想一直留给别人。下一版我优先考虑补上它;你要是有这个需要,说一声——在仓库提个 issue,或者在你看到这篇文章的地方留一句话,说清楚你手上的文件是什么格式、一次多少页,比一句"支持一下"有用十倍。要的人多,我就把它往前排。
如果你想复制这套做法,我觉得最少需要三条
- 让验证不依赖人的眼睛和手。
编译要能一条命令跑完,验收要能写成断言。做不到这条,AI 写得再快也只是在给你生产待检查的作业。 - 断言要跑在交付物上,不是跑在测试工程里。
测私有方法、测打包出来的 exe、测安装完的目录——问题都出在"最后那一步的转换"上。 - 给 AI 设几条它不能自己放宽的硬约束,并且写进代码。
哪些目录永不打包、哪些措辞永不出现、哪个开关永不执行。写进注释和断言,而不是写进对话。
最后一句,不吹
我以前对"做个软件"的想象是有团队、有外包、有一台专门配好环境的机器。这八天下来,我真正拿到的不是"AI 帮我写代码",而是三件更实在的东西:
- 门槛没了
:一台没装 IDE 的电脑,一条命令编译,一套断言替我量到界面像素。我不用先成为程序员,再成为会打包的程序员。 - 验收不必长在我身上
:以前每个窗体的每个动作都要我用眼睛和手过一遍;现在我把"什么算对"讲清楚,它自己跑 727 条断言,跑不过就不让它发货。 - 它敢说不
:桌面图标那个 bug 是我报的,但根因埋在上一版的升级流程里,是它挖出来的;合规那几条也是它先提的——"你这两枚示例章不能做得像真章"。一个只会顺着我的工具,我不敢把发版键交给它。
所以对我来说,最实用的从来不是它写得快,而是它把"我一个人能不能维护一个发给别人用的软件"这个问题,从不能变成了能。这八天里我干得最像程序员的部分,是决定哪些事不交给它。
数字怎么核对
发行版时间线:代码托管平台 tdcn/word-seal-tool 的发行版列表,1.0.0 起共 11 个,1.0.4 在 10 月 24 日 22:32,1.1.0 在 10 月 31 日 16:00。 两截工作方式的分界线,数附件就能数出来:1.0.0—1.0.3 每个发行版三个附件(手工打的 文件盖章.msi + zip + tar.gz,四个 MSI 哈希和大小都不同,说明一版一装);1.0.4 起变成四个,多出来的正是脚本自动产出的 WordSealTool-Setup-vX.Y.Z.exe。 省工时那段:工序步数(打印、理纸压边、盖章、扫描、逐页摆正裁边)是硬指标,谁都能自己数;分钟数(十八到二十分钟 / 三分钟)是我在自己设备上掐的表,不是抽样统计,请换成你的打印机和扫描仪重算。 提交数、文件数、行数:git rev-list --count HEAD、git ls-files '*.cs' | xargs wc -l。 727 条断言:打包脚本最后一步的输出 ALL PASS (727 assertions),每次发版都会重跑一遍。 界面几何断言、水印墨点数、假发布源升级,都是那台开发机上的实测输出,不是估算。
配图说明
九张截图里出现的印章,全是程序自带的示例章(红色实心圆 + 绿色十字),没有任何一张含真实公章;图 1 页面上那层斜纹,就是默认的"副本"水印。















































































