如何实施WiX安装程序升级?


233

在工作中,我们使用 WiX来构建安装包。我们希望产品X的安装将导致在该计算机上卸载该产品的先前版本。

我已经在Internet上的多个地方阅读过有关重大升级的信息,但无法使其正常工作。任何人都可以指定将卸载早期版本功能添加到WiX所需的确切步骤吗?

Answers:


189

在最新版本(从3.5.1315.0 beta版开始)中,可以使用MajorUpgrade元素,而不必使用自己的元素

例如,我们使用此代码进行自动升级。它可以防止降级,提供本地化的错误消息,还可以防止升级已经存在的相同版本(即仅升级较低的版本):

<MajorUpgrade
    AllowDowngrades="no" DowngradeErrorMessage="!(loc.NewerVersionInstalled)"
    AllowSameVersionUpgrades="no"
    />

8
鲍勃·阿恩森(Bob Arnson)的博客文章提供了许多不错的信息。
戴夫·安徒生2012年

17
注意:在任何地方都没有记录,但<MajorUpgrade>必须在后面 放置“ ”元素<Package>。否则,candle给出以下错误:“错误CNDL0107:模式验证失败,第1行,第473列出现以下错误:名称空间' schemas.microsoft.com/wix/2006/wi '中的元素'Product '具有无效的子元素' “命名空间'schemas.microsoft.com/wix/2006/wi'中的MajorUpgrade '。预期的可能元素列表:'Package'。”。
罗伯W

21
+1此答案需要获得尽可能多的支持;答案是5倍,但使用较旧的方法,这很诱人。
Lynn在2014年

1
好点子。我添加了一个示例,以使人们不会因为没有示例而忽略它!
2014年

6
只是想指出您不需要指定AllowDowngradesAllowSameVersionUpgrades。它们默认为否。
发光的

221

最终,我找到了一个解决方案-我在这里将其发布给可能有相同问题的其他人(你们中的全部5个人):

  • 将产品ID更改为*
  • 在产品下添加以下内容:

    <Property Id="PREVIOUSVERSIONSINSTALLED" Secure="yes" />
    <Upgrade Id="YOUR_GUID">  
       <UpgradeVersion
          Minimum="1.0.0.0" Maximum="99.0.0.0"
          Property="PREVIOUSVERSIONSINSTALLED"
          IncludeMinimum="yes" IncludeMaximum="no" />
    </Upgrade> 
  • 在InstallExecuteSequence下添加:

    <RemoveExistingProducts Before="InstallInitialize" /> 

从现在开始,每当我安装产品时,它都会删除以前的安装版本。

注意:用您自己的GUID替换升级ID


153
是的,学习WiX就像试图弄清楚某人认为“有意义”以执行简单操作的晦涩咒语。有点像UNIX。
mmr

6
另外,“将产品ID更改为*”到底能做什么?每次都会产生一个新产品ID吗?不再具有固定ID会对您的产品造成影响吗?-听起来太过分了。
安东尼

10
@ Antony,@ Dror Helper:我很确定您不应该在这里使用“ *”来生成新的GUID。(Upgrade Id =“”)中的GUID应该经过硬编码和固定,并且应该与(Product UpgradeCode =“”)属性中的GUID相匹配。
乔纳森·哈特利

37
我认为您可能应该在此处编辑示例,使其没有实际的GUID。我敢肯定,人们会复制并粘贴并逐字使用它。也许使用“您的产品的升级代码-GUID-HERE”?
布朗2010年

12
您的示例中有错误。MSI ProductVersion仅支持三个版本字段;因此,将完全不比较第四个字段。见VersionMin和VersionMax下的音符msdn.microsoft.com/en-us/library/aa372379(VS.85).aspx
斯里达尔Ratnakumar

89

以下是我用于主要升级的语法:

<Product Id="*" UpgradeCode="PUT-GUID-HERE" Version="$(var.ProductVersion)">
 <Upgrade Id="PUT-GUID-HERE">
    <UpgradeVersion OnlyDetect="yes" Minimum="$(var.ProductVersion)" Property="NEWERVERSIONDETECTED" IncludeMinimum="no" />
    <UpgradeVersion OnlyDetect="no" Maximum="$(var.ProductVersion)" Property="OLDERVERSIONBEINGUPGRADED" IncludeMaximum="no" />
</Upgrade>

<InstallExecuteSequence>
    <RemoveExistingProducts After="InstallInitialize" />
</InstallExecuteSequence>

正如@Brian Gillespie指出的那样,还有其他地方可以根据所需的优化来安排RemoveExistingProducts。注意,PUT-GUID-HERE必须相同。


