返回

Wix Toolset 安装到 Program Files (x86) 解决指南

windows

Wix Toolset 创建的 MSI 安装到 Program Files (x86) 目录的解决办法

最近搞了个项目,用 Wix Toolset 打包成了 MSI 安装程序。 结果装完一看,程序跑 C:\Program Files (x86) 下面去了,可我明明需要它安装到C:\Program Files。这可不行,得想办法解决!

问题原因分析

Windows 系统有两种不同的 "Program Files" 目录:

  • C:\Program Files:用于 64 位应用程序。
  • C:\Program Files (x86):用于 32 位应用程序。

安装程序默认安装到 C:\Program Files (x86),说明 Windows Installer 把它当成了 32 位程序。尽管我的程序文件本身(如上所示reslirp.exe)确实是 x86-64 架构,但是安装包的配置出了差错,导致安装行为发生偏差。 这可能是 Wix 项目配置的问题,也可能是因为某些遗留的设置造成的。

解决方案

经过一番排查和实验,找到了以下几个需要注意的地方,逐一尝试和结合,最终可以解决安装路径问题:

1. 确保 Package 元素的属性设置

在 WiX v4 中, 不再使用Platform属性。正确指定安装包目标平台,应该这么做:

  1. 删除不必要的属性: 首先检查你的.wxs 文件, 确保 没有 任何 Package/@Platform 属性. 如果有, 删除。

  2. InstallerVersion: 虽然和安装路径看似无关,但较旧的 Installer 版本可能行为有异。为了保险起见, Package/@InstallerVersion 设置成 500 或更高. 这代表使用Windows Installer 5.0或更高版本, 对64位的支持更完善。

  3. Scope: 指定安装的范围。"perMachine" 表示为所有用户安装,这是安装到Program Files的必要条件。如果设置成"perUser", 那就安装到用户目录去了。

修改后的 <Package> 元素大概是这样:

<Package Compressed="yes" InstallerVersion="500" Manufacturer="HappyRobotsLTD"
         Name="reSLIRP" Scope="perMachine"
         UpgradeCode="12345678-ABCD-0001-0001-250131143054" Version="1.1.0.0">
    <!-- 移除了任何可能存在的 Platform 属性 -->
</Package>

2. 使用 StandardDirectory 的正确 ID

要让程序安装到 64 位程序的 Program Files,需要使用 ProgramFiles64Folder 这个预定义的目录 ID. 看你的原始代码,这部分是正确的:

<StandardDirectory Id="ProgramFiles64Folder">
  <Directory Id="INSTALLFOLDER" Name="reSLIRP">
    <!-- ... -->
  </Directory>
</StandardDirectory>

3. 仔细检查 ComponentBitness 属性

确保所有包含 64 位文件的 Component 都设置了 Bitness="always64"。在你的例子里,你已经这么做了:

<Component Bitness="always64" Id="ProductComponent">
  <File Id="MainExecutable" KeyPath="yes" Source="build\reslirp.exe"/>
</Component>

确保每个<Component> 都设置好 Bitness="always64"

4. 排查隐式 32 位组件 (重要!)

即使所有显式定义的组件都正确设置了 Bitness,Wix Toolset 仍有可能自动生成 32 位的组件。

检查在 WiX 处理过程产生的文件:
使用 dark.exe 对msi文件进行反编译。查看wxs文件确定有没有隐藏的32位组件。

使用如下命令进行编译和链接,生成 MSI 安装包。
wix build reslirp.wxs -ext WixToolset.UI.wixext
检查生成的ProductComponent.wxs等中间文件.
如果仍有地方将程序安装至错误位置, 可以进一步采用排除法,例如分别测试每一个dll。

最常见的原因是自定义操作(Custom Actions)。 如果你用了自定义操作,且这个操作是 32 位的,整个安装包就会被视为 32 位。检查.wxs 文件中有没有<CustomAction>,确保他们也是 64 位的.

5. 强制使用64位注册表视图(进阶)

在某些极端情况下,即使上述步骤都做了, 程序仍然可能安装在错误的地方.这可能和注册表重定向有关. 在64位 Windows 上, 32 位和 64 位应用程序有不同的注册表视图.

可以在 Component 内部使用 RegistryKey 元素, 并通过 Win64="yes"强制写入到 64 位注册表, 作为最后的尝试:

<Component Bitness="always64" Id="ProductComponent" >
    <File Id="MainExecutable" KeyPath="yes" Source="build\reslirp.exe"/>
      <RegistryKey Root="HKLM"
                 Key="Software\MyCompany\MyApplication"
                 Win64="yes">
           <RegistryValue Type="string" Name="InstallDir" Value="[INSTALLFOLDER]" />
      </RegistryKey>
</Component>

这会强制向 64 位注册表写入一个键值。但要注意, 随意修改注册表可能造成问题. 仅在必要时这样做,并确保清楚自己在做什么。而且写入一个用不着的注册表信息属于画蛇添足.通常不推荐这么做。

6. 检查构建环境

虽然不太可能,但为了完整起见,仍然值得确认下:

  • 构建机器: 确保在 64 位 Windows 上构建。
  • WiX 版本: 用比较新的 WiX Toolset 版本, 建议用 v4或更高。 可以通过 wix -version 来确认使用的 Wix Toolset 版本号。
  • 清理并重建: wix build -clean reslirp.wxs , wix build reslirp.wxs -ext WixToolset.UI.wixext . 彻底清理并重新构建项目。

如果用了持续集成 (CI) 系统, 也检查 CI 环境的配置。

通过以上的排查方法,修改和配置后重新编译构建,你的MSI安装程序就能够正确地安装到C:\Program Files目录下。仔细排查配置,一定可以解决!