Message Map 사용

API 2009. 1. 22. 10:13

메시지 맵이란 무엇인가?


메시지 맵을 이해 하기 전에 먼저 WIN32 API가 어떤 방식으로 구동 되는 지를 알아야 한다.  윈도우 GUI프로그래밍 언어인 WIN32 API는

메시지 처리방식으로 프로그램이 움직인다.

메시지 처리방식이란 런타임중 환경의 변화등이 있었을때 예를 들어 키보드를 눌렀다거나 화면에 변화가 왔다거나 하는 등의 변화가 있을때

운영체제인 윈도우로 부터 메시지가 송신되고 우리가 만든 프로그램에서 그메시지를 처리하는 방식으로 프로그램이 움직이게 된다.

API에는 이 메시지 처리를 담당하는 함수가 존재하는데 그것을 메시지 처리 프로시저라고도  한다.

메시지 처리 프로시저의 프로토타입(함수 원형)은  다음과 같다.

LRESULT CALLBACK WndProc(HWND ,UINT ,WPARAM ,LPARAM )

이런 프로시저를 보통 사용할 때는 다음과 같이 사용한다.

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
    switch(iMessage)

    {

       case WM_PAINT:

                /화면에 변화가 있었을 때 WM_PAINT 메시지가 발생하고 그때 처리해야할 일들을 이곳에서 처리/

          break;

       case WM_KEYDOWN:

                /키보드가 눌려지면 WM_KEYDOWN 메시지가 발생하고 그때 처리해야할 일들을 이곳에서 처리/

          break;

             .

             .

             .

    }

 return (DefWindowProc(hWnd,iMessage,wParam,lParam));
}

위에서 볼수 있는 것과 같이 프로그램 구동중에 생길 수 있는 모든 메시지들을 처리하게 되며 메시지가 왔을때 그것을 처리하기 위해

분기명령인 switch문을 사용 하게 된다.

프로그램의 크기가 적어 처리 해야할 메시지가 많지 않을 경우에는 별 문제가 되지 않지만 프로그램의 크기가 커져  처리해야할 메시지가 많아지고 각 메시지당 처리해야할 일들이 많아진다면 소스코드의 복잡성이 늘어나며 소스의 이해도가 떨어지게 된다.


어차피 switch문은 해당 하는 곳으로 바로 점프하는 분기방식아닌가 !!!!

해당 하는 곳말고는 없는 코드나 마찬가지가 아닌가 !!!!

메시지가 올때마다 해당하는 메시지에 맞는  함수를 호출 시켜 줄수 있다면 !!!!!!


이런 생각에서 나온게 바로 메시지 맵이란 기법이다.


사설이 길었다..... 본론으로..

메시지 맵이란 각각의 메시지 처리함수로 만들어 처리함수 마다 해당 메시지에 대한 처리만을 담당하게 하고 메시지가 호출되면 해당 함수를

호출 시켜주는 기능을 말한다.


기존의 메시지 처리함수(WndProc)에서는 들어오는 메시지를  메시지 맵에서 찾아 해당 하는 메시지 처리함수를 호출하는 일만 처리하게 된다.


이렇게 메시지 맵 기법이 사용 가능한것은 모든 메시지가 같은 메시지 처리함수에서 처리된다는 점 때문이다.

같은 함수내에서 처리하는 방식만 틀리기 때문에 함수포인트를 이용해서 함수를 분리해 내는 것이 가능한것이다.


여기서 또하나 !!

함수 포인터란 무었인가?

아는 사람은 살포시 패스~!! 모르는 사람은 필독!! 모르면  다음 부터 이해하기 힘이 든다.

프로그램을 실행 시킨다는 의미는 프로그램을 메모리에 올린다는 의미다. 변수가 메모리에 올라가듯 함수역시 메모리 어딘가에 올라가게 되는 것이다.

메모리에 올라간다는 것은 당연 해당 번지가 할당되게 되며 그 해당 번지가 함수의 주소가 되는 것이다. 해당 주소를 찾아가면 그 함수를 실행

시킬수 있게 되는 것이다. 하지만 무턱대고 찾아간다고 함수가 실행 되는 것이 아니다. 변수 역시 자료형을 알아야  포인터를 이용해서 사용이 가능하듯 함수 역시 자료형이 존재 하며 함수의 자료형은 그함수의 프로토타입을 의미하기도 한다. 함수의 자료형이라고 어렵게 생각할거 없다.

