Click here to Skip to main content
15,895,084 members
Articles / Desktop Programming / MFC

S.I.V.: Simple registry config class

Rate me:
Please Sign up or sign in to vote.
3.00/5 (6 votes)
1 Nov 20044 min read 35K   912   15  
Simplicity Is Virtue: How to store your app's settings in Windows registry with minimum effort.
//************************************************************
//*
//*	RegSettings.cpp
//*
//*	RegSettings class implementation
//*
//*	DESCRIPTION:
//*		One MFC CObject derived class to implement a simple
//*		interface for storing app settings into registry.
//*
//*	ASSUMES:
//*		Only MFC and an average coder :-)
//*
//*	AUTHOR: T1TAN <t1tan@cmar-net.org>
//*
//*	COPYLEFT:
//*		Copyleft (C) T1TAN 2004 - 3827
//*		Copyleft (C) SprdSoft Inc.2004 - 3827
//*		FREE for (ab)use in any way except selling the code.
//*		Leave the headers be.
//*
//*	VERSIONS:
//*		VERSION		AUTHOR		DATE		NOTES
//*		-------		------		----		-----
//*		1.0			T1TAN		18/10/2004	initial version
//*
//*
//*	OTHER:
//*		Em well, nothing yet. Though, this is only a basic
//*		implementation, and there is MUCH that could be
//*		implemented, I believe this is a good start..(-:
//*
//************************************************************

#include "stdafx.h"
#include "RegSettings.h"

#include <shlwapi.h> // for SHDeleteKey
#pragma comment( lib, "shlwapi.lib" )

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

/*
	The one and only contructor.
	If you want to use flushing, set it here
*/
CRegSettings::CRegSettings( BOOL bUseFlushing /*= FALSE*/  )
{
	m_szAppName = _T("");
	m_szCompanyName = _T("");
	m_bUseFlushing = bUseFlushing;
}

CRegSettings::~CRegSettings()
{

}

BOOL CRegSettings::GetHKEY( LPCTSTR szKey, PHKEY hKey, BOOL bRead /*= FALSE*/ )
{
	CString clean_key = CleanKeyName( szKey );

	// we're always opening a key like this one
	// (assuming the company name is "SprdSoft"
	// and program is "Bullocks")
	//
	//		HKCU\Software\SprdSoft\Bullocks\Key_You_Want\Its_Subkey\ETC
	//
	CString the_key = _T("Software");

	/*
		You do need to use AT LEAST one of company/app name
	*/
	if ( m_szCompanyName.IsEmpty() == TRUE && m_szAppName.IsEmpty() == TRUE )
	{	// so you can extract it by CRegSettings::GetLastErrorText()
		SetLastErrorEx(ERROR_INVALID_DATA, NULL);
		return FALSE;
	}

	/*
		By checking each one of these (company/app name), we can make
		the thing work if you want to use only one of them.
	*/
	if ( m_szCompanyName.IsEmpty() == FALSE )
	{
		the_key += _T("\\");
		the_key += m_szCompanyName;
	}
	
	if ( m_szAppName.IsEmpty() == FALSE )
	{
		the_key += _T("\\");
		the_key += m_szAppName;
	}

	
	the_key += _T("\\");
	the_key += clean_key;

	LONG result = 0;

	if ( bRead == TRUE )
	{	// don't create it, just open existing
		result = RegOpenKeyEx(
					HKEY_CURRENT_USER,
					the_key,
					REG_OPTION_NON_VOLATILE,
					KEY_ALL_ACCESS,
					hKey );
	}
	else
	{	// open for writing, so create if it doesn't exist
		result = RegCreateKeyEx(
					HKEY_CURRENT_USER,
					the_key,
					0,							// reserved
					NULL,						// class
					REG_OPTION_NON_VOLATILE,	// default
					KEY_ALL_ACCESS,				// desired access
					NULL,						// security attributes
					hKey,						// result
					NULL );
	}

	if ( result == ERROR_SUCCESS )
		return TRUE;
	else
	{
		SetLastErrorEx(result, NULL);
		return FALSE;
	}
}


void CRegSettings::CloseHKEY( HKEY hKey )
{	
	if ( m_bUseFlushing == TRUE )
		RegFlushKey( hKey );

	RegCloseKey( hKey );	
}

