2011. 1. 2. 23:47

binary의 resource를 file로 저장하기

.exe가 실행될 때 임의의 data나 module이 필요한 경우가 많을 겁니다.
만일, 배포를 간단하게 하기 위해, .exe만 사용하는 경우를 생각해 봅시다. 물론 .exe는 설치본이 아닙니다.
그럴려면, 필요한 파일을 .exe의 resource에 넣어 compile하고, .exe 실행 시작시, 해당 resource를
파일로 저장하면 해결될 듯 합니다. (용량관계상, 해당 파일(들)은 윈도우 기본 압축 방식인 cab으로 압축된 것을
사용할 수 있습니다.)

이런 경우에 유용한 아래 함수를 공유합니다.
아래 함수는 .exe 혹은 주어진 바이너리의 resource를 file로 저장합니다.

DWORD
ResourceToFile
IN UINT uResourceId
IN LPCTSTR lpszPathName
IN LPCTSTR lpszType
IN OPTIONAL LPCTSTR lpszModuleFullPath)

  • 리턴 : Win32 Error Code (ERROR_SUCCESS 성공)
  • uResourceId : 파일로 저장할 resource id
  • lpszPathName : 대상 파일 경로
  • lpszType : 대상 resource의 type (::FindResource(...) API의 lpType값. MSDN 참고)
  • lpszModuleFullPath : 모듈 명. Full 경로를 넣어야 보안상 문제가 없음. NULL 가능.

중간에 AfxGetInstanceHandle() 함수를 사용하고 있는데, 그로 인해 MFC를 사용하는 모듈로 되었습니다.
물론, 해당 부분을 NULL로 하면 .exe의 resource를 가져오는 것올, MFC 의존성을 제거할 수 있습니다.


와 같은 경우,
ResourceToFile(IDR_CAB, TEXT("CAB"), szTmpFile, NULL);
와 같이 사용할 수 있습니다.

// lpszType : FindResource의 lpType 값
DWORD ResourceToFile(IN UINT uResourceId, IN LPCTSTR lpszPathName, IN LPCTSTR lpszType, IN OPTIONAL LPCTSTR lpszModuleFullPath)
{
	DWORD	dwRtnValue		= ERROR_SUCCESS;
	HMODULE	hModule			= NULL;
	HANDLE	hResInfo		= NULL;
	HANDLE	hResource		= NULL;
	LPBYTE	lpBuf			= NULL;
	BOOL	bLoadLibrary	= FALSE;
	DWORD	dwCbSize		= 0;
	DWORD	dwCbWritten		= 0;
	HANDLE	hFile			= INVALID_HANDLE_VALUE;

	if ((NULL == lpszPathName) || (NULL == lpszType))
	{
		dwRtnValue = ERROR_INVALID_PARAMETER;
		ASSERT(FALSE);
		goto FINAL;
	}

	if (NULL != lpszModuleFullPath)
	{
		hModule = ::LoadLibrary(lpszModuleFullPath);
		if (NULL == hModule)
		{
			dwRtnValue = ::GetLastError();
			ASSERT(FALSE);
			goto FINAL;
		}
		bLoadLibrary = TRUE;
	}
	else
	{
		hModule = AfxGetInstanceHandle();
	}

	hResInfo = ::FindResource(hModule, MAKEINTRESOURCE(uResourceId), lpszType);
	if (NULL == hResInfo)
	{
		dwRtnValue = ::GetLastError();
		ASSERT(FALSE);
		goto FINAL;
	}

	hResource = ::LoadResource(hModule, (HRSRC)hResInfo);
	if (NULL == hResInfo)
	{
		dwRtnValue = ::GetLastError();
		ASSERT(FALSE);
		goto FINAL;
	}

	lpBuf = (LPBYTE)::LockResource(hResource);
	if (NULL == lpBuf)
	{
		dwRtnValue = ERROR_RESOURCE_FAILED;
		ASSERT(FALSE);
		goto FINAL;
	}

	dwCbSize = ::SizeofResource(hModule, (HRSRC)hResInfo);
	if (NULL == dwCbSize)
	{
		dwRtnValue = ERROR_EMPTY;
		ASSERT(FALSE);
		goto FINAL;
	}

	hFile = ::CreateFile(lpszPathName, 
						 GENERIC_WRITE, 
						 0, 
						 NULL, 
						 CREATE_ALWAYS, 
						 FILE_ATTRIBUTE_NORMAL, 
						 NULL);
	if (INVALID_HANDLE_VALUE == hFile)
	{
		dwRtnValue = ::GetLastError();
		ASSERT(FALSE);
		goto FINAL;
	}

	::WriteFile(hFile, lpBuf, dwCbSize, &dwCbWritten, NULL);

FINAL:

	if (INVALID_HANDLE_VALUE != hFile)
	{
		::CloseHandle(hFile);
		hFile = INVALID_HANDLE_VALUE;
	}

	if ((TRUE == bLoadLibrary) && (NULL != hModule))
	{
		::FreeLibrary(hModule);
		hModule = NULL;
	}

	return dwRtnValue;
}