API-리소스관련

1.리소스란?
 

프로그램은 코드데이터로 구성된다.

=>데이터는 프로그램의 처리 대상. 
   코드는 데이터를 처리하는 수단.

(데이터의 의미를 확장하여 코드가 아닌 모든것을 데이터라고 할 때 비트맵 , 아이콘 , 메뉴 , 문자열 등등 프로그램의 논리와 무관한 모든 것들이 데이터에 속한다. 이런 것들은 프로그램의 동작을 통제한다기 보다는 단순한 장식인 경우가 많다.)

 

도스 프로그래밍 에서는 이런 데이터를 만들고 관리하는 작업이 하나의 과정에 통합되어 있지만

윈도우즈 프로그래밍에서는 별도의 작업과정으로 분리하고 있다.

코드의 논리와 무관한 데이터들을 리소스 (Resource) 라고 하며

메뉴 , 비트맵 , 엑셀러레이터 , 문자열 , 아이콘 , 커서 등등이 여기에 속한다.

리소스들은 별도의 편집기로 만들어져 컴파일 되며 링크시에 실행파일에 결합된다.

이런 컴파일 과정은 API 나 MFC 에서나 모두 동일하다.

 

*.h + *.cpp = *.obj

*.ico + *.bmp + *.rc = *.res

*.obj + *.res = *.exe

 

윈도우즈 프로그래밍이 도스에서와 구별되는 큰 차이점 중 하나가 바로 리소스와 코드가 분리 되어있다는 점이다.

도스에서 게임을 하나 만들려면 코드를 작성하는 시간보다  
이미지나 비트맵을 작성하고 수정하는 시간이 더 많이 요구된다.

아이콘이나 비트맵들은 16진수 배열로 작성하거나 , 실행중에 파일을 읽어서 사용했었다.

콘솔환경에서 만들어진 게임을 보면 이런 거대한 배열이나 이미지 파일을 볼 수 있는데 느리고 불편했다
윈도우즈 환경에서는 리소스를 만드는 과정과 코딩과정이 분리되어 있어 여러가지 장점이 있다. 

 

[1] 디자이너와 프로그래머의 분담작업이 용이하다.
 

[2] 리소스를 수정하더라도 소스를 일일이 다시 컴파일하지 않고 리소스만 컴파일 하면 되고

       반대의 경우도 마찬가지 이므로 컴파일 속도가 현저히 빨라진다.

       이는 모듈 분할 컴파일 방식의 장점과도 같은데 리소스는 보통 덩치가 커서 컴파일이 느리며

       잘 바뀌지도 않으므로 매번 컴파일할 필요가 없다.
 

[3] 리소스의 재사용이 용이하다.
 

[4] 리소스는 실행중에 교체가 가능한 모듈이므로 상황에 따라 다른 형태의 리소스를 사용할 수 있따.

       이 기법을 사용하면 다국어 버전을 쉽게 만들 수 있으며 스킨 기능이나 플러그인도 비슷한 기법을 사용한다.

 

리소스의 종류에는

메뉴 , 비트맵 , 단축키 , 문자열 , 아이콘 , 커서 등등이 있으며

이 외에도 사용자가 나름대로 리소스를 만들어 사용할 수도 있다.

( 리소스 == 프로그램이 요구하는 대량의 데이터 )



2.rc파일
이제 리소스를 만들고 프로젝트에 포함시키는 기본작업에 대해 알아본다.


리소스의 소스 파일인 RC파일(.rc)은 메모장 등의 텍스트 편집기로 작성할 수 있는 텍스트 파일이다.

RC파일 에 사용하고자 하는 리소스의 종류 , 모양 등을 작성한 후

이 파일을 리소스 컴파일러로 컴파일 하면 RES 라는 이진파일이 생성되며

이 파일이 링크 과정에서 최종적으로 실행 파일에 합쳐진다.

 

리소스를 기술하는 RC파일을 작성하는데는 고유의 문법이 적용되며 이 문법이 비록 쉽기는 하지만 대충이라도 숙지하고 있어야 리소스 스크립트를 작성할 수 있는것이 원칙이었다. 아주 간단한 리소스 파일의 예를 든다면 다음과 같다.


MYMENU MENU

BEGIN

     POPUP"&FILE"

     BEGIN

          MENUITEM "&New", 101

          MENUITEM "&Open",102

     END

END

 

MYBITMAP BITMAP "ko.bmp"

 

MYACCELERATORS ACCELERATORS

BEGIN

     "A", 1, VIRTKEY , NOINVERT

     "Z", 9,  VIRTKEY , NOINVERT

END

 

사용된 문법이 직관적이긴 해도 생소하다.

HTML 보다 더 쉬운 수준이라 몇가지 예약어만 배우면 누구나 이 스크립트를 작성할 수 있다.

비주얼 C++ 같은 편리한 개발툴이 나오기 전에는 C소스를 작성하듯이

RC파일을 편집기로 직접 입력하였으며 리소스 파일의 작성문법도 알아야 했다.