2
我正在阅读Nick Ramirez在Wix上的书中的“升级和修补”部分,他说,如果您在InstallInitialize之后计划RemoveExistingProducts,那么您还必须计划<InstallExecute After="RemoveExistingProducts" />。您的示例没有此内容-这是否表示这本书是错误的?
Wim Coenen 2010年

3
我从未明确安排InstallExecute。
Rob Mensching 2010年

1
我不。在WiX v3.6中,刻录将使次要升级易于执行,但如果没有刻录,则需要用户手动进行交互(必须提供命令行选项),这使得次要升级基本无用。:)
Rob Mensching 2011年

1
@RobMensching:如何避免安装较新版本的旧版本?您的答案对我有用(唯一可以使用WiX v3.5.2519.0进行编译的“主要升级”示例),但是可以安装较旧的版本(此后,在“添加/删除程序”)。
Christian Specht

4
好的,我刚刚在此答案中找到了MajorUpgrade元素元素正是我想要的,包括防止降级。
Christian Specht

40

Product元素内的Upgrade元素与正确的操作计划相结合,将执行您要执行的卸载操作。确保列出要删除的所有产品的升级代码。

<Property Id="PREVIOUSVERSIONSINSTALLED" Secure="yes" />
<Upgrade Id="00000000-0000-0000-0000-000000000000">
  <UpgradeVersion Minimum="1.0.0.0" Maximum="1.0.5.0" Property="PREVIOUSVERSIONSINSTALLED" IncludeMinimum="yes" IncludeMaximum="no" />
</Upgrade>

请注意,如果您对构建感到谨慎,则可以防止人们意外地安装较新版本的产品。这就是“最大值”字段的作用。在构建安装程序时,我们将UpgradeVersion Maximum设置为正在构建的版本,但是将IncludeMaximum =“ no”设置为防止这种情况。

您可以选择安排RemoveExistingProducts的时间。我更喜欢在InstallFinalize之后进行调度(而不是像其他人建议的那样在InstallInitialize之后进行调度):

<InstallExecuteSequence>
  <RemoveExistingProducts After="InstallFinalize"></RemoveExistingProducts>
</InstallExecuteSequence>

这将保留产品的先前版本,直到复制新文件和注册表项之后。这使我可以将数据从旧版本迁移到新版本(例如,您已将用户首选项的存储从注册表切换到XML文件,但是您要保持礼貌并迁移其设置)。此迁移是在InstallFinalize之前以延迟的自定义操作完成的。

另一个好处是效率:如果文件没有更改,则在InstallFinalize之后进行计划时,Windows Installer不会再麻烦地复制它们。如果计划在InstallInitialize之后进行,则首先会完全删除先前版本,然后再安装新版本。这导致不必要的删除和重新复制文件。

有关其他计划选项,请参阅MSDN中的RemoveExistingProducts帮助主题。本周,链接为:http : //msdn.microsoft.com/en-us/library/aa371197.aspx


2
@Brian Gillespie:“ ...如果文件未更改...”是什么意思?Windows Installer决定何时替换文件,AssemblyVersion,AssemblyFileVersion,文件大小...的标准是什么?
donttellya 2014年

2
@donttellya +1很难学到这一点。RemoveExistingProducts计划在此之后执行,InstallFinalize并且由于assemblyVersion不变而未更新dll,但其他字段(例如AssemblyProduct)却被更新。我不希望在文件比较常规的怜悯-我只是想以前的应用程序GONE
沃尔

16

您最好在WiX用户邮件列表中询问此问题。

最好是在对Windows Installer的工作有深刻了解的情况下使用WiX。您可能会考虑获取“ Windows安装程序权威指南 ”。

删除现有产品的操作RemoveExistingProducts操作。因为执行操作的后果取决于计划的时间-即故障是否导致旧产品的重新安装以及是否再次复制未更改的文件-您必须自己计划它。

RemoveExistingProducts处理<Upgrade>当前安装中的元素,使@Id属性与系统上所有已安装产品的UpgradeCode(在<Product>元素中指定)相匹配。该UpgradeCode定义了一系列相关产品。具有此UpgradeCode,版本在指定范围内且UpgradeVersion/@OnlyDetect属性为no(或省略)的所有产品将被删除。

有关RemoveExistingProducts提及设置UPGRADINGPRODUCTCODE属性的文档。这意味着要删除的产品的卸载过程收到该属性,该属性的值就是Product/@Id要安装的产品的。

如果您的原始安装不包含UpgradeCode,则将无法使用此功能。


21
毫无疑问,Mike确切地知道他在说什么,所有应得的尊重,但这让我感到沮丧,因为对Windows Installer的工作有了深刻的了解,使我的想法变得混乱。在不知不觉中,我将为这条令人讨厌的技术中心城镇,环城公路之外的Enterprise客户提供Java和.NET咨询工作,填写我的TPS报告,并想知道生活为何如此空虚。我认为我的下一个项目可能会安装NSIS,因为它存在所有的缺陷,就像荒谬的汇编语言一样,它并没有使我理解Windows Installer的功能。
乔纳森·哈特利2009年

