Download source files - 8 Kb
Download demo project - 11 Kb
Introduction
cout << "Birthday: " << dt << "; Height: " << d;
is better than the equivalent printf statement. It is easier to remember than the printf format
specifiers, less error prone and the operators << and >> can be used for different streams ( cout,files,CArchive).
This article presents stream operations for the registry. The above example would be written to
the registry by:
regStream << RegVal("Birthday",dt) << RegVal("Height",d);
All arithmetic data types and
the MFC value types CPoint, CSize, CRect, CSize,
COleDateTime and CFont are supported. This article merely presents
a new interface to an already existing CRegistry class by Robert Pittenger,
which can be found on this site.
Two stream variants are supported. CRegStream<CRegBaseHumanReadable> stores all registry entries
as human readable strings. The second stream variant supported is CRegStream<CRegBaseGeneral>. It uses all the
registry datatypes that are also used by Robert Pittenger's class. The first interface is mainly intended for the
application settings in which users of your software prefer readable registry entries over encoded ones.
Interface
Registry entries are Name/Value pairs. Each operand of an inserter
or extractor >> must be a Name/Value pair. The function
RegVar(LPCTSTR lpszEntry,T& t,const T& defaultVal= T()) returns a
Name/Value pair as an operand of >>, whereas
RegVal(LPCTSTR lpszEntry,const T& t) returns a Name/Value pair which
is suitable for the operand . The macros RVAR and RVAL
allow you to leave out the lpszEntry parameter. This is because the Name is constructed
from the C++ variable name supplied to the macro.
template<class T>
RegVariable<T> RegVar(LPCTSTR lpszEntry,T& t,const T& defaultVal= T())
{ return RegVariable<T>(lpszEntry,t,defaultVal);}
template<class T>
RegValue<T> RegVal(LPCTSTR lpszEntry,const T& t)
{ return RegValue<T>(lpszEntry,t); }
#define RVAL(v) RegVal(RegTrim(#v),v)
#define RVAR(v) RegVar(RegTrim(#v),v)
#define RVAR1(v) RegVar(RegTrim(#v),v,defaultVal)
template<class CRegBase>
class CRegStream : public CRegBase
{
public:
CRegStream(HKEY hKey=0):m_bSuccess(true)
{ if( hKey!=0 ){ SetRootKey(hKey);}}
bool Success() { return m_bSuccess;}
};
class CRegBaseGeneral : public CRegistry
{
};
class CRegBaseHumanReadable : public CRegistry
{
};
Example Usage
In the following example, human readable register entries are written to
the HKEY_CURRENT_USER registry part and encoded register entries are
written to the HKEY_LOCAL_MACHINE registry part. Afterwards the
entries are read from both parts and checked for equality.
int main(int argc,TCHAR* argv[])
{
float fFloatEps= FLT_EPSILON; CString strTitle= "Sir";
COleDateTime dtBirthday(1970,10,10,10,15,30); CPoint pt;
BOOL bOk;
CRegStream<CRegBaseHumanReadable> reg_user(HKEY_CURRENT_USER);
if( bOk=reg_user.SetKey("Software\\RegStreamDemo\\Settings",TRUE) ){
reg_user << RVAL(fFloatEps) << RVAL(strTitle) << RVAL(dtBirthday)
<< RegVal(_T("$-Point"),CPoint(3,5));
}
CRegStream<CRegBaseGeneral> reg_machine(HKEY_LOCAL_MACHINE);
if( bOk&& (bOk=reg_machine.SetKey("Software\\RegStreamDemo\\Settings",TRUE)) ){
reg_machine << RVAL(fFloatEps) << RVAL(strTitle) << RVAL(dtBirthday)
<< RegVal(_T("$-Point"),CPoint(3,5));
}
if( bOk ){
reg_user >> RVAR(fFloatEps) >> RVAR(strTitle) >> RVAR(dtBirthday)
>> RegVar(_T("$-Point"),pt);
float floatEps1; CString strTitle1; CPoint pt1;
reg_machine >> RegVar(_T("FloatEps"),floatEps1) >> RegVar(_T("Title"),strTitle1)
>> RegVar(_T("$-Point"),pt1);
ASSERT(fFloatEps==floatEps1 && strTitle==strTitle1 && pt==pt1);
}
}
Implementation Details
The implementation resides entirely in the header file "RegStream.h". It consists
of template types and functions. It's the first time that I used member template
functions. They helped a lot in reducing the coding task. The resulting code is
remarkably uniform, easy to understand and read.