WiX Bundle链中ExePackage始终被跳过,如何强制安装?
配置情况
我配置的WiX Bundle-Chain如下:
<Chain> <ExePackage Id="epVisualCPP2013Redist" SourceFile="$(var.Visual2013CPPRedistDir)vcredist_x64.exe" Permanent="yes" Vital="yes" Cache="no" Compressed="yes" PerMachine="yes" DetectCondition="0" InstallCondition="1"/> <MsiPackage Id="mpTestMsiPackage" SourceFile="$(var.TestMsiPackage.TargetPath)" Vital="yes" Visible="yes" LogPathVariable="LogLocation" Permanent="no" Compressed="yes"/> </Chain>
问题现象
我尝试强制安装Visual C++ 2013 Redistributable Package(vcredist_x64.exe),但无论设置何种DetectCondition或InstallCondition(包括省略这些属性),该包始终不会被安装,而Id="mpTestMsiPackage"的MsiPackage可正常安装。
注意: 我已能检测该运行时包是否安装,当前首要需求是实现强制安装该包。
查看Bootstrapper日志发现以下关键条目:
[D0D8:CE50][2023-08-19T01:05:38]i101: Detected package: epVisualCPP2013Redist, state: Absent, cached: None ... [D0D8:CE50][2023-08-19T01:05:41]w321: Skipping dependency registration on package with no dependency providers: epVisualCPP2013Redist ... [D0D8:CE50][2023-08-19T01:05:41]i201: Planned package: epVisualCPP2013Redist, state: Absent, default requested: Present, ba requested: None, execute: None, rollback: None, cache: No, uncache: No, dependency: None
但在Bootstrapper Application中添加以下代码后,该包可正常安装:
private void bootstrapperApplication_PlanPackageBegin(object sender, PlanPackageBeginEventArgs e) { if (e.PackageId == "epVisualCPP2013Redist") e.State = RequestState.Present; }
请问我哪里配置有误?是ExePackage配置错误,还是Bootstrapper Application中遗漏了什么?
核心原因
问题出在Bootstrapper Application(BA)的默认行为上:默认情况下,WiX的标准BA不会主动计划安装未被标记为"依赖项"的ExePackage。日志里的w321: Skipping dependency registration on package with no dependency providers提示已经明确这点——你的ExePackage没有被任何其他包标记为依赖,所以BA跳过了它的安装计划,即便DetectCondition设为0(表示未安装)、InstallCondition设为1(表示满足安装条件)也不会生效。
你在PlanPackageBegin事件里手动设置RequestState.Present,本质是绕过了BA的默认依赖检查逻辑,强制让它将该包纳入安装计划。
两种解决方案
方案1:通过配置声明依赖关系(推荐)
无需修改BA代码,只需在Chain中给MsiPackage添加依赖声明,表明它需要Visual C++ 2013运行时包:
<Chain> <ExePackage Id="epVisualCPP2013Redist" SourceFile="$(var.Visual2013CPPRedistDir)vcredist_x64.exe" Permanent="yes" Vital="yes" Cache="no" Compressed="yes" PerMachine="yes" DetectCondition="0" InstallCondition="1"/> <MsiPackage Id="mpTestMsiPackage" SourceFile="$(var.TestMsiPackage.TargetPath)" Vital="yes" Visible="yes" LogPathVariable="LogLocation" Permanent="no" Compressed="yes"> <!-- 添加依赖声明 --> <DependsOnPackage Id="epVisualCPP2013Redist"/> </MsiPackage> </Chain>
这样BA会识别到MsiPackage依赖该ExePackage,自动计划安装它,无需修改BA代码。
方案2:修改BA逻辑(适合无依赖的独立安装场景)
如果你的ExePackage不需要作为其他包的依赖,只是要强制安装,除了保留你现有的PlanPackageBegin事件处理代码外,也可以在BA初始化或PlanComplete事件中,主动调用Engine.Plan(RequestState.Present)触发所有包的安装计划。不过你当前的事件处理代码已经是最直接的方式,针对性强且简洁。
补充说明
- 为什么
DetectCondition和InstallCondition没生效?这两个属性是判断包是否需要安装的前提,但BA只有在认为该包是"需要处理"的(比如有依赖关系、或BA主动指定)时,才会去评估这两个条件。你的情况是BA一开始就没把它纳入处理列表,所以条件设置无效。 - 日志里的
default requested: Present表示根据条件应该安装,但ba requested: None表示BA没有主动要求安装,所以最终execute: None,不会执行安装。
内容的提问来源于stack exchange,提问作者Krys

