CIni, Ini-file IO with a minimum of codelines
Environment: VC6 SP4, NT4 SP6,W98 SE, W2000 SP1
// 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 KbDownload source - 5 Kb
The latest versions may be found at:
www.schikos.de







Comments
how to delete section
Posted by Legacy on 03/19/2003 12:00amOriginally posted by: Hardy
Hi,
Would you like to tell how to delete the whole section?
Thanks a lot!
ReplyHardyCao
Great
Posted by Legacy on 04/24/2002 12:00amOriginally posted by: vladimir
It is very easy to use and implement.
ReplyThanks !!!
problem with windows98
Posted by Legacy on 03/22/2002 12:00amOriginally posted by: Dian Suharto
Hi,
I am trying to create init file to keep data info. I know, it is better to use registry, but with init file you can put init file together with data in one distribute file.
The problem is: it is run well on XP, 2000, but windows98 (second edition).
In windows98, when we read from init file, using GetPrivateProfileString() or GetPrivateProfileInt(), the value is somehow delayed. I must keep trying to read it (sometime up to 1 minute) until I got the correct value.
But if I open the same directory where the init file reside, and refresh the directory, the correct value will come after refreshing the directory.
Again, in 2000 and XP the program run well without any delay.
Does anybody find similar problem?
Please help.
Thank you.
Best regards, Dian Suharto.
Replywant to use as database file
Posted by Legacy on 10/29/2001 12:00amOriginally posted by: Anuj
How can I use it as the database file. I want to add 'n' no of lines. Is it possible if yes how ?
ReplyComments / bug report?
Posted by Legacy on 10/14/2001 12:00amOriginally posted by: cpp
1) Bug? In the function:
/*static*/ void CIni::AddModulPath(CString& strFileName,BOOL bModulPath /*= TRUE*/)
{
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
_splitpath( strFileName, drive, dir, fname, ext );
if( ! drive[0] )
{
//PathCanonicalize(..) doesn't work with for all Plattforms !
CString strModule;
if( bModulPath )
GetModuleFileName(NULL,strModule.GetBuffer(MAX_INI_BUFFER),MAX_INI_BUFFER);
else
GetCurrentDirectory(MAX_INI_BUFFER,strModule.GetBuffer(MAX_INI_BUFFER));
strModule.ReleaseBuffer();
_splitpath( strModule, drive, dir, fname, ext );
strModule = drive;
strModule+= dir;
strModule+= strFileName;
strFileName = strModule;
}
}
_splitpath removes the last subdirectory and puts it in fname,
because GetCurrentDirectory returns the path without a "\" at the end.
This problem can be solved by appending "\" before calling _splitpath, e.g. by
adding
strModule.ReleaseBuffer();
strModule.TrimRight('\\');
strModule.TrimRight('/');
strModule += "\\";
to the else statement (like the author has already done in the GetDefaultIniFile method).
Is this the reason why it "doesn't work with for all Plattforms"?
2) I suggest to save CRects in the ini file with the parameters in the same order as in
the CRect constructor CRect( int left, int top, int right, int bottom ).
3) A general comment/suggestion: it is a good idea to prefix calls to global functions with "::".
ReplyThis makes it easier for other programmers (and for yourself in a few months)
to read the code, and it prevents the compiler from calling a class method with the same name.
Stringification..cool, but...
Posted by Legacy on 10/04/2001 12:00amOriginally posted by: Jeff Schiller
I didn't even know about pre-processor stringification, so I'm grateful for this article for showing me that.
However, I was confused until I looked up http://gcc.gnu.org/onlinedocs/cpp_3.html#SEC17 and understood what stringification is all about. Then I looked at your source. Your source is ok, but I think your article needs a correction :
#define SER_GET(bGet,value) SerGet(bGet,value,#value)
void CIni::SerGet(BOOL bGet,
LPCSTR szEntry,
TYPE& type,
...);
- the macro is correct, but the CIni::SerGet declaration here has the value and the entry arguments swapped (as I said, this is correct in code, the article just needs to be corrected).
Jeff Schiller
Reply