☰
Advanced Installer 20.7.1实战:从MSI原理到静默部署的Windows打包指南
2026/10/13 5:46:51 网站建设 项目流程

简介:Advanced Installer 20.7.1是一款面向Windows平台的专业软件打包工具,适合开发人员与软件发布人员在制作MSI安装包时使用。其图形化界面支持自定义欢迎页与安装流程界面,可生成符合Windows认证标准的安装程序。该资源包共2000个文件,大小161.36MB,完整包含419个aip工程文件与大量界面设计素材,其中png与jpg等图片资源逾千张,可辅助安装界面设计参考;xsd、xml、xaml与css等文件则覆盖工程配置与界面布局定义,rtf与chm文档便于查阅工具功能说明。整体目录按素材类型与工程文件划分,便于直接加载aip工程进行二次修改或学习打包逻辑。压缩包另含少量msi示例成品与ico图标资源,可供对照验证打包结果。已有941人学习使用,对于初次接触Windows Installer制作的开发者,可通过完整项目模板快速掌握界面定制、组件配置与输出打包等关键环节,避免从空白工程逐步摸索。

1. Advanced Installer 20.7.1 到底解决什么问题:Windows 软件打包的“黑匣子”与落地价值

很多开发者是在“要发版了”才发现,自己写的工具离“能装进别人电脑”还有一大截。Advanced Installer 20.7.1 这类软件打包工具,解决的不是文件复制,而是把安装、注册、卸载、升级变成用户双击就能走完的流程。用它可以把手头的软件、插件、带 COM/ActiveX 注册的加载项打成规范的 MSI 或带引导程序的 EXE:安装失败能回滚,卸载不会留垃圾,升级能被 Windows Installer 正确识别。适合三拨人:要对外发布 Windows 桌面工具的独立开发者,要批量部署软件的企业 IT,以及维护老插件需要重新打包发版的一线工程师。这篇笔记按“原理—流程—参数—避坑—自动化”的顺序拆,照着走也能出包。

2. 安装包背后的原理:MSI 的事务性安装与选型对比 InstallShield/WiX/NSIS

2.1 MSI 不是解压文件,而是带事务的安装契约

Windows Installer 处理 .msi 时,读的不是文件清单,而是一套数据库表。产品(Product)、组件(Component)、文件、注册表、快捷方式、自定义动作(CustomAction)都以表记录的形式存在,安装时按 InstallExecuteSequence 定义好的顺序执行:先校验条件,再拷贝文件、写注册表、注册服务,最后执行自定义动作。任何一个环节失败,系统会把本次全部写入内容回滚到安装前状态。这就是“事务性安装”——装到一半取消,不会留下一半新一半旧的半脏状态。

对用户来说这是好事,对打包的人来说意味着:文件放错目录、注册表写错位置或与别的软件冲突,系统会把这视为安装失败,而不是“只是没拷贝好”。我最初用 Advanced Installer 时以为把文件拖进去就算数,直到装坏了一台机器才意识到,MSI 的组件是原子单位,每个组件都带自己的 GUID,系统通过 KeyPath 文件或注册表来判断它是否已安装。之后的修复安装、卸载、补丁升级,全依赖这些 GUID 判断状态。

组件之上还有三层代码必须分清:ProductCode 标识当前产品版本,每次发版都要变;UpgradeCode 标识产品家族,永远不变;PackageCode 标识 MSI 包本身,每次构建都会重新生成。三者关系搞混是后面升级翻车的第一大原因,先记住这个结论。

2.2 工具圈里 Advanced Installer 的定位:要 MSI 能力又不想背 XML

打包工具各有各的脾气,给一份选择参考:

工具产出格式学习曲线适合场景
InstallShieldMSI/EXE陡,界面和概念偏旧大型商业软件、需要全功能授权的团队
WiX纯 XML 工程极陡,先学 schema愿意把安装逻辑代码化、完全控盘的团队
NSIS自解压 EXE中,脚本语言快速出 EXE、不依赖系统级安装服务
Advanced InstallerMSI/EXE 双形态缓,GUI 拖拽为主需要 MSI 升级回滚能力的中小团队

选 Advanced Installer 而不是 WiX 的核心理由有三条。第一,它保留了 MSI 的升级、修复、回滚能力,同时把 WiX 里需要用 XML 描述的东西变成了可视化视图:文件、注册表、COM 组件、服务、快捷方式、自动更新都在独立页签里。第二,它提供了命令行接口 AdvancedInstaller.com,构建步骤能接进 Jenkins 或 GitLab CI。第三,多语言和多版本构建可以放在同一个 .aip 工程文件里管理,不用为三种语言维护三套脚本。

