任务管理器「名称」那一列显示的,从来不是你给 exe 起的文件名,而是 PE 资源里的 FileDescription。这个事我当初不知道,为它多耗了两个小版本。
那阵子在收七亿压缩 0.34 系列,改到 0.34-26、0.34-27 的时候,顺手把自带的 7z.exe 复制一份、改成自己的引擎名,打包进安装目录。资源管理器里看,名字对了,图标也换了,我就当这事完了。
装完的机器上打开任务管理器,名称列还是「7z.exe」,有的机器干脆空白。进程路径明明指在我们目录下。第一反应是缓存,Windows 对图标和描述确实有缓存,这个解释最省事。搁了半天没想明白,才转去看版本资源。
后来才去看版本资源。右键属性→详细信息,那几栏本来就是空的,我之前一直当成「没填」,没往「结构坏了」上想。用 PowerShell 读:
(Get-Item .\7eZipEngine.exe).VersionInfo | Format-List *FileDescription 空,FileVersion 也读不出来。到这一步才确认不是缓存,是 Windows 根本不认这个版本块。
中间走过一段弯路。最早的包确实没写版本资源,空白算正常,我就找了个现成的资源编辑工具批量写。写完属性页里公司名、描述、版本号都能看见,看着挺像回事,任务管理器还是不认。后来把写出来的文件和正常的版本块并排 dump 出来对,才发现工具写的是畸形 VS_VERSIONINFO:szKey 是 UTF-16 字符串,结尾必须带 NUL,再按 4 字节边界补零;它省了结尾 NUL,键名长度又是奇数,后面整块全错位。属性页容错,能显示;GetFileVersionInfo / VerQueryValue 一读 wLength 对不上就失败,任务管理器拿不到描述,只能退回文件名或留空。
版本资源本来就是一棵有长度字段的树:StringFileInfo 下按语言代码页分 StringTable,常见 040904B0 是英文加 Unicode,旁边还得有 VarFileInfo 里的 Translation。每个节点都带 wLength,每个字符串都要对齐。少一个字节,后面全乱——这玩意儿手工写,最容易觉得自己对了。不管七亿压缩还是七亿批量远程管理工具,打包时都得过这一关。
最后自己写了个小工具,按结构一格一格重建:补每个 szKey 的结尾 NUL 和对齐,补 Translation 节,再把四段版本号写回去。重新打包,卸载重装,FileDescription 这次读出来了。
任务管理器还是显示旧的。这是第二个坑:它对跑过的进程描述有缓存,重启资源管理器不够,得重启机器。我一度以为工具又写坏了,来回对了几个包的资源 dump,差点把对的改错。重启之后名称列才终于变过来,当时也没什么成就感,主要是烦,前面两天有一半时间在怀疑错的东西。
回头看,真正的教训不是「版本资源要写对」,是验证方式太松。我拿「右键属性看着正常」当验收,松到能放过一个结构错误的文件。后来这类改动就固定两条命令回读:读 FileDescription,再看资源大小和 wLength;装完重启一次看任务管理器。麻烦,但比返工便宜。现在七亿压缩和七亿批量远程管理工具打包前都会跑一遍,两个都是 Win32 程序,同样吃 PE 资源这套规则。后者的说明书在这里,里面有版本号和文件校验的说明,遇到描述读不出来的可以先照着对一遍。七亿压缩的最新包在 zip.7ehl.com。
同系列还写过两个坑:升级安装后桌面只剩鼠标,和右键菜单第 0 项点了没反应,都在外壳和安装这一层。
顺手的工具:七亿批量远程管理工具,Windows 端,RDP 九宫格、SSH 终端、SFTP、FTP 都在里面,免费。
评论