Wix 3.11 "This action is only valid for projects that are currently installed" 重建项目后

Wix 3.11 "This action is only valid for projects that are currently installed" after rebuilding the project

我有一个 WiX 3 安装项目,使用 VS 2017 社区和 Wix 工具集 v3.11,安装输出使用:

msiexec /i cient.setup.msi /lv output.log

一切都很好。使用

卸载

msiexec /x cient.setup.msi /lv output.log

也可以。 但是 如果我重建 WiS 安装项目,然后尝试使用上述命令卸载,我会从 MSI 输出中收到错误 1602。即“此操作仅对当前安装的项目有效

这是我的 Product.wxs 文件的内容:

<?xml version="1.0" encoding="UTF-8"?>
<!-- The name of the product -->
<?define Name = "Notification Client" ?>
<!-- The manufacturer, for setup package publisher and folder info -->
<?define Manufacturer = "MyCompanies IT" ?>
<!-- The version number of this setup package-->
<?define Version = "1.0.1" ?>
<!-- UpgradeCode must be unique and not changed once the first version of the program is installed. -->
<?define UpgradeCode = "{GUID-HERE}" ?>

<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
  <?define ClientService_TargetDir=$(var.ClientService.TargetDir)?>
  <Product Id="*" Name="$(var.Name)" Manufacturer="$(var.Manufacturer)" Language="1033" Version="$(var.Version)" UpgradeCode="$(var.UpgradeCode)">
    <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />

    <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />

    <Feature Id="ProductFeature" Title="Client.Setup" Level="1">
      <ComponentGroupRef Id="ProductComponents" />
      <ComponentRef Id="ApplicationShortcut" />
    </Feature>
  </Product>

  <Fragment>
    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFilesFolder">
        <Directory Id="ROOTDIRECTORY" Name="$(var.Manufacturer)">
          <Directory Id="INSTALLFOLDER" Name="$(var.Name)" />
          <Component Feature="ProductFeature" Id="SetFolderPermissions" Guid="*">
            <CreateFolder>
              <util:PermissionEx User="Users" GenericAll="yes" />
            </CreateFolder>
          </Component>
        </Directory>
      </Directory>
      <Directory Id="StartupFolder" SourceName="Startup"/>
    </Directory>
  </Fragment>

  <Fragment>
    <DirectoryRef Id="StartupFolder">
            <Component Id="ApplicationShortcut" Guid="*">
              <Shortcut Id="StartupShortcut"
                   Directory="StartupFolder"
                   Name="Notification Client"
                   Target="[INSTALLFOLDER]\NotificationClient.exe"
                   WorkingDirectory="INSTALLFOLDER"
           />
              <RemoveFolder Id="CleanUpShortCut" Directory="StartupFolder" On="uninstall"/>
              <RegistryValue Root="HKCU" Key="Software\Microsoft\NotificationClient" Name="installed" Type="integer" Value="1" KeyPath="yes"/>
            </Component>
    </DirectoryRef>
  </Fragment>

  <Fragment>
    <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
      <!-- TODO: Remove the comments around this Component element and the ComponentRef below in order to add resources to this installer. -->
      <!-- <Component Id="ProductComponent"> -->
      <!-- TODO: Insert files, registry keys, and other resources here. -->
      <!-- </Component> -->
      <Component Id="NotificationClient.exe" Guid="*">
        <File Id="NotificationClient.exe" Name="NotificationClient.exe" Source="$(var.ClientService_TargetDir)NotificationClient.exe" DiskId="1" KeyPath="yes" />
      </Component>
      <Component Id="NotificationClient.exe.config" Guid="*">
        <File Id="NotificationClient.exe.config" Name="NotificationClient.exe.config" Source="$(var.ClientService_TargetDir)NotificationClient.exe.config" KeyPath="no" />
      </Component>
      <Component Id="Newtonsoft.Json.dll" Guid="*">
        <File Id="Newtonsoft.Json.dll" Name="Newtonsoft.Json.dll" Source="$(var.ClientService_TargetDir)Newtonsoft.Json.dll" KeyPath="no" />
      </Component>
      <Component Id="Notifications.dll" Guid="*">
        <File Id="Notifications.dll" Name="Notifications.dll" Source="$(var.ClientService_TargetDir)Notifications.dll" KeyPath="no" />
      </Component>
      <Component Id="OHR_StdFunctions.dll" Guid="*">
        <File Id="OHR_StdFunctions.dll" Name="OHR_StdFunctions.dll" Source="$(var.ClientService_TargetDir)OHR_StdFunctions.dll" KeyPath="no" />
      </Component>
      <Component Id="OHR_MSGraph.dll" Guid="*">
        <File Id="OHR_MSGraph.dll" Name="OHR_MSGraph.dll" Source="$(var.ClientService_TargetDir)OHR_MSGraph.dll" KeyPath="no" />
      </Component>
      <Component Id="ServiceInstallation" Guid="*">
        <!-- Remove all files from the INSTALLFOLDER on uninstall -->
        <RemoveFile Id="ALLFILES" Name="*.*" On="both" />
      </Component>
    </ComponentGroup>
  </Fragment>
</Wix>

我感觉这与 GUID 问题有关,但我遵循了其他帖子中关于大写 GUID 和每次都重新生成产品 ID 的指南,以确保可以毫无问题地推出升级。

我是 Wix 的新手(这是我的第一个项目)所以请多多关照! :)

升级代码用于枚举要删除的潜在候选者,以代替挂起的安装。当您重建时,/Wix/Product[@Id] 会重新生成,因此这会显示为一个新产品,它可以 "upgrade" 使用您维护的现有升级代码进行任何操作。

您已将产品 GUID 设置为自动生成(这很好)。这意味着您编译的每个 MSI 都会自然地拥有一个新的产品 G​​UID。您可以通过指定的 MSI 文件或指定要卸载的产品 G​​UID 来调用 MSI 卸载。有关这方面的信息,请参阅这个小 "reference",您的部分将是 第 3 部分Uninstalling an MSI file from the command line without using msiexec(这个答案是有点长,请关注第 3 部分)。

您在命令中指定要卸载的 MSI 文件不是当前安装在盒子上的 MSI - 因此嵌入在 MSI 中的产品代码对于当前卸载是错误的(安装的是您以前的版本之一 - 具有不同的产品 G​​UID)。

您可以找到用于安装在盒子上的原始 MSI(如果您还有),然后您的命令 msiexec /x cient.setup.msi /lv output.log 将起作用,或者您可以找出产品代码是什么安装的产品确实是,然后你这样卸载:msiexec /x {PRODUCT-GUID} /lv output.log。一旦找到正确的产品 G​​UID,这将始终有效。此卸载从 %SystemRoot%\Installer(超级隐藏文件夹)中原始 MSI 的缓存副本运行。

这是一种查找已安装产品的产品 G​​UID 的方法:(这个答案也有点长,只需查找 PowerShell 命令 - 它会做的)。


UPGRADE:如果您不为每个设置创建新的产品 G​​UID,那么您将无法使用重大升级。然后你得到的是一个小的升级。这必须以不同于主要升级的方式安装。大多数人使用重大升级,因为它们更灵活。您需要实施重大升级以使最新安装程序在安装时静默卸载现有安装程序,否则您会在声明的添加/删除程序中获得两个条目。

设置重大升级:How To: Implement a Major Upgrade In Your Installer

我会添加 link 你自己建议的:How to implement WiX installer upgrade?.