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_MACHINE
    for (const auto& path : paths) {
        auto softwareList = GetInstalledSoftwareFromKey(HKEY_LOCAL_MACHINE, path);
        allInstalledSoftware.insert(allInstalledSoftware.end(), softwareList.begin(), softwareList.end());
    }

    // 检查HKEY_CURRENT_USER
    for (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_MACHINE
    for (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_USER
    for (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的值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值