리소스 파일을 만든 후 별도의 리소스 컴파일러를 사용하여 RC파일을 컴파일 하는 고정도 필요했다.

 

하지만 최근의 개발툴은 리소스 스크립트 문법을 몰라도 리소스 파일을 작성할 수 있는

위지윅 편집을 지원하므로 리소스 편집기를 사용할 경우 굳이 RC 파일의 문법을 몰라도 상관없다.

( 웹 편집기를 사용하면 상세한 HTML 문법을 몰라도 웹페이지를 만들 수 있는 것과 같다 )

또한 통합 개발 환경이 알아서 리소스 컴파일러를 호출하므로 개발과정에도 리소스의 컴파일에는 신경쓰지 않아도 된다.

 

그러나 아주 특수한 경우에는 가끔 이 파일을 열어서 직접 편집해야 하는 경우도 있다.

예를 들어 다국어 버전을 만들 때 양쪽의 ID 를 일치시킨다거나 일련의 컨트롤에 연속적인 ID 를 부여하고 싶을 때이다.

이런 경우에라도 resource.h 라는 헤더 파일이 수정대상이지 리소스 스크립트 자체는 편집할 필요가 거의 없다.

 

비주얼 C++ 에서는 별도의 분리된 리소스 편집기가 없으며 개발자 스튜디오 자체에 리소스 편집기가 통합되어 있다.

워크스페이스의 아래쪽에 리소스 뷰 라는 탭이 있으며 이 탭을 눌러 나타나는 페이지에서 리소스를 관리하고 편집한다.



3.리소스 사용하기

메뉴를 가진 프로그램을 작성하면서 리소스를 만드는 절차와 , 만들어진 리소스를 프로그램에서 사용하는 방법에 대해서 알아본다.일단 기본적인 소스를 만들었다는 가정하에  리소스를 만들어 본다.

 



3-1)리소스 만들기 ( 메뉴 )

 

기본 코드를 만들고 이제 메뉴 리소스를 만들어 붙인다.

아직 이 프로그램에는 사용하는 리소스가 하나도 없으므로 새로운 리소스 스크립트 파일을 만들어야 한다.

[ 새항목 추가 ]  대화상자를 열어서 리소스 파일 ( .rc ) 을 선택하고 파일명은 Menu.c 로 입력한다.
(또는 그냥 리소스를 추가하면 rc파일이 자동으로 생성된다.) 

 

 

리소스 뷰???
=> 
프로젝트에 포함되어 있는 리소스들의 목록을 계층적으로 보여주며

팝업 메뉴를 통해 새로운 리소스를 작성하거나 다른 프로젝트에 있는 리소스를 임포트하는 등의 
 
전반적인 리소스 관리를 할 수 있다.

리소스 뷰의 팝업 메뉴를 이용해서 ( All Resource ) 리소스를 추가할 수 있다.

 

 

 

 

 어떤 종류의 리소스를 만들 것인가를 묻는 대화상자이다.

이 대화상자에서 Menu 를 더블클릭하여 선택해본다.

그러면 리소스 뷰에 IDR_MENU1 라는 빈 메뉴 리소스가 생성되며

작업영역에는 메뉴를 편집할 수 있는 메뉴 편집기가 열린다.

 

 

메뉴편집기의 작업영역에는 빈칸만 하나 있다.

이 빈칸에 메뉴 이름을 써 넣으면 메뉴 항목이 만들어지며 항목을 더블클릭하면 속성 편집 윈도우가 따로 열린다.

 

 

빈칸에 File 메뉴가 만들어 졌고 ,

오른쪽과 아래쪽으로 새로운 빈칸이 두 개 생겼다. ( 자식메뉴 인듯 하다 )

이 빈칸에 새로운 메뉴 항목을 만들어 나가되

아래쪽으로 메뉴 항목을 만들려면 아래쪽의 빈칸을 사용하고

오른쪽으로 메뉴항목을 만들려면 오른쪽 빈칸을 사용한다.

 

아래쪽 빈칸을 선택해서 [ Menu1 ] 을 입력하면 속성창에 이 항목의 속성이 나타난다.

Caption 에는 방금 입력한 Menu1 이 입력되어 있고

ID 에는 디폴트로 ID_FILE_MENU1 이 입력되어 있다. 

 

 

Caption 은 사용자에게 보여질 메뉴의 이름이며 메뉴 리스트에 그대로 나타난다.

문자열일 뿐이므로 기호나 숫자 , 한글 까지 사용할 수 있다.

ID 는 프로그램에서 이 메뉴 항목을 지칭하는 이름이다.

변수나 함수의 이름과 같은 자격을 가지는 명칭 이므로 명칭을 만드는 규칙에 맞게 작성해야 한다.

즉 첫 문자를 숫자로 쓸 수 없고 , 한글을 써서도 안 되며 , 메뉴 항목끼리 이름이 중복되어서도 안된다.

관습적으로 메뉴 항목의 이름은 " ID_상위메뉴_캡션 " 의 형식을 따라 작성한다.

