【问题标题】:Update Installed MSI Version from EXE从 EXE 更新已安装的 MSI 版本
【发布时间】:2015-01-28 15:00:18
【问题描述】:

我创建了一个通过 MSI 安装的应用程序,版本号为 X.X.X - 比如说 1.0.0。接下来,我们创建了一个不使用任何形式的 MSI 的自定义自我更新过程。 (我们正在通过代码替换文件。)这个自定义的自我更新过程是必需的,它使我们能够远程快速地管理大量用户。我们已经运行了一段时间了。困扰我的一件事是我们的应用程序的程序和功能屏幕上显示的版本仍然是 1.0.0。有没有办法从主可执行文件更新程序版本?

【问题讨论】:

    标签: c# .net windows-installer versioning


    【解决方案1】:

    从评论更改为答案以获得更好的可读性,并将事实讨论更改为您的问题和相关环境:

    首先让我们看看你关于更改DisplayVersion in 值的建议

    HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{MSI ProductCode}
    

    对于 32 位 MSI 设置(大多数设置仍然在这里运行,即使包含 64 位或独立(例如 .NET)代码,但这是另一回事)或

    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{MSI ProductCode}
    

    适用于 64 位 MSI 设置。首先,这只是机器范围(“LOCAL_MACHINE”)设置的地方,而不是依赖于用户的设置,但没关系,因为这是标准的。

    编辑 DisplayVersion 不是最佳做法。至少,如果要对其进行编辑,它可以进行讨论。事实上,它是一个免费的字符串,许多安装程序都在使用它,它们的版本不是“1.0”,而是“V1.0”或“1.0a”或类似的。 如果这样做,那么在 msi 本身的自定义操作中(在最后)中这样做是最糟糕的。

    至少,作为反对那些禁止更改此密钥的人的论据:这不是 MSI 与版本进行逻辑操作的地方,此版本不用于版本比较。实际上它只是一个输出字符串。

    OTOH,它可以被原始设置 (MSI) 修复/更新/重新安装再次覆盖。所以警告不要手动更改有背景。

    另外: 有些 Windows 版本,尤其是较旧的版本,存在更新问题,因此更改注册表值不会立即反映控制面板视图。例如,有一个 ARP 缓存保存所有安装条目。我不认为 Windows 7 或更高版本会出现这些问题,但是在过去看到问题并且知道 ARP 缓存仍然存在让我在这里保持谨慎。

    我建议并且我称之为好的做法是不要更改此编号,而是让它属于本机 MSI。

    Instad 使 MSI 设置对控制面板中的用户不可见(“程序和功能”或 ARP 由于它的名称较旧,我们仍然在 MSI 和设置社区中这样称呼它):

    将您的 MSI 修复程序中的 ARPSYSTEMCOMPONENT 属性设置为 1(通常是十六进制 1,但因为是您,所以您只能选择十进制 1 :-))。

    或者在安装时将ARPSYSTEMCOMPONENT=1 作为命令行参数提供给您想要的任何 MSI 设置。

    事实上,这也是微软对 SQL Server、Visual Studio、Office 设置所做的事情。它们由多个设置组成,其行为类似于不可见的(设置)组件。

    或者,您可以使(任何)MSI 设置在安装后“不可见”:只需将注册表中的注册表值 SystemComponent(或添加)直接更改为 1 即可。 但这又不是干净的,因为修复或更新或重新安装可能会再次改变这一点。但它不会破坏任何东西——在最坏的情况下,不可见的设置会变得可见。

    然后您为可视 ARP 设置构建另一个设置(可能是“主”设置),或者您只需在注册表中的上述“卸载”键下创建一个完整的 MSI 独立键。 (在程序或“正常”MSI 设置中)。这可以是 GUID 或普通名称。查看您的注册表,您会在那里找到一些非 GUID 的示例,例如由 Adob​​e 等提供。每个非 GUID 都不是“Windows Installer”(MSI)设置,但当然也有一些类似 GUID 的条目可以通过非 MSI 设置。

    主要优点是:这个新的DisplayVersion在MSI-independent key可以自己控制。

    【讨论】:

    • 上次我检查时,为了对用户可见,“卸载”下自己创建的注册表项必须至少有两个非空值,分别是“DisplayName”和“UninstallString”。正如我所写,通常也会添加“DisplayVersion”。还有很多其他有用的条目,您可以自己提供估计的“人造”产品的磁盘空间和安装路径。
    • 可能感兴趣的是,“UninstallString”和“ModifyPath”在另一种情况下完全不重要,如果它是一个 MSI 设置。您可以更改或删除它们,它不会打扰 Windows Installer,执行正常的 MSI 卸载过程,搜索缓存的 MSI 并执行读取它的工作。
    • 我会阅读 Windows Installer Rule # 21,因为我认为它适用于此。 blogs.msdn.com/b/windows_installer_team/archive/2006/05/12/…
    • 部分。在“卸载”区域创建自己的密钥不仅是允许的,而且对于设置是强制性的,例如引导程序或其他非 MSI 设置。使用 ARPSYSTEMCOMPONENT 也很好。 # 21 当然适用于直接在注册表中更改 MSI 设置的 SystemComponent 或 DisplayVersion。正如我所提到的。
    • 由于我们再次进入设计问题,我将声明我们的软件通过清理添加的文件来处理卸载,禁用广告快捷方式以防止自动修复,并且我们从不向客户发送 MSI .我们提供硬件和软件,MSI 从不发货。事实上,我们只安装一次,然后对其余设备进行映像。因此,大多数这些维修问题都不适合我们。我们不是在为标准客户端工作。我们在一个封闭的网络上有一个封闭的系统,所以考虑因素有点不同。
    【解决方案2】:

    您正在尝试重新发明修补程序。 Windows Installer 不支持此功能,并且无法执行您尝试执行的操作。

    更新:Tao of the Windows Installer, Part 2

    规则 21:避免使用不属于您的配置数据

    作为安装程序初始设计的一部分, 安装是通过 Microsoft 获得代码的所有权来实现的 对于安装引擎。这包括所有的位置和格式 配置数据。此数据由安装程序管理并直接 不鼓励用户或应用程序访问;事实上有些 数据被编码使得手动操作变得非常困难。

    您不应该尝试直接查看 Windows Installer 配置信息。相反,使用 Windows Installer API 获取您需要的信息。以这种方式访问​​数据可确保 您的包或应用程序将继续工作,即使 底层配置数据更改位置或格式。

    在这种情况下,API 是MsiGetProductInfo function。此函数返回INSTALLPROPERTY_VERSIONSTRING,即ProductVersion property。此 API 没有设置 ProductVerion 的机制,因为 MSI 在PublishProduct Action 期间在内部执行此操作。如果您查看注册表,您会在 HKCR\Installer\Products\PackedGuid\Version 下找到它。 Packed Guid 是 DWORD 格式的 ProductCode 的“达尔文变换”。 ProductVersion 以 DWORD 格式存储,其中 1 个字节用于主要,1 个字节用于次要,2 个字节用于构建。这是因为 ProductVersion 忽略了第 4 个字段,尽管它存储在 ARP 中。

    为了鼓励规则 21,对这个注册表结构进行了混淆处理。不要乱用进程外的 Windows Installer 配置数据。让微星来处理吧。

    【讨论】:

    • 修补过程实际上运行良好,比我使用 MSI 的经验要好得多。但我很难相信除了通过 MSI 文件之外,没有其他方法可以更新已安装应用程序的版本。
    • 我可以想象各种各样的问题。删除文件并点击修复,您得到的是旧文件而不是新文件。 DLL 引用计数被弄乱了。卸载完全失败。去过也做过。我理解你为什么要这样做,我也理解为什么它看起来是一个好的设计,但我可以向你保证它不是。
    • 我们已经在过去两年实施了它。这也不是我的决定。这不是设计问题,这是一个如何更新版本的问题。
    • 无法更新是因为MSI拥有版本号。它们仅在 MSI 中向您公开 ProductVersion 属性。然后,PublishProduct 标准操作负责在其自己的元数据(由 Win32_Product 公开)和 ARP/PF 的卸载注册表项中实现。它是私有数据,不存在 API,因为不存在创建它的有效用户故事。
    • 随心所欲地投票给我。我回答了你的问题:这是不可能的。
    【解决方案3】:

    可以通过修改位于两个位置之一的已安装应用程序的注册表值来更新已安装的 MSI 版本。在我的 Windows 8 PC 上,它位于以下位置:

    HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{MSI-GUID}

    它也可能位于: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{MSI-GUID}

    要更新“程序和功能”屏幕上显示的版本号,请修改注册表值“DisplayVersion”

    【讨论】:

    • 这个“答案”没有考虑 HKCR\Installer\Products 和 Win32_Product 类。这是一个 Windows Installer 反模式,无论如何都不应该建模。
    • @ChristopherPainter 小心指出这会在哪里发生故障?我刚刚测试了卸载和更新,没有任何问题。
    • 测试主要升级或次要升级,甚至可能是补丁和修复。当注册表中的版本不再与缓存的 MSI 文件中的版本匹配,并且与将用于修复丢失文件的原始 MSI 文件中的版本不匹配时,您认为 Windows 会做什么?
    • @PhilDW 根据其他答案中的讨论,通过不分发 MSI 已禁用修复,补丁仅通过我们的更新程序发生,并且我测试了对版本号进行重大和次要更改的卸载。
    • 您不能禁用修复 - 您只能在被要求时拒绝提供原始 MSI。
    猜你喜欢
    • 1970-01-01
    • 2014-08-18
    • 1970-01-01
    • 1970-01-01
    • 2013-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-22
    相关资源
    最近更新 更多