Wix 安装程序不会覆盖以前版本的可执行文件

Posted

技术标签:

【中文标题】Wix 安装程序不会覆盖以前版本的可执行文件【英文标题】:Wix installer does not overwrite previous version of an executable 【发布时间】:2015-04-25 19:55:34 【问题描述】:

我有一个非常简单的安装程序 - 将单个 dll 复制到 Program Files 子文件夹并使用 regsvr32.exe 注册它。效果很好,但如果安装了旧版本的 dll,“修复”不会覆盖现有的 dll。 dll 已签名,其版本(内部版本)编号始终递增(例如 2.0.0.123 - > 2.0.0.124)。

查看之前的类似帖子,我添加了 RemoveExistingProducts 并将 ProductId 指定为“*”。卸载然后安装较新版本的工作正常,但我确实需要修复来更新现有的 dll。

我还有什么需要做的吗?

谢谢!

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">

  <!--
When creating a new install for the next version, these fields must be modified
-->
  <?define ProductVersion = "2.0.00" ?>

  <?define ProductId64 = "*" ?>
  <?define ProductId32 = "*" ?>

  <?define PackageId   = "45F34788-66AC-441C-B666-707FFA7F1EE9" ?>


  <!-- Product name as you want it to appear in Add/Remove Programs-->
  <?if $(var.Platform) = x64 ?>
  <?define ProductName = "XYZ (64 bit)" ?>
  <?define Win64 = "yes" ?>
  <?define PlatformProgramFilesFolder = "ProgramFiles64Folder" ?>
  <?define ProductId = "$(var.ProductId64)" ?>
  <?define MainDllName = "XYZ64.dll" ?>
  <?define MainDllSource = "..\..\bin\Win64\Release\XYZ64.dll" ?>
  <?else ?>
  <?define ProductName = "XYZ (32 bit)" ?>
  <?define Win64 = "no" ?>
  <?define PlatformProgramFilesFolder = "ProgramFilesFolder" ?>
  <?define ProductId = "$(var.ProductId32)" ?>
  <?define MainDllName = "XYZ.dll" ?>
  <?define MainDllSource = "..\..\bin\Win32\Release\XYZ.dll" ?>
  <?endif ?>


  <?define UpgradeCode = "C3763742-7C1C-4AB7-A404-F030B7550E97" ?>


  <Product Id="$(var.ProductId)" Name="$(var.ProductName)" Language="1033" Version="$(var.ProductVersion)" Manufacturer="Advanced Messaging Systems LLC" UpgradeCode="$(var.UpgradeCode)">

    <Package Id="$(var.PackageId)" InstallerVersion="200" Compressed="yes" Description="XYZ Installer package"  InstallPrivileges="elevated"/>

    <!-- No restore point  -->
    <Property Id="MSIFASTINSTALL" Value="3" />

   <Media Id="1" Cabinet="media1.cab" EmbedCab="yes" />

    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="$(var.PlatformProgramFilesFolder)">
        <Directory Id="INSTALLLOCATION" Name="XYZ">

          <Component Id="XYZDll" Guid="E2CBEE41-6C0E-4A84-95C1-7282747B4A3D">
            <File Id='MainDll' Name="$(var.MainDllName)" DiskId='1' Source="$(var.MainDllSource)" SelfRegCost="0" />

            <!-- TODO: Insert files, registry keys, and other resources here. -->
          </Component>

        </Directory>
      </Directory>
    </Directory>

    <Property Id="WIXUI_INSTALLDIR" Value="INSTALLLOCATION" />

    <!-- Note: Custom actions to install/uninstall the dll using regsvr32.exe -->
    <CustomAction Id="RegisterDll"
                      Directory="INSTALLLOCATION"
                      ExeCommand='regsvr32.exe /s "[INSTALLLOCATION]$(var.MainDllName)"'

                      Return="check">
    </CustomAction>
    <CustomAction Id="UnregisterDll"
                  Directory="INSTALLLOCATION"
                  ExeCommand='regsvr32.exe /s /u "[INSTALLLOCATION]$(var.MainDllName)"'>
    </CustomAction>


    <Feature Id="ProductFeature" Title="XYZ" Level="1">
      <ComponentRef Id="XYZDll" />
      <!-- Note: The following ComponentGroupRef is required to pull in generated authoring from project references. -->
      <ComponentGroupRef Id="Product.Generated" />
    </Feature>

    <InstallUISequence>
      <Custom Action="WixCloseApplications" Before="AppSearch"/>
    </InstallUISequence>

    <InstallExecuteSequence>

      <!-- Uninstall previous version before installing this one. -->
      <RemoveExistingProducts Before="InstallInitialize"/>


      <SelfRegModules/>
    </InstallExecuteSequence>

    <Icon Id="XYZ.ico" SourceFile="..\Graphics\XYZ.ico"/>
    <Property Id="ARPPRODUCTICON" Value="XYZ.ico" />

    <!-- UI -->
    <UIRef Id="WixUI_InstallDir"/>
    <UIRef Id="WixUI_ErrorProgressText" />

    <WixVariable Id="WixUILicenseRtf" Value="..\EULA\license.rtf" />
    <WixVariable Id="WixUIBannerBmp"  Value="..\Graphics\banner.jpg" />
    <WixVariable Id="WixUIDialogBmp"  Value="..\Graphics\logo.jpg" />


    <!-- End UI -->
  </Product>