/**************************************************
	We want to have a clear key name, for example:
		SprdSoft\\IronMaiden\\Eddie

	A key name like this one:
		\\SprdSoft\\BlackSabbath\\PlanetCaravan
	would be illegal because of the slash thingie
	at the beggining.
**************************************************/
CString CRegSettings::CleanKeyName( LPCTSTR szKey )
{
	CString mod;
	mod = szKey;

	// remove extra spaces, tabs and whatever
	mod.TrimLeft();
	mod.TrimRight();

	// enables us to use it in two ways:
	// Write( "Settings\\Aerodynamics\\Pilot", "Moo", "Goo" );
	// OR
	// Write( "Settings/Aerodynamics/Pilot", "Moo", "Goo" );
	//
	mod.Replace( _T('/'), _T('\\') );

	// we cannot have these double slashes
	// so just in case..
	mod.Replace( _T("\\\\"), _T("\\") );

	// cannot start or end with this, or we'll get an error
	mod.TrimLeft(_T('\\'));
	mod.TrimRight(_T('\\'));

	return mod;
}

/*
	One of the ways to get a nice flashing and also
	VERY amusing MessageBoxes
*/
CString CRegSettings::GetLastErrorText()
{
	LONG err_code = GetLastError();

	char txt[2048];
	FormatMessage(
		FORMAT_MESSAGE_FROM_SYSTEM,
		NULL, err_code, 0, txt, 2048, NULL );
	
	CString sz(txt);
	return sz;
}

/*
	Deleting a key seemed simple, but(t)...

	IMPORTANT:	1. If you haven't used app name, you MUST use
					bDeleteCompany when deleting...
				2. If you haven't used company name, and you
					do set bDeleteCompany to TRUE, it is ignored
*/
BOOL CRegSettings::DeleteAll( BOOL bDeleteCompany /*= FALSE*/ )
{
	// first check that we have at least one of these...
	if ( m_szCompanyName.IsEmpty() == TRUE && m_szAppName.IsEmpty() == TRUE )
	{
		SetLastErrorEx(ERROR_INVALID_DATA, NULL);
		return FALSE;
	}

	HKEY hKey;
	CString the_key = "";
	the_key = _T("Software");

	// if the company name is not empty...
	if ( m_szCompanyName.IsEmpty() == FALSE )
	{
		if ( bDeleteCompany == TRUE )
		{	// we need to delete the entire company subtree
			LONG res = RegOpenKeyEx(
				HKEY_CURRENT_USER,
				the_key,
				REG_OPTION_NON_VOLATILE,
				KEY_ALL_ACCESS,
				&hKey );

			if ( res != ERROR_SUCCESS )
				return FALSE;

			if ( SHDeleteKey( hKey, m_szCompanyName ) == ERROR_SUCCESS  )
				return TRUE;
			else
				return FALSE;
		}
		else
		{	// just add it up..
			the_key += "\\";
			the_key += m_szCompanyName;
		}
	}

	if ( m_szAppName.IsEmpty() == FALSE )
	{	// now we're opening like this:
		// HKCU\Software\Company Inc
		LONG res = RegOpenKeyEx(
			HKEY_CURRENT_USER,
			the_key,
			REG_OPTION_NON_VOLATILE,
			KEY_ALL_ACCESS,
			&hKey );

		if ( res != ERROR_SUCCESS )
			return FALSE;

		if ( SHDeleteKey( hKey, m_szAppName ) == ERROR_SUCCESS  )
			return TRUE;
		else
			return FALSE;
	}

	return FALSE;
}

///////////////////////////////////////////////////////////////////////
// And now for something completely different...
// Id est: a bunch of Write(..) and Read(..) overloads
// to support common data types in MFC
//
// They are all quite simple, and quite the same, with exception of
// those related to REG_BINARY and REG_SZ data. The only difference
// is that we need to calculate their size in a different manner.
// Check these out for more info:
//		BOOL Write( ..., ..., LPCTSTR value );
//		BOOL Write( ..., ..., const LPVOID value, UINT size );
//		BOOL Read( ..., ..., LPTSTR value, ULONG& size );
//		BOOL Read( ..., ..., LPVOID value, ULONG& size );
///////////////////////////////////////////////////////////////////////
BOOL CRegSettings::Write( LPCTSTR szKey, LPCTSTR szName, UCHAR value )
{
	HKEY hKey;

	if ( GetHKEY( szKey, &hKey ) == FALSE )
		return FALSE;

	LONG result =
		RegSetValueEx( hKey, szName, NULL, REG_SZ, (UCHAR*)&value, sizeof(UCHAR) );

	CloseHKEY( hKey );

	if ( result == ERROR_SUCCESS )
		return TRUE;
	else
	{
		SetLastErrorEx(result, NULL);
		return FALSE;
	}
}

