Get/WritePrivateProfileString 함수를 사용하면 ini파일을 읽고 쓰고 할 수 있다.
GetPrivateProfileString 함수에 대응하는 이름은 SetPrivateProfileString 일텐데 이런 이름의 함수는 없고
대신 WritePrivateProfileString 함수가 있다.
32-버전의 윈도우에서는 레지스트리를 사용할 것을 권장하지만 ini 파일은 메모장 같은 텍스트 편집기로 쉽게 편집이 가능하기에 환경설정 같은 것을 하기에 좋다.
Windows CE로 포팅을 할 일이 있었는데 CE 5.0에 함수가 없었다.
인터넷을 검색해보니 '꼬마늑대의 골방' 블로그에서 이미 만들어 놓으신 것이 있었다.
그 외에도 크로스 플랫폼을 위해 SimpleIni 가 있었다.
약간 수정을 하여 사용하는 실행파일(예. some.exe)의 이름과 똑같은 ini파일(some.ini)에 알아서 사용하도록 하였다.
GetModuleFileName 함수를 이용하였고, 실행파일 이름이 바뀌면 자동으로 ini 파일도 바뀌도록 구현이 된 것.
꼬마늑대님이 만드신 함수는 파일이름을 받게끔 되어 있는데 따라서 그 인자는 사라짐.
<win_ce_ini.h>
BOOL SaveToFile(LPCTSTR lpSection, LPCTSTR lpKeyName, LPCTSTR lpValue);
BOOL LoadFromFile(LPCTSTR lpSection, LPCTSTR lpKeyName, LPCTSTR lpDefault, LPTSTR lpReturnedString, DWORD nSize);
<win_ce_ini.cpp>
BOOL GetIniFilename(LPTSTR filename, DWORD dwLength)
{
DWORD dw = GetModuleFileName(NULL,filename,dwLength);
if(dw!=0) { // SUCCESS
filename[dw-3] = _T('i');
filename[dw-2] = _T('n');
filename[dw-1] = _T('i');
return TRUE;
} else {
dw = GetLastError();
CString msg;
msg.Format(_T("Failed to Get INI Filename from module (%u)"), dw);
AfxMessageBox(msg, MB_OK | MB_ICONSTOP);
return FALSE;
}
}
BOOL SaveToFile(LPCTSTR lpSection, LPCTSTR lpKeyName, LPCTSTR lpValue)
{
CString out;
CString str;
TCHAR ch;
bool search = true;
bool app = false;
bool find = false;
int state = 0;
int idx = 0;
// Get INI filename
TCHAR lpFileName[MAX_PATH] = {0};
if(!GetIniFilename(lpFileName, MAX_PATH)) return FALSE;
FILE* fp = _tfopen(lpFileName, _T("rt"));
// Open file
if (fp == NULL)
search = false;
else
{
while (1 == _ftscanf(fp, _T("%c"), &ch))
out += ch;
fclose(fp);
}
for (int i = 0; search && i < out.GetLength(); i++)
{
ch = out[i];
switch (state)
{
case 0: // 첫글자
if (ch == _T(';'))
state = 10; // 주석 넘기기
else if (ch == _T('['))
{
idx = 0;
str = _T("");
state = 20; // AppName 비교
}
break;
case 10:
if (ch == _T('\n'))
state = 0;
break;
case 20:
if (ch == _T(']'))
{
if (str.Compare(lpSection) == 0)
{
idx = 0;
str = _T("");
state = 30;
app = true;
}
else
state = 10;
}
else
str += ch;
break;
case 30: // AppName이 일치한 후
if (ch == _T('\n'))
state = 31;
break;
case 31:
if (ch == _T('['))
{ // 다른 AppName이 시작한다면 여기에 삽입
str.Format(_T("%s=%s\n"), lpKeyName, lpValue);
out.Insert(i, str);
search = false;
find = true;
}
else if (ch == _T(';'))
state = 30;
else
{
idx = 0;
str += ch;
state = 32;
}
break;
case 32:
if (ch == _T('='))
{
if (str.Compare(lpKeyName) == 0)
{
idx = 0;
str = _T("");
state = 40;
}
else
{
str = _T("");
state = 30;
}
}
else
str += ch;
break;
case 40: // KeyName이 일치한 후
if (ch == _T('\n'))
{
out.Delete(i - str.GetLength(), str.GetLength());
out.Insert(i - str.GetLength(), lpValue);
search = false;
find = true;
}
else
str += ch;
break;
}
}
if (!find) // AppName도KeyName도찾지못했다면
{
if (out.GetLength() > 0)
{
ch = out[out.GetLength()-1];
if (ch != _T('\n'))
out += _T('\n');
}
if (!app)
{
str.Format(_T("[%s]\n"), lpSection);
out += str;
}
str.Format(_T("%s=%s\n"), lpKeyName, lpValue);
out += str;
}
fp = _tfopen(lpFileName, _T("wt"));
if (fp == NULL)
return FALSE;
_ftprintf(fp, out);
fclose(fp);
return TRUE;
}
BOOL LoadFromFile(LPCTSTR lpSection, LPCTSTR lpKeyName, LPCTSTR lpDefault, LPTSTR lpReturnedString, DWORD nSize)
{
TCHAR ch;
bool search = true;
bool find = false;
int state = 0;
int idx = 0;
// Get INI filename
TCHAR lpFileName[MAX_PATH] = {0};
if(!GetIniFilename(lpFileName, MAX_PATH)) return FALSE;
// Open file
FILE* fp = _tfopen(lpFileName, _T("rt"));
if (fp == NULL)
search = false;
while (search && 1 == _ftscanf(fp, _T("%c"), &ch))
{
switch (state)
{
case 0: // 첫글자
if (ch == _T(';'))
state = 10; // 주석 넘기기
else if (ch == _T('['))
{
idx = 0;
lpReturnedString[0] = 0;
state = 20; // AppName 비교
}
break;
case 10:
if (ch == _T('\n'))
state = 0;
break;
case 20:
if (ch == _T(']'))
{
lpReturnedString[idx++] = 0;
if (_tcscmp(lpReturnedString, lpSection) == 0)
{
idx = 0;
lpReturnedString[0] = 0;
state = 30;
}
else
state = 10;
}
else
lpReturnedString[idx++] = ch;
break;
case 30:
if (ch == _T('\n'))
state = 31;
break;
case 31:
if (ch == _T('['))
search = false;
else if (ch == _T(';'))
state = 30;
else
{
idx = 0;
lpReturnedString[idx++] = ch;
state = 32;
}
break;
case 32:
if (ch == _T('='))
{
lpReturnedString[idx++] = 0;
if (_tcscmp(lpReturnedString, lpKeyName) == 0)
{
idx = 0;
lpReturnedString[0] = 0;
state = 40;
}
else
state = 30;
}
else
lpReturnedString[idx++] = ch;
break;
case 40:
if (ch == _T('\n'))
{
lpReturnedString[idx++] = 0;
search = false;
find = true;
}
else
lpReturnedString[idx++] = ch;
break;
}
}
if (!find)
_tcscpy(lpReturnedString, lpDefault);
if (fp != NULL)
fclose(fp);
return _tcslen(lpReturnedString);
}
Back