Я рассматривал использование класса CSettingsStore.
Я знаю, как прочитать значение из реестра. Пример:
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("");
}
}
}
Теперь в документации указано:
The security access depends on the
bReadOnlyparameter. IfbReadonlyisFALSE, the security access will be set toKEY_ALL_ACCESS. IfbReadyOnlyisTRUE, the security access will be set to a combination ofKEY_QUERY_VALUE,KEY_NOTIFYandKEY_ENUMERATE_SUB_KEYS.
Таким образом, это означает, что вы можете перечислить подключи. Но я не могу найти пример, объясняющий перечисление набора пар ключ/значение с использованием этого класса.
@BarmakShemirani Возможно, я запрошу это как функцию. Кажется разумным улучшением.
Отвечает ли Microsoft на запросы обновления MFC? Наверное, проще просто написать.
@BarmakShemirani Я разместил это здесь: developercommunity.visualstudio.com/idea/528425/…
@BarmakShemirani Они не отвечают уже 2 года. Так что я думаю, что я должен написать это. Это единственное, что заставляет меня сейчас использовать другой набор классов.





Этот ответ находится в стадии разработки.
#pragma once
#include <afxsettingsstore.h>
#include <vector>
class CMySettingsStore :
public CSettingsStore
{
public:
CMySettingsStore(BOOL bAdmin, BOOL bReadOnly);
void EnumKey(std::vector<CString> &vecKeys);
};
#include "pch.h"
#include "CMySettingsStore.h"
CMySettingsStore::CMySettingsStore(BOOL bAdmin, BOOL bReadOnly)
: CSettingsStore(bAdmin, bReadOnly)
{
}
void CMySettingsStore::EnumKey(std::vector<CString>& vecKeys)
{
DWORD dwIndex = 0;
long lResult = ERROR_SUCCESS;
vecKeys.clear();
while (lResult == ERROR_SUCCESS)
{
CString strSubKey;
DWORD dwLength = _MAX_PATH;
lResult = m_reg.EnumKey(dwIndex, strSubKey.GetBuffer(_MAX_PATH), &dwLength);
strSubKey.ReleaseBuffer();
dwIndex++;
vecKeys.push_back(strSubKey);
}
}
Код предполагает, что в вашем диалоговом окне есть элемент управления CListBox:
CMySettingsStore mySettings(FALSE, TRUE);
if (mySettings.Open(_T("Software\\xxxx")))
{
std::vector<CString> list;
mySettings.EnumKey(list);
mySettings.Close();
for (const auto& strSubKey : list)
{
m_lbData.AddString(strSubKey);
}
}
Вышеприведенное работает и дает мне список подразделов для указанного ключа. Однако я еще не разобрался, как перечислить значения в заданном ключе.
lResult = m_reg.EnumKey(...) может потерпеть неудачу, мы должны немедленно сломаться, иначе мы получим лишний подключа со значением ""@BarmakShemirani Хороший вопрос. Я принял ваше предложение ответа и предоставил измененный код для вашего ответа.
Обратите внимание, что KEY_ENUMERATE_SUB_KEYS — это флаг, который запрашивает доступ для перечисления подразделов, на самом деле он этого не делает.
KEY_ALL_ACCESS — это комбинация разных флагов, в том числе KEY_ENUMERATE_SUB_KEYS. Таким образом, в обоих случаях запрашивается доступ к перечислению.
Для перечисления значений нам нужен ::RegEnumValue API, этот метод не обёрнут в CRegKey, но это не беда, мы можем получить HKEY напрямую.
Вот пример, основанный на вашем коде и Образец Майкрософт
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);
}
}
Этот код не устраняет все предупреждения анализа кода, но добавляет обработку ошибок и поддержку получения значения типы:
#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;
}
Спасибо за ваш код. Я получаю несколько предупреждений анализа (распад указателя и т. д., а также использование nullptr вместо NULL. Но я могу посмотреть на это. Я посмотрю на добавление обработки ошибок, поскольку, как вы говорите, EnumKey возвращает определенное значение для успеха, завершения или ошибки. И для EnumValues мне пришлось передать std::map<CString, DWORD>, так как мне нужно было знать тип значения.
Я добавил вторую версию кода к вашему ответу - это нормально? Спасибо.
Единственное предупреждение, которое у нас есть (после замены NULL на nullptr, — это использование этого буфера и уменьшение указателя.
Я не знаком с этим классом, но, похоже, у него нет метода перечисления. У него есть
ATL::CRegKey m_reg, но он защищен. Вы должны создать свой собственный классclass CMySettingsStore : public CSettingsStore, использоватьm_regдля перечисления ключей.