You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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.WindowsInstaller NuGet包):
    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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 11:53:01