如何避免使用 Windows Installer/MSI 安装产品的两个版本? [英] How to avoid having two versions of a product installed with Windows Installer / MSI?

查看:19
本文介绍了如何避免使用 Windows Installer/MSI 安装产品的两个版本?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经编写并维护了许多 Wix 安装源文件,我使用这些文件构建 MSI 文件以分发我的应用程序.

I have written and am maintaining a number of Wix installation source files which I use to build MSI files for distribution of my application.

我没有为任何类型的升级、更新、重新安装或任何类型的任何东西明确编程 - 有一个功能由许多具有稳定 GUID 的组件组成,我观察到至少干净安装可以我的期望.

I have not explicitly programmed for any kind of upgrading, updating, reinstallation or anything of the kind -- there is a single feature that consists of a number of components with stable GUIDs and I have observed that at least a clean installation does what I expect it to.

但是,我(以及拥有我分发的 MSI 文件的任何人)可能会使用它们各自的(不同的)MSI 文件并排安装我的应用程序的不同版本.这本身不是问题,除了我显然使用与安装目标相同的文件夹 - %ProgramFiles(x86)%Foobar" - 来安装应用程序(无论版本).这意味着实际上有总是会安装一个版本.

However, I (and anyone in possession of the MSI files I distribute) may seemingly install distinct versions of my application side-by-side using their respective (distinct) MSI files. Which isn't a problem in itself, except that I obviously use the same folder as installation target -- "%ProgramFiles(x86)%Foobar" -- to install the application (version regardless) in. Meaning that in effect there is always ever one version that ends up being installed.

我认为到目前为止,Windows Installer 的行为是正确的,它会从它最后安装的任何 MSI 软件包中更新文件.这样做的一个有趣的副作用是,如果最后一个 MSI 是早期版本,则应用程序文件夹中的文件将被该早期版本的副本覆盖.

I would argue that Windows Installer behaves correctly in so far that it updates files from whichever MSI package it installed last. One interesting side-effect of this is that if the last MSI was of earlier version, the files in the application folders would be overwritten with the copies from that earlier version.

但对我来说,这些似乎都不是真正的问题.我想解决实际安装的内容(单个应用程序版本)与 Windows 跟踪安装的内容之间的差异——在我的例子中,两个不同应用程序版本的两条记录.

But none of that seems to be the actual problem to me. I want to fix the disparity between what is actually installed (a single application version) and what Windows tracks as installed -- in my case two records of two distinct application versions.

由于我将应用程序安装在不依赖于所安装版本的文件夹中,因此通过 Windows 跟踪多个应用程序版本是错误的.

Since I install the application in a folder that doesn't depend on the version being installed, tracking multiple application versions by Windows is a mistake.

所以我想我的问题是,我该如何解决这个问题,以便只显示一个版本(反映现实)或者在这种情况下的惯用方法是什么?我故意没有过度指定我的 Wix 源代码,希望作为回报,Windows Installer 会使用一些内置的智能来自行解决所有问题.但我想我可能需要添加一些明确的升级或卸载先前版本的说明.

So I guess my question is, how do I fix this so that only one version is shown (reflecting reality) or what's the idiomatic approach in these kind of cases? I deliberately did not overspecify my Wix source code, hoping in return that Windows Installer would use some built-in intelligence to figure everything out on its own. But I may need to add some explicit upgrade or uninstall-previous-version-first instructions, I suppose.

