본문 바로가기

Programing/MFC

CSettingsStore 클래스

MFC에는 CSettingsStore 클래스가 있어 레지스트리를 편집할 수 있다. (afxsettingsstore.h에 선언)
내부적으로protected로 선언된 ATL::CRegKey 타입의 m_reg 맴버변수가 있어서 동작을 하게 되어 있다. (atlbase.h에 선언)

키의 선택 : HKEY_LOCAL_MACHINE 또는 HKEY_CURRENT_USER

CSettingsStore 클래스는 파라메터가 없는 기본생성자를 레지스트리의 구조에 대하여 알고 있다면 윈도우 레지스트리에는 루트키가 여러가지 있다는 것을 알 수 있다.
대신 오버라이드된 인자 두 개를 받는 형태의 다른 생성자가 있다.

class CSettingsStore : public CObject
{
// Construction
public:
    CSettingsStore(BOOL bAdmin, BOOL bReadOnly);

protected:
    CSettingsStore();

이것을 이용하면 어쨌든 인스턴스를 만들 수 있다.
두 번째 인자는 BOOL 타입이고 이름역시 읽기 전용이라는 이름이라, 읽기 전용으로 열려면 TRUE, 쓰기도 하려면 FALSE를 지정하면 된다는 것을 쉽게 알 수 있다.
그런데 첫 번째 인자는 무엇인지 감을 잡기 가 어렵다. UAE랑 관련된 건지...
소스를 확인해 본 결과 TRUE로 주면 HKEY_LOCAL_MACHINE를 루트키로 사용하고, FALSE를 지정하면 HKEY_CURRENT_USER하게 되어 있었다.

CSettingsStore::CSettingsStore(BOOL bAdmin, BOOL bReadOnly) :
    m_bReadOnly(bReadOnly), m_bAdmin(bAdmin), m_dwUserData(0)
{
    m_reg.m_hKey = bAdmin ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
}

값을 읽을 경우는 메모리 누수 주의

값을 읽는 Read 메소드(함수)의 경우는 각각 다른 레지스트리의 타입에 쉽게 적용할 수 있게 5개로 오버로딩이 되어 있다.
(물론 Visual Studio 2008기준이고 2012에서는 14개로 늘어났다. MSDN에 따르면...)
주의해야 할 점은 BYTE 값을 읽을 경우 BYTE 포인터의 포인터를 넘겨주게 되어 있다. 따라서 내부적으로 동적할당을 해줄 가능성이 높다.
구현부 소스를 확인해 본 결과 역시 new를 이용해서 동적 할당을 하고 있었다.

BOOL CSettingsStore::Read(LPCTSTR lpszValueName, BYTE** ppData, UINT* pcbData)
{
    // ...
    if (m_reg.QueryBinaryValue(lpszValueName, NULL, (ULONG*)pcbData) != ERROR_SUCCESS || *pcbData == 0)
    {
        return FALSE;
    }
    *ppData = new BYTE [*pcbData];
    // ...
}

따라서 값 읽기가 성공을 했을 때 delete로 적절하게 메모리 해제를 하지 않는다면 메모리 누수가 생길 수 있다.

Detected memory leaks!
Dumping objects ->
{398} normal block at 0x00951E80, 234 bytes long.
Data: <_ ? ? _ U S B S > 5F 00 3F 00 3F 00 5F 00 55 00 53 00 42 00 53 00
Object dump complete.

또한 주의해야 할 점은 배열을 메모리 할당 했기 때문에 그냥 delete가 아닌 delete [] 를 사용해야 한다.

PBYTE pBuf = NULL;
UINT bufSize = 0;
BOOL bRes = setting.Read(volName, &pBuf, &bufSize);
if(bRes && pBuf!=NULL) {

    delete [] pBuf;

}
setting.Close();