在Windows操作系统中,HKEY_CLASSES_ROOT是一个合并了HKEY_LOCAL_MACHINE\SOFTWARE\Classes和HKEY_CURRENT_USER\Software\Classes的视图。因此,无论是32位还是64位的应用程序,都可以通过访问HKEY_CLASSES_ROOT来获取在操作系统中注册的COM组件、文件类型关联等信息。
然而,由于64位操作系统的存在,当32位的应用程序访问HKEY_CLASSES_ROOT时,它们实际上访问的是HKEY_LOCAL_MACHINE\SOFTWARE\Classes,而当64位的应用程序访问HKEY_CLASSES_ROOT时,它们实际上访问的是HKEY_LOCAL_MACHINE\SOFTWARE\Classes和HKEY_CURRENT_USER\Software\Classes的合并视图。这是因为64位应用程序在运行时会被Windows操作系统自动重定向到了64位视图,而32位应用程序则没有被重定向。
因此,如果在32位的应用程序中读取HKEY_CLASSES_ROOT\CLSID下的值时,它们只能访问到HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID下的值,而在64位的应用程序中读取HKEY_CLASSES_ROOT\CLSID下的值时,它们可以访问到HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID和HKEY_CURRENT_USER\Software\Classes\CLSID的合并视图,这就导致了在64位操作系统中,读取到的注册表值数量要比32位操作系统中的要多。
需要注意的是,如果在32位的应用程序中使用了“KEY_WOW64_64KEY”参数打开注册表项,则可以访问到64位视图下的注册表项,但这并不是默认的行为。
下面的代码是32位的,读到的值要比64位的要少
#include <Windows.h>
#include <iostream>
int main()
{
HKEY hKey;
if (RegOpenKeyEx(HKEY_CLASSES_ROOT, "CLSID", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
{
char keyName[1024];
DWORD keySize = 1024;
for (DWORD i = 0; RegEnumKeyEx(hKey, i, keyName, &keySize, NULL, NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS; i++, keySize = 1024)
{
std::cout << keyName << std::endl;
}
RegCloseKey(hKey);
}
return 0;
}
要想达到一样的效果,要在RegOpenKeyEx增加一个KEY_WOW64_64KEY参数才可以完全读取!
#include <Windows.h>
#include <iostream>
int main()
{
HKEY hKey;
if (RegOpenKeyEx(HKEY_CLASSES_ROOT, "CLSID", 0, KEY_READ | KEY_WOW64_64KEY, &hKey) == ERROR_SUCCESS)
{
char keyName[1024];
DWORD keySize = 1024;
for (DWORD i = 0; RegEnumKeyEx(hKey, i, keyName, &keySize, NULL, NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS; i++, keySize = 1024)
{
std::cout << keyName << std::endl;
}
RegCloseKey(hKey);
}
return 0;
}
与x64平台上的代码类似,这段32位的代码使用了RegOpenKeyEx函数的KEY_WOW64_64KEY参数。这个参数会让系统在32位进程中使用64位注册表视图来访问HKEY_CLASSES_ROOT\CLSID键。
这样,在32位进程中也能够访问和操作64位系统上的注册表信息,从而实现与x64平台上代码相同的效果。