I have been looking at using CSettingsStore
class.
I know how to read a value from the registry. Example:
CSettingsStore store(TRUE, TRUE);
if (store.Open(_T("Software\\TruckleSoft\\VisitsRota")))
{
if (store.Read(_T("AppPath"), m_strPathVisitsRota))
{
//yes, but is the path still valid
if (!PathFileExists(m_strPathVisitsRota))
{
// it exists
m_strPathVisitsRota = _T("");
}
}
}
Now, in the documentation is states:
The security access depends on the
bReadOnly
parameter. IfbReadonly
isFALSE
, the security access will be set toKEY_ALL_ACCESS
. IfbReadyOnly
isTRUE
, the security access will be set to a combination ofKEY_QUERY_VALUE
,KEY_NOTIFY
andKEY_ENUMERATE_SUB_KEYS
.
So it implies you can enumerate sub keys. But I can't find an example explaining about to enumerate a set of key / value pairs using this class.
Note that KEY_ENUMERATE_SUB_KEYS
is a flag which request access to enumerate the subkeys, it doesn't actually do it.
KEY_ALL_ACCESS
is a combination of different flags, including KEY_ENUMERATE_SUB_KEYS
. So in both cases enumeration access is requested.
To enumerate values we need ::RegEnumValue
API, this method is not wrapped in CRegKey
, but it doesn't matter, we can get HKEY
directly.
Here is example, based on your code and Microsoft sample
void CMySettingsStore::EnumKeys(std::vector<CString>& vec)
{
vec.clear();
DWORD subkey_total;
if (ERROR_SUCCESS != RegQueryInfoKey(m_reg.m_hKey, NULL, NULL, NULL,
&subkey_total, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
return;
wchar_t buf[1024];
for (DWORD i = 0; i < subkey_total; i++)
{
DWORD len = _countof(buf);
if (ERROR_SUCCESS == m_reg.EnumKey(i, buf, &len))
vec.push_back(buf);
}
}
void CMySettingsStore::EnumValues(std::vector<CString>& vec)
{
vec.clear();
DWORD values_total;
if (ERROR_SUCCESS != RegQueryInfoKey(m_reg.m_hKey, NULL, NULL, NULL,
NULL, NULL, NULL, &values_total, NULL, NULL, NULL, NULL))
return;
wchar_t buf[1024];
for (DWORD i = 0; i < values_total; i++)
{
DWORD len = _countof(buf);
if (ERROR_SUCCESS == RegEnumValue(m_reg.m_hKey, i, buf, &len,
NULL, NULL, NULL, NULL))
vec.push_back(buf);
}
}
This code does not resolve all the code analysis warnings but it does add error handling and support for obtaining the value types:
#include "stdafx.h"
#include "MySettingsStore.h"
CMySettingsStore::CMySettingsStore(BOOL bAdmin, BOOL bReadOnly)
: CSettingsStore(bAdmin, bReadOnly)
{
}
bool CMySettingsStore::EnumKeys(std::vector<CString>& vec)
{
vec.clear();
DWORD subkey_total{}, lResult{};
if (RegQueryInfoKey(m_reg.m_hKey, NULL, NULL, NULL,
&subkey_total, NULL, NULL, NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
{
const DWORD dwError = ::GetLastError();
AfxMessageBox(GetLastErrorAsString(dwError), MB_OK | MB_ICONWARNING);
return false;
}
wchar_t buf[1024];
for (DWORD i = 0; i < subkey_total; i++)
{
DWORD len = _countof(buf);
lResult = m_reg.EnumKey(i, buf, &len);
if(lResult == ERROR_SUCCESS || ERROR_NO_MORE_ITEMS)
vec.push_back(buf);
}
if (lResult != ERROR_NO_MORE_ITEMS)
{
const DWORD dwError = ::GetLastError();
AfxMessageBox(GetLastErrorAsString(dwError), MB_OK | MB_ICONWARNING);
return false;
}
return true;
}
bool CMySettingsStore::EnumValues(std::map<CString, DWORD>& map)
{
map.clear();
DWORD values_total{}, dwType{}, lResult{};
if (RegQueryInfoKey(m_reg.m_hKey, NULL, NULL, NULL,
NULL, NULL, NULL, &values_total, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
{
const DWORD dwError = ::GetLastError();
AfxMessageBox(GetLastErrorAsString(dwError), MB_OK | MB_ICONWARNING);
return false;
}
wchar_t buf[1024];
for (DWORD i = 0; i < values_total; i++)
{
DWORD len = _countof(buf);
lResult = RegEnumValue(m_reg.m_hKey, i, buf, &len,
NULL, &dwType, NULL, NULL);
if(lResult == ERROR_SUCCESS || lResult == ERROR_NO_MORE_ITEMS)
map.emplace(buf, dwType);
}
if (lResult != ERROR_NO_MORE_ITEMS)
{
const DWORD dwError = ::GetLastError();
AfxMessageBox(GetLastErrorAsString(dwError), MB_OK | MB_ICONWARNING);
return false;
}
return true;
}
CString CMySettingsStore::GetLastErrorAsString(DWORD dwError)
{
LPVOID lpMsgBuf{};
CString strError;
::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr,
dwError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR)&lpMsgBuf,
0,
nullptr);
strError = static_cast<LPTSTR>(lpMsgBuf);
LocalFree(lpMsgBuf);
return strError;
}