RESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam);
첫번째 인수(HWND hWnd) : 메시지를 받을 윈도우 핸들. 한 클래스로부터 여러 개의 윈도우가 만들어
졌을 때 어떤 윈도우로 전달된 메시지 인지를 구분해야 하므로 이 인수가 필요함.
두번째 인수(UINT iMessage) : Message ID이며 0x00 ~ 0x3FF 사이의 값이다. “WM_”으로 시작하는 상수로 정의 되어 있다.(전달된 메시지의 값)
WPARAM wParam, LPARAM lParam : 32비트 정수값이며 메시지의 추가 정보를 가진다.
메시지 큐
메시지는 시스템이나 사용자에 의해 발생한다.
키보드나 마우스 등의 사용자 입력 시 시스템은 이 입력에 대해 메시지를 발생시키며 또한
시스템 상황 변화를 통지하기 위해서도 메시지를 발생시킨다. 응용 프로그램도 윈도우간의
통신을 위해 메시지를 발생하며 특정 함수 호출에 의해 간접적으로 메시지가 발생하기도 한다.
윈도우즈라는 운영체제는 끊임없는 메시지의 생성과 처리를 무수히 반복하면서 실행되는
것 이므로 메시지는 윈도우즈 운영체제에서 중요하다고 할 수 있다.
메시지는 크게 메시지큐로 들어가는 큐(Queued)메시지와 큐에 들어가지 않고 곧바로
윈도우 프로시저로 보내지는 비큐(Non Queued)메시지로 구분된다.
윈도우 프로시져(Window Procedure) : 메시지를 처리하는 함수
- 윈도우 클래스당 하나씩 배정되며 메시지에 대응하는 방식을 정의하여 윈도우의 행동 양식을
결정한다.
- 윈도우 클래스로부터 생성된 모든 윈도우의 메시지는 이 함수가 처리한다.
- 이름은 사용자가 마음대로 바꿀 수 있으나 일반적으로 WndProc이라는 이름을 사용한다.
- 4개의 인수를 가지며 정수값 하나를 리턴한다. 대부분 잘 처리했으면 0을 리턴하지만 어떤
메시지는 처리 결과를 운영체제로 리턴하여 보고하는 경우도 있다.
Ex) WM_CREATE 는 초기화 과정에서 에러가 없으면 0을 리턴 에러가 발생했으면 -1을 리턴한다.
WM_NCHITTEST 는 마우스가 윈도우의 어떤 부분에 있는지를 리턴한다.
*WM_NCHITTEST : 윈도우에게 커서가 움직이거나 마우스버튼이 눌리거나 띄어졌을 때 메시지를 보낸다.
v Window Procedure |
모든 윈도우는 메시지를 처리하기 위해 메시지 처리 함수가 있어야 한다. 메시지 처리 함수의 모양은 아래 와 같다. |
LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); |
윈도우 클래스를 만들때 메시지 처리함수의 주소를 등록한다. |
|
|
v Non-Queued Message |
사용자가 윈도우를 만들기 위해 CreateWindowEx()함수를 호출하면 윈도우가 만들어 지고 윈도우가 만들어 졌다는 사실을 사용자에게 알리기 위해 WM_CREATE라는 메시지가 메시지 처리함수에 전달된다.(메시지 처리 함수가 호출된다.) |
이때 WM_CREATE 메시지는 Message Queue에 놓이지 않고 직접 Window Procedure에 전달 되는 데 이를 non-Queued Message라고 한다. |
입력 메시지(마우스 메세지, 키보드 메시지)를 제외한 대부분의 메시지가 non-Queued Message 이다. |
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch( msg ) {
case WM_CREATE:
MessageBox( 0, "WM_CREATE도착", "", MB_OK);
return 0;
…
}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE , LPSTR lpCmdLine, int nShowCmd)
{
HWND hwnd = CreateWindowEx(…);
ShowWindow(hwnd, nShowCmd); |
v Queue Message |
마우스나 키보드 메세지들은 직접 Window Procedure로 전달되지 않고 메시지 Queue에 놓이게 되는데 이를 Queue Message라고 한다. Queue에 놓인 메시지를 처리하려면 반드시 사용자가 Queue에 놓여 있는 메시지를 가져오는 메시지 루프가 필요하다. |
MSG msg;
while ( GetMessage( &msg, 0, 0, 0 ) ) {
TranslateMessage(&msg);
DispatchMessage(&msg);
} |
GetMessage()는 메시지 Q에 WM_QUIT 메시지가 있을 경우에만 FALSE를 리턴한다. 그래서 위 코드는 WM_QUIT메세지가 Q에 들어 올때 까지는 무한 루프가 된다. |
|
|
v 프로그램의 종료 |
사용자가 만든 윈도우가 파괴될 때 나오는 메시지는 WM_DESTROY 이다. 그러므로 사용자가 윈도우를 파괴 해도 프로그램은 계속 메시지 루프를 돌게 된다.( 하지만 윈도우는 파괴 되었다.- 모니터 화면에는 더 이상 아무 것도 볼 수 가 없다.) |
윈도우를 1개 만든 경우 프로그램의 main 윈도우가 파괴 될 때 프로그램을 같이 종료 되게 하려면 WM_DESTROY 메시지에서 WM_QUIT메세지를 메시지 Q에 넣는 작업을 해야 한다. |
case WM_DESTROY:
PostQuitMessage( 0 ); return 0; |
v 처리하지 않은 메시지 |
|
메시지 처리 함수에서 발생된 메시지를 처리하지 않은 경우 반드시 아래 함수로 보내서 default 처리가 되게 해야 한다.
LRESULT CALLBACK DefWindowProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); |
메시지 루프
- 사용자에 의해 입력된 메시지는 시스템 메시지 큐에 일단 저장되고 스레드 메시지 큐로 이동했다가 메시지 루프에 의해 해당 윈도우의 윈도우 프로시저로 보내져 처리된다.
- 메시지는 최종 처리되기 직전까지 계속 큐에 유지되는데 이때 메시지는 다음과 같이 정의된 구조체의 형태로 존재한다.
Typedef struct tagMSG{HWND hwnd; UINT message; PARAM wParam; LPARAM lParam; WORD time; POINT pt;}MSG;
HWND hWnd : 메시지를 받을 윈도우 핸들.
UINT iMessage : 전달된 메시지의 값
WPARAM wParam, LPARAM lParam : 메시지의 추가 정보를 가진다.
DWORD time : 메시지가 발생한 시간(time)
POINT pt : 발생시의 마우스 좌표(pt)
시간과 마우스 좌표는 모든 메시지들이 필요로 하는 정보가 아니므로 WndProc까지 전달되지 않는다.
필요할 경우 다음 두 함수를 사용하여 직접 조사해야 한다.
※ DWORD GetMessagePos(VOID) : 하위워드(LOWORD)에 x좌표, 상위워드(HIWORD)에 y좌표를 리턴한다.
※ LONG GetMessageTime(VOID) : 메시지 발생 시간을 부팅된 후 경과된 1/1000초 단위로 리턴한다.
- 메시지 루프는 메시지 큐에서 메시지를 꺼내 메시지 처리 함수로 보내는 일을 한다.
- 보통 WinMain의 제일 끝부분에 위치하며 다음과 같이 그 형태가 정형화 되어 있다.
while(GetMessage(&Message,NULL,0,0)
{
TranslateMessage(&Message);
DispatchMessage(&Message);
}
- while문에 싸여져 있는데 이 루프는 프로그램이 끝날 때까지 계속반복된다.
(메시지큐에 WM_QUIT[kwɪt]이라는 윈도우 메시지가 도착해 있으면 위의 반복문 조건속에 있는
GetMessage함수는 FALSE값을 리턴하고 종료한다.)
* WM_QUIT : PostQuitMessage 함수가 실행되면 발생하는 메시지
BOOL GetMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax);
- 스레드 메시지 큐에 대기중인 메시지를 꺼내 첫 번째 인수로 전달된 MSG 구조체에 복사한다.
- 복사한 메시지를 큐에서 제거하고 TRUE를 리턴하며, 만약 큐에서 가져온 메시지가 WM_QUIT이면
FALSE를 리턴하여 메시지 루프를 탈출할 수 있다.
LPMSG lpMsg : MSG 구조체의 번지를 지정한다.
HWND hWnd : 현재 메시지를 큐에 올린 윈도우의 핸들값. 메시지를 처리해서 되돌려 줄때 필요하다.
UINT wMsgFilterMin : 회수된 메시지의 범위 중 최소값을 정수형태로 지정
UINT wMsgFilterMax : 회수된 메시지의 범위 중 최대값을 정수형태로 지정
*wMsgFilterMin : 첫번째 키보드 메시지인 WM_KEYFIRST 메시지 혹은 첫번째 마우스 메시지를 저장하는 WM_MOUSEFIRST 메시지 정수값을 저장한다.
*wMsgFilterMax : 마지막 키보드 메시지인 WM_KEYLAST 메시지 혹은 마지막 마우스 메시지를 저장하는 WM_MOUSELAST 메시지 정수값을 저장한다.
*wMsgFilterMin, wMsgFilterMax에 메시지의 범위를 지정하면 이 범위 내의 메시지만 가져온다.
*wMsgFilterMin과 wMsgFilterMax 인자의 값이 둘 다 0이면 GetMessage함수는 메시지 사용범위의 지정없이 모든 메시지를 돌려준다.
TranslateMessage
GetMessage 함수에 의해 큐로부터 가져온 메시지는 WM_QUIT가 아닌 한은 TranslateMessage 함수로 전달된다. 이 함수는 가상키 입력을 문자 입력(WM_CHAR)으로 바꾸는 역할을 하며 가상키 입력이 아닌 경우는 아무 처리도 하지 않는다.
* 컴퓨터의 가장 기본적인 입출력 장치는 아직까지는 키보드이다. 입력이 발생했을 경우 윈도우즈는 포커스를 가진 프로그램에게 키보드 메시지(WM_CHAR)를 보내주며 프로그램은 이 메시지를 받아 키보드 입력을 처리한다.(포커스(FOCUS)를 가진 프로그램이란 활성화되어 있는 윈도우를 말하며 한번에 오직 하나의 프로그램만 활성화 된다.멀티 태스킹 환경이라도 활성화될 수 있는 프로그램은 오직 하나밖에 없으며 활성화된 프로그램만 포커스를 가지고 키보드 입력을 받아들일 수 있다.
DispatchMessage
메시지를 윈도우 프로시저로 보내 처리하도록 하는데 MSG 구조체의 hwnd 멤버를 보고 정확하게 목적 윈도우의 메시지 처리 함수로 배달한다. 윈도우 핸들로 부터 어떤 윈도우 프로시저에게 메시지를 전달할 것인가를 결정하는 중요한 일을 이 함수가 담당한다.
출처 - 선문비트 최강사님 도큐먼트