如何让MSI安装完成后启动多个EXE?无需多按钮/控件方案
MSI安装完成后启动多个EXE的问题
已有成熟方案让MSI在安装结束时启动单个EXE:开发者创建Javascript文件,作为生成MSI的.vdproj项目的POST-BUILD-EVENT由Visual Studio执行,脚本会修改.vdproj生成的MSI。
微软文档提到:"用于对绑定到同一控件的多个事件进行排序的整数,必须为非负数,该字段可留空",这意味着安装最终对话框中的单个控件可触发多个事件。
我据此修改代码,试图启动两个EXE,但始终只有第二个EXE被启动。希望实现无需两个按钮即可启动两个EXE,甚至能否不使用任何控件来启动EXE?
相关代码
WScript.Echo("Inserting events to launch the applications..."); // Insert the Event to launch the application sql = "INSERT INTO `ControlEvent` (`Dialog_`, `Control_`, `Event`, `Argument`, `Condition`, `Ordering`) VALUES ('FinishedForm', 'CloseButton', 'DoAction', 'VSDCA_Launch0', 'LAUNCHAPPS=1', '0')"; sql = "INSERT INTO `ControlEvent` (`Dialog_`, `Control_`, `Event`, `Argument`, `Condition`, `Ordering`) VALUES ('FinishedForm', 'CloseButton', 'DoAction', 'VSDCA_Launch1', 'LAUNCHAPPS=1', '1')"; view = database.OpenView(sql); view.Execute(); view.Close(); WScript.Echo("Updating the CustomAction table..."); // Insert the custom actions to launch the applications when finished sql = "INSERT INTO `CustomAction` (`Action`, `Type`, `Source`, `Target`) VALUES ('VSDCA_Launch0', '210', '" + fileId1 + "', '')"; sql = "INSERT INTO `CustomAction` (`Action`, `Type`, `Source`, `Target`) VALUES ('VSDCA_Launch1', '210', '" + fileId2 + "', '')"; view = database.OpenView(sql); view.Execute(); view.Close();
日志信息(仅执行了第二个EXE)
我原本期望能启动两个EXE,以下是相关日志内容: MSI (c) (1C:E8) [08:49:24:280]: 执行动作: FinishedForm 动作 8:49:24: FinishedForm. 动作开始 8:49:24: FinishedForm. MSI (c) (1C:E8) [08:49:24:280]: 注意: 1: 2235 2: 3: ExtendedType 4: SELECT `Action`,`Type`,`Source`,`Target`, NULL, `ExtendedType` FROM `CustomAction` WHERE `Action` = 'FinishedForm' MSI (c) (1C:84) [08:49:24:280]: 注意: 1: 2262 2: Error 3: -2147287038 DEBUG: 错误 2826: 对话框 FinishedForm 上的控件 Line1 向右超出对话框边界 3 像素 安装程序在安装此软件包时遇到意外错误。这可能表明此软件包存在问题。错误代码是 2826。参数为: FinishedForm, Line1, to the right MSI (c) (1C:84) [08:49:24:280]: 注意: 1: 2262 2: Error 3: -2147287038 DEBUG: 错误 2826: 对话框 FinishedForm 上的控件 Line2 向右超出对话框边界 3 像素 安装程序在安装此软件包时遇到意外错误。这可能表明此软件包存在问题。错误代码是 2826。参数为: FinishedForm, Line2, to the right MSI (c) (1C:84) [08:49:24:296]: 注意: 1: 2262 2: Error 3: -2147287038 DEBUG: 错误 2826: 对话框 FinishedForm 上的控件 BannerBmp 向右超出对话框边界 3 像素 安装程序在安装此软件包时遇到意外错误。这可能表明此软件包存在问题。错误代码是 2826。参数为: FinishedForm, BannerBmp, to the right MSI (c) (1C:84) [08:49:24:296]: 注意: 1: 2262 2: CheckBox 3: -2147287038 动作 8:49:24: FinishedForm. 创建对话框 MSI (c) (1C:84) [08:49:28:499]: 执行动作: VSDCA_Launch1 动作 8:49:28: VSDCA_Launch1. 动作开始 8:49:28: VSDCA_Launch1. MSI (c) (1C:84) [08:49:28:499]: 注意: 1: 2235 2: 3: ExtendedType 4: SELECT `Action`,`Type`,`Source`,`Target`, NULL, `ExtendedType` FROM `CustomAction` WHERE `Action` = 'VSDCA_Launch1' 动作结束 8:49:28: FinishedForm. 返回值 1. 动作结束 8:49:28: INSTALL. 返回值 1. 动作结束 8:49:28: VSDCA_Launch1. 返回值 0.
问题分析与解决方案
为什么只执行了第二个EXE?
代码存在核心错误:每次赋值sql = "INSERT..."时,都会直接覆盖之前的sql变量,导致最终只有最后一条INSERT语句被执行。不管是ControlEvent表还是CustomAction表,都只插入了第二条记录,第一条被完全覆盖。
修复代码(实现单个按钮启动两个EXE)
需要分别执行每条INSERT语句,不能覆盖sql变量:
WScript.Echo("Inserting events to launch the applications..."); // 插入第一个启动事件 sql = "INSERT INTO `ControlEvent` (`Dialog_`, `Control_`, `Event`, `Argument`, `Condition`, `Ordering`) VALUES ('FinishedForm', 'CloseButton', 'DoAction', 'VSDCA_Launch0', 'LAUNCHAPPS=1', '0')"; view = database.OpenView(sql); view.Execute(); view.Close(); // 插入第二个启动事件 sql = "INSERT INTO `ControlEvent` (`Dialog_`, `Control_`, `Event`, `Argument`, `Condition`, `Ordering`) VALUES ('FinishedForm', 'CloseButton', 'DoAction', 'VSDCA_Launch1', 'LAUNCHAPPS=1', '1')"; view = database.OpenView(sql); view.Execute(); view.Close(); WScript.Echo("Updating the CustomAction table..."); // 插入第一个自定义动作 sql = "INSERT INTO `CustomAction` (`Action`, `Type`, `Source`, `Target`) VALUES ('VSDCA_Launch0', '210', '" + fileId1 + "', '')"; view = database.OpenView(sql); view.Execute(); view.Close(); // 插入第二个自定义动作 sql = "INSERT INTO `CustomAction` (`Action`, `Type`, `Source`, `Target`) VALUES ('VSDCA_Launch1', '210', '" + fileId2 + "', '')"; view = database.OpenView(sql); view.Execute(); view.Close();
无需控件启动EXE的方案
如果不想依赖对话框控件触发,可以直接将自定义动作绑定到安装序列的末尾,在InstallFinalize之后执行:
- 确保自定义动作类型为210(同步执行,需等待程序退出)或3090(异步执行,适合启动外部程序,不阻塞安装流程)
- 将自定义动作添加到
InstallExecuteSequence表中,设置在InstallFinalize之后执行:
// 为VSDCA_Launch0添加序列 sql = "INSERT INTO `InstallExecuteSequence` (`Action`, `Condition`, `Sequence`) VALUES ('VSDCA_Launch0', 'LAUNCHAPPS=1', 6601)"; view = database.OpenView(sql); view.Execute(); view.Close(); // 为VSDCA_Launch1添加序列 sql = "INSERT INTO `InstallExecuteSequence` (`Action`, `Condition`, `Sequence`) VALUES ('VSDCA_Launch1', 'LAUNCHAPPS=1', 6602)"; view = database.OpenView(sql); view.Execute(); view.Close();
注:
InstallFinalize的默认序列值是6600,设置为6601和6602可确保在安装完成后执行。推荐使用3090类型,避免因启动的程序未退出导致安装流程阻塞。
内容的提问来源于stack exchange,提问作者HackTheStack
相关产品推荐
相关产品推荐

