본문 바로가기

Programming/Win32&MFC&COM

Windows 메시지의 구조와 처리

반응형

Windows 프로그래밍은 메시지를 기반으로 하는 프로그램을 작성합니다.

Windows는 메시지를 끊임없이 발생시키고 이 메시지를 처리하게 만들어 주는 것입니다.

Win32 프로그래밍을 하다보면 메시지 루프라는 용어가 쓰입니다.

이 부분이 메시지를 받아서 메시지를 처리하는 부분이 됩니다.

WinMain에는 다음과 같은 코드가 들어가 있습니다.

MSG msg;
HACCEL hAccelTable;

// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_WIN32PROJECT1, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);

// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
	return FALSE;
}

hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32PROJECT1));

// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
	if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
}

return (int) msg.wParam;

MSG msg라고 되어 있는 선언 부분이 메시지 구조체 변수를 선언하는 것입니다.

그리고 while (GetMessage(&msg, NULL, 0, 0)) 부분이 메시지 루프입니다.

메시지를 계속 처리하기 위해서 GetMessage()가 FALSE를 반환하기 전까지 while이 계속 돌게 됩니다.

GetMessage()는 메시지 큐(Queue)에서 메시지를 가져오는 역할을 합니다.

GetMessage()는 TRUE를 리턴하다가 WM_QUIT(종료) 메시지가 올 경우 FALSE를 리턴합니다.

프로그램이 종료될 때 while문도 종료가 되면서 정상적으로 종료가 완료되는 것입니다.

그리고 TranslateMessage()는 키보드 이벤트를 적절하게 바꿔주는 역할을 합니다.

WM_KEYDOWN(키보드 누를 때)과 WM_KEYUP(키보드 뗄 때)가 연속 발생하면 그것을 WM_CHAR로 변경합니다.

마지막으로 DispatchMessage()는 메시지를 처리할 프로시저에 메시지를 넘겨주는 역할을 합니다.

메시지 처리 프로시저는 다음과 같은 형식으로 작성되어야 합니다.

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

윈도우를 생성할 때 다음과 같은 형식으로 메시지를 처리하는 프로시저를 등록하게 됩니다.

wcex.lpfnWndProc	= WndProc;

함수의 이름은 변경이 가능하지만 원형은 양식을 지켜서 작성해야 합니다.

CALLBACK 함수로 메시지가 있으면 알아서 호출되게 됩니다.

기본적으로 WndProc은 다음과 같이 swtich로 메시지를 구분해서 처리하게 되어 있습니다.

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;

	switch (message)
	{
	case WM_COMMAND:
		wmId    = LOWORD(wParam);
		wmEvent = HIWORD(wParam);
		// Parse the menu selections:
		switch (wmId)
		{
		case IDM_ABOUT:
			DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
			break;
		case IDM_EXIT:
			DestroyWindow(hWnd);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
		break;
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		// TODO: Add any drawing code here...
		EndPaint(hWnd, &ps);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

메시지 구조체는 다음과 같이 되어 있습니다.

typedef struct tagMSG {
    HWND        hwnd;
    UINT        message;
    WPARAM      wParam;
    LPARAM      lParam;
    DWORD       time;
    POINT       pt;
#ifdef _MAC
    DWORD       lPrivate;
#endif
} MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG;

메시지를 받은 윈도우의 핸들과 메시지 종류, WPARAM, LPARAM, 메시지 발생 시간, 마우스의 위치 등이 전달됩니다.

일반적으로 메시지의 종류는 위에 보이는 WM_으로 시작하는 메시지입니다.

그 외에도 사용자 정의 메시지나 WM_으로 시작하지 않는 메시지 등도 사용할 수 있습니다.

WPARAM과 LPARAM은 메시지의 부가 정보입니다.

메시지마다 다른 값을 가지고 있기 때문에 잘 맞춰서 사용하면 됩니다.

기본적인 메시지 처리에 대한 구조를 알면 좀 더 쉽게 Windows 프로그램 개발이 가능합니다.

반응형