본문 바로가기
C & C++/C & C++

[Message] Getmessage, Translatemessage, DispatchMessage, PeekMessage

by izen8 2011. 4. 14.
반응형
*/
while(GetMessage(&Message,0,0,0)) {
TranslateMessage(&Message);
DispatchMessage(&Message);
}
/*
윈도우즈 프로그램에서 메시지를 처리하는 부분을 메시지 루프라고 하며
보통 WinMain 함수의 끝에 이와 같은 형식으로 존재한다.
*/

/*
BOOL GetMessage( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax);

이 함수는 시스템이 유지하는 메시지 큐에서 메시지를 읽어들인다.
읽어들인 메시지는 첫번째 인수가 지정하는 MSG 구조체에 저장된다.
이 함수는 읽어들인 메시지가 프로그램을 종료하라는 WM_QUIT일 경우 False를 리턴하며
그 외의 메시지이면 True를 리턴한다.
따라서 WM_QUIT 메시지가 읽혀질 때까지, 즉 프로그램이 종료될 때까지 전체 while 루프가 계속 실행된다.
나머지 세 개의 인수는 읽어들일 메시지의 범위를 지정하는데 잘 사용되지 않으므로 일단 무시하기로 한다.

BOOL TranslateMessage( CONST MSG *lpMsg);

키보드 입력 메시지를 가공하여 프로그램에서 쉽게 쓸 수 있도록 해 준다.
윈도우즈는 키보드의 어떤 키가 눌러졌다거나 떨어졌을 때 키보드 메시지를 발생시키는데
이 함수는 키보드의 눌림(WM_KEYDOWN)과 떨어짐(WM_KEYUP)이 연속적으로 발생할 때
문자가 입력되었다는 메시지(WM_CHAR)를 만드는 역할을 한다.
예를 들어 A키를 누른 후 다시 A키를 떼면 A문자가 입력되었다는 메시지를 만들어 낸다.

LONG DispatchMessage( CONST MSG *lpmsg);

시스템 메시지 큐에서 꺼낸 메시지를 프로그램의 메시지 처리 함수(WndProc)로 전달한다.
이 함수에 의해 메시지가 프로그램으로 전달되며 프로그램에서는 전달된 메시지를 점검하여 다음 동작을 결정하게 된다.

메시지 루프에서 하는 일은 메시지를 꺼내고, 필요한 경우 약간 형태를 바꾼 후
응용 프로그램으로 전달하는 것 뿐이다.
이 과정은 WM_QUIT 메시지가 전달될 때까지, 즉 프로그램이 종료될때까지 반복된다.
결국 메시지 루프가 하는 일이란 메시지 큐에서 메시지를 꺼내 메시지 처리 함수로 보내주는 것 뿐이다.
*/

BOOL PeekMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin,

                                      UINT wMsgFilterMax, UINT wRemoveMsg);
 

▶hWnd : 메시지를 받을 윈도우이며 이 윈도우로 보내지는 메시지를 조사한다. 이 윈도우는 반드시 같은 스레드에 소속된 윈도우여야 하며 다른 스레드로 보내지는 메시지는 조사할 수 없다. 이 인수가 NULL이면 이 함수를 호출한 스레드로 전달된 모든 메시지를 조사한다.

▶wMsgFilterMin : 조사할 메시지의 최소값.

▶wMsgFilterMax : 조사할 메시지의 최대값. 이 두 인수를 사용하면 일정한 범위에 속한 메시지만 조사할 수 있는데 이를 메시지 필터링이라고 한다. 예를 들어 키보드 관련 메시지만 조사하고 싶으면 WM_KEYFIRST, WM_KEYLAST로 범위를 지정할 수 있다. 두 인수가 모두 0이면 메시지 필터링을 하지 않으며 모든 메시지를 조사한다.

▶wRemoveMsg : 조사한 메시지를 처리할 방법을 지정하는 플래그의 조합이다.

 