想验证自己对 MSI 的理解是否靠谱,有一个不用装任何工具就能做的动作:拆开任意一个 .msi 看它的真实文件结构。Windows 自带的管理安装模式可以做到:

msiexec /a "MyInstaller.msi" /qb TARGETDIR="C:\msi_extract"

/a 是管理安装模式,/qb 只显示进度条,TARGETDIR 指定展开目录。执行完,C:\msi_extract 下就是 MSI 数据库里记录的目录结构。这个操作不需要 Advanced Installer,但能让你看清 MSI 包的真实形态,也方便核对打包产物。

构建出来的包通常有两种形态。纯 MSI 直接由 Windows Installer 执行,适合组策略下发;EXE 引导(Bootstrapper)则先做启动条件判断——检测 .NET Framework、VC++ 运行库、操作系统版本,不满足就提示或拉取前置组件,满足后再把 MSI 交给系统安装服务。Advanced Installer 的常见做法是生成 EXE 引导加 MSI 载荷,这也是它和 NSIS 看着都是 EXE、底层却完全不同的原因:NSIS 的 EXE 是自己干所有活,前者最终走的是系统安装服务。20.7.1 这个版本的工作流跟它前几代基本一致,工程文件以 .aip 保存,GUI 维护内容,命令行负责构建,理解这个双通道后换版本不用从头学一遍。

3. 把手头软件或插件打成安装包:从新建工程到出包的可复现流程

3.1 新建工程:先选对产品类型,别把插件做成普通软件

打开 Advanced Installer 新建工程时,它会让你选产品类型。常见做法是:普通桌面应用选 Simple 或 Professional 工程,浏览器插件、Office 加载项这类带注册动作的资源,要选择带 Add-on 或 COM 模板的工程类型。这里选错后面会绕路:普通软件模板不会自动给你 COM 注册的入口,你真需要注册时得手动写注册表,不如一开始就选对。

工程属性窗口里有几个关键项需要先定下来:产品名称(ProductName)、厂商(Manufacturer)、版本号(Product Version)、升级代码(UpgradeCode)。版本号决定后续升级能否被识别,初次不建议乱填,按 1.0.0 起步。UpgradeCode 随机生成后就不要改了,它是这个产品家族的身份证,第二条里提到的升级逻辑全靠它。这几项确认后建立工程,后面所有动作都在这个 .aip 工程文件上改。

3.2 文件、快捷方式与插件注册:把安装内容落进 MSI 组件

Files and Folders 视图里把要发布的文件拖进目标文件夹。目标路径建议用属性表示,而不是写死 C:\Program Files\某公司\某产品。对桌面应用常见的是 [ProgramFilesFolder]公司名产品名,对插件则是 [CommonAppDataFolder] 或 [LocalAppDataFolder] 这类公共目录。用属性是 MSI 的硬规则:不同语言系统的 Program Files 路径不一样,写死了装到非英文系统上就只能靠用户手动改目录。

快捷方式在 Shortcuts/Folders 里添加,每个快捷方式都要指定工作目录和图标文件位置,不然用户从开始菜单点开插件会提示“路径不存在”。对插件场景还有一个关键动作:在工程里找到 COM 或 ActiveX 注册视图,添加 DLL 的注册信息,选择进程内(In-proc server)或进程外类型,并指定 CLSID、ProgID、线程模型。这个视图会自动生成对应的注册表写入项,不需要手写 HKCR 下面的一大串路径。

如果插件需要“双击某个文件就能打开”,还要做文件关联配置:在关联文件类型里加扩展名,绑定到你的 ProgID,并指定打开动作的命令行参数。这一步放到构建之后做,大概率会因为路径解析问题多返工一轮。文件关联的参数在 MSI 里默认是“写入 HKEY_CLASSES_ROOT”,注意后续做用户级安装时要单独勾选“每用户关联”,否则会出现管理员装了、普通用户双击却不生效的问题。

3.3 构建出包:命令行里留一份可重复的构建路径

构建前检查两处:Install Prerequisites 里的启动条件列表,以及 Builds 页签里的 Release 配置。Release 配置决定输出形态:MSI Only、EXE、还是带自动更新器的 EXE。勾选需要的配置,点 Build,产物默认在工程目录的 Output 或你指定的输出路径下。

GUI 点击适合首次试水,重复构建我更推荐命令行,方便接到 CI 和后续自动化验证里:

AdvancedInstaller.com /path "D:\build\MyPlugin.aip" /build "SimpleRelease" -log "build.log" # /path 指定 .aip 工程文件路径 # /build 指定要构建的 Release 名称,与 GUI 里的 Builds 配置一致 # -log 把构建过程写到 build.log,排查失败时先看这个文件

