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

如何使WIX在执行主要升级时不删除特定文件,wix,windows-installer,wix3,preserve,major-upgrade,Wix,Windows Installer,Wix3,Preserve,Major Upgrade,我有两个组件,其中一个组件在一个MSI中具有simple.exe,另一个组件在一个MSI中具有sample.dll。如果我安装MSI,simple.exe和sample.dll都将安装,并安装在某个文件夹下的程序文件中,它有两个文件夹,一个是.exe和.dll。如果我对整个MSI进行重大升级,它将用新文件夹替换程序文件中创建的文件夹。那么,如果我为.dll文件更改/提供更新,如何使wix不替换.exe,反之亦然。在提供对.dll的更新时,我将使用一些.bat文件注册和注销密钥。请帮助我解决我需要

我有两个组件,其中一个组件在一个MSI中具有
simple.exe
,另一个组件在一个MSI中具有
sample.dll
。如果我安装MSI,
simple.exe
sample.dll
都将安装,并安装在某个文件夹下的程序文件中,它有两个文件夹,一个是
.exe
.dll
。如果我对整个MSI进行重大升级,它将用新文件夹替换程序文件中创建的文件夹。那么,如果我为
.dll
文件更改/提供更新,如何使wix不替换
.exe
,反之亦然。在提供对
.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>

未检测到新的错误
有几件事:

  • 为什么您有一个主要的升级元素以及升级元素?MajorUpgrade元素应该是您所需要的所有元素,因此它很容易混淆

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

  • 似乎您需要在安装后执行主要升级计划。这将使用文件版本覆盖规则在旧文件上安装新产品文件。如果二进制文件的文件版本没有更改,则不会替换它们。这种类型的升级程序还要求您遵守组件规则:


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

    我赞同菲尔的观点,也许我可以补充几点:

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


    选择性文件更新:如果您想做的是在磁盘上保留旧版本的文件,同时以选择性方式安装包含更高版本文件的新软件包,那么除了尝试将文件设置为只读,我不知道有什么方法可以做到这一点(这是我从未尝试过的-老实说,不确定会发生什么)。您还可以设置一个空白的组件GUID(这样的GUID也称为-这将安装一个或多个文件,并且不再触摸或覆盖它们。如果组件密钥路径存在,还可以将组件标志设置为“从不覆盖”(我通常将此与设置组件永久性结合使用)。还可以通过对生成的MSI进行后处理来为文件伪造版本号。某些第三方工具(如Installshield和Advanced Installer)在编译前提供GUI来执行此操作

    MSI通常只会在安装程序中使用较高版本的二进制文件覆盖目标位置中的较低版本的文件(这取决于默认值,可以通过为文件覆盖规则的-a“修饰符”设置自定义值来影响和修改)。如果目标目标中的文件版本与正在安装的文件版本相同或更高,则不会覆盖目标(除非
    重新安装模式
    设置为
    amus
    -强制覆盖-这是一个可怕的概念,具有许多副作用)

    在不明显的情况下:如果您的某些文件没有针对给定版本进行更新,那么您只需要包含旧安装中包含的那些文件的早期版本,它们将与您有新版本的文件一起显示在磁盘上。您无需做任何事就可以实现这一点,这将是自动魔法


    延迟顺序的主要升级:Phil的第3点是关于主要升级的延迟顺序。这种主要升级不是卸载所有文件,然后重新安装,而是作为一个补丁安装,比较新旧软件包之间的差异,只删除最近一次删除的文件包。所有其他文件将保留在磁盘上,或根据文件覆盖规则进行相应更新


    保留设置文件:如果您有要在不同版本之间保留的设置文件,典型的问题是主要升级不会覆盖已更改的、未版本化的文件(文件覆盖规则不会覆盖已更改的设置文件),但它会很高兴地卸载并重新安装它们,除非它们在原始设置中被标记为永久,然后在原始状态下重新安装它们,使它们看起来被覆盖(当它们实际卸载并重新安装时,或者如果您愿意的话被还原)。在我看来,这是一种技术反模式

    以上提到的延迟顺序主要升级功能/方法可防止此设置文件恢复问题,因为文件不是立即卸载和重新安装的,而是在安装版本之间进行比较,如果它们是有更改的设置文件,则保持不变-前提是您已根据对于MSI组件规则来说,这不是一件轻松的事情
    <?define SourceFiles= "C:\Projects\MySetup\Releases\1.0.0\"?>
    
    <...>
    
    <Icon Id="Icon.exe" SourceFile="$(var.SourceFiles)\MyApp.exe" />