Search code examples
c++winapivisual-studio-2008registry

Is there a Proper way of Checking if an HKEY/PHKEY is Valid?


REGISTRY()
{
    /*HKEY*/m_pRoot = nullptr;
    /*HKEY*/m_pReturnKey = nullptr;
    m_pPath = nullptr;
    m_pValueName = nullptr;
}
~REGISTRY()
{
    if ( m_pReturnKey ) 
    {
        RegCloseKey(m_pReturnKey);
        m_pReturnKey = nullptr;
    }
    if ( m_pRoot ) 
    {
        RegCloseKey(m_pRoot);
        m_pRoot = nullptr;
    }
}

I have a class which handles All Registry functions of my applications, I let the Object's Destructor handle the closing of the HKEYs (as Shown Above). I have adopted the answer provided here, but instead of using HANDLES I've simply Set the HKEYs as nullptr during the object's construction and check if it's not nullptr during destruction and close it. I'm also using Smart Pointers<unique_ptr> when using it to ensure that the Destructor get's called even when it throws an exception.

Since Upon Checking ,when RegOpenKeyExA ,RegCreateKeyExA , RegSetValueEx , or RegQueryValueExA returns anything other than ERROR_SUCCESS it doesn't do anything to the passed HKEY and it remained as a nullptr.

Aside from this method is there a proper way to check if a HKEY/PHKEY is active and valid? Scouring the MSDN page on winreg.h provided me nothing, if it's there I might be blind or it's not using a Function Name that is not obvious to an amateur like me.


Solution

  • The winreg API doesn't set aside a value that represents an invalid HKEY (unlike, say, the fileapi, where CreateFileW uses INVALID_HANDLE_VALUE for this purpose). Instead, API calls report whether they succeeded, and only then guarantee to have written an HKEY to the location provided by the caller.

    If your implementation needs to know whether any given piece of information represents valid data, you'll have to record this information separately. Starting with C++17, std::optional is the standard tool for this purpose.

    A possible solution to your problem could thus be:

    class REGISTRY
    {
        std::optional<HKEY> m_pRoot;
        std::optional<HKEY> m_pReturnKey;
        // ...
    }
    
    REGISTRY::~REGISTRY()
    {
        if (m_pReturnKey)
        // equivalent to
        // if (m_pReturnKey.has_value())
        {
            RegCloseKey(m_pReturnKey.value());
            m_pReturnKey = {};
        }
        // ...
    }
    

    m_pRoot and m_pReturnKey are default-initialized, meaning, they hold a value of type std::nullopt_t. The d'tor will observe this, and not do anything. Which solves the problem as stated.