Search code examples
c++winapiregistry

Cannot read string from Windows registry


My goal is to get the current SetupPath of the installed Outlook Version.

I use the following code in order to achieve that:

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);

But however this won't work. It fails at opening the Key.

EDIT

I found that the "open key failed" Output was simply an Acces Denied caused by non admin rights. But however if i run it in Admin mode the output is a Hexadecimal Value which will change everytime.


Solution

  • First, since you are using C++, consider making your coding life simpler, defining a simple class that automatically calls RegCloseKey() on the open key.

    Then, when you open the key, consider the minimum flag you need for access: in particular, this sounds like KEY_READ in your case.

    Moreover, I would call RegGetValue() instead of RegQueryValueEx(), as the former makes sure that the returned string is NUL-terminated (simplifying your code a little bit).

    Moreover, when you print the CString, consider calling its GetString() method, to get the const wchar_t* C-style string pointer, instead of passing the CString object to cout.

    Finally, I've simplified your code using wchar_t instead of TCHAR.

    Compilable code follows (I used VS2015 and tested it on 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;
    }
    

    Output:

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

    In addition, you can even use RegGetValue() to automatically open (and close) the registry key for you, e.g.:

    #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;
    }