C++ RegEnumValue() - fail to iterate to each value - c++

I want to get all the registry values under specific key path, but RegEnumValue() always returns back the error code 259 as ERROR_NO_MORE_ITEMS and sectionValue has nonsense value. I check the registry manually and there are values under the specified key.
For example.
key is MyTestApp
key value is ManualTestCase = 10
key value is AutomationTestCase = 50
HKEY hKey; //registry key handle
LONG lResult; //result of registry operations
DWORD dwType, dwSize=0;
//try to open the key that we are currently pointing at with rootPath
lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, rootPath, NULL, KEY_ALL_ACCESS, &hKey);
if (lResult == ERROR_SUCCESS)
{
LPTSTR className = NULL;
DWORD classNameSize = MAX_PATH;
DWORD subKey = 0;
DWORD maxSubKey;
DWORD maxClass;
DWORD value;
DWORD maxValue;
DWORD maxValueData;
DWORD securityDescriptor;
FILETIME ftLastWriteTime;
DWORD sectionNameSize;
int j;
//to get total keys for the specified path
lResult = RegQueryInfoKey(hKey, className, &classNameSize, NULL,
&subKey, &maxSubKey, &maxClass, &value, &maxValue,
&maxValueData, &securityDescriptor, &ftLastWriteTime);
if(lResult == ERROR_SUCCESS)
{
for(int i = 0; i < subKey; i++)
{
LPTSTR sectionName = new TCHAR[1096];
sectionNameSize = 1096;
ftLastWriteTime.dwHighDateTime = 0;
ftLastWriteTime.dwLowDateTime = 0;
//enumerate all the registry key names for specified path
lResult = RegEnumKeyEx(hKey, i, sectionName,
&sectionNameSize, NULL, NULL,
NULL, &ftLastWriteTime);
CString testStr = sectionName;
if(lResult == ERROR_SUCCESS)
{
j = 0;
do
{
LPTSTR sectionValue;
DWORD sectionValueSize = 4096;
DWORD dwType;
//enumerate all the values for specified key
lResult = RegEnumValue(hKey, j, sectionName,
&sectionNameSize, NULL, &dwType,
(LPBYTE)sectionValue, &sectionValueSize);
//
if(lResult == ERROR_SUCCESS)
{
//do something to the data
bool whatever = true;
}
else if(lResult == ERROR_MORE_DATA)
{
//
bool yeahSure = true;
}
j++;
}while(lResult != ERROR_NO_MORE_ITEMS);
}
delete[] sectionName;
}
}
}
RegCloseKey(hKey);

