Programming - cpueblo.com

[웹글] 사용자 정의 리소스의 생성과 사용


글쓴이 : 유광희 날짜 : 2007-09-07 (금) 17:46 조회 : 16366
프로젝트 공장: MFC 자료실 (개발자 스튜디오/Developer Studio)

사용자 정의 리소스의 생성과 사용


MFC 인덱스
DevStudio 인덱스


목차

  1. 서론
  2. 사용자 정의 리소스 만들기
  3. 사용자 정의 리소스 사용하기
  4. 예제 소스
  5. 정리

1. 서론
메뉴, 툴바, 대화상자, 비트맵, 아이콘, 커서, ... 리소스 편집기를 사용하여 만들수 있는 리소스들이다. 그러면 리소스는 이런것들로 제한되는 것일까? 물론 아니다. 프로그래머는 원하는 어떤 종류의 리소스도 만들어 저장할 수 있다. 예를들어 사운드 파일이나 기타 문서 파일을 리소스에 포함시켜 사용할 수도 있다.

여기서는 MS ACCESS의 DB 파일인 MDB 형식의 파일(*.mdb)을 리소스에 포함시키고 프로그램 내에서 리소스를 불러 동일한 파일을 복사하는 방법을 예로들어 사용자 정의 리소스를 생성하고 사용하는 방법에 대해 설명한다.



2. 사용자 정의 리소스 만들기
① [Insert] - [Resource...] 메뉴를 실행한 후 나타난 대화상자에서 "Import..." 버튼을 누르거나 워크스페이스 창의 리소스 탭에서 아이템을 선택한 후 오른쪽 마우스 버튼을 눌러 나타난 컨텍스트 메뉴의 "Import..." 를 선택한다.

② 파일선택 대화상자가 나타나면 리소스에 추가할 대상 파일을 선택하고 "확인" 버튼을 누른다.
파일선택 대화상자가 사라진 후엔 다음과 같은 대화상자가 나타난다.

이것은 "비트맵", "아이콘"과 같은 리소스의 타입을 요구하는 대화상자인데 추가하는 리소스가 MDB 형식의 파일이므로 편의상 MDB라고 입력을 했다.
또한 이전에 선택한 파일이 "mainform.mdb" 임이 나타나 있다.

현재 리소스 타입을 입력하는 edit 콘트롤 밑에 있는 리스트 박스는 비어있지만 다음부턴 MDB 타입이 목록으로 나타나게 되므로 선택만 해주면 된다.

입력이 끝났으면 "OK" 버튼을 누른다.

③ 이제 워크스페이스의 리소스 탭엔 "MDB" 타입 리소스 폴더가 생기고 그 아래 IDR_MDB1 리소스가 추가된다.

오른쪽 창엔 추가된 파일의 내용이 마치 옛날 DOS 유틸리티 였던 PC-TOOLS나 노턴 유틸리티의 파일 편집기에서 볼 수 있었던 2진 파일 형태로 나타난다.
(물론 여기서도 직접 편집이 가능하지만 MDB 파일의 형식을 모르므로 수정해선 안된다.)

리소스의 ID인 IDR_MDB1의 수정을 원한다면 해당 리소스를 선택한 후, 오른쪽 마우스로 컨텍스트 메뉴를 불러 [Properties]를 실행하여 나타난 대화상자에서 해주면 된다.

이런 식으로 몇개든지 추가할 수 있다.



3. 사용자 정의 리소스의 사용하기
① 리소스 찾기

    HRSRC FindResource( HINSTANCE hModule, LPCTSTR lpszName, LPCTSTR lpszType )

win32 API의 FindResource() 함수는 실행모듈이 가진 리소스를 검색하는데 사용하며 검색이 성공하면 리소스의 핸들을 반환해 준다. 실패면 NULL을 반환

첫번째 인자는 리소스를 가진 모듈의 인스턴스 핸들이다. 만약 실행파일이 리소스를 가지고 있다면 전역함수인 AfxGetInstanceHandle()를, DLL 모듈이 리소스를 가지고 있다면 LoadLibrary( "*.dll" ) 을 사용하여 인스턴스를 구할 수 있다.
두번째 인자는 리소스의 이름을 포함하는 NULL로 끝나는 문자열 포인터인데 리소스의 ID로 사용한 명칭이 된다. 만약 리소스 ID가 문자열로 지정되지 않고 앞에서 했던 것처럼 IDR_MDB1 식으로 상수를 사용했다면 MAKEINTRESOURCE() 매크로를 사용해야 한다.
세번째 인자는 리소스의 타입을 의미하는 문자열 (NULL로 끝나는)의 포인터이다.

리소스 파일 (*.rc)을 텍스트 형식으로 열어보면 다음과 같은 표현을 찾을 수 있을 것이다. 비교를 위해 아래줄엔 아이콘을 정의한 리소스 표현식을 보였다.


// MDB 리소스 타입
IDR_MDB1        MDB    DISCARDABLE   "res\\\\mainform.mdb"

// 아이콘 리소스의 예
IDR_MAINFRAME   ICON   DISCARDABLE   "res\\\\tt.ico"
② 리소스 로드하기

    HGLOBAL LoadResource( HINSTANCE hModule, HRSRC hResInfo )

리소스를 찾았으면 메모리로 읽어 두어야 한다. 이때는 API 함수인 LoadResource()를 사용한다. 작업이 성공하면 리소스가 로드된 메모리 블록의 핸들이 리턴된다. 실패면 NULL을 반환