BOOL CRegSettings::Write( LPCTSTR szKey, LPCTSTR szName, char value )
{
	HKEY hKey;

	if ( GetHKEY( szKey, &hKey ) == FALSE )
		return FALSE;

	LONG result =
		RegSetValueEx( hKey, szName, NULL, REG_SZ, (UCHAR*)&value, sizeof(char) );

	CloseHKEY( hKey );

	if ( result == ERROR_SUCCESS )
		return TRUE;
	else
	{
		SetLastErrorEx(result, NULL);
		return FALSE;
	}
}

BOOL CRegSettings::Write( LPCTSTR szKey, LPCTSTR szName, USHORT value )
{
	HKEY hKey;

	if ( GetHKEY( szKey, &hKey ) == FALSE )
		return FALSE;

	LONG result =
		RegSetValueEx( hKey, szName, 0, REG_SZ, (UCHAR*)&value, sizeof(USHORT) );

	CloseHKEY( hKey );

	if ( result == ERROR_SUCCESS )
		return TRUE;
	else
	{
		SetLastErrorEx(result, NULL);
		return FALSE;
	}
}

BOOL CRegSettings::Write( LPCTSTR szKey, LPCTSTR szName, short value )
{
	HKEY hKey;

	if ( GetHKEY( szKey, &hKey ) == FALSE )
		return FALSE;

	LONG result =
		RegSetValueEx( hKey, szName, 0, REG_SZ, (UCHAR*)&value, sizeof(short) );

	CloseHKEY( hKey );

	if ( result == ERROR_SUCCESS )
		return TRUE;
	else
	{
		SetLastErrorEx(result, NULL);
		return FALSE;
	}
}

BOOL CRegSettings::Write( LPCTSTR szKey, LPCTSTR szName, UINT value )
{
	HKEY hKey;

	if ( GetHKEY( szKey, &hKey ) == FALSE )
		return FALSE;

	LONG result =
		RegSetValueEx( hKey, szName, 0, REG_DWORD, (LPBYTE)&value, sizeof(UINT) );

	CloseHKEY( hKey );

	if ( result == ERROR_SUCCESS )
		return TRUE;
	else
	{
		SetLastErrorEx(result, NULL);
		return FALSE;
	}
}

BOOL CRegSettings::Write( LPCTSTR szKey, LPCTSTR szName, int value )
{
	HKEY hKey;

	if ( GetHKEY( szKey, &hKey ) == FALSE )
		return FALSE;

	LONG result =
		RegSetValueEx( hKey, szName, 0, REG_DWORD, (LPBYTE)&value, sizeof(int) );

	CloseHKEY( hKey );

	if ( result == ERROR_SUCCESS )
		return TRUE;
	else
	{
		SetLastErrorEx(result, NULL);
		return FALSE;
	}
}

BOOL CRegSettings::Write( LPCTSTR szKey, LPCTSTR szName, ULONG value )
{
	HKEY hKey;

	if ( GetHKEY( szKey, &hKey ) == FALSE )
		return FALSE;

	LONG result =
		RegSetValueEx( hKey, szName, 0, REG_DWORD, (LPBYTE)&value, sizeof(ULONG) );

	CloseHKEY( hKey );

	if ( result == ERROR_SUCCESS )
		return TRUE;
	else
	{
		SetLastErrorEx(result, NULL);
		return FALSE;
	}
}

BOOL CRegSettings::Write( LPCTSTR szKey, LPCTSTR szName, long value )
{
	HKEY hKey;

	if ( GetHKEY( szKey, &hKey ) == FALSE )
		return FALSE;

	LONG result =
		RegSetValueEx( hKey, szName, 0, REG_DWORD, (LPBYTE)&value, sizeof(long) );

	CloseHKEY( hKey );

	if ( result == ERROR_SUCCESS )
		return TRUE;
	else
	{
		SetLastErrorEx(result, NULL);
		return FALSE;
	}
}

BOOL CRegSettings::Write( LPCTSTR szKey, LPCTSTR szName, float value )
{
	HKEY hKey;

	if ( GetHKEY( szKey, &hKey ) == FALSE )
		return FALSE;

	LONG result =
		RegSetValueEx( hKey, szName, 0, REG_DWORD, (LPBYTE)&value, sizeof(float) );

	CloseHKEY( hKey );

	if ( result == ERROR_SUCCESS )
		return TRUE;
	else
	{
		SetLastErrorEx(result, NULL);
		return FALSE;
	}
}

