在 Wix 中进行重大升级会在 Add/Remove 个程序中创建 2 个条目

Doing Major Upgrade in Wix creates 2 entries in Add/Remove Programs

我遵循了官方 Major Upgrade 指南,但我似乎遗漏了一些东西。 这是我的 MCVE:

<?xml version="1.0" encoding="UTF-8"?>

<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">

  <Product Id="*" Codepage="1252" Language="1033" Manufacturer="Bla Corporation"
           Name="Bla" UpgradeCode="PUT-GUID-HERE" Version="31.00.0000">

    <Package Comments="Contact: Refael Sheinker, refael.sheinker@bla.com." Description="Bla"
             InstallerVersion="500"
             Compressed="yes"
             InstallScope="perMachine"
             Keywords="Installer,MSI,Database" Languages="1033" Manufacturer="Bla Corporation" Platform="x64" />

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

    <MajorUpgrade AllowDowngrades="no"
                  AllowSameVersionUpgrades="no"
                  Disallow="no"
                  IgnoreRemoveFailure="no"
                  MigrateFeatures="yes"
                  Schedule="afterInstallInitialize"
                  DowngradeErrorMessage="A later version of [ProductName] is already installed" />

    <Property Id="WIXUI_INSTALLDIR" Value="APPLICATIONROOTDIRECTORY" />
    <UIRef Id="WixUI_InstallDir" />

    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFiles64Folder">
        <Directory Id="PROGRAMFILESSUBDIR" Name="Bla">
          <Directory Id="APPLICATIONROOTDIRECTORY" Name="BlaInternal" />
        </Directory>
      </Directory>
    </Directory>

    <DirectoryRef Id="APPLICATIONROOTDIRECTORY">

      <Component Id="tenlira.ini" Guid="*">
        <File Id="tenlira.ini" Source="..\ConfigurationFile\x64\tenlira.ini" KeyPath="yes" />
      </Component>

    </DirectoryRef>

    <Feature Id="MainApplication" Title="TenLira" Level="1">
      <ComponentRef Id="tenlira.ini" />
    </Feature>

  </Product>

</Wix>

它只是以安装单个文件为例。到目前为止,一切都很好。现在,我所做的就是添加另一个 ComponentFile,当然还有 Feature 中相应的 ComponentRef。我特别保留 Version 原样:31.00.0000。我期望的是新安装程序 不会 执行主要升级,但确实如此。为什么?此外,Add/Remove 程序中现在有 2 个条目。

请帮我找出我在这里遗漏了什么。谢谢。雷法尔.

更新: 发布问题让我再次阅读文档,我发现 MajorUpgrade 元素中的 AllowSameVersionUpgrades 应该设置为 yes。这次 Add/Remove Programs 中只有一个 entree,但它仍然执行 Major Upgrade。为什么?

它进行了重大升级,因为两个 MSI 具有相同的 UpgradeCode,并且您现在指定了 AllowSameVersionUpgrades,因此它进行了以前没有的升级。

您的构建每次都会生成一个新的 ProductCode,因此每个 MSI 都是一个新产品,因此如果它不进行升级,您将安装两次,如果进行升级则安装一次。您可能对升级的工作方式有一些未明确说明的假设。

UPDATE:这是一个列表,通过识别最常见的问题来帮助调试失败的主要升级:


主要升级 - “旧的手动方式”

我猜你遇到了一个奇怪的问题,WiX MajorUpgrade 元素可能无法通过组合 auto-generated product GUIDAllowSameVersionUpgrades 设置为 yes 并保持version number一样。

我在 WiX 的 MajorUpgrade element 中看不到任何明显的设置 MinInclusive 属性的方法 - 我可能弄错了,可能有一种方法我不知道.对于它的价值,我不太热衷于允许“相同版本升级”。

但是,您可以尝试“使用旧方法”使用“旧方法”编写升级table元素”UpgradeUpgradeVersionMajorUpgrade element 本质上是一个“方便”的功能,可以轻松设置您的主要升级,我相信它适用于大多数用户。 Bob Arnson 有一篇博客解释 MajorUpgrade 元素的介绍。此博客还展示了如何使用“旧元素”UpgradeUpgradeVersion“手动”执行操作的示例(一定要检查一下)。

我快速制作了一个模型,它可能会满足您的要求,这只是一个“粗略的草稿”——无法做出任何保证。我使用 preprocessor defines 设置一些可以在 WiX 源文件中引用的变量 - 作为 C++ 开发人员,这对你来说是小菜一碟,所以我不会浪费时间解释它 - 源代码应该是有意义的:

<?define MyProductVersion = "31.00.0000" ?>
<?define MyProductCode = "PUT-GUID-HERE" ?>
<?define MyUpgradeCode = "PUT-GUID-HERE" ?>

<!--Recommendation: set a path variable that you can redirect at will to a new release folder (new build output folder): -->

<!-- <?define MyBasePath = "C:\Projects\MyApp\Release.00.0000\" ?> -->

  <!-- SAMPLE: 
   <Component Win64="yes" Feature="MainApplication">
     <File Source="$(var.MyBasePath)\myapp.exe" />
   </Component> -->

