Windows installer “如何安装以及为什么安装”;“每用户”;设法写信给HKLM?

Windows installer “如何安装以及为什么安装”;“每用户”;设法写信给HKLM?,windows-installer,Windows Installer,“每个用户”的安装模式似乎有一些神奇之处 我们的应用程序有一个不使用insaller的自动更新程序,我想更新“添加/删除程序”窗口中显示的应用程序版本。我很惊讶安装信息(以及版本)实际上存储在 HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{ProductId} 及 所以我的问题是:安装程序如何在不请求提升的情况下在那里编写代码?为什么每个用户的安装都会在HKLM中注册,尤其是第一个入口,这看起来与任

“每个用户”的安装模式似乎有一些神奇之处

我们的应用程序有一个不使用insaller的自动更新程序,我想更新“添加/删除程序”窗口中显示的应用程序版本。我很惊讶安装信息(以及版本)实际上存储在

 HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{ProductId}

所以我的问题是:安装程序如何在不请求提升的情况下在那里编写代码?为什么每个用户的安装都会在HKLM中注册,尤其是第一个入口,这看起来与任何特定用户都没有关系


另一个后续但更实际的问题是如何从代码中更新它(当然没有提升)?

Windows可以写入卸载位置,因为它是Windows。安全限制适用于您所做的事情,而不是Windows所做的事情。它毕竟是操作系统,可以做它需要的事情。如果非提升安装无法在程序和功能中创建条目,那就相当奇怪了。这些注册表项实际上不在MSI文件中

严格来说,每个用户都不是问题所在。如果需要,可以提升每个用户的安装,尽管通常的约定是不提升每个用户的安装。如果更新程序写入卸载键,则需要提升


旁注:如果您的自动更新程序正在更新或替换Windows Installer安装的文件,则您违反了规则。只能使用基于MSI的解决方案进行更新。问题是Windows知道(例如)您安装的每个版本文件的文件版本。如果用户进行了修复(或由于某种原因进行了修复),则您可能会发现Windows希望将文件还原到最初安装的版本。类似地,如果您执行修补程序或主要升级,则如果磁盘上的版本与注册的版本不匹配,Windows将不知道是否需要更新文件,因此可能会要求原始MSI文件来还原这些文件

Windows可以写入该卸载位置,因为它是Windows。安全限制适用于您所做的事情,而不是Windows所做的事情。它毕竟是操作系统,可以做它需要的事情。如果非提升安装无法在程序和功能中创建条目,那就相当奇怪了。这些注册表项实际上不在MSI文件中

严格来说,每个用户都不是问题所在。如果需要,可以提升每个用户的安装,尽管通常的约定是不提升每个用户的安装。如果更新程序写入卸载键,则需要提升


旁注:如果您的自动更新程序正在更新或替换Windows Installer安装的文件,则您违反了规则。只能使用基于MSI的解决方案进行更新。问题是Windows知道(例如)您安装的每个版本文件的文件版本。如果用户进行了修复(或由于某种原因进行了修复),则您可能会发现Windows希望将文件还原到最初安装的版本。类似地,如果您执行修补程序或主要升级,则如果磁盘上的版本与注册的版本不匹配,Windows将不知道是否需要更新文件,因此可能会要求原始MSI文件来还原这些文件

Windows Installer在多个上下文中运行。调用它的上下文(通常是有限用户,或者至少是管理员组中用户的非管理员变体)和服务上下文。后者几乎可以完全访问机器,但大部分工作都是在模拟原始调用程序的情况下完成的。自定义和内置操作可以访问服务上下文(如果UAC或早期广告允许),并且服务始终可以使用它

这就是它获得访问权限的方式。但它为什么要使用此访问在HKLM中存储有关该产品的信息?虽然您可能熟悉SharedDLRefCount,但它仅用于与其他解决方案的互操作性。相反,Windows Installer会自行跟踪类似或扩展的信息,并且需要访问其管理的所有安装的所有实例,即使这些实例是按用户的,并且该用户未登录。当用户未登录时,无法可靠访问其HKCU密钥,因此Windows Installer无法使用该位置。因此,它使用HKLM

您可能还想知道为什么它必须能够访问每个用户安装的数据。简而言之,因为它无法判断安装是否真的是按用户进行的。尤其是在Windows 7和
MSInstallPerUser
之前,但即使现在也无法轻松确定安装是否可以写入共享计算机位置。所以我猜他们甚至没有试图确定这一点。毕竟,既然简单的方法已经足够,为什么还要实现困难或脆弱的特性呢


那么你如何更新它呢?安装更新的.msi文件并让Windows Installer服务为您更新;这些注册表项是允许Microsoft随时更改的实现详细信息。只能通过Msi*API调用(如或)读取或写入它们。(无可否认,将后者称为编写这些值的API有点牵强,但这是为数不多的有效方法之一。)即使数据存储在HKCU中,这部分答案也不会有任何不同。

Windows Installer在多个上下文中运行。调用它的上下文(通常是有限用户,或者至少是管理员组中用户的非管理员变体)和服务上下文。后者几乎可以完全访问机器,但大部分工作都是在模拟原始调用程序的情况下完成的。自定义和内置操作可以访问服务上下文(如果UAC或早期广告允许),并且服务始终可以使用它

这就是它获得访问权限的方式。但它为什么要使用这条通往圣彼得堡的通道呢
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\{SId}\Products\{ProductId}
using (var uninstallSubKey = Registry.CurrentUser.OpenSubKey
        ("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall",true))
{
    if (uninstallSubKey != null)
    {
        var subKeyNames = uninstallSubKey.GetSubKeyNames();
        foreach (var subKeyName in subKeyNames)
        {
            using (var subKey = uninstallSubKey.OpenSubKey(subKeyName, writable: true))
            {
                if (subKey?.GetValue("DisplayName") as string == "YOUR_PRODUCT_NAME")
                {
                    subKey.SetValue("DisplayVersion", "YOUR_NEW_VERSION",
                        RegistryValueKind.String);
                    break;

                }
            }

        }

    }
}