BOOL CRegSettings::Write( LPCTSTR szKey, LPCTSTR szName, double value )
{
	HKEY hKey;

	if ( GetHKEY( szKey, &hKey ) == FALSE )
		return FALSE;

	LONG result =
		RegSetValueEx( hKey, szName, 0, REG_BINARY, (LPBYTE)&value, sizeof(double) );

	CloseHKEY( hKey );

	if ( result == ERROR_SUCCESS )
		return TRUE;
	else
	{
		SetLastErrorEx(result, NULL);
		return FALSE;
	}
}

BOOL CRegSettings::Write( LPCTSTR szKey, LPCTSTR szName, LPCTSTR value )
{
	HKEY hKey;

	if ( GetHKEY( szKey, &hKey ) == FALSE )
		return FALSE;

	// according to Platform SDK
	// we need string length + 1 for the Terminator II (the liquid one)
	int length = _tcslen( value );
	length += 1;

	LONG result =
		RegSetValueEx( hKey, szName, 0, REG_SZ, (LPBYTE)value, length );

	CloseHKEY( hKey );

	if ( result == ERROR_SUCCESS )
		return TRUE;
	else
	{
		SetLastErrorEx(result, NULL);
		return FALSE;
	}
}

/*
	The only write function in desperate need of "size" variable.
*/
BOOL CRegSettings::Write( LPCTSTR szKey, LPCTSTR szName, LPVOID value, UINT size )
{
	HKEY hKey;

	if ( GetHKEY( szKey, &hKey ) == FALSE )
		return FALSE;

	LONG result =
		RegSetValueEx( hKey, szName, 0, REG_BINARY, (LPBYTE)value, size );

	CloseHKEY( hKey );

	if ( result == ERROR_SUCCESS )
		return TRUE;
	else
	{
		SetLastErrorEx(result, NULL);
		return FALSE;
	}
}


BOOL CRegSettings::Read( LPCTSTR szKey, LPCTSTR szName, UCHAR& value )
{
	HKEY hKey;

	if ( GetHKEY( szKey, &hKey, TRUE ) == FALSE )
		return FALSE;

	ULONG size = sizeof(UCHAR);

	LONG result =
		RegQueryValueEx( hKey, szName, 0, NULL, (LPBYTE)&value, &size );

	CloseHKEY( hKey );

	if ( result == ERROR_SUCCESS )
		return TRUE;
	else
	{
		SetLastErrorEx(result, NULL);
		return FALSE;
	}
}

BOOL CRegSettings::Read( LPCTSTR szKey, LPCTSTR szName, char& value )
{
	HKEY hKey;

	if ( GetHKEY( szKey, &hKey, TRUE ) == FALSE )
		return FALSE;

	ULONG size = sizeof(char);

	LONG result =
		RegQueryValueEx( hKey, szName, 0, NULL, (LPBYTE)&value, &size );

	CloseHKEY( hKey );

	if ( result == ERROR_SUCCESS )
		return TRUE;
	else
	{
		SetLastErrorEx(result, NULL);
		return FALSE;
	}
}

BOOL CRegSettings::Read( LPCTSTR szKey, LPCTSTR szName, USHORT& value )
{
	HKEY hKey;

	if ( GetHKEY( szKey, &hKey, TRUE ) == FALSE )
		return FALSE;

	ULONG size = sizeof(USHORT);

	LONG result =
		RegQueryValueEx( hKey, szName, 0, NULL, (LPBYTE)&value, &size );

	CloseHKEY( hKey );

	if ( result == ERROR_SUCCESS )
		return TRUE;
	else
	{
		SetLastErrorEx(result, NULL);
		return FALSE;
	}
}

BOOL CRegSettings::Read( LPCTSTR szKey, LPCTSTR szName, short& value )
{
	HKEY hKey;

	if ( GetHKEY( szKey, &hKey, TRUE ) == FALSE )
		return FALSE;

	ULONG size = sizeof(short);

	LONG result =
		RegQueryValueEx( hKey, szName, 0, NULL, (LPBYTE)&value, &size );

	CloseHKEY( hKey );

	if ( result == ERROR_SUCCESS )
		return TRUE;
	else
	{
		SetLastErrorEx(result, NULL);
		return FALSE;
	}
}

BOOL CRegSettings::Read( LPCTSTR szKey, LPCTSTR szName, UINT& value )
{
	HKEY hKey;

	if ( GetHKEY( szKey, &hKey, TRUE ) == FALSE )
		return FALSE;

	ULONG size = sizeof(UINT);

	LONG result =
		RegQueryValueEx( hKey, szName, 0, NULL, (LPBYTE)&value, &size );

	CloseHKEY( hKey );

	if ( result == ERROR_SUCCESS )
		return TRUE;
	else
	{
		SetLastErrorEx(result, NULL);
		return FALSE;
	}
}

