2010. 12. 15. 16:17

WritePrivateProfileString unicode encoding 지원하기

ini 파일을 사용하기 위해서, WritePrivateProfileString / GetPrivateProfileString을 사용합니다.
또한 웬만한 경우, _UNICDOE를 사용하여 WritePrivateProfileStringW(...)가 실제로 사용하게 됩니다.
여기에서 주의할 점은,

별다른 처리 없으면, ::WritePrivateProfileString(...)는 파일을 Unicode로 저장하지 않는다.

입니다. 즉, ::WritePrivateProfileString(...)의 lpString이 WCHAR로 되어 있더라도, 실제 저장된 ini를 hexa editor로 열어 보면 ANSI로 적혀졌음을 알 수 있습니다.
그렇기 때문에, ::WritePrivateProfileString(..., "특수문자들") 와 같은 경우는 자칫 ::GetPrivateProfileString(...) 하면 ???... 로 가져올 수 있습니다.

이를 해결하기 위해 WritePrivateProfileString(...)하기 전, 비어있는 ini를 만들고, bom 설정을 해주면 WritePrivateProfileString(...)은 비로소 제대로된 Unicode 문자열로 쓰게 됩니다.
(msdn에서는, If the file was created using Unicode characters, the function writes Unicode characters to the file. Otherwise, the function writes ANSI characters. 와 같이 설명되어 있습니다.)

bom 설정은 CreateNewFileAsUTF16(...)를 참고하시기 바랍니다. (little endian)
자세한 내용은 google등을 이용하시기 바랍니다.

아래 코드는 C:\info.ini에 [dat] val=을 각각 WritePrivateProfileString하고 GetPrivateProfileString을 하여 메시지창을 띄웁니다.
"ウェブ"를 쓰는 경우, 한글 XP, 일본어 XP에서 재대로 동작이 보장되었지만,
"초록생선"를 쓰는 경우 일본어 XP에서 재대로 동작하지 못하였습니다.
그리고,

1 번은 "ウェブ", 2번은 "초록생선", 3번은 bom 설정후 "초록생선"을 각각 쓰는 과정을 나타냅니다.

"ウェブ"는 read/write 성공입니다.


"초촉생선"은 read/write 실패입니다.


ini파일의 bom 설정 이후에 "초록생선"은 read/write 성공입니다.

즉, 다음과 같이 한줄 정리가 가능합니다

::WritePrivateProfileString(...) / ::GetPrivateProfileString(...)에서 경로명 같이 unicode 문자열이 ini 파일 내부에 들어갈 수 있는 경우, bom 설정을 해주고 ::WritePrivateProfileString(...)을 실행한다.

관련된 내용은 http://www.codeproject.com/KB/files/unicode_ini.aspx 에서 참고하시기 바랍니다.

#include "stdafx.h"
#include "BOM.h"

DWORD CreateNewFileAsUTF16(IN LPCTSTR lpszFilePath)
{
	HANDLE	hFile		= INVALID_HANDLE_VALUE;
	DWORD	wBOM		= 0xFEFF;
	DWORD	dwCbWritten	= 0;

	hFile = ::CreateFile(lpszFilePath, 
						 GENERIC_WRITE, 
						 0, 
						 NULL, 
						 CREATE_ALWAYS, 
						 FILE_ATTRIBUTE_NORMAL, 
						 NULL);
	if (INVALID_HANDLE_VALUE == hFile)
	{
		return ::GetLastError();
	}

	::WriteFile(hFile, 
				&wBOM, 
				sizeof(WORD), 
				&dwCbWritten, 
				NULL);

	::CloseHandle(hFile);
	hFile = INVALID_HANDLE_VALUE;

	return ERROR_SUCCESS;
}

int APIENTRY _tWinMain(HINSTANCE hInstance,
					   HINSTANCE hPrevInstance,
					   LPTSTR    lpCmdLine,
					   int       nCmdShow)
{
	TCHAR szVal[MAX_PATH] = {0,};

	// 1
	{
		::WritePrivateProfileString(TEXT("dat"), TEXT("val"), TEXT("ウェブ"), TEXT("C:\\info.ini"));
		::GetPrivateProfileString(TEXT("dat"), TEXT("val"), TEXT(""), szVal, MAX_PATH, TEXT("C:\\info.ini"));
		::MessageBox(NULL, szVal, TEXT("1"), MB_OK);
		::DeleteFile(TEXT("C:\\info.ini"));
	}

	// 2
	{
		::WritePrivateProfileString(TEXT("dat"), TEXT("val"), TEXT("초록생선"), TEXT("C:\\info.ini"));
		::GetPrivateProfileString(TEXT("dat"), TEXT("val"), TEXT(""), szVal, MAX_PATH, TEXT("C:\\info.ini"));
		::MessageBox(NULL, szVal, TEXT("2"), MB_OK);
		::DeleteFile(TEXT("C:\\info.ini"));
	}

	// 3
	{
		CreateNewFileAsUTF16(TEXT("C:\\info.ini"));
		::WritePrivateProfileString(TEXT("dat"), TEXT("val"), TEXT("초록생선"), TEXT("C:\\info.ini"));
		::GetPrivateProfileString(TEXT("dat"), TEXT("val"), TEXT(""), szVal, MAX_PATH, TEXT("C:\\info.ini"));
		::MessageBox(NULL, szVal, TEXT("3"), MB_OK);
		::DeleteFile(TEXT("C:\\info.ini"));
	}

	return 0;
}