삽질의 현장/- 윈도우 API

#008_WIndow_API_리소스 (Resource)

shovelman 2015. 9. 11. 16:40


안녕하세요 삽잡이입니다.

이번 시간에는 리소스에 대해서 알아보도록 하겠습니다.


리소스라는 단어는 이곳 저곳에서 굉장히 많이 사용되는 용어입니다.

리소스의 한글 뜻은 '자원'으로써 스타크래프트에서는 SCV가 캐는 미네랄이 바로 '자원'이죠...


아무튼... 

IT 분야에서 리소스란 '코드와 분리되어 실행 파일에 포함되는 데이터'라고 정의 할 수 있습니다...

코드는 리소스와 어떤 차이가 있기에 코드와 분리한다고 하는 것일까요?


우리가 프로그램을 만들게 되면 해당 프로그램은 바이너리 코드 .exe에 만들어집니다.

프로그램이란 무수히 많은 데이터와 명령어의 집합으로 구성 되어있습니다.

이 집합을 로직 코드로 나누어 

따로 데이터를 관리해보자는 취지에서 만들어진 개념이 바로 리소스입니다.


우선 리소스에 대해서 이야기하기전,

GUI에서는 UI를 관리하는 것이 매우 중요하다는 사실을 알아야됩니다.

UI 측면에서 데이터를 보게 될 때,

각 UI의 요소들은 해당 요소에대해서 연결된 데이터를 가지고 있습니다.


데이터 영역의 로직은 프로그래머가 작성하게 됩니다.

하지만, 사용자의 눈에 보이는 UI의 경우 그래픽 디자이너가 작성하게 되어있습니다.

즉, 프로그램 하나를 완성하기 위해서는 프로그래머와 디자이너의 시너지(협업)이 필요하다는 것입니다.

(물론, 제품을 하나 만들 때 이 둘의 역할만이 절대적으로 필요한 것은 아닙니다.)


프로그램은 모두 협업을 통해 이루어집니다.

아무리 프로그램을 잘 만들어놨다고 해도 우리눈에 보이게 되는 UI가 좋지 않다면

결국 그 프로그램은 좋아보이지 않는 결과를 초래합니다.

즉, 디자인 관점 또한 무시할 수 없다 이겁니다.

왜냐하면, 어플리케이션으로 말하자면 사용자와 대면하는 곳이 UI이기 때문입니다.

아무리 축구선수가 농구를 잘하게 된다 해도 농구선수보다 농구를 잘 할 수 없듯이, 

자기 전문 분야의 기술력을 무시할 수 없습니다.


이 말을 왜 하게 되었냐 하면, 

GUI가 만들어지면서 협업의 중요성이 더욱 높아지게 되었습니다.

이 이유는, 보이는 측면을 무시할 수 없게 되어 

디자이너의 능력이 절대적으로 필요한 시점이 찾아왔기 때문입니다.

하지만, UI가 중요하게 되었는데 

UI가 없다고 개발을 못하면 안되기때문에 독립적으로 개발 할 수 있는 환경이 제공되어야 됬습니다.

따라서 API에서는 해당 환경을 미흡하게나마 제공하게 된 것입니다.


그렇다면 API 측면에서 리소스에 대한 정의를 한번 생각해보려고 합니다.

API에서 리소스란, 그래픽 디자이너와 협업을 통해 만드는 UI를 말합니다.

이 말인 즉, 코드 즉, 동작방식(알고리즘)은 프로그래머가 담당하지만,

눈에 보이는 UI 측면은 그래픽 디자이너가 담당하기에 

서로 독립적으로 개발하고 구현할 수 있도록 만든 것이 API 리소스라는 것입니다.


API에서 리소스의 핵심은 

독립적으로 개발하기 위해 코드와 분리되어 존재할 수 있는 데이터이며,

코드에 포함될 수 있다는 것입니다.


원칙적으로 리소스의 개념이란 한정적으로 남아돌지 않고, 유한한 것을 뜻합니다.

컴퓨터 상의 자원은 일반적으로 어플리케이션들이 공유하고

OS가 관리하는 것들을 통칭하기 있습니다.

즉,컴퓨터에서 자원의 정의를 

시스템에게서 얻어 사용한 후 다시 돌려줘야하는 모든 것들을 이야기 한다는 것입니다.


왜 돌려줘야 할까요? 공유하기 때문입니다.

공유하지 않고 유한한 자원을 자시만 사용하게 된다면, 문제가 생기게 됩니다.

왜냐하면 자원은 한정적이기 떄문이지요...

(우리가 추후 알아볼 시스템 프로그래밍에서 배우는 내용들 중 자원에 대하여 많은 언급이 있을 것입니다.)


하지만, API에서 말하는 리소스는 그 자원이 아닙니다.

다시한번 말씀드리지만, API에서 자원은 코드와 분리해서 존재될 수 있는 데이터를 뜻합니다.


API는 이미 30여년 전에 만들어진 개념으로 그 당시 협업이라는 자체가 구체적이지 않았기 때문에 

API의 리소스는 완벽하게 독립적이라고 말하기는 힘듭니다.


아무튼... API에서 대표적인 리소스는 메뉴입니다.

사용자에게 Input을 받아들이고 명령을 실행하는 것을 메뉴라고 부릅니다.


물론, 다른 GUI에서도 이런 개념이 존재하기에

부족하지만 이번 시간을 통해 리소스에 대한 개념이 전해졌으면 좋겠군요...