</Wix>

更新。修改升级条目后,以下内容对我有用:

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">

  <!--
When creating a new install for the next version, these fields must be modified
-->
  <?define ProductVersion = "2.0.4" ?>

  <?define ProductId64 = "*" ?>
  <?define ProductId32 = "*" ?>

  <?define PackageId   = "*" ?>


  <!-- Product name as you want it to appear in Add/Remove Programs-->
  <?if $(var.Platform) = x64 ?>
  <?define ProductName = "XYZ (64 bit)" ?>
  <?define Win64 = "yes" ?>
  <?define PlatformProgramFilesFolder = "ProgramFiles64Folder" ?>
  <?define ProductId = "$(var.ProductId64)" ?>
  <?define MainDllName = "XYZ64.dll" ?>
  <?define MainDllSource = "..\..\bin\Win64\Release\XYZ64.dll" ?>
  <?else ?>
  <?define ProductName = "XYZ (32 bit)" ?>
  <?define Win64 = "no" ?>
  <?define PlatformProgramFilesFolder = "ProgramFilesFolder" ?>
  <?define ProductId = "$(var.ProductId32)" ?>
  <?define MainDllName = "XYZ.dll" ?>
  <?define MainDllSource = "..\..\bin\Win32\Release\XYZ.dll" ?>
  <?endif ?>


  <?define UpgradeCode = "C3763742-7C1C-4AB7-A404-F030B7550E97" ?>


  <Product
    Id="$(var.ProductId)"
    Name="$(var.ProductName)"
    Language="1033"
    Version="$(var.ProductVersion)"
    Manufacturer="Advanced Messaging Systems LLC"
    UpgradeCode="$(var.UpgradeCode)"
    >

    <Package Id="$(var.PackageId)"
             InstallerVersion="200"
             Compressed="yes"
             Description="XYZ Installer package"
             InstallPrivileges="elevated"
     />

    <!-- No restore point  -->
    <Property Id="MSIFASTINSTALL" Value="3" />


    <Upgrade Id="$(var.UpgradeCode)">
      <UpgradeVersion Minimum="1.0.0"
                      IncludeMinimum="yes"
                      OnlyDetect="no"
                      Maximum="$(var.ProductVersion)"
                      IncludeMaximum="no"
                      Property="PREVIOUSFOUND" />
    </Upgrade>


    <Media Id="1" Cabinet="media1.cab" EmbedCab="yes" />

    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="$(var.PlatformProgramFilesFolder)">
        <Directory Id="INSTALLLOCATION" Name="XYZ">

          <Component Id="XYZDll" Guid="E2CBEE41-6C0E-4A84-95C1-7282747B4A3D">
            <File Id='MainDll' Name="$(var.MainDllName)" DiskId='1' Source="$(var.MainDllSource)" SelfRegCost="0" />

            <!-- TODO: Insert files, registry keys, and other resources here. -->
          </Component>

        </Directory>
      </Directory>
    </Directory>

    <Property Id="WIXUI_INSTALLDIR" Value="INSTALLLOCATION" />

    <!-- Note: Custom actions to install/uninstall the dll using regsvr32.exe -->
    <CustomAction Id="RegisterDll"
                      Directory="INSTALLLOCATION"
                      ExeCommand='regsvr32.exe /s "[INSTALLLOCATION]$(var.MainDllName)"'

                      Return="check">
    </CustomAction>
    <CustomAction Id="UnregisterDll"
                  Directory="INSTALLLOCATION"
                  ExeCommand='regsvr32.exe /s /u "[INSTALLLOCATION]$(var.MainDllName)"'>
    </CustomAction>


    <Feature Id="ProductFeature" Title="XYZ" Level="1">
      <ComponentRef Id="XYZDll" />
      <!-- Note: The following ComponentGroupRef is required to pull in generated authoring from project references. -->
      <ComponentGroupRef Id="Product.Generated" />
    </Feature>

    <InstallUISequence>
      <Custom Action="WixCloseApplications" Before="AppSearch"/>
    </InstallUISequence>

    <InstallExecuteSequence>

     <RemoveExistingProducts After="InstallInitialize"/>

      <SelfRegModules/>

    </InstallExecuteSequence>

    <Icon Id="XYZ.ico" SourceFile="..\Graphics\XYZ.ico"/>
    <Property Id="ARPPRODUCTICON" Value="XYZ.ico" />

    <!-- UI -->
    <UIRef Id="WixUI_InstallDir"/>
    <UIRef Id="WixUI_ErrorProgressText" />

    <WixVariable Id="WixUILicenseRtf" Value="..\EULA\license.rtf" />
    <WixVariable Id="WixUIBannerBmp"  Value="..\Graphics\banner.jpg" />
    <WixVariable Id="WixUIDialogBmp"  Value="..\Graphics\logo.jpg" />


    <!-- End UI -->
  </Product>