함수의 프로토 타입에서 함수의 이름부분을 ( * ) 로 바꿔주면 그만이다.


이쯤에서 함수포인터에 대한 연습한번 !!

기존의 메시지 처리함수의 프로토타입(원형)을 가지고 함수 포인터를 만들어 보자


LRESULT  WndProc(HWND ,UINT ,WPARAM ,LPARAM )

프로토 타입이 위와 같으므로  메시지 처리 함수의 자료형은 다음과 같이 만들수 있다.


LRESULT (*) (HWND ,UINT ,WPARAM ,LPARAM );

 

붉은색 으로 표시한 곳을 보듯이 함수명 부분을 (*)로 변경 해주면 자료형이다. 어렵지 않다.

함수의 자료형이 있다면 함수형의 변수 역시 선언 가능하지 않겠는가!!

그렇다 있다.

(*) 부분에 변수 명을 써주면 된다. 어떻게? ( * Fxn) 이렇게 쓰면 된다.

LRESULT (*)(HWND ,UINT ,WPARAM ,LPARAM ) 형 함수를 가리키는 함수포인터 Fxn을 선언 하는 것이다.



- 메시지 맵의 구현

1.메시지 맵에 사용할 구조체를 생성 한다.

typedef struct _DecodeMsg
{
 UINT Code;
 LRESULT (*Fxn)(HWND ,UINT ,WPARAM ,LPARAM );
}DecodeMsg;


Code는 실제 메시지의 값을 저장할 곳이며 아래있는 함수 포인터는 메시지 처리함수에서 발생한 메시지와 Code를 비교하여 해당하는 함수포인트를 호출할때 사용하게 될것이다.


2.메시지 맵 구현( 메시지와 해당하는 함수포인트로 구성된 구조체의 배열 )

const DecodeMsg MsgProc[] = {      // : []는 배열을 나타내는 대괄호다. 폰트가 대괄호를 []로 표시해 버린다....  ;;
 WM_PAINT,Dopaintmain,
 WM_CREATE,Docreatemain,
 WM_TIMER,Dotimermain,
 WM_KEYDOWN,Dokeydownmain,
 WM_DESTROY,Dodestroymain

                     .

                     .

                     .
};
위에서 Dopaintmain,Docreatemain,Dotimermain등은 미리 정의 되어있는 각각의 메시지를 처리하게될 함수다.

함수의 이름은 그 함수의  해당 메모리 주소를 나타낸다. 배열의 이름이 배열의 시작 번지를 나타내는 것이랑 같다고 생각하자


각각의 함수 프로토 타입은

LRESULT Dopaintmain(HWND hWnd , UINT iMessage , WPARAM wParam , LPARAM lParam)

처럼 메시지처리 함수(WndProc)과 같은 타입으로 정의 되어야 한다. 그래야 함수 포인터를 사용해서 호출이 가능하다.


3.메시지 처리함수 내에서의 메시지 비교 와 함수 호출( 실재 메시지 맵을 사용해서 메시지를 처리하는 모습 )

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
 int Cnt;
 for (Cnt = 0;Cnt < dim(MsgProc);Cnt++)
 {
    if (iMessage == MsgProc[Cnt].Code)
    {
       return (*MsgProc[Cnt].Fxn)(hWnd,iMessage,wParam,lParam);
    }
 }
 return (DefWindowProc(hWnd,iMessage,wParam,lParam));
}

메시지가 발생 하게 되면 기존에 만들어 두었던 메시지 맵의 Code와 비교를 하게된다. 비교 후 같은 메시지를 발견 하게되면

해당하는 메시지의 함수를 호출하게 된다.


메시지 맵에서 메시지를 찾을수 없는(메시지맵에서 처리하지않은)메시지는 반복문을 빠져나와

DefWindowProc 함수가 이를 처리하게 된다.


실재 MFC가 이런 메시지 맵 방식으로 메시지를 처리하며 메시지 맵이 어떤 방식으로 움직이는 지를 알아 놓으면  MFC를 이해 하는데 많은 도움이

될것이며 이런 기법을 응용해서 좀더 구조적인 프로그래밍을 할 수 있을 것이다.

자 메시지 맵은 여기까지 !!

 
Posted by 응이

Dream come true.
응이

달력

태그목록