【问题标题】:Wix - MSI Upgrade without removing older versionWix - MSI 升级而不删除旧版本
【发布时间】:2017-12-27 04:27:53
【问题描述】:

我想知道是否有任何方法可以使用更新版本的产品覆盖旧文件。有几百个文件,那么有没有更好的方法来做到这一点?由于升级完全清除了所有文件。我希望升级 MSI 覆盖文件。

我的升级逻辑如下:

<Upgrade Id="$(var.UpgradeCode)">
      <UpgradeVersion Minimum="$(var.ProductVersion)"
                      IncludeMinimum="no"
                      OnlyDetect="yes"                        
                      Property="NEWPRODUCTFOUND" />
      <UpgradeVersion Minimum="$(var.RTMProductVersion)"
                      IncludeMinimum="yes"
                      Maximum="$(var.ProductVersion)"
                      IncludeMaximum="no"                         
                      Property="UPGRADEFOUND" />
</Upgrade>

<CustomAction Id="PreventDowngrading" Error="Newer version already installed" />

<InstallUISequence>
  <Custom Action="PreventDowngrading" After="FindRelatedProducts">NEWPRODUCTFOUND</Custom>
</InstallUISequence>

<InstallExecuteSequence>
  <Custom Action="PreventDowngrading" After="FindRelatedProducts">NEWPRODUCTFOUND</Custom>
  <RemoveExistingProducts After="InstallFinalize" />      
  <InstallExecute After="RemoveExistingProducts"  />
</InstallExecuteSequence>

【问题讨论】:

  • 重大升级会做到这一点,但您没有提供足够的信息,也没有描述正在发生的事情。升级需要相同的 UpgradeCode、新的 ProductCode 和 PackageCode、前 3 个字段中递增的 ProductVersion,以及您希望更新的文件版本递增。
  • 升级完全卸载了所有文件,只安装了少数文件。我有相同的 UpgradeCode,对于我使用的产品代码 *,包代码 &lt;Package InstallerVersion="405" Compressed="yes" InstallPrivileges="elevated" InstallScope="perMachine"/&gt;。我还将产品版本从 1.0.0 增加到 1.0.1。
  • 只是为了说明这一点,您正在进行的升级不是“补丁”,它需要是一个完整的产品安装,它将为新用户安装全新的。它必须包含所有文件。如果你想要一个只更新一些文件的包,那么构建一个补丁包,一个 .msp 文件。
  • 所以我创建了基于两个版本的补丁文件。第二个有很多更新的文件。现在,当我运行 pyro 命令时,我得到一个关于没有不同转换文件的异常。这可能吗?补丁文件是根据文件的时间戳或文件的文件大小创建的,还是仅在新版本中添加新文件时创建?
  • 这是错误消息.. 错误 PYRO0227 : 正在构建的转换不包含任何差异,因此无法创建

标签: wix windows-installer upgrade


【解决方案1】:

我需要尽快写这篇文章,请耐心等待,但这里是:

组件 GUID 必须在包之间保持相同,文件才能正确更新,尤其是在您通过补丁部署时。组件 GUID 不匹配的关键症状是在部署完成后完全丢失文件(以及永远无法工作的补丁)。

按照 PhilDW 的说明设置适当的主要升级,并在版本之间保持组件 GUID 一致并遵循组件创建规则,您的升级应该可以正常工作(以及您的补丁)。

请注意,您可以将组件 GUID 保留在 WiX 源文件之外,并允许它们自动生成而不是硬编码,并且您仍将获得一致的 GUID。 GUID 的自动生成将 calculate a stable GUID(请阅读链接的问题、已接受的答案及其所有 cmets)在版本之间保持稳定,除非您重命名或移动有问题的文件 - 这需要新的组件 GUID 和 @987654322 @(这也解释了为什么可以自动生成稳定的 GUID)。自动 GUID 生成将检测何时需要新的 GUID。

我无法加快通过 heat.exe 收集的速度,但我认为它允许自动生成组件 GUID,而不是硬编码。只需更改您的脚本或自动化过程以将组件 GUID 设置为自动生成(这在组件标记中使用 * 而不是 GUID)。请阅读整个答案以及所有答案和 cmets:Syntax for guids in WIX?

重要提示! 补丁只是 MSI 升级的一种交付方式,它已经作为一个完整的软件包运行。在您确认完整的、更新的 MSI 软件包正确升级了以前的版本之前,不要浪费任何时间来生成补丁。如果这样做,您只会浪费时间 - 如果完整更新不起作用,补丁将永远无法工作。不能。

您的产品的第一个版本已经上线了吗?如果不是,我建议从头开始并使用自动生成的 GUID。如果您以前的版本是活动的并且您有硬编码的组件 GUID,您需要将第一个版本中的现有组件 GUID 与更新版本中的组件 GUID 匹配,或者您必须按照 zett42 的建议将 RemoveExistingProducts 放在 InstallExecuteSequence 的早期以允许在安装新版本之前完全卸载旧版本。这将防止之前的组件引用错误影响主要升级,并且升级后不应丢失任何文件。 由于组件引用不正确,这种方法根本不可能打补丁。这会导致次要和主要升级补丁都失败 - 两者都需要 100% 的组件引用才能正常工作。

这已经很长了。如果这一切对您来说听起来很希腊,请阅读链接的 stackoverflow 答案,并大致了解 MSI 组件创建最佳实践和组件引用。请参阅 MSDN。我会回来看看你的进展情况,一旦我知道什么不清楚以及你在哪里,也许会稍微清理一下这个答案。

【讨论】:

  • 我确实有该产品的第一个版本。我一直在使用 -gg 选项使用热量生成组件 GUID。但我没有使用选项 -ag(在编译时自动生成组件 guid,例如 set Guid="*".)。 InstallExecuteSequence 删除现有产品的想法是我想要避免的。如果产品的安装与 ProgramFilesFolder 不同,则 -aa in heat 的选项将引发异常,如此处 stackoverflow.com/questions/24665555/… 所述。
  • 您有实时发布的 wxs 文件吗?您可以使用添加/删除的文件手动更新此文件,从而在版本之间保留组件 GUID。这无疑需要一些时间,但我看不到任何其他选项,除非您走“首先完全卸载现有产品”路径(将 RemoveExistingProduct 放在 InstallExecuteSequence 的早期)。好消息是,如果您以这种手动方式遵循组件规则,您也许可以使您的补丁正常工作,但不建议使用主要的升级补丁。
  • 我能问一下您在 ProgramFilesFolder 层次结构之外安装文件的位置吗?有有效的案例可以这样做,但通常这是一种“部署气味”。在 Windows 上部署存在越来越多的障碍 - 使用 vanilla 通常会为您节省大量工作。在许多情况下,对应用程序设计的微小更改可能会导致部署的巨大改进(避免不需要的部署设计)。
  • 我动态生成了 was 文件,因为它的文件不是很少,而是数百个。 .wxs 文件是使用 heat.exe 生成的。是的,当我没有任何其他选项时,我将尝试卸载现有产品作为最后一个选项。我正在为 IIS 上托管的 Web 应用程序创建安装程序。不将产品安装到 ProgramFilesFolder 的原因是权限。此外,某些用户可能无权将产品安装到 ProgramFilesFolder。
  • 是的,IIS 部署将是在 ProgramFilesFolder 之外进行部署的一个很好的理由。我猜你除了“尽早彻底卸载”之外别无选择?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-01-12
  • 1970-01-01
  • 2018-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-03
相关资源
最近更新 更多