执行完,去输出目录核对 .msi 和 .exe 两个文件。构建日志里会出现大量校验信息,包括“组件遗漏”“路径不存在”等,凡是红色 Error 都要停下处理,黄色 Warning 可以先记录再判断。首次构建后建议跑一遍自测清单:全新机器安装一次、带旧版覆盖安装一次、卸载一次、修复安装一次。这套动作能过滤掉大半低级问题。

4. 打包配置里的关键参数:签名、运行库与升级代码最容易翻车

4.1 数字签名与时间戳:没签名的 EXE 会被 SmartScreen 和杀软特别关照

对外分发时没有数字签名,Windows SmartScreen 会弹蓝色警告,杀软对无签名安装包的启发式扫描也会更严格。这不是玄学,企业网管看无签名 EXE 和看未验证脚本是一个心态。代码签名证书需要向合规证书机构购买,内部测试阶段可以用自签证书,但自签证书只解决“文件没被篡改”,解决不了 SmartScreen 警告。

签名参数里有两个容易被忽略:签名算法必须用 SHA-256,不要再用 SHA-1,新系统对 SHA-1 签名的信任度已大幅降低;时间戳服务器务必填写,常见做法是填公开时间戳服务的地址。没有时间戳,证书两年后过期,老用户重装包时会直接报“签名已损坏或无效”。装完可以用系统自带工具验证签名状态:

signtool verify /v /pa "MyInstaller.exe" # /v 显示详细签名信息,/pa 只验证 Authenticode 签名 # 输出里重点看 SHA256 哈希和时间戳是否有效

签名动作建议放在构建的最后一步。因为一旦修改包内容,原签名就失效,需要重新签名;如果还要做多语言本地化,更是要等所有语言资源都合入后再签。常见做法是让 Advanced Installer 在构建后自动调起签名,前提是证书文件保存在构建机器上,且 CI 里能访问到证书密码。

4.2 运行库依赖:不要把 VC++ 和 .NET Framework 直接塞进 MSI

桌面软件常见的依赖有 VC++ 运行库、.NET Framework、WebView2 运行时等。处理方式有两种:一是用启动条件检测,不满足就阻止安装并提示用户;二是用引导程序在前置安装阶段从官方源安装。很多新手会把运行库直接并进 MSI 的组件里,结果包体膨胀几十兆,还可能和目标机器上已装的运行库冲突,引发“运行时错误而不是安装错误”的怪问题。

检测条件通常在 Search 里配置:对 VC++ 可以查注册表项 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64,对 .NET Framework 可以查 Release 注册表值。组件缺失时启动条件会返回 False,安装器按预设逻辑停下。带引导的 EXE 场景下,更稳的做法是把运行库作为 Prerequisite,由引导程序在拉起 MSI 前先装。注意 Prerequisite 包来源要固定,别在正式环境里临时下载第三方源。

4.3 ProductCode、UpgradeCode、版本号三条规则:升级装不上的元凶

升级逻辑一共就三条规则,多数升级翻车都能归到这三条上:

代码什么时候变作用
ProductCode每次发版都改标识当前版本的安装状态,卸载也靠它
UpgradeCode永远不变标识产品家族,升级靠它找到旧版本
PackageCode每次构建自动生成标识 MSI 包文件本身,不影响业务升级

发新版本时常见做法是:版本号按 Major.Minor.Build 递增,ProductCode 重新生成,UpgradeCode 保持原样,并在 Upgrades 视图里配置 Major Upgrade。Major Upgrade 意味着安装新版本时会先卸掉旧版本,这是“覆盖安装老版本”能不能成功的关键开关。如果只改版本号却忘了配 Major Upgrade,新包装上去会和旧版并存,用户机器上出现两个同名软件,卸载时还会互相打架。

版本号还有一个坑:Windows Installer 的版本号前三位参与比较,第四位基本不参与。1.0.0.1 和 1.0.0.99 在升级判断里可能被识别为同一版本,导致新包拒绝安装。发布脚本里建议只递增前三位,第四位留给测试构建区分用,避免踩这个识别边界。

5. 避坑与排查:装不上、被杀软误报、插件不出现怎么办

5.1 现象:旧版本没卸干净,新版本安装直接报“已安装同版本或更高版本”

原因分析:ProductCode 没变,系统认为同一个产品已经装过;或者 UpgradeCode 变了,Major Upgrade 找不到旧版本,新包和旧包共存后互相冲突。