첫번째 인자는 리소스를 가진 모듈의 인스턴스 핸들이고
두번째 인자는 FindResource() 함수가 반환해 준 리소스의 핸들이다. (리소스 검색엔 FindResourceEx() 도 사용할 수 있다. 이것은 특정 언어의 리소스를 검색하는 점만 빼면 FindResource()와 동일하다)

③ 메모리 잠그기와 해제

    LPVOID LockResource( HGLOBAL hglb )

리소스가 메모리에 로드되면 API 함수인 LockResource()로 메모리를 잠근다. 성공하면 잠겨진 메모리의 포인터가 반환되는데 이는 메모리에 놓인 리소스 데이터의 첫 바이트의 어드레스 이다. 실패하면 NULL이 반환된다.

인자엔 LoadResource()가 반환해 준 값을 사용하면 된다.

잠겨진 메모리를 해제하는 함수는 UnLockResource()인데 32bit 응용 프로그램에선 사용할 필요가 없다. 그 만큼 win95에선 메모리 관리가 수월한 것이다.

④ 리소스의 크기 알아내기

    DWORD SizeofResource( HINSTANCE hModule, HRSRC hResInfo )

설명하고 있는 예제에선 리소스로 저장한 파일을 복사하게 되는데 대개의 파일 복사 함수들이 원본 파일의 크기를 필요로 하므로 리소스의 크기를 알아내야 할 필요가 있다. 이 때 API 함수인 SizeofResource()를 사용한다. 반환값은 Byte 단위의 리소스 크기이다. 크기를 알아내지 못하면 '0'을 반환한다.

#주의 :API 라이브러리엔 이 함수가 반환해준 크기값이 실제 리소스 크기보다 클 수도 있으므로 이 값에 의존하지 말라고 씌어 있는데 예제의 테스트 결과는 만족스러웠다. 그러나 그렇더라도 부담스럽기는 마찬가지이므로 사용에 신중을 기할 것.



4. 예제 소스
예제를 위해 MDB 타입의 리소스로 여러개의 MDB 형식 파일을 import 했고 각각의 리소스는 IDR_MDBn 식으로 ID 상수를 지정했다.

예제는 MDB 파일 리소스를 불러 복사하는 함수이며 함수의 인자로 복사하려는 리소스 파일의 ID와 복사로 생성되는 파일의 이름을 준다.


BOOL CopyMdbFile( int nFileID, CString strTarget )
{
   HANDLE hResInfo, hRes;
   LPSTR lpRes;

   HINSTANCE hInst = AfxGetInstanceHandle();// LoadLibrary( "ecr.exe" );
   if ( hInst == NULL ) return FALSE;

   // 실행파일이 가진 MDB 파일 리소스를 찾아 가져온다. (메모리에 읽어둔다.)
   hResInfo = ::FindResource( hInst, MAKEINTRESOURCE( nFileID ), "MDB" );
   hRes     = ::LoadResource( (HMODULE) hInst, (HRSRC) hResInfo );
   
   if ( hRes == NULL )
   {
      AfxMessageBox( "리소스를 찾을 수 없거나 불러올 수 없습니다." );
      return FALSE;
   }
   
   // 리소스를 위한 전역 메모리를 잠근다. 이 때 리턴되는 값은 메모리상에서의
   // 리소스 시작 포인터이다.
   lpRes = (LPSTR) ::LockResource( hRes );

   if ( lpRes == NULL )
   {
      AfxMessageBox( "메모리를 할당할 수 없습니다." );
      return FALSE;
   }

   // 파일을 만들고 리소스의 크기를 구해 MDB 파일 내용을 모두 기록한다.
   CFile file( (LPCTSTR) strTarget,
               CFile::modeCreate | CFile::modeWrite | CFile::typeBinary );
   file.Write( (void*) lpRes, SizeofResource( hInst, (HRSRC) hResInfo ) );
   file.Close();
   
   // 잠겨진 메모리를 해제한다. (win32 기반에선 호출하지 않아도 된다.)
   //::UnlockResource( hRes );

   return TRUE;
}

파일복사를 위해 MFC의 CFile 클래스를 사용하였다.
먼저 CFile 클래스의 생성자를 통해 인자로 주어진 파일명으로 쓰기모드, 바이너리 타입으로 파일을 만든다. 그리고 만들어진 파일에 Write() 멤버함수를 사용하여 메모리에 로드된 리소스를 모두 쓰고 파일을 닫으면 작업은 끝난다.



5. 정리
사용자 정의 리소스를 만들고 사용하는 방법을 간단히 정리하면 다음과 같다.

HINSTANCE hInst;
HANDLE    hF, pF;
LPSTR     lpRes;

// 리소스를 가진 모듈의 인스턴스를 구한다.
hInst = LoadLibrary( "abc.dll" );

// 리소스를 찾는다.
pF = FindResource( hInst, "MYRESOURCE", "MYRESOURCETYPE" );

// 리소스를 로드한다.
hF = LoadResource( hInst, pF );

// 메모리를 잠근다.
lpRes = LockResource( hF );

// lpRes를 파일처럼 사용한다.
..............

// LoadLibrary()를 사용하여 DLL을 로드했다면...
FreeLibrary( hInst );



DevStudio 인덱스 위로


ⓒ copyright 1998~ bamsaram, Project Factory