어찌됬건 UI쪽을 개발하기 위해서 만들어 놓은 이 리소스 파일 

즉, .rc 파일은 컴파일 하게 되면 .res 파일로 만들어 집니다.

또한, 코드쪽을 개발하기 위해 .cpp 파일인 로직을 만들어내고, 

해당 파일을 컴파일하게 되면 .obj 파일이 만들어집니다.

이 모두를 묶어서 .exe 파일이 만들어지게 되는 것입니다.

즉, UI 분야는 리소스 컴파일러가, 로직은 코드 컴파일러가 만들어내는데 이를 .exe파일로 만드는 것입니다.



API 리소스에서 가장 중요한 것은 ID입니다.

리소스는 원래 코드에 포함되어 있어야 합니다. 

따라서, 독립적으로 만든 리소스를 코드 상에 사용할 수 있어야 하는 것입니다.

코드와 리소스가 소통할 줄을 알아야하는데 ID를 통해 소통을 하는 것입니다.


정리를 해볼까요?

리소스의 메뉴나 그 외 등등 모두 코드에서 만들 수 있는데 그렇게 하면

복잡해지고 시간도 많이 소요되기 때문에 분류를 했습니다.

따라서 리소스를 따로 만들었고, 리소스에서 만들어진 데이터를 코드로 가져와야할 필요성이 생긴 것이지요...

가져오는 방법이 바로 ID라는 것입니다.

즉, 코드와 리소스의 다리를 이어주는 것이 ID라는 것입니다...


그렇다면, API의 리소스 중 메뉴를 한번 살펴보도록 하겠습니다.



(해당 메뉴바에 써있는 이름은 메뉴들의 각 이름을 뜻합니다.)


메뉴를 선택했을 때 그에 맞는 Action이 발생하도록 하는 것이 리소스의 기능입니다.

메뉴 아이템을 누르게 되면 Action이 발생해야합니다.

이를 위해서는 메뉴 아이템의 속성 중 ID가 중요한 역할을 하게 됩니다.


우선, 코드상에서 메뉴를 가져오기 위해서는 

WNDCLASS에 정의한 내용 중에 lpszMenuName 부분을 설정해줘야 합니다.

그 전에 우선 메뉴 아이템의 ID와 메인 메뉴의 ID는 다르기 때문에 주의하셔야 합니다.

그렇다면, 메인 메뉴의 ID를 등록하도록 해보겠습니다.


이와 같은 메인 메뉴의 이름을 코드 상에 등록해주면 됩니다.



ID는 정수이기 때문에 형변환을 해줘야하는데 가시성을 위해서

윈도우에서는 형식을 변환시키는 메크로를 만들어 줬습니다.

바로, MAKEINTRESOURCE 메크로 입니다.


또한, 이처럼 ID의 정수를 정의한 리소스를 헤더에 포함시켜줘야 합니다.


반복해서 말씀드리지만,

리소스는 원래 코드에서 만들었어야하는데, 

리소스에서 메뉴를 만들고 코드에서 불러와 쓰는 방식을 사용하고 있습니다.

따라서 ID를 통해 불러 올 수 있는 것을 알게 되었습니다.


그렇다면 잠시 어떻게 그래픽 디자이너들과 협업을 할지 생각해보겠습니다.

감을 잡으셨겠지만, 리소스는 그래픽 디자이너가 만들고

서로 규약을 정의하여 UI와 반응을 서로 만들고 ID를 통해 적용시킴으로 협업을 진행하는 것이지요...


위에서 언급한 메뉴에 대해서 다시 언급해보도록 하겠습니다.

메뉴는 메뉴라는 리소스를 눌렀을때 무엇인가 Action을 하려고 만든 기능 아닌가요?

즉, 메뉴는 사용자의 Input을 받아 어떤 행동을 하려고 만들게 되는 것입니다.


윈도우 메시지 중 WM_COMMAND 메시지는 이러한 메뉴의 엑션을 위해

호출되는 메시지 입니다.


잠시 WM_COMMAND에 대해서 말씀을 드리자면,

해당 메시지는 두가지 경우에 발생하게 됩니다.


1. 사용자의 메뉴 혹은 단축키가 눌렸을때 발생한다.

2. 자식 윈도우(컨트롤)이 부모에게 자신의 상태를 알리기 위해서 발생한다.


우리는 현재 메뉴에 대해서 생각해보고 있으니 2번의 경우는 고려하지 않겠습니다.

WM_COMMAND 메시지가 발생하게 될때

wParam의 상위 워드로 메뉴가 눌렸는지 혹은 단축키가 눌렸는지에 대해 전달이 됩니다.

하위 워드로는 우리에게 중요한 ID가 전달됩니다.

lParam의 경우 사용하지 않습니다.


2번의 경우 고려하지는 않지만 잠시 전달되는 파라메터 값을 살펴보자면,

wParam의 상위 워드로는 알림에 대한 상태 즉, 통지 코드(Notification Message)가 전달 되고,

하위 워드는 1번의 경우와 동일하게 ID가 전달됩니다.

그리고 lParam에 자식의 윈도우 Handle이 전달되게 됩니다...


아무튼... 메뉴를 선택했을때에 대한 Action을 고려하기 위해서는

wParam의 ID를 신경써줘야겠군요...


재미있게 리소스에 대해 더 공부해보고 열심히 연습해봐야겠습니다!

이상 삽잡이였습니다!