我正在构建一个InstallShield项目,该项目对现有安装执行[主要升级] [1](即我在保留Product Code
的同时更改了Upgrade Code
)。
先前版本(已部署)的卸载程序已损坏,无法运行某些脚本。这本身并不是一个严重的问题,因为事先删除了所有相关文件。
问题是当新安装程序尝试卸载以前的版本时,它会在卸载程序失败时中止。我已经尝试设置'继续失败'标记(媒体 - >升级 - > MajorUpgrade - >高级 - >其他设置),但没有效果。
问题:
修改
不确定这是否相关,但以前的卸载程序出现了问题:
安装顺序包括一些自定义操作。其中两个调用可执行文件,后者又安装了一些设备驱动程序。显然,它们只应在安装正在进行时运行。不幸的是,之前的设计师没有设置“NOT REMOVE”条件,这导致在卸载操作期间运行操作。因此卸载程序失败(因为它找不到驱动程序可执行文件)。
答案 0 :(得分:2)
这更多的是评论而不是答案,但评论的时间太长了。
通常真正的修复是为"修补程序"创建次要升级(或次要升级修补程序)卸载顺序中的错误,然后以正常方式卸载产品(无论是主要升级卸载还是手动触发卸载,都可以正常工作)。这是可能的,因为次要升级不会卸载现有产品(失败的卸载自定义操作永远不会运行),而只是更新产品"就位" (或覆盖它)。这允许您在调用之前修复卸载序列中的任何错误。
我已多次成功使用此方法来修复可能包含大量已安装实例且卸载顺序失败的公司包中的严重错误。然而,这并不是一件微不足道的事情 - 需要时间和测试工作。我通常也会将更新作为补丁发布,但是稍微升级就足够了(补丁很复杂)。
次要升级包的最简单方法可能是设置一个条件,在所有失败的卸载自定义操作中始终为false,以便它们永远不会运行一旦卸载实际被触发。这显然会留下一些垃圾"在盒子上,但你可以忽略它或更好地清理它。但是要小心清理代码 - 它往往包含你必须在适当的时候处理的新bug。部署是一个过程,每个添加的发布周期,错误修复和调整都会为意外错误开辟新的可能性,从而为下一个版本增加新的复杂性和不可预测性。让事情尽可能简单。简单地说:只是更多的东西可以打破而不增加任何好处。如果你没有操作问题,一定要把事情搞干净。关于如何实施次要升级,我不会详细了解。 Installshield帮助文件在这个主题上相当不错,应该可以帮助您完成任务。我会做一个除了更改卸载操作的条件之外什么都不做的更新。
一旦进行了次要升级,您需要使用适当的命令行应用它,或者只需使用Installshield的setup.exe为您执行此操作。再次查看Installshield帮助文件(" Run-Time Behavior for Minor Upgrades" - 此帮助页面应该是您所需要的全部内容。)
在没有setup.exe包装器的情况下应用次要升级的命令行通常是:
msiexec.exe /i product.msi REINSTALLMODE=vomus REINSTALL=ALL
如果在没有setup.exe包装的情况下通过msiexec.exe手动安装,则为the v option
添加REINSTALLMODE
非常重要。这会将新的MSI缓存在系统上,对于小型升级正常工作至关重要 - 特别是为了修复卸载顺序。
Applying Minor Upgrades的MSDN文档。
答案 1 :(得分:1)
通过次要升级改变或删除现有包是一种很好的方法来解决那里的问题。但是在主要升级之前确保这种情况发生了窘境。您无法将其集成到单个基本MSI程序包中,主要是因为在Windows Installer本身中无法实现。虽然您可以向UI序列添加自定义操作,但这对于静默安装它的任何人都不起作用。由于Windows Installer中的限制,您无法在执行序列中执行任何操作。
如果你可以使用套件/高级UI项目,理论上你可以提供一个可以安装未成年人然后进行主要升级的exe;我不确定这种方法有什么障碍;通常,套件不会用于安装临时软件包,例如次要升级,也不会在安装过程中自动删除软件包。
以下两个选项可以帮助您的用户以最小的困惑到达他们需要的位置。
识别,指导和中止
主要升级的ActionProperty充满了计算机上存在的相关软件包的产品代码。通常,这是单个产品代码。如果您遵循ISPreventDowngrade条目和自定义操作的模式,则可以使用类型19"错误"自定义操作以显示消息并在旧版本存在时中止主要升级。该消息应指示用户在安装新版本之前卸载旧版本的产品;或者,或者,应用次要升级,然后继续。
使自定义操作的条件尽可能具体;如果您知道单个产品代码展示了该行为,请使您的条件检查其在action属性中的值。如果所有特定版本的版本都表现出这种行为(但是较旧的版本可以正常工作),请考虑添加辅助版本"仅检测"主要升级并根据二级升级的操作属性调整自定义操作。
注意:您可以尝试将此与尝试自动执行卸载或次要升级的UI序列操作结合使用。但绝对要保持执行顺序中的条件,以确保无提示卸载失败在日志文件中获得良好的信息。
尝试忽略错误
(哎呀;写完这篇文章之后,我重读了你说过的地方,你已经尝试过这种方法但它并不适合你。所以你可能会回到识别,指示和中止,或者可能使用套件/高级UI项目来提供东西。但是,我将此留给后人,因为我认为它包含了很好的建议,以避免使用此选项时的其他问题。)
我还没有使用它,所以我不知道它的行为的全部后果,我不会推荐它。但是Upgrade table的“属性”列中有一个选项,允许您在删除旧版本时忽略失败。 InstallShield在“高级”选项卡上将其公开为继续失败。
如果您100%确定您的旧版本最终处于令人满意的状态,并且您的新版本将在此之后运行,您可以尝试这样做。我强烈建议对这种方法进行一些彻底的质量保证,包括伪造一个较新的主要版本,以确保进一步的升级仍然是正确的。
与我在识别,指示和中止中提供的建议类似,尝试将继续失败设置为尽可能少的先前版本。例如,您可能希望将升级条目拆分为三个版本范围:问题出现之前(不要继续);那些受问题影响的人(继续);那些问题之后,即未来的重大升级(不要继续)。这样可以避免隐藏将来出现的任何类似问题,以便您可以明确选择如何处理它们。
答案 2 :(得分:0)
如果只有一个没有该条件的部署,那么您可以编写一个自定义操作,您可以在其中运行以下命令行:
msiexec.exe / x {PRODUCT_CODE_OF_OLD_MSI} REMOVE =" ALL" / QN
另一个可行的技巧是在InstallInitialize操作之前安排RemoveExistingProducts操作,如下所述:How to uninstall previous version as part of msi install?
您还可以编写自己的自定义MSI DLL,以便在继续之前终止正在运行的进程。