Notice
Recent Posts
관리 메뉴

Hacking Arts

WinMain - 4.메시지 루프 돌리기 본문

Programing/API Programing

WinMain - 4.메시지 루프 돌리기

Rakehell 2014. 9. 20. 01:47

-WinMain의 마지막 메시지 루프돌리기 입니다.

윈도우를 나타내는 것까지는 다 완성했습니다. 그 다음 이젠 윈도우에 명령이 들어왔을 때 처리해주는 부분을 완성 시켜야 됩니다. 그 부분이 WndProc윈도우 프로시져 부분입니다.


1.이벤트 처리 방식 : 임의의 이벤트가 발생하면 즉시 처리되는 방식이며 이벤트는 키보드나 마우스의 입력을 말합니다.

메세지 내용

1) 이벤트가 발생한 윈도우 핸들

2) 이벤트의 종류

3)이벤트가 접수된 시간

4) 이벤트가 발생한 위치(좌표)

위와 같은 메시지가 들어오게 되면 윈도우는 다음의 내용을 처리하게 됩니다.


2.메시지 루프

일단 메세지를 받으면 윈도우 프로시저로 보내줘야되는데 이때 메시지 루프가 그 역할을 하게 됩니다.


[그림 1 이벤트 발생시 처리 과정]


1)어떤 이벤트가 발생하면 가장 먼저 운영체제가 가지고 있는 시스템 큐에 저장

2)시스템 큐에 저장된 메시지는 순서대로 해당하는 애플리케이션 큐로 옮겨진다.

-------------------OS가 자동으로 처리하는 일----------------------

3)애플리케이션 큐에 있는 메시지를 메시지 루프가 가져온다

4)메시지 루프는 가져온 메시지를 윈도우 프로시저 함수로 보낸다.


위와 같은 과정으로 메시지가 처리된다.



LPWSTR lpszClass = L"ApiBase";

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)
{
	HWND hWnd;
	MSG Message;
	WNDCLASS WndClass;
	g_hInst = hInstance;

	WndClass.cbClsExtra = 0;					//클래스 여분 바이트수
	WndClass.cbWndExtra = 0;					//윈도우 여분 바이트수
	WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);	//윈도우의 배경색
	WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);			//프로그램에서 사용할 커서
	WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);		//프로그램에서 사용할 아이콘
	WndClass.hInstance = hInstance;					//프로그램의 인스턴스 핸들
	WndClass.lpfnWndProc = (WNDPROC)WndProc;			//프로시져 함수명
	WndClass.lpszClassName = lpszClass;				//구조체로 만들어질 클래스명
	WndClass.lpszMenuName = NULL;					//프로그램에서 사용할 메뉴
	WndClass.style = CS_HREDRAW | CS_VREDRAW;			//윈도우 스타일

	RegisterClass(&WndClass);

	hWnd = CreateWindow(lpszClass, lpszClass, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
		CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, (HMENU)NULL, hInstance, NULL);

	ShowWindow(hWnd, nCmdShow);

	while (GetMessage(&Message, 0, 0, 0)){
		TranslateMessage(&Message);
		DispatchMessage(&Message);
	}
}
위 와 같은 코드로 구현이 된다. 아래쪽에 GetMessage라는 함수의 반환값이 거짓일 때 까지 계속 루프를 반복해서 돈다. 이 함수가 애플리케이션 큐에 저장된 메시지를 인수 Message에 담아 온다. Message 구조체의 내부는 아래와 같다.
typedef struct tagMSG {
    HWND        hwnd;		//이벤트가 발생한 윈도우 핸들
    UINT        message;	//이벤트 메시지 종류
    WPARAM      wParam;		//부가 정보
    LPARAM      lParam;		//부가 정보
    DWORD       time;		//이벤트가 접수된 시각
    POINT       pt;		//이벤트가 발생한 위치(좌표)
} MSG;

GetMessage 함수는 에플리케이션 큐에서 메시지를 인수 Message에 담아오면 Message.message는 메시지의 종류를 구분할 수 있는 값이 들어 있다. 이때 값이 WM_QUIT일 경우는 거짓을 반환 하고 나머지는 참 값을 반환한다. 참일 경우 TranslateMessage함수와 DispatchMessage 함수를 수행하며 계속 루프를 돌게 된다. 


-TranslateMessage 함수 : 키보드 입력 이벤트 중 문자 입력을 처리하는 함수이다. 사용자가 A라는 키를 누르면WM_KEYDOWN,WM_CHAR,WM_KEYUP 세 가지 메시지가 발생한다. WM_CHAR 메시지는 사용자에 의해서 생긴 메시지가 아닌 메시지 루프에서 인위적으로 생긴 메시지이며 GetMessage 함수로 읽은 메시지는 TranslateMessage 함수로 넘겨지고, 메시지가 WM_KEYDOWN 키가 눌려졌는지 문자 키가 눌려졌는지 검사한 후에 문자 키가 눌려졌다면 WM_CHAR 메시지를 발생시킨다. 문자가 아니라면 DispatchMessage 함수로 바로 넘어간다. Translate는 즉 문자키가 눌려졌는지 확인후 눌려지면 WM_CHAR 메시지를 발생시키는 기능을 한다. 


-DispatchMessage 함수 : GetMesssage 함수로부터 전달된 메시지를 윈도우 프로시저로 보낸다. 이 함수는 윈도우 프로시저가 메시지를 완전히 처리하기 전까지는 반환하지 않는다. 

지금 까지 우리는 시스템 큐를 거쳐 애플리케이션 큐로 메시지를 보냈지만 때때로 애플리케이션 큐에 직접 보내야되는 경우가 있는데 이때 사용하는 함수가 SendMessage와 PostMessage 함수이다.

-SendMessage함수 : 모든 메시지는 시스템 큐에서 애플리케이션 큐를 거쳐 윈도우 프로시저 함수로 전달된다고 하였다 하지만 바로 윈도우 프로시저 함수로 전달되는 메시지가 있는데 이 경우 SendMessage함수가 메시지를 전달하는 역할을 한다. 이 함수는 메시지가 완전히 처리되기 전까지 반환하지 않는다. 그러므로 메시지 처리 후 반드시 처리 확인이 필요한 경우에 이 함수를 사용한다. 

-PostMessage 함수 : PostMessage 함수를 이용하면 메시지는 시스템 큐를 거치지 않고 직접 애플리키에션 큐에 보내진다. 이 함수로 메시지를 보내면 곧바로 반환되므로, 해당 메시지를 바로 처리하지 않고도 해당 메시지를 붙인 스레드는 다른 작업을 할 수 있다. 즉 메시지가 비동기적으로 처리 되어도 상관없는 경우에 이 함수를 사용한다. 

 -참고 서적 API Programing / 이창현 / 혜지원