ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Inno Setup实战:打造专业Windows安装包的完整指南

2026/9/29 15:22:06 拓冰建站 浏览量
Inno Setup实战:打造专业Windows安装包的完整指南 前阵子公司要分发一个内部运维工具代码早就改完了卡在最后一步怎么给 Windows 用户一个“像样的安装包”。试了一圈之后我最终把方案定在 Inno Setup Compiler 上。这个免费软件比很多人想象中要强大得多用它可以很轻松地把 exe、DLL、资源文件、注册表项、快捷方式打包成一个常规的 Windows 安装程序。这篇文章把它的完整使用流程和踩过的坑整理出来适合正在给桌面软件做发行版的开发者、测试和运维同学参考。1. 先把概念理清你要的到底是“绿色免安装”还是“安装程序”很多新手第一反应是我把程序文件夹打个 zip 扔给用户不就行了确实能跑但这只是“绿色免安装版”和真正意义上的“安装程序”不是一回事。绿色版的核心缺点是没有卸载入口、没有文件关联、没有开始菜单和快捷方式管理、也不会有“已安装程序”列表。用户哪天不想要了只能自己摸索着删文件夹很容易留下注册表残留、配置文件残留过段时间系统就被这些小东西拖累了。个人工具这么干没问题但凡是面向团队、面向客户的软件交付一个安装包几乎是必须的。一个合格的 Windows 安装程序至少要做这几件事把程序文件复制到固定目录通常不是用户乱放的桌面而是 Program Files 或用户自己的 AppData在开始菜单创建程序组和快捷方式可选地在桌面创建快捷方式在注册表写入应用配置、卸载信息、文件关联安装后能通过“设置 → 应用”或“控制面板 → 程序和功能”被识别、能正常卸载卸载时能找回自己复制过的文件、注册表键尽量不留下垃圾。Inno Setup 就是专门干这个的。它用一套类似 INI 的脚本语言描述安装逻辑编译后生成一个自解压的安装引导程序。用户双击安装包它会按照脚本执行复制、建快捷方式、写注册表这些动作安装完还能生成一个配套的卸载程序注册到系统的“添加/删除程序”里。这套机制非常成熟很多商业软件表面上不说实际上安装包就是用 Inno Setup 做的。所以先别急着写脚本想清楚你的软件需要什么级别纯命令行工具可以只给免安装版带 GUI、带资源文件、需要文件关联或者要长期维护的趁早上 Inno Setup。2. 开局准备下载、安装和用向导跑通第一版Inno Setup Compiler 的下载很简单直接去官网 jrsoftware.org 就能找到下载入口。安装过程一路“下一步”不需要额外配置。装完后开始菜单里会有 Inno Setup Compiler默认安装目录通常是 Program Files (x86)\Inno Setup 6里面除了图形界面还有一个命令行编译工具 ISCC.exe这个后面做自动化构建会用到。首次打开会弹出一个欢迎页让你选择创建新脚本还是打开已有脚本。如果第一次用我建议先走一遍向导别急着手写 .iss 文件。向导的大致流程会依次问你应用名称、版本号、发布者和官网地址默认安装目录、是否允许用户修改程序文件目录下的主可执行文件和依赖文件要不要开始菜单文件夹、要不要桌面快捷方式帮助文档相关跳过即可安装包语言、输出目录和输出文件名。填完这些向导会生成一个 .iss 脚本你直接点编译就能在 output 目录下得到第一个安装包。这时候我建议立刻做一件事把这个安装包当成普通用户去安装一遍再卸载一遍。你会发现卸载后开始菜单的快捷方式没了“程序和功能”里的条目也没了这个过程能让你直观理解安装包到底帮你做了什么。跑通向导主要是为了让你知道“脚本长什么样”。真正要做得规范还是得看懂脚本、手改脚本。因为向导能覆盖的场景很有限项目稍微复杂一点——比如需要写注册表、静默安装、检测 .NET、做多语言——就必须直接动代码了。3. 看懂 .iss 脚本骨架常量、段落与“安装后行为”的组合逻辑Inno Setup 的脚本是纯文本以;开头的是注释文件后缀是 .iss。整个脚本按段落组织每个段落用方括号开头比如[Setup]、[Files]、[Icons]、[Registry]、[Run]很像老式的 INI 配置但功能比普通配置强得多。[Setup]段定义安装程序自身的元信息和行为比如AppName、AppVersion、DefaultDirName、OutputBaseFilename、Compression。同一个项目的不同版本这里是主要需要维护的地方。要注意AppId它是安装包识别“同一个软件”的唯一标识如果你做版本升级AppId一定要保持不变否则新安装包不认为自己是从前那个软件可能出现旧版本没卸载、新版本又装一遍的情况。[Files]段负责把文件从源目录复制到目标目录。源路径可以用相对路径目标路径一般都用常量{app}表示安装目录。比如[Files] Source: release\MyApp.exe; DestDir: {app}; Flags: ignoreversion Source: release\assets\*; DestDir: {app}\assets; Flags: ignoreversion recursesubdirs createallsubdirs这里的Flags很关键。ignoreversion表示目标位置已有同名文件时直接覆盖不做版本比较recursesubdirs表示递归复制子目录createallsubdirs表示自动创建目录。这三个是复制整个资源目录最常用的组合。除了{app}还有一些高频常量常量含义{app}安装目录默认是{autopf}\应用名{autopf}Program Files 目录按安装模式自动选择 64 位或 32 位{group}开始菜单程序组路径{autodesktop}所有用户的公共桌面目录{userdesktop}当前用户的桌面目录{tmp}临时目录常用于安装过程中解压临时文件{src}指向编译时脚本所在的源文件目录[Icons]段负责快捷方式它把安装目录里的主 exe 映射到开始菜单或桌面。[Registry]段负责注册表操作可以指定根键、子键、值名、值类型和值数据。[Run]段则定义安装结束后的动作比如立即运行程序、打开网页、启动某个服务。你不要试图一次记下所有段落这种工具的使用逻辑是先知道每个段落解决哪一类问题遇到需求时再去查官方帮助文档。Inno Setup 的文档做得很细每个人的代码里都有几十条官方注释遇到不确定的Flag按 F1 查一下就行。4. 实战把 release 输出打成标准安装包可直接抄脚本光看段落概念容易浮我直接用一套实际能跑的脚本演示。假设我有一个桌面程序用 Electron 或 PyInstaller 之类的工具已经打出了 release 目录里面包含主程序和资源文件夹。现在要把这个 release 目录做成安装包。先创建脚本文件推荐放在与 release 目录同级的位置这样源路径可以写得很短。脚本如下; DemoApp 安装包脚本 ; 这里用了 Inno Setup 6 的指令低版本可能需要微调 [Setup] AppId{{6F3E2C10-7A8D-4F0B-9C35-0E8E6D4A1B23} AppNameDemoApp AppVersion1.0.0 AppPublisherMy Company AppPublisherURLhttps://example.com DefaultDirName{autopf}\DemoApp DefaultGroupNameDemoApp UninstallDisplayIcon{app}\DemoApp.exe OutputDiroutput OutputBaseFilenameDemoApp_Setup_1.0.0 Compressionlzma2 SolidCompressionyes ; 下面两条确保 64 位程序装到 Program Files而不是 Program Files (x86) ArchitecturesAllowedx64compatible ArchitecturesInstallIn64BitModex64compatible ; 需要管理员权限因为安装要写 Program Files 和公共开始菜单 PrivilegesRequiredadmin ; 卸载时可选的保存配置项 UninstallDisplayNameDemoApp [Languages] Name: chinesesimp; MessagesFile: compiler:Languages\ChineseSimplified.isl [Tasks] Name: desktopicon; Description: 创建桌面快捷方式; GroupDescription: 附加图标:; Flags: unchecked [Files] Source: release\DemoApp.exe; DestDir: {app}; Flags: ignoreversion Source: release\resources\*; DestDir: {app}\resources; Flags: ignoreversion recursesubdirs createallsubdirs [Icons] Name: {group}\DemoApp; Filename: {app}\DemoApp.exe Name: {autodesktop}\DemoApp; Filename: {app}\DemoApp.exe; Tasks: desktopicon [Registry] ; 把安装目录写入当前用户的软件配置卸载时自动删掉这个值 Root: HKCU; Subkey: Software\MyCompany\DemoApp; ValueType: string; ValueName: InstallDir; ValueData: {app}; Flags: uninsdeletevalue ; 做一个简单的文件关联扩展名 .demo 用 DemoApp 打开 Root: HKCR; Subkey: .demo; ValueType: string; ValueName: ; ValueData: DemoApp.File; Flags: uninsdeletekey Root: HKCR; Subkey: DemoApp.File\shell\open\command; ValueType: string; ValueName: ; ValueData: {app}\DemoApp.exe %1; Flags: uninsdeletevalue [Run] Filename: {app}\DemoApp.exe; Description: 启动 DemoApp; Flags: nowait postinstall skipifsilent这一段脚本我逐点解释。AppId那一串带大括号的字符串你在自己项目里千万别照抄因为 GUID 必须唯一。如果你不写AppIdInno Setup 会随机生成一个但同一个软件的不同版本之间要保持一致所以建议用 GUID 生成器创建一个固定的值填进去。注意在 .iss 文件里花括号要用双写转义所以你会看到{{开头。DefaultDirName用了{autopf}它在 64 位安装模式下指向 Program Files。如果你的程序是 32 位的不要写ArchitecturesAllowed和ArchitecturesInstallIn64BitMode默认装到 Program Files (x86) 即可否则注册表重定向会出问题。[Tasks]段落创建了一个可选项“创建桌面快捷方式”并且Flags: unchecked表示安装时默认不勾选让用户自己决定。[Icons]里通过Tasks: desktopicon把这个快捷方式绑定到那个可选项上。[Registry]里我做了两件常见的事写入一个安装路径备用以及注册扩展名.demo的文件关联。uninsdeletevalue和uninsdeletekey是卸载时自动删除对应键值的核心写多深的注册表都没关系关键是卸载时要清理掉。[Run]里的postinstall表示安装完成后如果用户没取消勾选就运行程序skipifsilent表示静默安装时不要自动运行。编译时直接在这个脚本编辑器里按 CtrlF9或者在命令行执行C:\Program Files (x86)\Inno Setup 6\ISCC.exe DemoApp.iss输出目录下会出现DemoApp_Setup_1.0.0.exe。这个包拿到任何一台 Windows 10/11 机器上双击就能完成安装、创建快捷方式、建立文件关联、卸载清理这一整套流程。安装完去“设置 → 应用”里能看到 DemoApp 的条目点卸载能彻底清干净。5. 专业安装包的进阶玩法静默部署、依赖检测、多语言和签名上面那份脚本已经能交付了但企业环境里还会遇到更挑剔的要求这里挑几个高频需求说。静默安装是运维最需要的。一样一套安装包手动双击是一种体验批量部署是另一种场景。Inno Setup 原生支持命令行参数最常用的组合是DemoApp_Setup_1.0.0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP-/VERYSILENT表示不显示任何界面连进度条都不出/SUPPRESSMSGBOXES抑制所有弹窗/SP-跳过“确认是否安装”提示/NORESTART阻止重启。批处理里如果拿不准哪里弹了窗加一个/LOGC:\install.log结束后看日志就行。如果要在静默模式下强制指定安装目录可以再加DemoApp_Setup_1.0.0.exe /VERYSILENT /DIRD:\App\DemoApp这个参数优先级比脚本里的DefaultDirName更高对做软件分发很有用。依赖检测也是实战常客。比如你的软件依赖 .NET但用户机器上可能没装。Inno Setup 用的是 Pascal 脚本你可以写[Code]段在InitializeSetup函数里检查环境。网上有大把现成的检测函数复制进来稍微改改就能用。大体逻辑是如果检测不到目标环境弹个对话框问用户“是否现在安装”确认后执行一个预先准备好的依赖包。这个方案不像 WiX 那样能把依赖做成完整的 MSI 链但胜在简单可控中小型软件完全够用。多语言这个问题Inno Setup 官方的处理方式很省心。你只需要把想要的语言文件加到[Languages]段[Languages] Name: english; MessagesFile: compiler:Default.isl Name: chinesesimp; MessagesFile: compiler:Languages\ChineseSimplified.isl编译结束后安装包会根据系统语言自动选择界面语言用户在安装过程中也可以手动切换。注意语言文件的路径是相对于 Inno Setup 安装目录的不要自己乱改。数字签名往往被人忽略但对分发影响很大。未签名的安装包被 SmartScreen 拦截的概率极高用户会看到“Windows 已保护你的电脑”这种红色警告软件还没装信任感先减一半。解决思路是向证书机构购买代码签名证书然后用 Windows SDK 里的 signtool 工具签名。Inno Setup 的菜单里有签名配置入口也可以在脚本里配置SignTool每次编译后自动对输出 exe 签名。签名之后的安装包在多数 Windows 机器上不会再被 SmartScreen 提示“未知发布者”。安装包更新问题也要有心理准备。Inno Setup 本身不提供增量更新服务但它的结构很适合配合自动更新工具。常见做法是软件内检测到新版本后下载一个新的完整安装包静默执行并带/DIR参数装到原目录。因为 Inno Setup 允许在已安装的基础上覆盖安装只要AppId不变用户数据不会丢。6. 最容易翻车的几个坑以及我的排查思路工具再成熟实际操作中还是会踩坑。我把这几年用 Inno Setup 遇到的高频问题按排查链路整理出来。第一个坑是中文路径和文件名。Inno Setup 本身支持 Unicode脚本文件记得用 UTF-8 编码保存最好带 BOM。如果你用旧版记事本保存成 ANSI 码脚本里出现中文注释或中文文件路径编译很容易乱码。现在的 VS Code 默认 UTF-8 没大问题但万一遇到编译报错第一件事就是检查文件编码。注意源文件路径中有中文时建议保持脚本文件本身也是 UTF-8同时把源目录放在一个纯英文路径下能省掉很多莫名其妙的权限和长度问题。第二个坑是 64 位目录。很多程序的 exe 明明是 64 位但因为没有写ArchitecturesInstallIn64BitModex64compatible结果被装到了 Program Files (x86)。这不是 Inno Setup 不智能而是它默认按 32 位安装程序来处理。判断方法很简单安装完打开任务管理器看进程架构或者直接看安装目录到底在哪个 Program Files 下。写 64 位配置时也要确认你的源程序确实是 64 位不然运行时可能因为缺 32 位依赖而直接崩溃。第三个坑也是我见过最多的杀毒软件误报。Inno Setup 打包出的东西偶尔会被某些杀毒软件识别为“潜在不受欢迎程序”或者直接报毒。这时候不用慌先用 VirusTotal 网站把安装包传上去跑一遍看看报毒的是哪些引擎。如果只有一两个名气不大的引擎报大概率是误报更新下病毒库或者添加白名单就行如果大厂引擎也报那就要怀疑你的源文件是否真的被上层脚本污染了。另外安装包没有数字签名时误报率会高很多签完名能明显改善。我自己有条原则内部工具如果没有购买证书的条件至少用自签名证书做测试正式发布前再换正式证书不要裸奔。第四个坑是以前版本卸载不掉。这个十有八九是AppId变了。假设你版本 1.0 的AppId是 A版本 1.1 写脚本时随手复制了别的东西的AppId变成了 B那么在系统眼里这就是两个完全不同的软件新安装包不会覆盖旧的卸载信息也各自独立。用户想卸载会很痛苦先卸 1.0再卸 1.1。我在做自动化构建时秉承一条规则AppId单独放在一个配置文件里由 CI 脚本统一注入谁都不准手工改动它。第五个坑是静默安装参数忽略了数据目录。有些程序会把用户配置写在安装目录下而不是 AppData 或 ProgramData。这么设计本身就有点危险因为安装目录通常需要管理员权限才可写。但如果你一定要这么做卸载的时候要让 Inno Setup 保留用户数据方法是在[UninstallDelete]段精确声明只删除程序文件不要整个目录uninsdelete。否则用户装新版本前的配置文件会被卸载器顺手清掉这属于真正的安全事故。最后一个建议是写[Files]段时尽量用Source: release\*把整个目录收进来而不是挨个文件列。你说你记得加真加到第 50 个 DLL 的时候大概率会漏。目录收集的坏处是会把临时文件、调试符号带一起打进来所以发布之前先把 release 目录清理一遍再交给 Inno Setup 去收集。这样能减少“本地能跑装上不行”的水土不服现象。7. 和其他打包方案怎么配合怎么选最后聊点选型问题。很多人会把 Inno Setup 和 PyInstaller、Electron 这类工具放在一起比较但这是两码事。PyInstaller 解决的是“Python 脚本怎么变成 exe”Electron 解决的是“Web 前端怎么变成桌面程序”Unity 和 Unreal 的打包工具解决的是“游戏资源怎么变成可执行包”。这些工具做到最后产出的往往是一个目录或一堆文件里面可能有几十个 DLL、一堆资源、一些配置文件。这堆东西离“用户能正常安装使用”还差一步——你需要一个安装程序把目录放到合适的位置、注册快捷方式、写入关联。Inno Setup 正好补上这最后一步。我经常在山顶打包 Python 桌面工具流程是PyInstaller 先打成 exe然后用 Inno Setup 脚本把 exe 和相关文件装成正式安装包最后静默安装到各台电脑上。Electron 项目也是一样Electron-builder 本身能生成安装包但它生成的是 NSIS 或 MSI如果你想完全掌控安装流程Electron 打包出的 win-unpacked 目录也可以用 Inno Setup 二次封装。那 Inno Setup 和其他安装程序工具怎么选这里一个简单的对照工具输出格式特点适合场景Inno Setupexe脚本简单上手快功能足够绝大多数 Windows 桌面软件NSISexe插件生态强大但脚本语法复杂需要高度定制安装界面的程序WiX Toolsetmsi支持组策略和企业域部署企业内部大规模软件分发InstallShieldmsi/exe商业方案贵重大型商业软件流水线Electron-builderexe/msi/macOS与 Electron 深度集成Electron 项目快速发行我的个人倾向是如果公司没有强制要求 MSI 格式用于域分发Inno Setup 几乎是最均衡的选择。它免费、支持脚本化、能处理注册表、能静默安装、卸载干净、中文文档也足够全。从向导生成第一个安装包到维护上百个产品版本这套工具的曲线都没有陡峭到让人劝退。最后提醒一点安装包发布不代表工作结束。我习惯在每个安装包目录里放一个编译信息文件记录版本号、编译时间、Git commit 和 Inno 脚本版本。以后用户报“装上之后无法启动”你能很快定位到是代码问题还是打包漏了文件。这个习惯帮我省过很多回头找版本的麻烦。