WiX工具集Bootstrapper:访问内嵌MSI包的属性
解决WiX Bootstrapper内嵌MSI属性访问问题的几种方案
我之前处理过类似的WiX迁移场景,针对你遇到的外部EXE需要读取内嵌MSI属性的问题,这里有几个实用的解决方案,你可以根据自己的需求选择:
方案1:提前暴露MSI属性到Bootstrapper层
这种方法不需要直接操作内嵌的MSI,而是把需要的属性提前提取到Bootstrapper的可访问位置,让EXE2直接读取Bootstrapper的信息。
步骤1:在Bundle中映射MSI属性
在你的Bundle.wxs文件里,通过Variable标签把MSI里的目标属性映射到Bundle层面:<Bundle> <!-- 定义变量关联MSI属性 --> <Variable Name="AppVersion" Value="[ProductVersion]" Type="string" /> <Variable Name="InstallDir" Value="[INSTALLDIR]" Type="string" /> <Chain> <MsiPackage SourceFile="YourApp.msi" Id="MainMsi" /> </Chain> </Bundle>步骤2:让Bootstrapper支持属性查询
如果你用的是自定义Bootstrapper应用(C#编写),可以添加命令行参数支持,比如当外部EXE调用Bootstrapper时传入/getproperty:AppVersion,Bootstrapper就返回对应的属性值。示例代码片段:static void Main(string[] args) { if (args.Length > 0 && args[0].StartsWith("/getproperty:")) { var propName = args[0].Split(':')[1]; var engine = new Engine(); var propValue = engine.StringVariables[propName]; Console.WriteLine(propValue); return; } // 正常启动Bootstrapper的逻辑 }
方案2:从Bootstrapper EXE中提取内嵌MSI到临时目录
如果需要访问MSI的任意属性(不止提前定义的几个),可以把内嵌的MSI从Bootstrapper中提取到临时文件,再用msi.Database.ExecuteScalar操作。
- 核心代码示例(C#)
这里需要引用WiX的DTF库(Microsoft.Deployment.WindowsInstallerNuGet包):using System.IO; using System.Reflection; using Microsoft.Deployment.WindowsInstaller; public string GetMsiProperty(string propertyName) { string tempMsiPath = Path.Combine(Path.GetTempPath(), "TempApp.msi"); Assembly bootstrapperAssembly = Assembly.GetExecutingAssembly(); // 注意:替换成你内嵌MSI的资源名称,可在项目属性的"资源"页查看 string resourceName = "YourBootstrapperProject.Resources.YourApp.msi"; // 提取MSI到临时文件 using (Stream resourceStream = bootstrapperAssembly.GetManifestResourceStream(resourceName)) using (FileStream fileStream = new FileStream(tempMsiPath, FileMode.Create)) { resourceStream.CopyTo(fileStream); } // 读取MSI属性 string propertyValue = null; using (Database db = new Database(tempMsiPath, DatabaseOpenMode.ReadOnly)) { propertyValue = db.ExecuteScalar($"SELECT Value FROM Property WHERE Property='{propertyName}'") as string; } // 清理临时文件 File.Delete(tempMsiPath); return propertyValue; }
方案3:保留独立MSI文件(最省心的向后兼容方案)
如果你不想改动太多代码,可以在构建Bootstrapper时,同时输出一份独立的MSI文件到输出目录。WiX的Burn默认会把内嵌的MSI同时复制到输出目录,只要你不手动删除它,EXE2就可以像以前一样直接访问这个独立MSI。
- 注意事项:
检查你的Bundle配置,确保MsiPackage的Embed属性为yes(默认值),这样Bootstrapper会内嵌MSI,同时输出目录里也会保留原始MSI文件:<MsiPackage SourceFile="YourApp.msi" Id="MainMsi" Embed="yes" />
方案对比
| 方案 | 优点 | 缺点 |
|---|---|---|
| 方案1 | 无IO开销,性能好,仅暴露必要属性 | 需要修改Bootstrapper代码,只能访问提前定义的属性 |
| 方案2 | 可访问MSI任意属性,灵活性高 | 有临时文件IO开销,需要处理资源名称和文件清理 |
| 方案3 | 完全兼容旧逻辑,无需额外代码 | 输出目录会多一个MSI文件,需要确保文件不被误删 |
内容的提问来源于stack exchange,提问作者Marcomattia Mocellin
相关产品推荐
相关产品推荐

