Click here to Skip to main content
15,881,882 members
Articles / Desktop Programming / MFC

A Simple Class to Read and Write INI Files

Rate me:
Please Sign up or sign in to vote.
3.08/5 (16 votes)
30 Nov 2006CPOL1 min read 107.9K   4.8K   43  
This class is a thin MFC wrapper around Win32 API for reading/writing INI files.
// IniFile.cpp : implementation file
//

#include "stdafx.h"
#include "IniFileClass.h"
#include "IniFile.h"

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


/////////////////////////////////////////////////////////////////////////////
// CIniFile

CIniFile::CIniFile(LPCTSTR	strIniFileName,		// [in] new file name
				   INT		iMaxStringLength)	// [in] max length of a string that can be wtritten/read to/from the INI file by this instance
	: m_MAXSTRLEN(iMaxStringLength)
{
	SetIniFileName(strIniFileName);
}


CIniFile::~CIniFile()
{	
}


/////////////////////////////////////////////////////////////////////////////
// CIniFile operations

// PURPOSE: Get the name of the INI file.
CString	CIniFile::GetIniFileName()
{
	return m_strFileName ;
}

// PURPOSE: Set the name of the INI file.
void 
CIniFile::SetIniFileName(LPCTSTR lpIniFileName)	// [in] new file name
{
	m_strFileName = lpIniFileName;
}

// PURPOSE: Get the status of the ini file.  
//			This can be used, for example, to check the existence of the file.
BOOL 
CIniFile::GetStatus(CFileStatus& rStatus)	// [out] A reference to a user-supplied CFileStatus structure that will receive the status information.
{
	BOOL bRetVal = FALSE;
	bRetVal = CFile::GetStatus(m_strFileName, rStatus);
	return bRetVal;
}


// PURPOSE:			Create a new section.
// NOTE:	If the INI file doesn't exist, this method creates it.
//			::WritePrivateProfileSection() can create keys with duplicate names.  That can be viewed asa bug,
BOOL		// TRUE, if the API function call was successful.  FALSE, if there was an error.  To get extended error information, call ::GetLastError(). 
CIniFile::WriteSection(LPCTSTR lpSection,	// [in] name of the new section
					   LPCTSTR lpData)		// [in] for the new section.  See help for the ::WritePrivateProfileSection(...) function.
{
	BOOL bRetVal = FALSE;
	bRetVal = ::WritePrivateProfileSection(lpSection, lpData, m_strFileName);
	return bRetVal;
}

// PURPOSE:	Write string data to the INI file
BOOL		// TRUE, if the API function call was successful.  FALSE, if there was an error.  To get extended error information, call ::GetLastError(). 
CIniFile::WriteString(LPCTSTR lpSection,	// [in] section
					  LPCTSTR lpKey,		// [in] key. If key with this name doesn't exist, it's created.
					  LPCTSTR lpString)		// [in] String to be written into the file.  If this parameter is NULL, the key pointed to by the lpKeyName parameter is deleted.
{
	ASSERT(lpString == NULL || strlen(lpString) < m_MAXSTRLEN);
	return ::WritePrivateProfileString(lpSection, lpKey, lpString, m_strFileName);
}

// PURPOSE:	Write an integer (signed) to the INI file
BOOL		// TRUE, if the API function call was successful.  FALSE, if there was an error.  To get extended error information, call ::GetLastError(). 
CIniFile::WriteNumber(LPCTSTR lpSection, 	// [in] section name
					  LPCTSTR lpKey, 		// [in] key name
					  INT iValue)			// [in] integer value to be written to the INI file
{
	CString	str;
	str.Format("%d", iValue);
	return WriteString(lpSection, lpKey, str);
}

// PRUPOSE: Write the data into the specified key in the INI file.
BOOL		// TRUE, if the API function call was successful.  FALSE, if there was an error.  To get extended error information, call ::GetLastError(). 
CIniFile::WriteStruct(LPCTSTR lpSection,	// [in] pointer to section name
					  LPCTSTR lpKey,		// [in] pointer to key name
					  LPVOID lpStruct,		// [in] pointer to buffer that contains data to add
					  UINT iSizeStruct)		// [in] size, in bytes, of the buffer
{
	BOOL bRetVal = FALSE;
	bRetVal = ::WritePrivateProfileStruct(lpSection, lpKey, lpStruct, iSizeStruct, m_strFileName);
	return bRetVal;
}

// PURPOSE:	Write a float to the INI file.
BOOL		// TRUE, if the API function call was successful.  FALSE, if there was an error.  To get extended error information, call ::GetLastError(). 
CIniFile::WriteNumber(LPCTSTR	lpSection,	// [in] section name
					  LPCTSTR	lpKey,		// [in] key name
					  FLOAT		fValue)		// [in] floating point value to be written to the INI file
{
	CString	str;
	str.Format("%f", fValue);
	return WriteString(lpSection, lpKey, str);
}

// PURPOSE:	Remove a key from a specified section.
BOOL 
CIniFile::RemoveKey(LPCTSTR lpSection,		// [in] section name
					LPCTSTR lpKey)			// [in] key name
{
	return WriteString(lpSection, lpKey, NULL);	
}


