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

时间:2017-07-23 13:38:50

标签: 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);

但是这不起作用。它无法打开钥匙。

修改

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

1 个答案:

答案 0 :(得分:0)

首先,由于您使用的是C ++,因此请考虑使编码生活更简单,定义一个简单的类,自动在开放键上调用RegCloseKey()

然后,当您打开密钥时,请考虑访问所需的最小标记:特别是,在您的情况下,这听起来像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;
}