ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Visual Studio Installer Projects:WinForm/WPF程序打包与MSI部署实战指南

Visual Studio Installer Projects:WinForm/WPF程序打包与MSI部署实战指南 用Microsoft Visual Studio打包winform或WPF程序最容易被低估的一步就是Installer Projects。这个由微软官方提供的安装项目模板生成的是标准MSI安装包目标是让软件能装进Program Files、在开始菜单和桌面留下快捷方式、在控制面板卸载列表里出现、缺运行时能自动补上、装到一半失败还能自动回滚。说白了打包这件事不是把exe塞进压缩包发出去而是让程序以一种被Windows认可的方式住进系统。这篇东西是我这几年用Installer Projects给不同项目出包攒下来的实操笔记不是官方文档的复读。里面包含了从零搭建安装项目、配置依赖和快捷方式、处理注册表和自定义操作以及构建和升级过程中的踩坑记录。适合刚写完winform程序准备交付的开发者被客户机器上装不上打不开折磨过的同学以及想搞明白MSI到底怎么运作的入门者。读完你至少能交付一个装得上、卸得净、升得了级的安装包。1. 为什么交付时把exe文件夹拷过去是下策不是上策1.1 开发机能跑客户机器崩问题到底出在哪不少刚接触打包的同事第一反应是我编译完把Release文件夹压缩发给对方解压就能用。这个方案对完全没有第三方依赖、目标机器又恰好装了对应运行时的纯绿色小工具偶尔是行得通的。可一旦程序和运行环境稍微复杂一点绿色拷贝的缺陷就暴露得干干净净。我归纳下来至少有这么几类场景是拷贝文件夹解决不了的目标机器没装.NET Desktop Runtime而你的程序是.NET Framework 4.8跳到了.NET 6或.NET 8客户机器很可能是旧系统运行时全靠你带。程序调用了VC运行库、WebView2 Runtime这些系统级组件它们需要以受管方式安装到全局位置不是拷个DLL放旁边就有用。安装时需要往注册表写配置项比如数据库连接串、授权信息、文件关联。绿色版只能让程序在首次运行时自己写但有些场景必须在装的时候就写。程序要注册成Windows服务。服务注册要走系统API而且卸载时要能干净移除这根本不是一个文件夹分发能承担的事。客户方的IT部门要求软件在控制面板的程序和功能里能看到方便统一卸载、统计资产。你发个绿色压缩包过去对方IT直接给个差评。把这些场景摆在一起你会发现拷贝文件夹本质上是把文件落地这件事做了但安装程序真正要负责的是三件事文件落地、系统集成、生命周期管理。后面两件事才是安装包存在的意义。1.2 Windows Installer的事务机制为什么值得信任Installer Projects生成的MSI文件跑在Windows Installer引擎上。这套引擎不是简单地把文件复制到目录里就完事它把整个安装过程当成一个事务来处理。拷贝文件、写注册表、建快捷方式、注册服务这些动作会先被记录任何一个步骤失败了引擎会自动把已经完成的动作全部回滚让系统回到安装前的状态。这个能力比很多第三方安装程序强得多。你大概见过某些软件安装到一半卡死报错然后在控制面板里留下一个半残的记录想卸卸不掉想装装不上。Windows Installer之所以不太出这种问题就是因为它有回滚机制。另外它还支持修复模式程序文件损坏时不用重新下载安装包在控制面板里右键选修复就行了。这些能力都是绿色文件夹完全给不了的。理解了这一层再回头看Installer Projects里的那些选项就不会觉得它只是生成一个安装向导它实际上是在定义这个程序怎么和Windows系统打交道。1.3 这个方案适合谁不适合谁用Installer Projects打包最典型的对象是winform和WPF桌面程序。控制台程序当然也能打但控制台程序通常轻量发布成绿色版或者用ClickOnce更省事。如果你的程序需要安装到多用户机器的Program Files目录下、需要注册表项、需要文件关联、需要装成服务Installer Projects就是成本最低的正规路径。它也有明显不适合的场景。安装向导的界面很朴素就是微软那套下一步、下一步、完成的标准风格没法做出商业软件那种花哨的品牌安装界面。多语言、多组件选择、复杂的依赖关系配置它也能做但比较吃力。到那个程度就该换InstallShield或者WiX了。我在第6章会把几个主流方案摆在一起比较这里先不展开。顺带说一句很多人搜索Install Projects时其实想找的是给Visual Studio装扩展或者给VS打包VSIX扩展文件。注意了Installer Projects是给你打包待发布的桌面程序的不是用来打包VS本身的扩展。名字像用途完全是两码事。2. 搭起第一个Setup Project扩展安装、模板选择和六个编辑器2.1 装扩展不是装一个软件而是给VS加一类项目Installer Projects并不是Visual Studio默认装好的项目模板需要手动安装。打开VS 2022菜单栏进扩展→管理扩展在联机搜索框里输Installer Projects找到Microsoft Visual Studio Installer Projects下载之后重启VS就能用了。VS 2019、2017、2015也都有对应版本老项目的需求基本都能覆盖。装好之后新建项目时在创建新项目窗口搜索installer你会看到两个模板一个是Setup Project一个是Setup Wizard。如果你用的是VS 2015或更老的版本默认安装项目可能是InstallShield Limited Edition那个东西需要单独注册账号激活体验相当别扭所以我一般建议老版本用户还是优先把Installer Projects装上。这里提一个容易混淆的地方Installer Projects本质上是给Visual Studio增加了一类项目类型你在解决方案里看到它的图标和其他项目一起并列但它编译出来不是exe或dll而是一个安装工程——一堆文件、注册表项、快捷方式的组织描述。它的产出物是MSI和引导程序而不是一个可运行的程序。2.2 Setup Project还是Setup Wizard我的建议两个模板的区别在名字上就能看出来。Setup Wizard会弹一个五步向导边创建边问你要添加哪个项目的主输出、要不要创建快捷方式、要不要写注册表然后根据你的回答预生成一堆东西。Setup Project则是一个空的项目模板打开后只有干净的File System编辑器所有内容自己摆。我第一次用的时候图省事选了Setup Wizard后来发现它生成的那堆预设内容根本不符合实际需求又要一个个回去删改绕一大圈。现在我的习惯是直接建Setup Project空模板什么都要自己控制。安装项目本身结构不复杂空模板反而清爽不容易出现系统自动加了某个文件夹但我不知道的情况。2.3 六个编辑器在安装过程的哪个环节起作用创建好Setup Project之后在解决方案资源管理器里选中它你会看到它不是一个普通的代码项目更像一个容器。右键它或双击项目节点会弹出几个视图入口。其中真正核心的是六个编辑器按使用频率排个序File System负责规划目标机器上的文件结构。默认有应用程序文件夹用户的程序菜单用户桌面三个特殊文件夹你在这里决定exe、dll、配置文件装到哪快捷方式放哪。Registry负责往注册表写字。树形界面长得跟regedit很像可以直接配置键和值。File Types负责文件关联。比如让某种扩展名的文件双击后调用你的程序打开。User Interface负责安装向导的界面。欢迎页、安装路径选择页、进度条、完成页每一页的文案和图片都可以改。Custom Actions负责在安装、提交、回滚、卸载四个阶段执行你自己的程序或脚本。Launch Conditions负责检测目标机器是否满足条件比如.NET Framework版本、Windows Installer版本不满足就在安装开始前直接提示并中断。把这六个编辑器的职责记下来后面做任何配置都能对号入座。我见过很多人拿到项目不知道该干嘛就是因为不知道这些入口分别管什么。2.4 打开项目第一件事把属性页调对新建出来的Setup Project有几个属性字段是每次打包前必须过一遍的漏一个后面就是坑。我按对结果的影响程度列一下ProductName这是控制面板程序和功能里显示的名字也是默认开始菜单目录名。很多人打包出来温习一串Setup就是因为没改ProductName。Version版本号格式是1.0.0。每次发新版本必须递增如果装了旧版再装同版本Windows Installer会判定另一个版本已安装。Manufacturer厂商名。默认安装路径是[ProgramFilesFolder][Manufacturer][ProductName]所以厂商名和产品名共同决定了安装目录长什么样。InstallAllUsers决定是装到当前用户的AppData还是全局Program Files。给普通客户交付时我一般设True但升级时这个值不能变否则会出现旧版卸载记录和新版安装记录打架的怪问题。TargetPlatform必须和主程序平台匹配。64位程序如果选成x86装进64位系统后有些系统调用会异常。UpgradeCode升级标识相当于这个产品在Windows Installer体系里的血缘身份证。版本可以变这个GUID千万别变新版才能覆盖旧版。AddRemoveProgramsIcon控制面板里显示的图标。安装目录的变量用方括号包裹类似[TARGETDIR]、[ProgramFilesFolder]这是Windows Installer的环境属性语法后面自定义操作里传参也会用到这个写法。3. 把程序的家当完整摆进MSI3.1 用添加项目输出而不是添加文件以及输出类型差异在File System编辑器里选中应用程序文件夹右键→添加→项目输出选你的主项目。这时弹出的对话框里有几类东西主输出、内容文件、资源文件、源文件。主输出是项目编译出来的exe和dll它会自动把程序集引用关系带进来。内容文件对应项目里构建操作设为内容的那些文件比如appsettings.json、log4net.config、模板文件前提是这些文件的复制到输出目录属性被正确设置。资源文件对应构建操作设为资源的文件。源文件是项目的源代码除非你故意要发一份源码给客户否则别选。这里有一个很关键的差别用添加项目输出添加的内容是跟着主项目走的添加的是项目输出这个整体你在主项目里新增了文件再重新构建安装项目新的文件会自动带进来。而添加文件是手动把某个文件塞进来它不会自动跟随项目的变动。所以我建议凡是程序运行必需的、并会跟着版本迭代的尽量在源码项目里做好内容标记通过项目输出的方式带进来只有那些不方便纳入主项目构建的第三方DLL才用添加文件手动放。3.2 Detected Dependencies自动依赖检测能做什么不能做什么把主输出添加进去之后文件列表里会出现一个Detected Dependencies节点下面会列出项目引用的程序集和检测到的依赖项。这个列表经常让新人困惑有两个高频问题。第一为什么.NET Framework被列成依赖了因为Installer Projects会把.NET相关的东西识别出来但它不会把这些运行时程序集打进MSI而是在Prerequisites环节配成安装时检测并自动安装的引导程序。这是对的公共运行时不该每家公司都往安装包里塞一份。第二为什么我引用的第三方库有些没出现在依赖里Detected Dependencies能识别编译期静态引用的程序集但对于反射加载、MEF插件、运行时SetDllDirectory指定的非托管DLL它是检测不到的。这种就得手动添加。在Detected Dependencies里选中某个依赖右键可以Exclude排除。什么时候需要排除比如某个系统DLL你确定所有目标平台都有不想让MSI的版本检测逻辑引发安装告警或者你手动带了另一个版本的DLL避免两个文件冲突。但要十分谨慎排除了就意味着安装包不再承诺提供这个文件如果目标机器上真没有装完程序立刻跑不起来。3.3 快捷方式、开始菜单目录、桌面图标的正确摆法File System编辑器默认有三个特殊文件夹对应目标机器上的三个位置。做快捷方式的常规流程是这样先在应用程序文件夹里找到主输出的exe右键→创建快捷方式再把生成的快捷方式 到 xxx.exe重命名最后把这个快捷方式复制或拖到用户的程序菜单下新建的文件夹里还要桌面的话再复制一份到用户桌面。这里有个经常被问的点为什么不能直接在用户桌面里右键添加快捷方式因为那个文件夹代表的是桌面位置你右键添加进去的是真实文件而快捷方式必须指向安装目录里的exe。只有先对主输出创建快捷方式再把这个快捷方式挪到目标文件夹MSI才能记录正确的相对路径卸载时才会把快捷方式一并清理掉。快捷方式的属性里可以设置Icon注意别用非ICO格式的图标文件某些Windows版本会显示默认白纸图标。开始菜单目录我一般会在用户的程序菜单里先建一个公司名\产品名的层级文件夹再把快捷方式放进去避免装完一堆程序都堆在开始菜单根目录。3.4 Prerequisites引导程序把运行时交给安装包自动补齐这个功能藏在Setup项目的属性窗口里点Prerequisites…按钮打开对话框。它的作用是配置安装包的引导程序安装一开始先检查目标机器缺少哪些系统组件缺了就自动装装完再继续装你的MSI。常见的需要勾选的东西.NET Framework版本如果你的程序目标框架是.NET Framework 4.6.2系列引导程序会自动检测并安装。.NET Desktop Runtime如果目标是.NET 6/8这种新架构在这里选对应的Desktop Runtime版本。VC 2015-2022 Redistributable程序用了原生C库或者某些第三方控件库的话大概率需要。SQL Server Express LocalDB程序要带本地数据库的话有这一项。勾选之后要选从与我的应用程序相同的位置下载系统必备组件然后构建时输出目录会多出好几个安装包文件比如dotnet runtime的exe。setup.exe会先检查并处理这些前置依赖再启动MSI。这也意味着你最终交付的安装包不是一个孤零零的exe而是一个文件夹。网上经常有人抱怨我只要一个单文件安装包其实你把整个输出文件夹压缩成一个自解压包就能做到但不建议直接把setup.exe单独拷走——没带旁边那些依赖文件引导程序装到一半会提示找不到组件。我在项目里见过不止一次这种事故客户把setup.exe单独拖到桌面报错然后远程排查了半天。4. 注册表、文件关联、自定义操作安装时要做的额外动作4.1 用Registry编辑器写入配置项注意目录属性的替代如果你的程序需要在安装时往注册表写配置而不是等程序第一次运行再写Registry编辑器就能派上用场。它的树形结构和regedit几乎一样你顺着HKEY_CURRENT_USER\Software或者HKEY_LOCAL_MACHINE\Software分支展开新建项和值就行。例如在HKCU\Software\MyCompany\MyApp下添加一个字符串值InstallPath值内容填[TARGETDIR]安装时MSI会把方括号里的属性自动替换成真实的安装目录路径。这个方括号替换机制是整个Windows Installer的核心玩法不只是Registry编辑器File System里的DefaultLocation、自定义操作的Arguments都会用到。第一次用的时候容易忽略以为装完注册表里会原样存一个[TARGETDIR]实际不是MSI在写入时会完成替换。条件是项和值所在的注册表路径是MSI支持动态计算的位置多数情况下没问题。有一点我不太建议在安装时往HKCU\Software\Microsoft\Windows\CurrentVersion\Run里写开机自启动项。现在很多安全软件对Run键很敏感写入动作很容易被拦截用户体验也差。如果程序确实需要开机自启最好在程序第一次运行时自己询问用户而不是安装时偷偷写注册表。安装包本身应该尽量不碰这类容易被误解的行为。4.2 File Types双击你的数据文件调用你的程序打开如果你的程序有自定义的数据文件格式比如你的软件生成了一批.abc文件希望安装后用户双击.abc文件自动用你的程序打开那就要用File Types编辑器。右键添加文件类型需要设置的几个字段扩展名填abc不带点。命令填open这是右键菜单里默认动作的名字。打开该文件的命令在文件类型节点的属性里配置成类似[TARGETDIR]YourApp.exe %1的格式%1会被系统替换成被双击文件的完整路径。注册之后系统里的文件关联由MSI统一维护。好处是卸载时MSI会自动把这些关联清理掉不会在用户系统里留下孤儿扩展名。相比之下如果文件关联是在程序运行时往注册表HKCR里写卸载时往往会残留。4.3 Custom Actions四个阶段和不能踩的坑Custom Actions是Installer Projects里最强大也最容易翻车的功能。它在安装流程里划分了四个阶段Install文件复制完成后执行。CommitInstall阶段的动作全部成功后执行通常是确认收尾。Rollback安装失败时执行用于还原。Uninstall卸载时执行。添加自定义操作的方法是右键对应阶段选添加自定义操作然后从应用程序文件夹里挑一个exe或dll。这个被添加的程序会在对应的安装阶段被执行。我在这里强烈建议至少在Arguments属性里把安装目录传进去比如/dir[TARGETDIR] /name[ProductName]为什么要传安装目录因为自定义操作程序执行时它的当前工作目录不一定是安装目录甚至可能是系统目录。如果你的代码里用了相对路径去读写文件装的时候就会莫名奇妙失败。通过在参数里传入真实路径程序再用Environment.GetCommandLineArgs()解析是最稳的方案。自定义操作最常见的坑是异常处理不够。你在Install阶段抛一个未捕获异常MSI会立即判定安装失败并触发回滚用户看到的提示只有一句安装被中断完全没有你程序里的具体错误信息。排查这类问题有几个实用招数第一先把自定义操作的exe在命令行里手动执行一遍用相同的参数看它的真实行为和输出。第二用msiexec /l*v C:\msi.log把详细安装日志生成出来搜索CustomAction和Return value 3来定位是哪个操作失败。第三确认自定义操作exe依赖的DLL在目标机器上存在。安装进程的运行上下文和你在开发机双击运行不一样有些运行库在开发环境里有但安装进程的PATH里没有就会导致它在目标机器上启动即崩溃。还有一个原则不要在Install阶段弹窗或做任何需要用户交互的事。一旦安装走的是静默模式这些弹窗要么直接没反应要么挂起整个安装进程。4.4 Launch Conditions和Prerequisites的分工Launch Conditions编辑器是安装前的一道闸门。它检测目标机器是否满足硬性条件不满足就直接提示并退出。Installer Projects预置了一些常用条件比如.NET Framework的最低版本、Windows Installer版本。你可以添加一个.NET Framework 4.7.2的启动条件只要目标机器没装或版本不够安装程序会在任何文件复制之前停下来。这里要注意它和Prerequisites的分工Prerequisites是检测到缺了就自动下载安装Launch Conditions是检测到缺了就提示并中断。两者可以配合使用但不要混淆。Launch Conditions一般用于硬性门槛比如你的程序必须在某个Windows版本上运行不满足就没必要继续Prerequisites用于运行时补齐目标机器缺什么自动装什么。5. 构建产物、版本升级和五大经典报错的排查链路5.1 构建后拿到哪些文件交付时别只发setup.exe安装项目的构建和其他项目一样在解决方案配置里切到Release右键Setup项目→生成。构建成功后打开安装项目的输出目录你会看到一个setup.exe。这是引导程序负责检查并安装Prerequisites里的依赖项然后再把MSI交出去。一个MSI文件名字可能由你设置的OutputFileName决定也可能是Setup.msi或者项目名.msi。若干运行时安装包和cab文件这些取决于你勾选的Prerequisites和文件规模。MSI文件名最好在项目属性里手动设置成容易识别的名字比如MyApp-1.0.0.msi免得每次都要去看哪个文件是哪次构建出来的。构建之前我习惯先清理再生成尤其是文件系统编辑器里删除过文件之后。否则可能出现旧的配置文件被残留进新安装包的情况。这里有件事值得专门说给MSI和setup.exe做数字签名。公网分发的软件不签名的后果是你的安装包在Windows SmartScreen那里会弹未知发布者很多企业客户的策略甚至直接阻止未签名安装包运行。签名的方法有两种一是在安装项目属性里配置证书文件二是构建完成后用SignTool命令行统一签名。如果你手头有代码签名证书建议把这个动作固化到构建流程里。5.2 覆盖安装和自动升级的规则UpgradeCode、Version、ProductCodeInstaller Projects的升级逻辑不是检测到新版本就自动提示用户下载而是新版MSI在安装时发现机器上有同UpgradeCode的旧版就把它卸载替换掉。想让它正常工作得满足三个条件UpgradeCode不变。这是升级血缘关系的核心标识。Version递增。安装器只认数字大小不认你的版本号命名规则。ProductCode产品代码每次发新版时改成新GUID。属性窗口里默认是自动生成保持默认即可这样新版本能被识别成一个不同的产品同时通过UpgradeCode知道自己是旧版的继承者。升级过程中还得留意文件替换规则。Windows Installer默认按文件版本号决定是否替换如果你的某个配置文件没有版本资源、或者版本号写的是1.0.0新版本构建出来还是1.0.0MSI就可能认为新旧一样而不去覆盖导致升级后用户机器上还是旧配置。对于App.config、appsettings.json这类运行时配置有的团队会在File System编辑器里把文件设为永久Permanent让它卸载时也保留有的则用自定义操作在升级时主动更新配置。没有标准答案完全取决于你的配置是否需要跟随版本变化。5.3 报了另一个版本已安装怎么查这个报错几乎是必经之路。在一台已经装过旧版的机器上装新版弹了一句此产品的另一个版本已安装然后安装就中断了。排查链路固定如下先确认UpgradeCode是不是还在。用Orca工具打开新版MSI看Property表里的UpgradeCode再打开旧版MSI对比如果两个GUID不一致就谈不上升级。再确认Version是否真的比旧版高。很多人更新了Version属性但忘了重新生成安装项目构建出来的MSI还是旧版本。接着确认目标机器上的旧版是不是同一个产品。如果旧版是用ClickOnce发布的、或者用别的打包工具做的Installer Projects根本不认它是同一个产品。最后确认InstallAllUsers设置是否一致。旧版装的是用户级新版换成了机器级或者反过来都可能导致升级关系错乱。如果上面几项都对控制面板里却还留着旧记录那就先把旧版卸载干净清理注册表Uninstall分支里对应的残留项再重新试装新版。5.4 中途回滚的典型场景与日志排查安装到一半突然回滚这是最让人头疼的情况。两个典型场景我都在项目里遇到过。场景一是自定义操作抛异常。排查方法前面说过用msiexec /l*v生成日志日志里搜Return value 3或者CustomAction一般能锁定是哪一段逻辑的问题。隐蔽版是自定义操作程序本身可以运行但它依赖的某个DLL在目标机器上缺失导致它在安装进程的上下文里启动即崩溃。这种问题只能把相关DLL全部带进安装包并在代码里加日志。场景二是服务注册失败。如果你的程序要安装成Windows服务服务安装代码在Install阶段执行时需要处理服务账号、依赖关系、系统权限。一个非常容易踩的细节是安装进程虽然是提升权限的但它的安全上下文和你在开发机手动运行服务安装器不一样特别是当服务要绑定到当前用户Token或者读写用户Profile下的路径时就会在远程装机时翻车。遇到服务相关回滚先看事件查看器里的MSIInstaller日志确定是哪个服务安装调用失败再看具体API的错误码不要被安装程序未知错误四个大字带偏。5.5 静默安装命令与无人值守部署企业内部批量安装时经常需要无人值守。最常用的命令是msiexec /i MyApp.msi /qn TARGETDIRC:\MyApp /norestart/qn表示完全静默/qb表示显示基本进度条。TARGETDIR参数可以覆盖默认的安装目录。加/l*v C:\msi.log可以同时生成日志排障时一定带上。要注意/qn模式下如果MSI配置了必须用户交互的UI安装会直接失败所以安装包里应该避免放强制弹窗的自定义操作。如果依赖项有运行时没装msiexec本身不会帮你装要先在你的基础镜像或者通过配置管理器把依赖装好再执行MSI。向导里的setup.exe虽然能处理Prerequisites但它对静默参数的支持比较有限真正的无人值守部署我一般直接用msiexec加前置脚本。6. 和ClickOnce、WiX、InstallShield的横向对比以及我的选型习惯6.1 五类方案的对比表在给一个桌面程序选发布方案时我习惯把下面这些选项摆开来比较对比项Visual Studio Installer ProjectsClickOnceInstallShield LE/ProWiXNSIS/Inno Setup学习成本低最低中/高高中UI定制能力弱标准向导风格弱强自定义强强系统集成能力支持注册表、服务、文件关联基本不支持支持支持支持但需脚本自动更新需自己做升级包内置检测更新方便支持需自行设计需自行设计适合场景winform/WPF交付给客户内部轻量工具商业级安装包大型工程、CI/CD要求高免费小工具快速出包这个表是我实际使用感受的浓缩。Installer Projects的优势在于和Visual Studio集成得最顺畅图形化操作不需要碰XML或者脚本语言适合大多数winform/WPF项目的交付场景。ClickOnce的自动更新对内部工具来说很香但一旦涉及注册表、服务、文件关联这种系统级操作它就使不上劲了。WiX功能最全但它是用XML定义整个安装过程学习曲线比Installer Projects陡得多适合需要高度自动化和精细控制的大型项目。NSIS和Inno Setup则是免费小工具界的扛把子出包快社区脚本资料多。6.2 不同场景下的选型建议如果是公司内部工具用户是非技术同事我建议优先考虑ClickOnce或者直接绿色发布。内部工具通常不需要安装到Program Files不需要系统级注册ClickOnce的自动更新能省掉大量运维时间。如果是交付给外部客户客户安装了之后要控制面板能卸载、要能升级、要写配置或注册表Installer Projects是最平衡的选择。它不需要额外授权跟着Visual Studio走团队任何人接手都容易上手。如果客户对安装界面有品牌要求或者软件组件非常复杂、有多个模块要按需选择安装可以直接上InstallShield Pro或者WiX。Installer Projects的那套标准向导界面在这种需求面前再硬凑是浪费时间。6.3 我的习惯我把Installer Projects定位成桌面程序交付的默认起点。先在这里把需求理清楚真的发现不够用了再升级到复杂工具而不是一上来就选一个重型方案把团队拖进XML和脚本的坑里。打包工具本身不是核心技术壁垒但它决定着一个软件在客户机器上的第一印象和长期维护成本值得花点时间做对比和积累。最后说一个我坚持了很多年的习惯每次构建完安装包我会在一个干净的虚拟机里从头装一遍重点看三件事——第一次安装过程是否顺畅、控制面板里显示的图标和名字是否正确、升级安装后旧文件有没有被正确替换。虚拟机里装一次的成本很低但能避免绝大多数分发事故。Installer Projects的功能不算花哨但它和Windows Installer的原生配合很扎实用熟之后你会发现打包这扇门没有想象中那么难还能顺带学到不少Windows系统集成的底层知识。
返回列表