注意Windows 8.1registry读取虚拟化不适用于64位应用程序

(在David Heffernan的build议之后更新)

我有一个传统的Win32原生应用程序(Delphi 6),它将registry的值写入HKEY_LOCAL_MACHINE \ Software \\项下。 这些值稍后将被几个其他传统的Win32本地应用程序和一个新的.NET应用程序读取。 .NET应用程序构buildAnyCPU,因此正在执行一个64位图像。 因为它使用32位应用程序编写的configuration,.NET软件将其registry读取redirect到Win32 API应用程序实际写入的Wow6432Node。

没有任何应用程序正在运行提升。 所有应用程序都是互动 用于运行应用程序的帐户具有HKEY_LOCAL_MACHINE \ Software \\registry项和它的子键的“完全控制”。

据我所知这不是使用registry虚拟化,因为32位应用程序有写访问他们写的HKLM键。

这种情况在64位Windows 7和64位Windows 8计算机上工作得很好,但是在新的Windows 8.1 64位计算机上都不工作。

传统的Win32应用程序无误地写入registry,现在似乎变得虚拟化了。 这可以通过查看用户虚拟化registry项来确认; 我看到里面所有的书面价值。

当我使用REGEDIT查看HKEY_LOCAL_MACHINE \ Software \\键时,我写的大约一半的键只是从HKEY_LOCAL_MACHINE \ Software \\中丢失,但是都存在于虚拟化文件夹中。

据我所知,它与32位应用程序的写权限应该没有虚拟化,但有。 更糟糕的是,当我读取非虚拟化密钥时,我看到一些但并非全部写入虚拟化商店的值。

为什么它突然虚拟化了写入,为什么当读取原始密钥(即虚拟化读取没有按预期工作)时,读取不会显示所有的虚拟化值?

我认为这必须是一个权限问题,如果我运行的应用程序“作为pipe理员”的钥匙都在那里。 然而,运行提升不是一个允许的最终configuration。

更新

我清理了这台机器上的所有registry设置。 无论是在HKCU下的虚拟商店,还是在HKLM下的共享区域。 然后再次开始,没有运行提升。 这引起了类似的症状,但是这次我只看到HKLM键中的一个键。

我将编写一个Win32应用程序来枚举HKEY_LOCAL_MACHINE \ Software \\键,以防万一我在某个64位操作系统上运行时被regedit.exe所欺骗,那。 得到它传统的32位WinAPI应用程序和新的64位应用程序之间的虚拟化不匹配。 查看我的答案了解详情。

在Windows 8.1中,注册表的虚拟化工作与Vista,Win7和Win8中的完全一样。 没有任何更改可以解释您所报告的内容。

您是否意识到7年前在Vista中引入了虚拟化技术,以帮助无法修改的应用程序在UAC上工作。 这个想法是,你修复你的应用程序以了解UAC,并停止运行虚拟化。

关于虚拟化的一点是,如果以标准用户身份运行,应用程序将写入虚拟商店。 但是,如果您执行提升的应用程序,则应用程序将写入注册表的共享部分HKLM 。 从上面的描述看来,您似乎已经运行了应用程序,并且已经向HKLM而不是虚拟商店写入了值。

我建议你清理掉这台机器上的所有注册表设置。 无论是在HKCU下的虚拟商店,还是在HKLM下的共享区域。 然后再次启动您的应用程序,而不是运行提升。 我相信,它会像以前的版本一样工作。

但是,我很惊讶,你仍然在尝试使用虚拟化功能。 帮助无助是一个拐杖。 不要无奈 停止运行虚拟化。 远离虚拟化。

更新

你的问题编辑完全改变这一点。 事实上,你并没有问及Windows 8.1和早期版本之间的区别。 您正在Windows 8.1机器上运行一个不同的程序,一个是64位。 而64位进程永远不会被虚拟化。

我再次重申我的建议,即虚拟化不会像你这样使用。 依靠这种方式是愚蠢的。

好吧,我已经到了这个底部了。 大卫·赫弗南(David Heffernan)是正确的,因为过去这些应用程序运行了一些程序,水域确实非常混乱。

我写了一对测试应用程序来隔离这个问题(或者事实上没有问题),Delphi 6 32位Win32应用程序列举了所有其他传统应用程序所做的HKEY_LOCAL_MACHINE \ Software \\键; 即忽略密钥的虚拟化。 这看起来好像在HKEY_LOCAL_MACHINE \ Software \\区域中的所有键,即使他们实际上被写入到VirtualStore HKLU区域。 这就解释了为什么我们所有的传统应用程序都很开心

我也写了一个简单的.NET 64位应用程序来测试它如何枚举HKEY_LOCAL_MACHINE \ Software \\键的注册表。 看到注意,无论查看模式(32或64位)。 它确实在虚拟注册表位置看到了一切。

我的问题是虚拟化的范围。 它的传统应用程序。 Windows假定任何64位应用程序都不是传统应用程序,并且正在做正确的事情; 对64位应用程序禁用读取虚拟化; 如果您的64位应用程序必须读取操作系统为您虚拟化的传统32位应用程序编写的值,则必须自己执行此操作。

有关详细信息,请参阅此MSDN文章; 相关位(我错过了)在“ 注册表虚拟化范围 ”一节中

 Registry virtualization is disabled for the following: •64-bit processes. 

我已经修改了我的新应用程序,以说明这一事实,因为它必须继承传统的32位应用程序编写的设置; 这些设置可能会被虚拟化,因此现在它会在回退到未虚拟化之前检查虚拟化注册表位置。

我一直困扰同样的问题,我不使用64位应用程序。 我们的应用程序是一个销售点软件,它使用注册表中所有用户共用的密钥来存储关于业务应用程序的GLOBAL信息。 我们所进行的方式是,我们将授予对HKLM / software / Store管理密钥和子密钥的写入访问权限,以便应用程序不会被虚拟化到私人用户注册表中。 存储在那里的财务和配置信息必须可供运行我们软件的任何用户使用。

最重要的是,我们使用reg flags命令来设置该键和子键上的dont_virtualize dont_silent_fail recurse_flag,以警告Windows停止虚拟化该键和子键。 这在Vista和Windows 7上运行得非常好,但显然在Windows 8.1上不能正常工作。 无论是显而易见的,我都会得到一些虚拟化的密钥。

所以在我的情况下,我不指望虚拟化使我的程序工作,而是我被它踢的时候,它是不应该的。 我试图找到永久禁用此虚拟化的方法,因为我的程序不需要拐杖走路。

附录:在寻找可能的解决方案时,我发现如果32位程序有一个清单,向Windows解释它们与Vista和Windows 7的兼容程度,那么Windows停止虚拟化常见的注册表项,甚至会产生预期的访问错误用户没有适当的权利写入我们的程序的通用注册表部分。 因此,对于已经在该领域的版本,单独的清单文件将明显地解决这个问题,并且我们应该在我们的软件的新版本中嵌入清单。 我们仍然会使用reg flags命令来要求Windows不要虚拟化密钥,并在未授予访问权限时给出错误,因为它应该总是首先完成。