2
@Tartley-与InnoSetup一起使用,它将为您节省类似于汇编的语言:)确保您也掌握IStool,这会很有帮助。另外-同意对于简单安装来说,所有这些都太复杂了,但是我认为他们真的需要这种复杂性来安装SQL Server 2008之类的东西……
Roman Starkov 09年

11

我使用此站点来帮助我了解有关WiX升级的基础知识:

http://wix.tramontana.co.hu/tutorial/upgrades-and-modularization

之后,我创建了一个示例安装程序(安装了一个测试文件),然后创建了Upgrade安装程序(安装了两个示例测试文件)。这将使您对机制的工作原理有基本的了解。

正如Mike在Apress的书“ Windows安装程序权威指南”中所说的那样,它可以帮助您理解,但是它不是使用WiX编写的。

另一个非常有用的站点是:

http://www.wixwiki.com/index.php?title=Main_Page


该页面上的示例与预期的wix.tramontana.co.hu/tutorial/upgrades-and-modularization/…不一致。我玩过 当页面指出将被禁止时,甚至有可能降级
sergtk 2012年

10

我阅读了WiX文档,下载了示例,但是升级仍然有很多问题。小型升级不会执行先前产品的卸载,尽管可以指定那些卸载。我花了一天多的时间进行调查,发现WiX 3.5引入了新的升级标签。这是用法:

<MajorUpgrade Schedule="afterInstallInitialize"
        DowngradeErrorMessage="A later version of [ProductName] is already installed. Setup will now exit." 
        AllowDowngrades="no" />

但是出现问题的主要原因是文档说,对于小规模和小规模升级,都使用“ REINSTALL = ALL REINSTALLMODE = vomus ”参数,但是并没有说这些参数对于大型升级是禁止的-它们只是停止工作。因此,您不应该将它们用于主要升级。



7

我错过了一段时间的教程中的一件重要事情(从http://www.tramontana.co.hu/wix/lesson4.php中偷走了),导致出现“该产品的另一个版本已安装”错误:

* 小更新 意味着对一个或几个文件进行小的更改,其中的更改不保证更改产品版本(major.minor.build)。您也不必更改产品GUID。请注意,创建新的.msi文件在任何方面都与以前的文件不同时,始终必须更改Package GUID。当用户想要使用这些GUID更改或删除安装时,安装程​​序会跟踪已安装的程序并找到它们。对不同的软件包使用相同的GUID会使安装程序感到困惑。

较小的升级 表示产品版本已经更改的更改。修改产品标签的版本属性。产品将保持不变,因此您无需更改产品GUID,但是当然会获得新的Package GUID。

重大升级 表示重大更改,例如从一个完整版本转到另一个完整版本。更改所有内容:Version属性,Product和Package GUID。


3
软件包:Id类型:AutogenGuid说明:产品或合并模块的软件包代码GUID。编译产品时,不应设置此属性,以允许为每个版本生成软件包代码。编译合并模块时,必须将此属性设置为模块化guid。----所以我们不需要注意包裹ID,对吗?
Cooper.Wu 2011年

您的链接已死
bam500

5

我正在使用最新版本的WiX(3.0),但无法正常工作。但这确实有效:

<Product Id="*" UpgradeCode="PUT-GUID-HERE" ... >

<Upgrade Id="PUT-GUID-HERE">
  <UpgradeVersion OnlyDetect="no" Property="PREVIOUSFOUND"
     Minimum="1.0.0.0"  IncludeMinimum="yes"
     Maximum="99.0.0.0" IncludeMaximum="no" />
</Upgrade>

请注意,PUT-GUID-HERE应该与您在产品的UpgradeCode属性中定义的GUID相同。


2

下面为我​​工作。

<Product Id="*" Name="XXXInstaller" Language="1033" Version="1.0.0.0" 
    Manufacturer="XXXX" UpgradeCode="YOUR_GUID_HERE">
<Package InstallerVersion="xxx" Compressed="yes"/>
<Upgrade Id="YOUR_GUID_HERE">
    <UpgradeVersion Property="REMOVINGTHEOLDVERSION" Minimum="1.0.0.0" 
        RemoveFeatures="ALL" />
</Upgrade>
<InstallExecuteSequence>
    <RemoveExistingProducts After="InstallInitialize" />
</InstallExecuteSequence>

请确保产品中的UpgradeCode与升级中的ID匹配。


1

即使是主要的DOWN成绩,这对我也起作用:

<Wix ...>
  <Product ...>
    <Property Id="REINSTALLMODE" Value="amus" />
    <MajorUpgrade AllowDowngrades="yes" />
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.