플래그 설명
PM_NOREMOVE -  메시지를 읽은 후 큐에서 메시지를 제거하지 않는다.
PM_REMOVE     - 메시지를 읽은 후 큐에서 메시지를 제거한다.
PM_NOYIELD     - 다른 스레드로 제어를 양보하지 않는다.
PM_QS_INPUT    - 디폴트로 이 함수는 모든 메시지를 다 처리하는데 이하의 플래그들을 지정하면

                           특정 메시지들만 처리하도록 할 수 있다. 이 플래그들은 98이상, 2000이상에서

                            적용된다.

                            마우스나 키보드 등의 입력 메시지만 처리한다.
 
PM_QS_PAINT    - 그리기 메시지만 처리한다.
PM_QS_POSTMESSAGE - 타이머나 핫키 메시지를 포함하여 붙여지는 메시지만 처리한다.
PM_QS_SENDMESSAGE  - 보내지는 메시지만 처리한다.


리턴 메시지 큐에 메시지가 있으면 0이 아닌 값을 리턴하며 메시지가 없으면 0을 리턴한다.
 
설명

GetMessage 함수와 마찬가지로 메시지 큐에서 메시지를 읽는다. 메시지의 범위를 줄 수 있는 기능도 GetMessage와 동일하다. 그러나 이 함수는 GetMessage와는 달리 읽은 메시지를 무조건 제거하지 않으며 큐가 비어 있을 경우 대기하지 않고 곧바로 리턴한다는 점이 다르다. 따라서 이 함수는 메시지를 읽지 않고 단순히 메시지가 있는지 확인만 할 수 있으며 이런 특성은 백그라운드 작업에 적절하다.

 

 

 

 

 

 

 

