Wednesday, July 8, 2009

Reading Registry Values Using RegEnumValue

This time I am pretending that I don’t know or care what the name of the value is. You can do that by using RegEnumValue. I wrote a function with this prototype:


__checkReturn HRESULT ReadKeyValue(
__in LPCWSTR pszSubKey,
__in DWORD dwIndex,
__deref_out LPWSTR *ppszKeyValue);

Basically you can read regkey values by its index. If you wanted to print out all of the values you could do it like this:

DWORD keyIndex = 0;

do
{
hr = HRESULT_FROM_WIN32(ReadKeyValue(psCategory, psSubcategory, keyIndex++, &psKeyValue));
wprintf(L"%s 0x%x\n", psKeyValue, hr);
if (hr == HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS)) wprintf(L"this means there are no more key values\n");
} while (S_OK == hr);

So here is the complete function. If you knew that you were going to read a lot of values, you might want to open the regkey handle beforehand, do all of your reads, and close it when you are done. Other than that this code should look similar to the previous posting.

__checkReturn HRESULT ReadKeyValue(
__in LPCWSTR pszSubKey,
__in DWORD dwIndex,
__deref_out LPWSTR *ppszKeyValue)
{
HRESULT hr = S_OK;
LPWSTR pszSubKey = NULL;
HKEY hKey = NULL;
LPWSTR pszValueName = NULL;
DWORD lpcchValueName = 2048; // a reasonable initial buffer size
DWORD cbDataSize = 4096;
DWORD type = 0;

hr = HRESULT_FROM_WIN32(
RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
pszSubKey,
0,
KEY_QUERY_VALUE,
&hKey));

if (S_OK == hr)
{
*ppszKeyValue = (LPWSTR)malloc(cbDataSize);
pszValueName = (LPWSTR)malloc(lpcchValueName * sizeof(wchar_t));

if (!*ppszKeyValue || !pszValueName)
{
hr = E_OUTOFMEMORY;
}
else
{
**ppszKeyValue = L'\0';
*pszValueName = L'\0';
}
}

while (S_OK == hr && S_OK != (hr = HRESULT_FROM_WIN32(
RegEnumValue(
hKey,
dwIndex,
pszValueName,
&lpcchValueName ,
NULL,
&type,
(LPBYTE)*ppszKeyValue,
&cbDataSize))))
{
if (*ppszKeyValue)
{
free(*ppszKeyValue);
*ppszKeyValue = NULL;
}

if (pszValueName)
{
free(pszValueName);
pszValueName = NULL;
}

if (HRESULT_FROM_WIN32(ERROR_MORE_DATA) == hr)
{
hr = S_OK;

*ppszKeyValue = (LPWSTR)malloc(cbDataSize);
pszValueName = (LPWSTR)malloc(lpcchValueName * sizeof(wchar_t));

if (!*ppszKeyValue || !pszValueName)
{
hr = E_OUTOFMEMORY;
}
else
{
**ppszKeyValue = L'\0'; // PreFAST is still whining about this
*pszValueName = L'\0';
}
}
else
{
break;
}
}

// cleanup
(void)RegCloseKey(hKey);

if (pszValueName)
{
free(pszValueName);
}

if (S_OK != hr && *ppszKeyValue)
{
free(*ppszKeyValue);
*ppszKeyValue = NULL;
}

return hr;
}

No comments:

Post a Comment