BOOL CRegSettings::Read( LPCTSTR szKey, LPCTSTR szName, int& value )
{
	HKEY hKey;

	if ( GetHKEY( szKey, &hKey, TRUE ) == FALSE )
		return FALSE;

	ULONG size = sizeof(int);

	LONG result =
		RegQueryValueEx( hKey, szName, 0, NULL, (LPBYTE)&value, &size );

	CloseHKEY( hKey );

	if ( result == ERROR_SUCCESS )
		return TRUE;
	else
	{
		SetLastErrorEx(result, NULL);
		return FALSE;
	}
}

BOOL CRegSettings::Read( LPCTSTR szKey, LPCTSTR szName, ULONG& value )
{
	HKEY hKey;

	if ( GetHKEY( szKey, &hKey, TRUE ) == FALSE )
		return FALSE;

	ULONG size = sizeof(ULONG);

	LONG result =
		RegQueryValueEx( hKey, szName, 0, NULL, (LPBYTE)&value, &size );

	CloseHKEY( hKey );

	if ( result == ERROR_SUCCESS )
		return TRUE;
	else
	{
		SetLastErrorEx(result, NULL);
		return FALSE;
	}
}

BOOL CRegSettings::Read( LPCTSTR szKey, LPCTSTR szName, long& value )
{
	HKEY hKey;

	if ( GetHKEY( szKey, &hKey, TRUE ) == FALSE )
		return FALSE;

	ULONG size = sizeof(long);

	LONG result =
		RegQueryValueEx( hKey, szName, 0, NULL, (LPBYTE)&value, &size );

	CloseHKEY( hKey );

	if ( result == ERROR_SUCCESS )
		return TRUE;
	else
	{
		SetLastErrorEx(result, NULL);
		return FALSE;
	}
}

BOOL CRegSettings::Read( LPCTSTR szKey, LPCTSTR szName, float& value )
{
	HKEY hKey;

	if ( GetHKEY( szKey, &hKey, TRUE ) == FALSE )
		return FALSE;

	ULONG size = sizeof(float);

	LONG result =
		RegQueryValueEx( hKey, szName, 0, NULL, (LPBYTE)&value, &size );

	CloseHKEY( hKey );

	if ( result == ERROR_SUCCESS )
		return TRUE;
	else
	{
		SetLastErrorEx(result, NULL);
		return FALSE;
	}
}

BOOL CRegSettings::Read( LPCTSTR szKey, LPCTSTR szName, double& value )
{
	HKEY hKey;

	if ( GetHKEY( szKey, &hKey, TRUE ) == FALSE )
		return FALSE;

	ULONG size = sizeof(double);

	LONG result =
		RegQueryValueEx( hKey, szName, 0, NULL, (LPBYTE)&value, &size );

	CloseHKEY( hKey );

	if ( result == ERROR_SUCCESS )
		return TRUE;
	else
	{
		SetLastErrorEx(result, NULL);
		return FALSE;
	}
}

/*
	Same thing from above applies here, we deffinitely need to know
	the size of receiving bugger. Buffer. Whatever.
*/
BOOL CRegSettings::Read( LPCTSTR szKey, LPCTSTR szName, LPVOID value, ULONG& size )
{
	HKEY hKey;

	if ( GetHKEY( szKey, &hKey, TRUE ) == FALSE )
		return FALSE;

	LONG result =
		RegQueryValueEx( hKey, szName, 0, NULL, (LPBYTE)value, &size );

	CloseHKEY( hKey );

	if ( result == ERROR_SUCCESS )
		return TRUE;
	else
	{
		SetLastErrorEx(result, NULL);
		return FALSE;
	}
}

/*
	Unlike other Read functions, our dear programmer needs to specify the size
	of bugger. I mean, buffer. Check out RegQueryValueEx in MSDN or 
	Platform SDK if you need to know more.
*/
BOOL CRegSettings::Read( LPCTSTR szKey, LPCTSTR szName, LPTSTR value, ULONG& size )
{
	HKEY hKey;

	if ( GetHKEY( szKey, &hKey, TRUE ) == FALSE )
		return FALSE;

	LONG result =
		RegQueryValueEx( hKey, szName, 0, NULL, (LPBYTE)value, &size );

	CloseHKEY( hKey );

	if ( result == ERROR_SUCCESS )
		return TRUE;
	else
	{
		SetLastErrorEx(result, NULL);
		return FALSE;
	}
}


By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Croatia Croatia
A software developer for the masses..

Comments and Discussions