c++ - 无法从 Windows 注册表中读取字符串

标签 c++ winapi registry

我的目标是获取已安装 Outlook 版本的当前 SetupPath。

我使用以下代码来实现这一点:

HKEY hKey;

LONG lReturn = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
    _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\OUTLOOK.EXE"),
    0L,
    KEY_ALL_ACCESS,
    &hKey);

if (lReturn == ERROR_SUCCESS)
{
    CString strData;
    DWORD   dwSize = 1024;
    DWORD   dwType;

    lReturn = RegQueryValueEx(hKey,
        _T("Path"),
        0L,
        &dwType,
        (BYTE *)strData.GetBufferSetLength((int)dwSize),
        &dwSize);

    if (lReturn == ERROR_SUCCESS)
    {
        cout << strData;
    }
    else {
        cout << "Read DWORD failed";
    }
}
else {
    cout << "Open Key failed";
}

RegCloseKey(hKey);

但是无论如何这是行不通的。它无法打开 key 。

编辑

我发现“打开 key 失败”输出只是由非管理员权限引起的访问被拒绝。但是,如果我在管理员模式下运行它,输出是一个十六进制值,每次都会改变。

最佳答案

首先,由于您使用的是 C++,请考虑简化您的编码生活,定义一个自动在打开的 key 上调用 RegCloseKey() 的简单类。

然后,当您打开 key 时,请考虑访问所需的最小标志:特别是,在您的情况下这听起来像 KEY_READ

此外,我会调用 RegGetValue() 而不是 RegQueryValueEx(),因为前者确保返回的字符串以 NUL 结尾(稍微简化您的代码位)。

此外,当您打印CString 时,考虑调用其GetString() 方法,以获取const wchar_t* C 风格字符串指针,而不是将 CString 对象传递给 cout

最后,我使用 wchar_t 而不是 TCHAR 简化了您的代码。

可编译代码如下(我使用VS2015并在Windows 10上测试过):

#include <Windows.h>
#include <atlbase.h>
#include <atlstr.h>
#include <iostream>
using namespace std;

class ScopedKey
{
public:
    explicit ScopedKey(HKEY hKey)
        : m_hKey(hKey)
    {
    }

    ~ScopedKey()
    {
        ::RegCloseKey(m_hKey);
    }

    HKEY Get() const
    {
        return m_hKey;
    }

    // Ban copy
    ScopedKey(const ScopedKey&) = delete;
    ScopedKey& operator=(const ScopedKey&) = delete;

private:
    HKEY m_hKey;
};

int main()
{
    constexpr int kExitOk = 0;
    constexpr int kExitError = 1;

    //
    // Open the registry key
    // 
    HKEY hKey;
    LONG retCode = ::RegOpenKeyEx(
        HKEY_LOCAL_MACHINE,
        L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\OUTLOOK.EXE",
        0,
        KEY_READ,
        &hKey
    );

    if (retCode != ERROR_SUCCESS)
    {
        wcout << "RegOpenKeyEx() failed; error code = " << retCode << '\n';
        return kExitError;
    }

    // Auto-close the registry key
    ScopedKey key(hKey);


    //
    // Get the size of the path string
    //
    const wchar_t* valueName = L"Path";
    DWORD dataSizeInBytes = 0;
    retCode = ::RegGetValue(
        hKey, 
        nullptr, 
        valueName, 
        RRF_RT_REG_SZ, 
        nullptr, 
        nullptr, 
        &dataSizeInBytes
    );
    if (retCode != ERROR_SUCCESS)
    {
        wcout << "RegGetValue() failed; error code = " << retCode << '\n';
        return kExitError;
    }


    //
    // Read the path string from the registry
    // 
    const DWORD sizeInWchars = dataSizeInBytes / sizeof(wchar_t);
    CStringW str;
    wchar_t* buffer = str.GetBuffer(sizeInWchars);
    retCode = ::RegGetValue(
        hKey,
        nullptr,
        valueName,
        RRF_RT_REG_SZ,
        nullptr,
        buffer,
        &dataSizeInBytes
    );
    if (retCode != ERROR_SUCCESS)
    {
        wcout << "RegGetValue() failed; error code = " << retCode << '\n';
        return kExitError;
    }
    str.ReleaseBuffer();

    wcout << L"Path = [" << str.GetString() << L"]\n";

    // Auto-closed at end of scope
    // ::RegCloseKey(hKey);

    return kExitOk;
}

输出:

Path = [C:\Program Files (x86)\Microsoft Office\Root\Office16\]

此外,您甚至可以使用 RegGetValue() 为您自动打开(和关闭)注册表项,例如:

#include <Windows.h>
#include <atlbase.h>
#include <atlstr.h>
#include <iostream>
using namespace std;

int main()
{
    constexpr int kExitOk = 0;
    constexpr int kExitError = 1;

    //
    // Get the size of the path string
    //
    const wchar_t* subKey = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\OUTLOOK.EXE";
    const wchar_t* valueName = L"Path";
    DWORD dataSizeInBytes = 0;
    LONG retCode = ::RegGetValue(
        HKEY_LOCAL_MACHINE,
        subKey,
        valueName,
        RRF_RT_REG_SZ,
        nullptr,
        nullptr,
        &dataSizeInBytes
    );
    if (retCode != ERROR_SUCCESS)
    {
        wcout << "RegGetValue() failed; error code = " << retCode << '\n';
        return kExitError;
    }

    //
    // Read the path string from the registry
    // 
    const DWORD sizeInWchars = dataSizeInBytes / sizeof(wchar_t);
    CStringW str;
    wchar_t* buffer = str.GetBuffer(sizeInWchars);
    retCode = ::RegGetValue(
        HKEY_LOCAL_MACHINE,
        subKey,
        valueName,
        RRF_RT_REG_SZ,
        nullptr,
        buffer,
        &dataSizeInBytes
    );
    if (retCode != ERROR_SUCCESS)
    {
        wcout << "RegGetValue() failed; error code = " << retCode << '\n';
        return kExitError;
    }
    str.ReleaseBuffer();

    wcout << L"Path = [" << str.GetString() << L"]\n";

    return kExitOk;
}

关于c++ - 无法从 Windows 注册表中读取字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45265717/

相关文章:

c++ - 当我尝试定义这个 vector< pair< int , pair<int, int>>> vp(n)

c++ - 如何在 block 复制期间向量化范围检查?

c++ - 使用 valgrind 时在本地主机上运行的偶尔 boost::asio tcp 服务器故障

C++ 结构和构造

winapi - 在汇编程序中链接到 Kernel32.lib

c++ - 将彩色文本绘制为C++ Win32

C++ 搜索 Windows 注册表

c++ - Qt编译错误: 'emit' was not declared in this scope

c# - 获取已安装产品列表c#

c++ - RegOpenKeyEx 和 RegSetValueEx 失败,但我不知道为什么