解决办法:核对工程属性里的 ProductCode,每次发版重新生成;确认 UpgradeCode 从第一个版本起就没动过;在 Upgrades 视图里勾选 Major Upgrade 并设置“覆盖旧版本”。改完重新构建,建议在虚拟机里先装旧版再装新版验证一次。这个场景我遇到最多,十次里有六次是忘了改 ProductCode。

5.2 现象:安装包构建后被杀软隔离或删除,报“特洛伊木马”或“未知威胁”

原因分析:安装包里没有签名、签名过期,或包内某个 DLL 被启发式引擎识别为恶意行为特征。还有少数情况是安装脚本里有执行临时目录文件的操作,这类行为特征容易被安全软件盯上。

解决办法:正式发布走 4.1 的签名流程,确认时间戳有效;检查包内的 DLL 是否都经过编译环境的正常构建,避免把开发机的调试文件带进去;排查自定义动作里是否有从临时目录启动或调用脚本的行为,尽量改成安装目录内直接注册。注意,杀软误报不代表包有问题,但也不能直接认定杀软误判,先在 VirusTotal 上横向对比一遍。

5.3 现象:COM 插件装完之后,Excel 或 Word 里找不到这个加载项

原因分析:COM 注册没写对位。最常见的是 32 位插件注册到了 64 位 Office 的注册表区域,或 DLL 没有导出正确的 DllRegisterServer 入口,注册动作执行了但没有任何效果。

解决办法:回到工程的 COM 视图,确认注册类型选的是 In-proc server,CLSID 和 DLL 导出信息一致;检查位数匹配,32 位 Office 用 32 位 DLL,64 位 Office 用 64 位 DLL,混了就是白装。手动验证可以用系统自带的注册命令,装完确认没有错误码再排查 Office 配置:

regsvr32 "C:\Program Files\MyCompany\MyAddin.dll" # /s 参数可以静默执行,无弹窗 # 注册成功返回空,失败会弹错误码,常见 0x80070005 是权限不足

注意,regsvr32 只作为诊断手段,正常分发不要靠它注册,而是让 MSI 的组件表自动处理,否则卸载时清理不干净。

5.4 现象:批量部署时没人盯着,安装却在某台机器上弹窗卡住

原因分析:走的是带 UI 的安装流程,任何交互提示都会让静默部署挂起。常见交互点包括安装路径选择、是否创建桌面快捷方式、许可证确认。

解决办法:MSI 场景直接用 Windows Installer 标准静默参数,不要依赖 EXE 引导的弹窗交互:

msiexec /i "MyPlugin.msi" /qn /L*v "install.log" # /i 指定要安装的 MSI 文件 # /qn 完全静默,不显示任何界面 # /L*v 把详细日志写到 install.log,部署失败时靠它定位

如果安装逻辑里有需要用户确认的自定义动作,把它改成不加交互的默认值。批量分发前在干净的 Windows 虚拟机里用 /qn 完整跑一遍,看到安装日志末尾有“Installation success or error status: 0”才算稳。

6. 用命令行把打包变成每天可重复的工序:静默安装与日志验证两步走

6.1 自动化构建脚本

打包如果只靠 GUI 手工点,终究是给公司留了个“只有我会点”的黑匣子。把构建动作沉淀成脚本后,同事、CI、新接手的人都能复用同一套流程。我一般会留一个简单的批处理:

@echo off set AIP_PATH=D:\build\MyPlugin.aip set OUTPUT=D:\output "AdvancedInstaller.com" /path "%AIP_PATH%" /build "SimpleRelease" -log "%OUTPUT%\build.log"

脚本里唯一需要维护的是 .aip 工程路径和 Release 名称,其余全部固定。输出目录里的 MSI 和 EXE 就作为发布资产的唯一来源。

6.2 静默安装与回归验证

构建完成后,紧接着在干净环境下做一次静默安装验证,顺手把日志留档:

msiexec /i "%OUTPUT%\MyPlugin.msi" /qn /L*v "%OUTPUT%\install.log"

安装完检查两条:一是安装日志以状态码 0 结尾,二是注册表卸载项里能看到产品记录。用 PowerShell 可以把检查结果直接打印出来:

Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" | Where-Object { $_.DisplayName -like "*MyPlugin*" } | Select-Object DisplayName, DisplayVersion

这套“构建—静默装—查注册表—留日志”走完,基本能覆盖发布前 80% 的返工风险。从那以后,我每次发版前都强制自己把这条链跑一遍,哪怕只是改了一个界面文案,也不再跳过验证。毕竟打包工具的坑,大多藏在你看不见的注册表分支和升级规则里。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询