나머지 속성은 그대로 두도록 한다.

 

계속해서 아래쪽으로 Menu2 , Exit 메뉴 항목을 만들고 각각 ID 를 ID_FILE_MENU2 , ID_FILE_EXIT 로 지정한다.

여기까지 메뉴를 만들면 메뉴 편집기는 다음과 같아진다.

 

 


 

3-2_리소스를 코드에 삽입

 

만들어진 리소스를 프로젝트에서 사용하도록 코드를 수정한다.

Menu.cpp 를 열어서 다음과 같이 수정 또는 추가한다.

리소스를 추가하는 과정은 버전에 따라 조금씩 차이가 있지만

소스를 수정하는 과정은 어느 컴파일러에서나 동일하다.

  

 

 

 
우선 , resource.h 라는 헤더파일을 포함해야 하는데

이 파일에는 다음과 같이 우리가 만든 메뉴항목의 ID 가 정의되어 있다. 

이 파일은 리소스 편집기가 리소스 편집시에 작성하며 리소스를 편집하면 자동으로 같이 수정되므로 우리가 직접 편집할 필요는 없다. 리소스를 사용하는 소스파일에 포함시키기만 하면 된다. 

 


#define IDR_MENU1       101

#define ID_FILE_MENU1  40001

#define ID_FILE_MENU2  40002

#define ID_FILE_NEXT    40003

 

메뉴 항목의 ID 는 정수로 정의하되 사람이 일일이 정수값을 기억하기 곤란하므로 매크로 상수를 사용하여 ID를 정의 하고

메뉴 편집기는 사용자가 입력한 ID를 정수 매크로로 정의하여 resource.h 에 작성한다.

그래서 개발자는 속성편집기에서 메뉴의 ID 를 문자열 형태의 매크로 상수로 입력하고 resource.h 만 인클루드 하면 된다.


다음으로 WndClass 의 lpszMenuName 멤버에 아까 작성한 메뉴 이름인 IDR_MENU1 을 대입한다.

이때 숫자로 정의된 메뉴 이름을 문자열 형태로 바꾸기 위해 MAKEINTRESOURCE 매크로를 사용하였다.

윈도우에서 사용할 메뉴에 관한 정보를 가지는 lpszMenuName 은 문자열 변수이고

아까 작성한 메뉴의 ID 는 정수로 되어 있기 때문이다. 


리소스의 ID 는 문자열 또는 정수로 지정할 수 있다.

과거에는 리소스의 ID 를 "MainMenu" "PopUpMenu" 식으로 문자열로 된 이름을 붙였지만 ,

리소스 편집이 기계화가 된 요즘에는 문자열 보다는 숫자로 ID 를 주는 것이 더 편리해졌다.

사람은 문자열을 더 잘 구분하지만 , 기계가 다루기에는 숫자가 훨씬 효율적이기 때문이다.


그래서 리소스 편집기들은 리소스 ID 에 겹따옴표 없이 IDR_MENU 식으로 이름을 지정하면

이 이름을 resource.h 에 정수형의 매크로로 정의하고 사용되지 않는 정수를 배정한다.

정수 타입의 리소스 ID 를 문자열 포인터에 대입할 수 없으므로 적당히 캐스팅 해야 하는데

이 캐스팅을 대신 하는 매크로가 바로 MAKEINTRESOURCE 이다.


#define MAKEINTRESOURCEA(i) (LPSTR)((DWORD)((WORD)(i)))


매크로 정의를 보다시피 정수의 하위 16비트를  문자형 포인터 타입으로 강제 캐스팅하는 구문에 불과하다.

소스의 메뉴 지정문을 극단적으로 간단하게 기술하면 결국 (TCHAR*)IDR_MENU1 과 같을 뿐이다.

요즘은 리소스에 이름을 붙이는 경우가 없으므로 리소스를 쓸 때마다 늘상 이 매크로가 필요하다.

 

여기까지 작성하고다시 컴파일 해보면 리소스로 정의한 메뉴가 타이틀 바 아래쪽에 나타날 것이다.

그러나 아직 메뉴에 대한 코드가 작성되지 않았기 때문에 메뉴만 나타날 뿐 메뉴를 선택해도 아무런 반응이 없다.



 

3-3_이제 메뉴가 선택되었을 때의 프로그램 동작을 정의한다.

WndProc 부분을 추가하면 된다.

메뉴버튼을 눌렀을때의 반응 구현

 

 

 

이 코드에서는
메뉴 항목을 선택할 경우 WM_COMMAND 라는 메시지가 전달된다. 

메뉴를 누르면 메시지박스가 뜰 것이다.

 

 

.

종료 메뉴를 선택하면

Destroy Window 함수로 메인 윈도우를 파괴함으로써 프로그램을 종료한다.

메인 윈도우를 파괴하는 것은 정상적이고도 우아한 종료방법이며 PostQuitMessage 로 종료해서는 안된다



이 글을 공유하기

댓글

Designed by JB FACTORY