/*
실제 메시지 처리는 별도의 메시지 처리 함수(WndProc)에서 수행한다. 메시지는 시스템의 변화에 대한 정보이며 MSG라는 구조체에 보관된다. MSG 구조체는 다음과 같이 정의되어 있다.

typedef struct tagMSG
{
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG;

각 멤버의 의미는 다음과 같다.

멤버 | 의미
hwnd 메시지를 받을 윈도우 핸들이다.
message 어떤 종류의 메시지인가를 나타낸다. 가장 중요한 값이다.
wParam 전달된 메시지에 대한 부가적인 정보를 가진다. 어떤 의미를 가지는가는 메시지별로 다르다. 32비트값이다.
lParam 전달된 메시지에 대한 부가적인 정보를 가진다. 어떤 의미를 가지는가는 메시지별로 다르다. 32비트값이다.
time 메시지가 발생한 시간이다.
pt 메시지가 발생했을 때의 마우스 위치이다.

message 멤버를 읽음으로써 메시지의 종류를 파악하며 message값에 따라 프로그램의 반응이 달라진다.
wParam, lParam은 메시지에 대한 부가적인 정보를 가지되 메시지별로 의미가 다르다.
마치 인터럽터 루틴에서 각 레지스터의 의미가 인터럽터별로 다른 것과 마찬가지이다.
GetMessage 함수는 읽은 메시지를 MSG형의 구조체에 대입해 주며 이 구조체는 DispatchMessage 함수에 의해
응용 프로그램의 메시지 처리 함수(WndProc)로 전달된다.
*/
/*
메시지는 실제로 하나의 정수값으로 표현되는데
메시지의 종류가 무척 많아 메시지의 번호를 일일이 암기하여 사용할 수가 없으므로
windows.h에 메시지별로 매크로 상수를 정의해 두었으며 접두어 WM_으로 시작된다.
가장 자주 사용되는 메시지의 종류를 몇 개만 보인다.

메시지 | 의미
WM_QUIT 프로그램을 끝낼 때 발생하는 메시지이다.
WM_LBUTTONDOWN 마우스의 좌측 버튼을 누를 경우 발생한다.
WM_CHAR 키보드로부터 문자가 입력될 때 발생한다
WM_PAINT 화면을 다시 그려야 할 필요가 있을 때 발생한다.
WM_DESTROY 윈도우가 메모리에서 파괴될 때 발생한다.
WM_CREATE 윈도우가 처음 만들어질 때 발생한다.

 

 

예제 0번

 MSG msg;
 if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
  if (GetMessage(&msg, NULL, NULL, NULL)) {
   TranslateMessage(&msg);
   DispatchMessage(&msg);
  } else { // if WM_QUIT
   return ;
  }
 }

 

 

 

 

예제 1

다음 예제는 메시지 루프에 GetMessage를 사용하지 않고 PeekMessage를 사용함으로써 메시지를 처리하지 않는동안 백그라운드 작업을 한다.

 HDC hdc;
 hdc=GetDC(hWnd);
 int count=0;
 char str[255];
 for (;;) {
  if (PeekMessage(&Message,NULL,0,0,PM_REMOVE)) {
   if (Message.message==WM_QUIT)
    break;
   TranslateMessage(&Message);
   DispatchMessage(&Message);
  }
  else {
   count++;
   wsprintf(str,"현재 카운터는 %d입니다",count);
   TextOut(hdc,10,10,str,lstrlen(str));
  }
 }
 ReleaseDC(hWnd,hdc);

GetMessage 함수는 메시지 큐가 비어 있을 경우 무한 대기를 하기 때문에 백그라운드 작업을 할 수 없지만 PeekMessage 함수를 사용하면 즉시 리턴하며 리턴값으로 메시지의 유무를 알려 주므로 0을 리턴할 때 백그라운드 작업을 수행할 수 있다. 예제에서는 카운트를 세는 작업을 백그라운드로 하고 있다. 단 WM_QUIT 메시지에 대해서는 특별한 예외처리를 하여 메시지 루프를 벗어날 수 있도록 해 주어야 프로그램이 종료된다.

예제 2

다음 예제의 SortData 함수는 대량의 데이터를 정렬하는 함수이며 정렬 루틴대신 Sleep 함수로 시간을 끌도록 하였다.

void SortData()
{
 int i;
 char Caption[128];
 MSG Message;

 for (i=0;i<=1000;i++) {
  wsprintf(Caption,"소트중 %d%%",i/10);
  SetWindowText(hWndMain,Caption);
  Sleep(1);
 }
}

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
 switch(iMessage) {
 case WM_LBUTTONDOWN:
  SortData();
  return 0;
 case WM_DESTROY:
  PostQuitMessage(0);
  return 0;
 }
 return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

SortData 함수가 완전히 종료되기 전에는 제어를 리턴하지 않으므로 이 함수가 실행중인동안에 윈도우는 어떠한 메시지도 처리할 수 없다. 이런 시간이 오래 걸리는 작업 루틴에 PeekMessage 루틴을 삽입하면 작업을 하는 동안에도 윈도우가 정상적으로 메시지를 처리할 수 있도록 한다.

void SortData()
{
 int i;
 char Caption[128];
 MSG Message;

 for (i=0;i<=1000;i++) {
  wsprintf(Caption,"소트중 %d%%",i/10);
  SetWindowText(hWndMain,Caption);
  if (PeekMessage(&Message,NULL,0,0,PM_REMOVE)) {
   if (Message.message==WM_QUIT) {
    PostQuitMessage(0);
    break;
   }
   TranslateMessage(&Message);
   DispatchMessage(&Message);
  }
  Sleep(1);
 }
}

데이터를 정렬하는 동안에 메시지 큐를 주기적으로 점검하여 메시지가 들어오면 이 메시지를 윈도우로 보내주어 처리하도록 해 주었으므로 정렬하는 동안에도 다른 작업을 할 수 있다. 단, 이럴 경우 같은 작업을 두번 실행하지 못하도록 하는 장치가 필요할 수도 있다.
 


반응형

'C & C++ > C & C++' 카테고리의 다른 글

#pragma ?  (0) 2011.04.14
파일 정보(File information)  (0) 2011.04.14
[스레드] MFC에서 스레드(Thread) 사용하기  (0) 2011.04.14
CString Split 문자열 잘라내기  (0) 2011.04.14
[Api] Win32 API 기반으로 구현한 StopWatch  (0) 2011.04.14

댓글