CIni, Ini-file IO with a minimum of codelines

Environment: VC6 SP4, NT4 SP6,W98 SE, W2000 SP1

You know it takes lots of code lines when you use the API for storing data into an Ini-File. E.g. for just one double it would look like this:

// store
CString strTemp;
strTemp.Format("%g",m_dDouble);
WritePrivateProfileString("MySection",
                          "MyDouble",
                          strTemp,
                          "C:\\MyPath\\MyIni.ini");
// load
char pBuffer[256];
GetPrivateProfileString("MySection",
                        "MyDouble",
                        "1.23",
                        pBuffer,
                        256,
                        "C:\\MyPath\\MyIni.ini");
m_dDouble = atof(pBuffer);

With this CIni class, I tried to reduce the coding to a minimum. I usually use one function for reading and writing. (E.g. For these members of CMyClass)

int     m_nMember;
double  m_dMember;
CString m_strMember;
CPoint  m_arPoints[2];

The code for the ini file IO could be reduced to this:

void CMyClass::UpdateFromIni( bGet /*=TRUE*/ )
{
  CIni ini("C:\\MyPath\\MyIni.ini", "MySection" );
  ini.SER_GET( bGet, m_nMember );
  ini.SER_GETD( bGet, m_dMember, 1.23 );
  ini.SER_GET( bGet, m_strMember );
  ini.SER_ARR( bGet, m_arPoints, 2 );
}

The output will look like this:

[MySection]
m_nMember=0
m_nMember=1.23
m_strMember=
m_arPoints_0=(0,0)
m_arPoints_1=(0,0)

It supports overloaded functions for these standard types:

  • CString
  • short
  • int
  • WORD
  • DWORD
  • CPoint
  • CRect
  • float
  • double

and arrays of them:

  • CString*
  • short*
  • int*
  • WORD*
  • DWORD*
  • CPoint*
  • CRect*
  • float*
  • double*

Each function has the following parameters:

void CIni::SerGet(
  BOOL bGet,            // TRUE: Load from Ini,
                        // FALSE: Save to Ini
  LPCSTR szEntry,       // The Entry
  TYPE& type            // The type from the list above
//int nCount            // only the array versions:
                        // count of array elements to load/save
  LPCSTR szSection=NULL // An other value than NULL will effect
                        // all following entries
  TYPE default=0);      // 0 for numeric Types, "" for Strings

And to avoid coding the entry twice, there are 4 macros:

#define SER_GET(bGet,value) SerGet(bGet,value,#value)
#define SER_ARR(bGet,value,n) SerGet(bGet,value,n,#value)
#define SER_GETD(bGet,value) SerGet(bGet,value,#value,
                                    NULL,default)
#define SER_ARRD(bGet,value,n) SerGet(bGet,value,n,#value,
                                      NULL,default)

So my function typicaly contains a combination of this.

void CMyClass::UpdateFromIni( bGet /*=TRUE*/ )
{
  CIni ini( "" , "MyFirstSection" );//Default file name

  ini.SER_GETD( bGet, m_nMember, 42);
  ini.SER_GET( bGet, m_dMember );

  ini.SetSection("MyOtherSection");

  ini.SER_GET( bGet, m_strMeber );
  ini.SER_GETD( bGet, m_strOther, "Hello" );
  ini.SER_ARR( bGet, m_arPoints, 2 );
}

Using just a filename without a path, normaly causes the OS to store the Ini-file in the Windows directory.
To avoid this, the modul path will be insert in front of the filename by default.

Downloads

Download demo project – 17 Kb

Download source – 5 Kb

The latest versions may be found at:
www.schikos.de

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read