我缩小的 Wix 源代码(文件foobar.wxs")如下所示:

My minified Wix source code (file "foobar.wxs") would look like this:

<?xml version="1.0" encoding="utf-8" ?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
    <Product Name="Foobar" Manufacturer="ACME Inc." Id="*" UpgradeCode="ae9a7d6d-6c2d-446a-97d9-9dbe829d2ea8" Language="1033" Codepage="1252" Version="!(wix.PRODUCT_VERSION)">
        <Package Id="*" Languages="1033" SummaryCodepage="1252" Compressed="yes" InstallerVersion="200" />
        <Icon Id="foobar" SourceFile="!(wix.APPPATH)/foobar.ico" />
        <Property Id="ARPPRODUCTICON" Value="foobar" />
        <Property Id="ARPCOMMENTS" Value="Gives you full foobar powers" />
        <MediaTemplate EmbedCab="yes" CompressionLevel="high" />
        <Directory Id="TARGETDIR" Name="SourceDir">
            <Directory Id="DesktopFolder" />
            <Directory Id="ProgramFilesFolder">
                <Directory Id="INSTALLDIR" Name="Foobar" FileSource="!(wix.APPPATH)">
                    <Component>
                        <File Id="foobar.exe" Name="foobar.exe" />
                    </Component>
                    <!-- There are other components like above (assets) -->
                </Directory>
            </Directory>
            <Directory Id="ProgramMenuFolder">
                <Directory Id="foobar_menu" Name="Foobar">
                    <Component Id="foobar_shortcut" Guid="e80a6b95-a145-453a-b327-65a977e741fe">
                        <Shortcut Icon="foobar" Id="foobar_shortcut" Name="Foobar" Target="[foobar]foobar.exe" />
                        <Shortcut Directory="DesktopFolder" Icon="foobar" Id="foobar_desktop_shortcut" Name="Foobar" Target="[foobar]foobar.exe" />
                        <RegistryValue KeyPath="yes" Root="HKMU" Key="Software[Manufacturer][ProductName]" Type="string" Value="" /> 
                        <RemoveFolder Id="remove_foobar_menu" On="uninstall" />
                    </Component>
                </Directory>
            </Directory>
            <Directory Id="CommonAppDataFolder">
                <Directory Id="app_data_foobar" Name="foobar">
                    <Component Guid="" Id="app_data_config_folder">
                        <CreateFolder />
                    </Component>
                    <Component Guid="" Id="app_data_config_folder_log_file">
                        <File Name="foobar.log" Source="foobar.log.template">
                            <!-- Add write access permission to the log file to members of "Users" group. -->
                            <!-- PermissionEx Sddl="D:AR(A;;GWGR;;;BU)" / -->
                            <!-- Bug with Windows Installer, can't use PermissionEx/MsiLockPermissionsEx table. See https://stackoverflow.com/questions/55145282/how-to-include-inherited-permissions-when-specifying-permissions-for-a-file-inst -->
                            <util:PermissionEx Append="yes" GenericWrite="yes" User="Users" />
                        </File>
                    </Component>
                </Directory>
            </Directory>
        </Directory>
        <Feature Id="foobar">
            <ComponentGroupRef Id="foobar" />
            <ComponentRef Id="foobar_shortcut" />
            <ComponentRef Id="app_data_config_folder" />
            <ComponentRef Id="app_data_config_folder_log_file" />
        </Feature>
    </Product>
</Wix>

我正在使用以下 Windows 命令提示行编译目标文件:

I am compiling the object file with the following Windows Command Prompt line:

candle.exe -ext WixUtilExtension -out %TEMP% foobar.wxs

然后生成 MSI 文件:

And then generating the MSI file with:

light.exe -ext WixUtilExtension -spdb "-dAPPPATH=%apppath%" "-dPRODUCT_VERSION=%version%" -out %TEMP%foobar-%version%.msi %TEMP%foobar.wixobj

(使用 Wix 3.11.1.2318)

(using Wix 3.11.1.2318)

推荐答案

升级码:只要你设置了升级码(标识一堆相关的产品)您可以使用主要升级元素来指示要作为新 MSI 安装的一部分卸载的产品.

Upgrade Code: As long as you have set an upgrade code (which identifies a bunch of related products) you can use a major upgrade element to indicate products that are to be uninstalled as part of a new MSI's installation.

MajorUpgrade 元素:只需注入一个 MajorUpgrade 元素 用于默认处理现有 WiX 源的主要升级.它是一种神奇元素",可以为您做出许多(通常是好的)假设做很多事情.有更老更灵活的方法来做到这一点 - 如果您需要更详细的控制(通常用于遗留目的 - 自动魔法并不涵盖所有基础):

MajorUpgrade Element: Just inject a MajorUpgrade element for default treatment of major upgrades into your existing WiX source. It is a sort of "magic element" doing a lot for you making a number of (usually good) assumptions. There are older and more flexible ways to do it - if you need more detailed control (for legacy purposes usually - auto-magic does not cover all bases):

<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />

以上是在 Visual Studio 中创建的所有 WiX 文件的标准用法.

The above is the standard use for all WiX files created in Visual Studio.

注意:我会尽快尝试使用更多链接来调整这个答案,但先试试看?

Note: I will try to tune up this answer shortly with more links, but give that a go first?

第一个链接:使用 Visual Studio 制作 WiX 文件.Hello WiX 和 Visual Studio 类型的场景.

重大升级建议阅读:关于重大升级的一些知识.所有 WiX 标记基本上都围绕已编译的 MSI 的 升级表.在那里配置了主要的升级逻辑.自定义操作也可能会影响事物,可能还会影响其他一些事物,例如启动条件.​​

Major Upgrade Suggested Reading: A few things to know about major upgrades. All WiX markup essentially revolves around the compiled MSI's Upgrade table. It is there that major upgrade logic is configured. Custom actions could also affect things, and a few other things such as launch conditions perhaps.

  • WiX Documentation: How To: Implement a Major Upgrade In Your Installer
  • Major Upgrade - Common Problems: WIX does not uninstall older version
  • Major Upgrade - Manual Configuration: Adding entries to MSI UpgradeTable to remove related products (using old-style Upgrade elements)

进一步:

这篇关于如何避免使用 Windows Installer/MSI 安装产品的两个版本?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