// PURPOSE:	Read an integer to the INI file.
// NOTE:	The MSDN article on ::GetPrivateProfileInt(...) says: "If the value of the key is less than zero, the return value is zero."
//			However, ::GetPrivateProfileInt returns negative integers just fine.
UINT
CIniFile::GetInt(LPCTSTR lpSection,			// [in] section name
				 LPCTSTR lpKey,				// [in] key name
				 const INT iDefaultValue)	// [in] default value, which is returned, if the key is not found
{
	UINT iRet = ::GetPrivateProfileInt(lpSection, lpKey, iDefaultValue, m_strFileName);
	// ::GetLastError() is of no use here, because ::GetPrivateProfileInt() doesn't set an error-code.
	return iRet;
}

// PURPOSE:	Read a string from the INI file.
BOOL		// TRUE, if successful.  FALSE otherwise.
CIniFile::GetString(LPCTSTR lpSection,		// [in] section name
					LPCTSTR lpKey,			// [in] key name
					CString& strRet,		// [out] CString that receives the tring from the INI file
					LPCTSTR lpDefault)		// [in] default string, which is copied into strRet, if the key is not found.  NOTE: this pointer can't be NULL.
{
	ASSERT(lpDefault != NULL);
	ASSERT(strlen(lpDefault) < m_MAXSTRLEN);
	return CIniFile::GetString(lpSection, lpKey, strRet, lpDefault, m_MAXSTRLEN);
}

// PURPOSE:	Read a string from the INI file. (Helper function.)
// NOTE:	The calling code should check if strRet == lpDefault.
BOOL		// TRUE, if API call successful (incl. the case, when strRet == lpDefault).  
			// FALSE otherwise (incl. memory exception
CIniFile::GetString(LPCTSTR lpSection,		// [in] section name
					LPCTSTR lpKey,			// [in] key name
					CString& strRet,		// [out] CString that receives the tring from the INI file
					LPCTSTR lpDefault,		// [in] default string, which is copied into strRet, if the key is not found.  NOTE: this pointer can't be NULL. 
					const DWORD iSize)		// [in] buffer size
{	
	LPTSTR pBuffer;
	TRY
	{
		pBuffer = strRet.GetBuffer(iSize);		
	}
	CATCH(CMemoryException, pExc)	// GetBuffer() can throw a memory exceprion
	{
		THROW(pExc);				// rethrow
		return FALSE;
	}
	END_CATCH

	memcpy(pBuffer + iSize - 2, "xx",2);	// initialize the last 2 characters on the buffer with something other than \0
	DWORD iRet = ::GetPrivateProfileString(lpSection, lpKey, lpDefault, pBuffer, iSize, m_strFileName);
	ASSERT(iRet < iSize);
	BOOL bRet = (memcmp(pBuffer + iSize - 2, "\0\0", 2) != 0);	// check the last 2 characters of the buffer.
	strRet.ReleaseBuffer();	
	return bRet;
}

// PURPOSE:	Read an integer to the INI file.
FLOAT
CIniFile::GetFloat(LPCTSTR lpSection,		// [in] section name
				   LPCTSTR lpKey,			// [in] key name
				   const FLOAT fDefaultValue) // [in] default value, which is returned, if the key is not found, or if there's a memory exception
{
	const int MAXFLOATDIGS = 512;			// maximum number of digits that a floating point numebr can have.
	CString strRet, strDefault;
	strDefault.Format("%f", fDefaultValue);	// alternatinely, the default could be a non-numeric character, which would be checked with ?: in the return line
	BOOL bRet = CIniFile::GetString(lpSection, lpKey, strRet, strDefault, MAXFLOATDIGS);
	return ( bRet ? atof(strRet) : fDefaultValue );
}

// PURPOSE:	Read a struct from the INI file
BOOL
CIniFile::GetStruct(LPCTSTR lpSection,		// [in] section name 		  
					LPCTSTR lpKey, 			// [in]	key name	  
					LPVOID	lpRetStruct,	// [out] pointer to thye return buffer
					const UINT iSizeStruct) // [in] size of the return buffer
{
	ASSERT(lpRetStruct != NULL);
	ASSERT(iSizeStruct > 0);
	return ::GetPrivateProfileStruct(lpSection, lpKey, lpRetStruct, iSizeStruct, m_strFileName);
}

// PURPOSE:	Get the list of section names from the INI file.
void	
CIniFile::GetSectionNames(CStringList& lstSectionNames)	// [out] array of section name strings
{
	// Get the section names through an API function call.
	LPTSTR lpRetBuff = new CHAR[m_MAXSTRLEN];
	DWORD iRetVal = ::GetPrivateProfileSectionNames(lpRetBuff, m_MAXSTRLEN, m_strFileName);
	
	// Parse out the individual names and store them in the list
	for (LPCTSTR p = lpRetBuff; *p != '\0'; p += strlen(p) + 1)
	{
		lstSectionNames.AddTail(p);		
	}	
	delete [] lpRetBuff;
}

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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Systems Engineer Prolitech
United States United States
doing business as Prolitech
Redwood City, CA

blog (mostly technical)
http://prolifictec.com/blog/index.html

Comments and Discussions