使用 CSettingsStore 枚举子项

Enumerating subkeys with CSettingsStore

我一直在考虑使用 CSettingsStore class。

我知道如何从注册表中读取值。示例:

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 bReadOnly parameter. If bReadonly is FALSE, the security access will be set to KEY_ALL_ACCESS. If bReadyOnly is TRUE, the security access will be set to a combination of KEY_QUERY_VALUE, KEY_NOTIFY and KEY_ENUMERATE_SUB_KEYS.

所以这意味着你可以枚举子键。但是我找不到一个例子来解释如何使用这个 class.

来枚举一组键/值对

此答案正在进行中。

页眉

#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);
    }
}

上面的方法有效并为我提供了指定键的子键列表。但是,我还没有弄清楚如何枚举给定键中的值

请注意,KEY_ENUMERATE_SUB_KEYS 是一个请求访问枚举子项的标志,它实际上并没有这样做。

KEY_ALL_ACCESS 是不同标志的组合,包括 KEY_ENUMERATE_SUB_KEYS。因此在这两种情况下都需要枚举访问权限。

枚举值我们需要::RegEnumValueAPI,这个方法没有包裹在CRegKey中,不过没关系,我们可以直接得到HKEY

这是基于您的代码和 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);
    }
}

来自问题作者的更新

此代码并未解决所有代码分析警告,但它确实添加了错误处理并支持获取值 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;
}