My guess is your problem is with how you use lResult = RegEnumKeyEx(hKey, i, sectionName,...
You are trying to enumerate values of a subkey without actually opening that subkey.

Related

How fast is the build-in function SHGetValueA function (shlwapi.h) in C++?

I have been in doubt about what should be a better approach:
To cache the registry and use it later (I won't be doing it multiple times).
To run this function when needed (if it is fast)
How can I measure the speed of this function?
int ReadUACRegistryKey(LPCWSTR key)
{
LPCWSTR pszSubKey, pszValue = key;
const std::wstring sPath = L"XXXXXXXXXXX";
pszSubKey = sSearchPattern.c_str();
DWORD dwType = 0;
DWORD dwValue = 0;
DWORD dwValueSize = sizeof(dwValue);
int retval = SHGetValue(HKEY_LOCAL_MACHINE, pszSubKey, key, &dwType, &dwValue, &dwValueSize);
if (retval != ERROR_SUCCESS)
{
Trace(TRACE_ERROR, _T("ERROR: Failed to retrieve Registry setting and check Input_Image format."));
}
return dwValue;
}

WinApi: Cant read registry

Im trying to read a registry using the winapi and c++.
The code runs, but the result is not the contents of the registry
After a hexdump is just 0xCD repeated over and over. (So, as if the data hasnt been modified by RegQueryValueEx, and is just the result of the malloc)
I tried running as admin too, with no luck.
This is the code im using:
HKEY hKey;
if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\Shell\\Bags\\1\\Desktop", 0, KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS)
return;
//Read & save
DWORD BufferSize = TOTALBYTES;
DWORD cbData;
DWORD dwRet;
LPBYTE data = (LPBYTE)malloc(BufferSize);
cbData = BufferSize;
DWORD type = REG_BINARY;
dwRet = RegQueryValueEx(hKey, "IconLayouts", NULL, &type, data, &cbData);
while (dwRet == ERROR_MORE_DATA) {
BufferSize += BYTEINCREMENT;
data = (LPBYTE)realloc(data, BufferSize);
cbData = BufferSize;
dwRet = RegQueryValueEx(hKey, "IconLayouts", NULL, &type, data, &cbData);
}
if (dwRet == ERROR_SUCCESS)
{
//Write current registry to a file
std::ofstream currentRegistryFile(DIRECTORY + currentDesktop + ".bin");
if (!currentRegistryFile) {
log(currentDesktop + " file couldn't be opened.");
return;
}
for (int i = 0; i < cbData; i++)
currentRegistryFile << (data)[cbData];
}
else
log("Couldnt read registry");
//Close registry
RegCloseKey(hKey);
Your saving code is the problem. It’s actually accessing the array out of bounds:
for (int i = 0; i < cbData; i++)
currentRegistryFile << (data)[cbData];
Note you’re indexing data with constant value of cbData and not loop variable i. Change that.

How to correct store LPTSTR in map

I need to store values from registry in map. I have such code:
map<int, LPTSTR> mymap;
for (i = 0, retCode = ERROR_SUCCESS; i<cValues; i++)
{
cchValue = MAX_VALUE_NAME;
achValue[0] = '\0';
retCode = RegEnumValue(hKey, i,
achValue,
&cchValue,
NULL,
NULL,
NULL,
NULL);
if (retCode == ERROR_SUCCESS)
{
DWORD lpData = cbMaxValueData;
buffer[0] = '\0';
LONG dwRes = RegQueryValueEx(hKey, achValue, 0, NULL, buffer, &lpData);
LPTSTR val = (TCHAR*)buffer;
MessageBox(NULL, val, L"VALUE", MB_OK);
auto r = mymap.insert(pair<int, LPTSTR>(i, val));
for (map<int, LPTSTR>::const_iterator it = mymap.begin(); it != mymap.end(); it++)
{
wchar_t szMessage2[1300];
if (SUCCEEDED(StringCchPrintf(szMessage2, ARRAYSIZE(szMessage2), L"+ %d : %s\n", it->first, it->second)))
{
MessageBox(NULL, szMessage2, L"MAP", MB_OK);
}
}
}
}
How to correct save val to map? Right now all keys have the same value (latest).
The problem is that you have a single buffer that you are reusing during enumeration, and you are storing just a pointer to that buffer into your map. So every entry will be pointing at the same physical memory, which contains the last piece of data written to it.
You need to store copies of the enumerated string data into your map. Use std::string/std::wstring for that, eg:
using tstring = basic_string<TCHAR>;
map<int, tstring> mymap;
for (i = 0, retCode = ERROR_SUCCESS; i < cValues; i++)
{
cchValue = MAX_VALUE_NAME;
retCode = RegEnumValue(hKey, i,
achValue,
&cchValue,
NULL,
NULL,
NULL,
NULL);
if (retCode == ERROR_SUCCESS)
{
DWORD dwData = cbMaxValueData;
DWORD dwType = 0;
LONG dwRes = RegQueryValueEx(hKey, achValue, 0, &dwType, buffer, &dwData);
if (dwRes == ERROR_SUCCESS)
{
switch (dwType)
{
case REG_SZ:
case REG_MULTI_SZ:
case REG_EXPAND_SZ:
{
tstring val((LPTSTR)buffer, dwData / sizeof(TCHAR));
//MessageBox(NULL, val.c_str(), TEXT("VALUE"), MB_OK);
mymap.insert(make_pair(i, val));
break;
}
}
}
}
}
for (auto &value: mymap)
{
TCHAR szMessage2[1300];
if (SUCCEEDED(StringCchPrintf(szMessage2, ARRAYSIZE(szMessage2), TEXT("+ %d : %s\n"), value.first, value.second.c_str())))
{
MessageBox(NULL, szMessage2, TEXT("MAP"), MB_OK);
}
}
However, since you are clearly compiling with UNICODE enabled, you shouldn't be using TCHAR at all:
map<int, wstring> mymap;
for (i = 0, retCode = ERROR_SUCCESS; i < cValues; i++)
{
cchValue = MAX_VALUE_NAME;
retCode = RegEnumValueW(hKey, i,
achValue,
&cchValue,
NULL,
NULL,
NULL,
NULL);
if (retCode == ERROR_SUCCESS)
{
DWORD dwData = cbMaxValueData;
DWORD dwType = 0;
LONG dwRes = RegQueryValueExW(hKey, achValue, 0, &dwType, buffer, &dwData);
if (dwRes == ERROR_SUCCESS)
{
switch (dwType)
{
case REG_SZ:
case REG_MULTI_SZ:
case REG_EXPAND_SZ:
{
wstring val((LPWSTR)buffer, dwData / sizeof(WCHAR));
//MessageBoxW(NULL, val.c_str(), L"VALUE", MB_OK);
mymap.insert(make_pair(i, val));
break;
}
}
}
}
}
for (auto &value: mymap)
{
WCHAR szMessage2[1300];
if (SUCCEEDED(StringCchPrintfW(szMessage2, ARRAYSIZE(szMessage2), L"+ %d : %s\n", value.first, value.second.c_str())))
{
MessageBoxW(NULL, szMessage2, L"MAP", MB_OK);
}
}

CRegKeyEx GetValuesCount returns invalid number

I have this code in C++/VS2013/Win7x64, the app is compiled in 64-bit
CString strKey=_T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\SharedDLLs");
CRegKeyEx reg;
// Count entries
if (reg.Open(HKEY_LOCAL_MACHINE, strKey, KEY_ALL_ACCESS) != ERROR_SUCCESS)
return;
if (reg.QueryInfo() != ERROR_SUCCESS) return;
dwCountEntries = reg.GetValuesCount();
This is the CRegKeyEx class
ifndef __REGKEYEX_H__INCLUDED__
#define __REGKEYEX_H__INCLUDED__
#include <atlbase.h>
//
// Enhanced version of ATL's CRegKey class
// After you open/attach the key, you should call QueryInfo in order
// to initialize some members which this class use.
//
class CRegKeyEx : public CRegKey
{
public:
// Retreives information about the key
LONG QueryInfo();
// Number of subkeys
DWORD GetSubKeysCount() { return m_cSubKeys; }
// Number of values
DWORD GetValuesCount() { return m_cValues; }
// Enumerate values of arbitrary type
// allocate space in ppBuff (you have to free() it)
LONG EnumValue(DWORD dwIndex, CString& strName,
LPBYTE* ppBuff, DWORD* pBuffSize, DWORD* pType);
// Enum value as String
// *pType will be REG_SZ or REG_EXPAND_SZ
LONG EnumValue(DWORD dwIndex, CString& strName, CString& strValue, DWORD* pType);
// EnumKey with CString output
LONG EnumKey(DWORD dwIndex, CString& strName);
protected:
DWORD m_cSubKeys;
DWORD m_cMaxSubKeyLen;
DWORD m_cValues;
DWORD m_cMaxValueNameLen;
DWORD m_cMaxValueLen; // this is in bytes (can be any kind of data)
};
// ---- implementation ----
// Retreives information about the key
inline LONG CRegKeyEx::QueryInfo()
{
LONG ret;
m_cSubKeys = 0;
m_cMaxSubKeyLen = 0;
m_cValues = 0;
m_cMaxValueNameLen = 0;
m_cMaxValueLen = 0;
ret = ::RegQueryInfoKey(m_hKey,
NULL, NULL, NULL,
&m_cSubKeys, &m_cMaxSubKeyLen,
NULL,
&m_cValues, &m_cMaxValueNameLen, &m_cMaxValueLen,
NULL, NULL);
// include the terminating NULL character(s)
m_cMaxSubKeyLen++;
m_cMaxValueNameLen++;
return ret;
}
// Enumerate values of arbitrary type
// allocate space in ppBuff (you have to free() it)
inline LONG CRegKeyEx::EnumValue(DWORD dwIndex,
CString& strName,
LPBYTE* ppBuff,
DWORD* pBuffSize,
DWORD* pType)
{
TCHAR *pName;
DWORD cName;
LPBYTE pBuff = NULL;
DWORD dwBuffSize = 0;
DWORD dwType;
LONG ret;
// Allocate space for buffers
pName = (TCHAR*)malloc(m_cMaxValueNameLen * sizeof(TCHAR));
cName = m_cMaxValueNameLen;
if (ppBuff != NULL) // data may not be required
{
pBuff = (LPBYTE)malloc(m_cMaxValueLen);
dwBuffSize = m_cMaxValueLen;
}
// Retreive name and data
ret = ::RegEnumValue(m_hKey, dwIndex,
pName, &cName,
NULL, &dwType,
pBuff, pBuff ? &dwBuffSize : NULL);
if (ret != ERROR_SUCCESS)
{
free(pName);
free(pBuff);
return ret;
}
// Resize the buffers
pName = (TCHAR*)realloc(pName, (cName + 1) * sizeof(TCHAR));
if (pBuff)
pBuff = (LPBYTE)realloc(pBuff, dwBuffSize);
if (ppBuff)
*ppBuff = pBuff;
if (pBuffSize)
*pBuffSize = dwBuffSize;
if (pType)
*pType = dwType;
strName = pName;
free(pName);
return ERROR_SUCCESS;
}
// Enum value as String
// *pType will be REG_SZ or REG_EXPAND_SZ
inline LONG CRegKeyEx::EnumValue(DWORD dwIndex,
CString& strName,
CString& strValue,
DWORD* pType)
{
DWORD dwType;
LPBYTE pBuff;
LONG ret;
ret = EnumValue(dwIndex, strName, &pBuff, NULL, &dwType);
if (ret != ERROR_SUCCESS)
return ret;
if (pType)
*pType = dwType;
if (dwType == REG_SZ || dwType == REG_EXPAND_SZ)
{
strValue = (TCHAR*)pBuff;
free(pBuff);
}
else
{
free(pBuff);
return ERROR_INVALID_DATATYPE;
}
return ERROR_SUCCESS;
}
// EnumKey with CString output
inline LONG CRegKeyEx::EnumKey(DWORD dwIndex, CString& strName)
{
TCHAR *pName;
DWORD dwLen;
LONG ret;
// Allocate space for buffers
dwLen = m_cMaxSubKeyLen;
pName = (TCHAR*)malloc(dwLen * sizeof(TCHAR));
memset(pName, 0, dwLen * sizeof(TCHAR));
ret = CRegKey::EnumKey(dwIndex, pName, &dwLen, NULL);
strName = pName;
free(pName);
return ret;
}
#endif __REGKEYEX_H__INCLUDED__
The registry key have 1725 values and GetValuesCount returns only 762 !

Print name, type and data of registry

I am trying to print info about registry. My problem is in the first for loop.
I can't get it to print dataType and data correctly.
Also, adding them in the same print will crash the program or not print correctly.
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
void EnumerateValues(HKEY hKey, DWORD numValues)
{
DWORD dwIndex = 0;
LPSTR valueName = new CHAR[64];
DWORD valNameLen;
DWORD dataType;
DWORD data;
DWORD dataSize;
for (int i = 0; i < numValues; i++)
{
RegEnumValue(hKey,
dwIndex,
valueName,
&valNameLen,
NULL,
&dataType,
(BYTE*)&data,
&dataSize);
dwIndex++;
_tprintf(TEXT("(%d) %s %d\n"), i+1, valueName, dataType);
// printf("Code: 0x%08X\n", data);
}
}
void EnumerateSubKeys(HKEY RootKey, char* subKey, unsigned int tabs = 0)
{
HKEY hKey;
DWORD cSubKeys; //Used to store the number of Subkeys
DWORD maxSubkeyLen; //Longest Subkey name length
DWORD cValues; //Used to store the number of Subkeys
DWORD maxValueLen; //Longest Subkey name length
DWORD retCode; //Return values of calls
RegOpenKeyEx(RootKey, subKey, 0, KEY_ALL_ACCESS, &hKey);
RegQueryInfoKey(hKey, // key handle
NULL, // buffer for class name
NULL, // size of class string
NULL, // reserved
&cSubKeys, // number of subkeys
&maxSubkeyLen, // longest subkey length
NULL, // longest class string
&cValues, // number of values for this key
&maxValueLen, // longest value name
NULL, // longest value data
NULL, // security descriptor
NULL); // last write time
if(cSubKeys>0)
{
char currentSubkey[MAX_PATH];
for(int i=0;i < cSubKeys;i++){
DWORD currentSubLen=MAX_PATH;
retCode=RegEnumKeyEx(hKey, // Handle to an open/predefined key
i, // Index of the subkey to retrieve.
currentSubkey, // buffer to receives the name of the subkey
&currentSubLen, // size of that buffer
NULL, // Reserved
NULL, // buffer for class string
NULL, // size of that buffer
NULL); // last write time
if(retCode==ERROR_SUCCESS)
{
for (int i = 0; i < tabs; i++)
printf("\t");
printf("(%d) %s\n", i+1, currentSubkey);
char* subKeyPath = new char[currentSubLen + strlen(subKey)];
sprintf(subKeyPath, "%s\\%s", subKey, currentSubkey);
EnumerateSubKeys(RootKey, subKeyPath, (tabs + 1));
}
}
}
else
{
EnumerateValues(hKey, cValues);
}
RegCloseKey(hKey);
}
int main()
{
EnumerateSubKeys(HKEY_CURRENT_USER,"SOFTWARE\\Dropbox");
getchar();
return 0;
}
Your call to RegEnumValue is incorrect. It has the following problems:
You are expected to initialise valNameLen before calling the function.
You are expected to initialise dataSize before calling the function.
You fail to check the return value of RegEnumValue and thus assume that the function succeeds. And in fact it fails because you of the aforementioned errors.
Let's ignore the value for now, since that's much more complex. Let's just try and enumerate the names of the values. That code would look like this:
void EnumerateValues(HKEY hKey, DWORD numValues)
{
for (DWORD dwIndex = 0; dwIndex < numValues; dwIndex++)
{
char valueName[64];
DWORD valNameLen = sizeof(valueName);
DWORD dataType;
DWORD dataSize = 0;
DWORD retval = RegEnumValue(hKey, dwIndex, valueName, &valNameLen,
NULL, &dataType, NULL, &dataSize);
if (retval == ERROR_SUCCESS)
{
printf("(%d) %s %d\n", dwIndex+1, valueName, dataType);
}
else
{
// handle error
}
}
}
Note also that I stopped using a dynamically allocated character array as your code did. Your code leaked that array. Obviously if you need to cope with arbitrarily large value names, then you would need to use dynamically allocated arrays.
As for extracting the data, that's a bigger task that I don't believe is in the scope of
this question. You need special code for each individual data type.
For instance, to read a REG_SZ you would use code like this:
char *data = new char [dataSize+1];
data[dataSize] = '\0';
valNameLen = sizeof(valueName);
DWORD retval = RegEnumValue(hKey, dwIndex, valueName, &valNameLen,
NULL, NULL, (LPBYTE)data, &dataSize);
if (retval == ERROR_SUCCESS)
{
printf("(%d) %s %d %s\n", dwIndex+1, valueName, dataType, data);
}
else
{
// handle error
}
delete[] data;