</Wix>

【问题讨论】:

【参考方案1】:

如果您想进行重大升级,请从 WiX MajorUpgrade 元素开始。升级的一般规则是:

    ProductCode 和 PackageCode 与旧产品不同。 在前三个字段的某处增加 ProductVersion。 与旧产品相同的升级代码。 做一些事情(如 Wix MajorUprade 或升级元素)以确保您已进行升级。 按用户安装不会升级按系统安装,反之亦然。

在您原来的情况下,未能遵循规则 1 和 2 意味着 Windows 认为已安装相同的产品并进入修复模式。这应该是您的第一个警告,因为重大升级看起来像是全新安装,而不是修复。如果您在 Programs&Features 中有两个条目,则意味着未满足这 4 个要求中的一个或多个。如果您收到“已安装此产品的另一个版本”,则表示您没有遵循规则 1,并且与已安装产品相比,行为变化与 ProductCode 和 PackageCode 值有关。

【讨论】:

对我来说,这是第二点。前三个字段中的产品版本未更改。 joshstechnij 在此线程上也有相同的说明。 community.flexerasoftware.com/archive/index.php?t-197700.html 我假设在您的规则 1 中,ProductCode 应该是 Product Id,PackageCode 应该是 Package Id。它们都应该是"*" 并且是自动生成的。【参考方案2】:

我很惊讶 Wix compilerlinker 允许这条线:

 <?define PackageId   = "45F34788-66AC-441C-B666-707FFA7F1EE9" ?>

如果这确实有效并且通过了,我没有测试过,这意味着你的包有一个硬编码包ID。我认为 Wix 具有针对此问题的保护功能?也许确实如此?如果允许硬编码的包 guid 是否有意义,我们应该与 Wix 社区核实。我想这对于调试和测试目的可能是必要的 - 但至少应该有一个编译器警告。

包 GUID 的想法是它对于每个编译的 MSI 文件应该是唯一的。它只是用来唯一标识一个文件。 Windows Installer 将根据定义将具有相同包 guid 的两个不同 MSI 文件视为同一个文件。各种 x 文件问题的结果。因此,包 GUID 应该始终自动生成,因为它应该是唯一的。请先尝试解决此问题,以检查这是否解决了您的整体问题。将其设置为 *。

我的建议是自动生成 package idproduct id,但是设置一个硬编码的升级代码。升级代码标识“产品系列”,可用于标识您的产品的任何实例,无论语言和版本如何。为您的 64 位和 32 位设置使用单独的升级代码可能会很有用,因为这两个版本可以同时安装在某些系统上。

您可能还希望不再使用 regsvr32.exe 进行自我注册,并从 dll 中提取 COM 数据以获得适当的 MSI 支持:MSI register dll - Self-Registration considered harmful。也许还可以检查一下:Register ActiveX exe server using WiX(如果 Heat 不起作用,请查看 RegSpy2)。

还要注意 you can leave out a lot of source attributes from your Wix xml file 并依赖 Wix 默认值而不是硬编码值。

有关 GUID 和文件替换的更多详细信息:

Change my component GUID in wix? MSI Reference Counting: Two products install the same MSIs Forcing an upgrade of a file that is modified during its initial installation msi version numbers File Versioning Rules Replacing existing files (diagram, both files have version) Plain English file versioning description by Aaron Stebner

【讨论】:

我使用 regsvr32.exe 安装 dll,因为 dll 的 DllRegisterServer / DllUnregisterServer 实现足够智能 - 它知道如何在有限权限的环境中工作并将自己安装在 HKCU 而不是 HKLM 中。【参考方案3】:

简短的回答(另一个变得太乱了):尝试删除这一行并通过将包 ID 设置为“*”来自动生成包 ID:

 <?define PackageId   = "45F34788-66AC-441C-B666-707FFA7F1EE9" ?>

请注意,您必须在卸载所有以前的 MSI 版本后停止使用它们。这是由于错误的硬编码包 guid 可能导致不可预知和不可预见的问题。

【讨论】:

如果 PackageId 为“*”,我的安装程序现在会覆盖旧文件,但它始终作为新安装运行,因此没有修复和卸载按钮,并且“程序和功能”中有多个条目. 如果我对 ProductId guid 进行硬编码,我会收到“已安装此产品的另一个版本”错误提示我先将其删除... 正如 Phil 指出的那样,您现在有一个重大升级可以解决这些问题。这里是some suggested resources for getting familiar with Wix

以上是关于Wix 安装程序不会覆盖以前版本的可执行文件的主要内容,如果未能解决你的问题,请参考以下文章

降级会删除新版本的可执行文件,但不会重新安装旧版本

Wix“高级”安装不会卸载以前的版本

恢复到以前版本的 wix 安装程序

WiX Burn:如何将安装程序可执行文件部署到某个位置?

如何在同一部 iPhone 中获取两个不同版本的可执行文件?使用 Xcode

WIX:安装应用程序的多个实例并升级应用程序(如果安装在以前安装的位置)