RegEnumKeyExW函数遍历注册表的错乱问题
程序测试环境是:windows 10 64位系统,c++程序。
#include <windows.h>
#include <iostream>
#include <vector>
#include <string>// 辅助函数:从指定的注册表路径中获取已安装的软件列表
std::vector<std::wstring> GetInstalledSoftwareFromKey(HKEY rootKey, const std::wstring& subKey) {std::vector<std::wstring> installedSoftware;HKEY hKey;// 打开注册表项if (RegOpenKeyExW(rootKey, subKey.c_str(), 0, KEY_READ, &hKey) != ERROR_SUCCESS) {return installedSoftware;}FILETIME ftLastWriteTime;wchar_t szSubKeyName[MAX_PATH] = L"";DWORD cchSubKeyName = MAX_PATH;DWORD dwIndex = 0;// 遍历注册表项while (RegEnumKeyExW(hKey, dwIndex++, szSubKeyName, &cchSubKeyName, NULL, NULL, NULL, &ftLastWriteTime) == ERROR_SUCCESS) {HKEY hSubKey;std::wstring subSubKey = subKey + L"\\" + szSubKeyName;// 打开子项if (RegOpenKeyExW(rootKey, subSubKey.c_str(), 0, KEY_READ, &hSubKey) == ERROR_SUCCESS) {DWORD type = 0;DWORD size = MAX_PATH;wchar_t displayName[MAX_PATH] = L"";DWORD displayVersion[MAX_PATH] = 0;// 获取显示名称if (RegQueryValueExW(hSubKey, L"DisplayName", NULL, &type, (LPBYTE)displayName, &size) == ERROR_SUCCESS) {installedSoftware.push_back(std::wstring(displayName));}RegCloseKey(hSubKey);}cchSubKeyName = MAX_PATH;}RegCloseKey(hKey);return installedSoftware;
}// 主函数:获取所有已安装的软件
std::vector<std::wstring> GetAllInstalledSoftware() {std::vector<std::wstring> allInstalledSoftware;// 定义需要检查的注册表路径const std::wstring paths[] = {L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall",L"SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall",L"SOFTWARE\\Kingsoft"};// 检查HKEY_LOCAL_MACHINEfor (const auto& path : paths) {auto softwareList = GetInstalledSoftwareFromKey(HKEY_LOCAL_MACHINE, path);allInstalledSoftware.insert(allInstalledSoftware.end(), softwareList.begin(), softwareList.end());}// 检查HKEY_CURRENT_USERfor (const auto& path : paths) {auto softwareList = GetInstalledSoftwareFromKey(HKEY_CURRENT_USER, path);allInstalledSoftware.insert(allInstalledSoftware.end(), softwareList.begin(), softwareList.end());}return allInstalledSoftware;
}int main() {std::vector<std::wstring> installedSoftware = GetAllInstalledSoftware();std::wcout << L"已安装的软件列表:\n";for (const auto& software : installedSoftware) {std::wcout << software << L"\n";}return 0;
}
以上就是一个完整遍历注册表的代码。我在vscode自己写的demo测试发现可以遍历到office软件,比如word、excel等。
但是当我把这部分代码移植到我的工程里之后,发现就无法遍历到office软件了。而且还发现另一个现象:
RegEnumKeyExW函数在HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall下遍历时,竟然遍历到HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall下的信息
最终定位到原因是,我的工程程序是32位的,在64位Windows系统中,32位应用程序默认访问的是32位注册表视图,这会导致一些路径被重定向。
修改代码如下:
#include <windows.h>
#include <iostream>
#include <vector>
#include <string>// 辅助函数:从指定的注册表路径中获取已安装的软件列表
std::vector<std::wstring> GetInstalledSoftwareFromKey(HKEY rootKey, const std::wstring& subKey, REGSAM samDesired) {std::vector<std::wstring> installedSoftware;HKEY hKey;// 打开注册表项if (RegOpenKeyExW(rootKey, subKey.c_str(), 0, samDesired, &hKey) != ERROR_SUCCESS) {return installedSoftware;}FILETIME ftLastWriteTime;wchar_t szSubKeyName[MAX_PATH] = L"";DWORD cchSubKeyName = MAX_PATH;DWORD dwIndex = 0;// 遍历注册表项while (RegEnumKeyExW(hKey, dwIndex++, szSubKeyName, &cchSubKeyName, NULL, NULL, NULL, &ftLastWriteTime) == ERROR_SUCCESS) {HKEY hSubKey;std::wstring subSubKey = subKey + L"\\" + szSubKeyName;// 打开子项if (RegOpenKeyExW(rootKey, subSubKey.c_str(), 0, samDesired, &hSubKey) == ERROR_SUCCESS) {DWORD type = 0;DWORD size = MAX_PATH;wchar_t displayName[MAX_PATH] = L"";DWORD displayVersion[MAX_PATH] = 0;// 获取显示名称if (RegQueryValueExW(hSubKey, L"DisplayName", NULL, &type, (LPBYTE)displayName, &size) == ERROR_SUCCESS) {installedSoftware.push_back(std::wstring(displayName));}RegCloseKey(hSubKey);}cchSubKeyName = MAX_PATH;}RegCloseKey(hKey);return installedSoftware;
}// 主函数:获取所有已安装的软件
std::vector<std::wstring> GetAllInstalledSoftware() {std::vector<std::wstring> allInstalledSoftware;// 定义需要检查的注册表路径const std::wstring paths[] = {L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall",L"SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall",L"SOFTWARE\\Kingsoft"};// 检查HKEY_LOCAL_MACHINEfor (const auto& path : paths) {auto softwareList = GetInstalledSoftwareFromKey(HKEY_LOCAL_MACHINE, path, KEY_READ | KEY_WOW64_64KEY);allInstalledSoftware.insert(allInstalledSoftware.end(), softwareList.begin(), softwareList.end());// 32位视图softwareList = GetInstalledSoftwareFromKey(HKEY_LOCAL_MACHINE, path, KEY_READ | KEY_WOW64_32KEY);allInstalledSoftware.insert(allInstalledSoftware.end(), softwareList.begin(), softwareList.end());}// 检查HKEY_CURRENT_USERfor (const auto& path : paths) {auto softwareList = GetInstalledSoftwareFromKey(HKEY_CURRENT_USER, path, KEY_READ);allInstalledSoftware.insert(allInstalledSoftware.end(), softwareList.begin(), softwareList.end());}return allInstalledSoftware;
}int main() {std::vector<std::wstring> installedSoftware = GetAllInstalledSoftware();std::wcout << L"已安装的软件列表:\n";for (const auto& software : installedSoftware) {std::wcout << software << L"\n";}return 0;
}
重点看 RegOpenKeyExW函数的参数samDesired的值。