<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">

  <Product Id="$(var.MyProductCode)" Codepage="1252" Language="1033" Manufacturer="Bla Corporation"
           Name="Bla" UpgradeCode="$(var.MyUpgradeCode)" Version="$(var.MyProductVersion)">

    <Package Comments="Contact: Refael Sheinker, refael.sheinker@bla.com." Description="Bla"
             InstallerVersion="500"
             Compressed="yes"
             InstallScope="perMachine"
             Keywords="Installer,MSI,Database" Languages="1033" Manufacturer="Bla Corporation" Platform="x64" />

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

   <!-- Major upgrade -->
    <Upgrade Id="$(var.MyUpgradeCode)">
      <!-- Downgrade Protection -->
      <UpgradeVersion Minimum="$(var.MyProductVersion)" OnlyDetect="yes" IncludeMinimum="yes" Property="DOWNGRADE_DETECTED"  />
      <!-- Major Upgrade Configuration -->
      <UpgradeVersion IncludeMinimum="no" Maximum="$(var.MyProductVersion)" IncludeMaximum="no" MigrateFeatures="yes" Property="UPGRADE_DETECTED"   />
    </Upgrade>

    <!-- Major Upgrade: Schedule RemoveExistingProducts -->
    <InstallExecuteSequence>
      <!-- Potential scheduling (after): InstallValidate, InstallInitialize, InstallExecute, InstallExecuteAgain, InstallFinalize -->
      <RemoveExistingProducts After="InstallInitialize" /> 
    </InstallExecuteSequence>

    <!--Launch Condition: Abort setup if higher version found-->
    <Condition Message="!(loc.NewerVersionDetected)">
      NOT DOWNGRADE_DETECTED
    </Condition>

    <Property Id="WIXUI_INSTALLDIR" Value="APPLICATIONROOTDIRECTORY" />
    <UIRef Id="WixUI_InstallDir" />

    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFiles64Folder">
        <Directory Id="PROGRAMFILESSUBDIR" Name="Bla">
          <Directory Id="APPLICATIONROOTDIRECTORY" Name="BlaInternal" />
        </Directory>
      </Directory>
    </Directory>

    <DirectoryRef Id="APPLICATIONROOTDIRECTORY">

      <Component Id="Test.ini" Guid="PUT-GUID-HERE" Win64="yes" Feature="MainApplication">
        <CreateFolder Directory="APPLICATIONROOTDIRECTORY" />
        <IniFile Id="SomeSetting" Action="addLine" Directory="APPLICATIONROOTDIRECTORY" Key="Setting1" Name="Test.ini" Section="MySection" Value="Some Setting" />
        <IniFile Id="OtherSetting" Action="addLine" Directory="APPLICATIONROOTDIRECTORY" Key="Setting2" Name="Test.ini" Section="MySection" Value="Other Setting" />
      </Component>
   </DirectoryRef>

    <Feature Id="MainApplication" Title="TenLira" Level="1">
      <!--<ComponentRef Id="tenlira.ini" />-->
    </Feature>

  </Product>

</Wix>

现在必须解释!(loc.NewerVersionDetected)。这是一个本地化的字符串(用于以不同语言提供您的设置)。要使用它,请右键单击 Visual Studio 中的 WiX 项目,然后转到:Add New Item... => Localization File => Add。添加本地化文件后,您的输出 MSI 现在也将进入主输出位置(调试或发布)下的 en-us 文件夹。

在本地化文件中,添加:

<?xml version="1.0" encoding="utf-8"?>
<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization">
    <String Id="NewerVersionDetected">A later version of [ProductName] is already installed.</String>
</WixLocalization>

现在您应该能够向该文件添加新字符串并使用此类语言文件轻松翻译您的整个设置。

同时添加 WiX GUI 扩展。 Right click "References". Add Reference... => Browse to WixUIExtension.dll => Double click this file, and press OK。找到文件的普通文件夹是:C:\Program Files (x86)\WiX Toolset v3.11\bin.


INI 文件

我只想提一下,INI 文件最好通过 IniFile table (entries are treated as atomic key-value pairs allowing advanced merging of keys and values for existing INI files), and not via the File table (the file is treated as a regular file either overwriting the whole existing file or leaving it in place - not enforcing any new values). The WiX element corresponding to the MSI IniFile table is naturally the IniFile element 安装。

临时示例:

<Component Id="Test.ini" Guid="PUT-GUID-HERE" Win64="yes" Feature="MainApplication">
    <CreateFolder Directory="APPLICATIONROOTDIRECTORY" />
    <IniFile Id="SomeSetting" Action="addLine" Directory="APPLICATIONROOTDIRECTORY" Key="Setting1" Name="Test.ini" Section="MySection" Value="Some Setting" />
    <IniFile Id="OtherSetting" Action="addLine" Directory="APPLICATIONROOTDIRECTORY" Key="Setting2" Name="Test.ini" Section="MySection" Value="Other Setting" />
</Component>

链接:

我有同样的问题,版本相同,但 ID 不同,在 Add/Remove 程序中创建多个条目。 我的简单修复是设置 AllowSameVersionUpgrades="yes".

<MajorUpgrade AllowSameVersionUpgrades="yes" DowngradeErrorMessage="A newer version of $(var.ServiceName) is already installed." />