如何使WIX在执行重大升级时不删除特定文件

时间:2018-07-19 04:04:06

标签: wix windows-installer wix3 preserve major-upgrade

我有两个组件,其中一个组件在一个MSI中具有simple.exe,另一个组件具有sample.dll。如果我安装了MSI,simple.exesample.dll都将安装,并且在某个文件夹下的程序文件中,它有两个,分别为.exe.dll。如果我要对整个MSI进行重大升级,它将用新文件替换在程序文件中创建的文件夹。因此,如果我更改/提供.exe文件的更新,如何使wix不替换.dll,反之亦然。在提供对.dll的更新的同时,我将使用一些.bat文件注册和注销密钥。请帮我解决,我需要有条件的重大升级,当我更改特定文件时,它们将替换特定文件。

请找到以下代码:

product.wxs

<?xml version="1.0" encoding="UTF-8"?>
<?define ProductVersion = "0.0.4"?>
<?define ProductUpgradeCode = "d3170abf-b41c-4274-a3a0-85576052f35c"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <Product Id="*" Name="saranSample" Language="1033" Version="$(var.ProductVersion)" Manufacturer="example" UpgradeCode="$(var.ProductUpgradeCode)">
    <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />

    <MajorUpgrade DowngradeErrorMessage="A newer version of product is already installed." AllowSameVersionUpgrades="no" AllowDowngrades="no" />
    <MediaTemplate EmbedCab="yes" />

<Upgrade Id="$(var.ProductUpgradeCode)">
  <UpgradeVersion Minimum="$(var.ProductVersion)" OnlyDetect="yes" Property="NEWERVERSIONDETECTED"/>
  <UpgradeVersion Minimum="0.0.0" Maximum="$(var.ProductVersion)" IncludeMinimum="yes" IncludeMaximum="no" Property="OLDERVERSIONBEINGUPGRADED"/>
</Upgrade>
<InstallExecuteSequence>
  <Custom Action="Filecleaner" After="InstallFinalize"></Custom>
</InstallExecuteSequence>
<Condition Message="A newer version of this software is already installed.">NOT NEWERVERSIONDETECTED</Condition>

    <Directory Id="TARGETDIR" Name="SourceDir">
        <Directory Id="ProgramFilesFolder">
    <Directory Id="INSTALLFOLDER" Name="saranSample_$(var.ProductVersion)">
      <Component Id="exeFiles" Guid="12345678-1234-1234-1234-222222222222">
        <File Id="exe" Source="$(sys.CURRENTDIR)npp.7.5.7.Installer.exe" KeyPath="yes"/>
      </Component>
      <Component Id="dllFiles" Guid="12345678-1234-1234-1234-222222222223">
        <File Id="dll" Source="$(sys.CURRENTDIR)saran.dll" KeyPath="yes"/>
      </Component>
    </Directory>
        </Directory>
    </Directory>

<Feature Id="ProductFeature" Title="saranSample" Level="1">
  <ComponentRef Id="exeFiles"/>
  <ComponentRef Id="dllFiles"/>
</Feature>

2 个答案:

答案 0 :(得分:0)

几件事:

  1. 为什么同时具有MajorUpgrade元素和Upgrade元素? MajorUpgrade元素应该是您所需要的,因此很混乱。

  2. 与MajorUpgrade文档中一样,升级的默认顺序为afterInstallValidate。这是升级中的“早期”版本,可以在安装新版本之前有效地卸载所有较旧的产品。这就是为什么要删除文件(通过卸载)然后再次安装文件的原因。

  3. 似乎您的MajorUpgrade Schedule需要在InstallExecute之后。使用文件版本覆盖规则,这会将新产品文件安装在旧文件上。如果二进制文件的文件版本未更改,则将不会替换它们。这种类型的升级程序还要求您遵循组件规则:

http://robmensching.com/blog/posts/2003/10/18/component-rules-101/

https://docs.microsoft.com/en-us/windows/desktop/msi/what-happens-if-the-component-rules-are-broken

此外,您提到使用bat文件进行注册,并且这不是必需的。 WiX具有Heat工具,用于在构建ti,e处提取注册。

答案 1 :(得分:0)

我将所有Phil的观点都列为第二,也许我可以补充两点:

每个组件一个文件 :确保每个安装文件使用一个组件。我对所有文件类型都执行此操作,但是您必须对二进制文件(dll和exe)执行此操作。这是为了使安装程序正确运行并符合MSI组件规则(Phil提到)。我看到您有一个组件EXE文件和一个DLL文件。为添加到设置中的每个二进制文件创建新组件,然后将二进制文件设置为组件的关键路径。


选择性文件更新 :如果要执行的操作是将旧版本的文件保留在磁盘上,同时选择性地安装具有更高版本文件的新软件包时尚,那么除了尝试将文件设置为只读(我从未尝试过-不确定会发生什么老实)之外,我不知道有什么方法可以做到这一点)。您还可以设置空白组件GUID (这样的GUID也称为"Little Bobby Void-GUID", just check this very official source)-这将安装一个或多个文件,而不会再次触摸或覆盖它们。还有一个组件标记,可以将其设置为如果存在组件密钥路径,则永远不会覆盖(我通常将其与设置组件永久性结合使用)。也可以通过对您构建的MSI进行后处理来伪造版本号。一些第三方工具(例如Installshield和Advanced Installer)提供了一个GUI,可以在编译之前执行此操作。

MSI通常只会在安装程序中使用较高版本的二进制文件覆盖目标位置中较低版本的文件(这是根据默认的file versioning rules进行的,可以通过为{{3 }}-文件覆盖规则的“修饰符”。如果目标位置中的文件与所安装文件的版本相同或更高,则目标将不会被覆盖(除非将REINSTALLMODE设置为amus-强制覆盖-这是一个可怕的概念,并且有很多副作用)。

以防万一:如果您的某些文件未针对给定版本进行更新,则只需包含旧设置中包含的那些文件的先前版本,它们就会与磁盘一起显示在磁盘上您具有新版本的文件。您无需做任何事情就可以做到这一点,这将是自动魔术。


后期重大升级 :Phil的第3点是关于重大升级的后期排序。无需卸载所有文件,然后重新安装它们,这种重要的升级可以有效地作为补丁安装,比较旧软件包与新软件包之间的差异,并仅删除在最新软件包中删除的文件。所有其他文件都保留在磁盘上或根据文件覆盖规则进行适当更新。


保留设置文件 :如果您有要在发行版之间保留的设置文件,则典型的问题是主要升级不会覆盖已更改的,非版本的文件(文件覆盖规则不会覆盖已更改的设置文件),但是除非文件在原始设置中被标记为永久文件,否则它会很乐意卸载并重新安装它们-然后以原始状态重新安装它们,使它们看起来被覆盖(在实际卸载时,重新安装-或根据需要还原)。我认为这是一种技术反模式。

上述后来的主要升级功能/方法可防止此设置文件恢复问题,因为不会立即卸载并重新安装文件,而是在安装程序版本之间进行比较,并且如果它们是具有更改的设置文件则保持不变-为您提供已根据MSI组件规则正确实施了所有操作,这不是正确的选择。例如,您需要100%遵守组件规则,以避免其他副作用,例如更新完成后丢失文件。 REINSTALLMODE

或者,您可以将设置文件永久设置在MSI中。这样,除非您创建自己的构造文件,否则它们将永远不会被卸载,而且可能永远也不会更新和卸载。


路径变量 $(sys.CURRENTDIR)是否适合您?我喜欢定义自己的路径变量,可以轻松地将其重新拖动到想要的任何文件夹中:

<?define SourceFiles= "C:\Projects\MySetup\Releases\1.0.0\"?>

<...>

<Icon Id="Icon.exe" SourceFile="$(var.SourceFiles)\MyApp.exe" />

某些链接