Win32_API - 프로그램 동작 구조

컴퓨터/Win32-API

728x90
반응형

서론

본격적인 실습을 하기 전 기존에 간소화한 실습용 소스코드가 어떤 식으로 동작하는지 이해할 필요가 있습니다. 프로그램이 어떻게 동작하는지 이해를 해야만 어느 부분에 프로그래밍을 할 수 있을지 알게 됩니다.

 

WinMain함수와 WndProc콜백 함수

소스코드를 동작시키면 WinMain함수가 동작하여 메시지 루프에 들어가게 됩니다. 이 과정 이후 WndProc함수에 작성한 내용들이 운영체제의 콜백 함수에 의해 실행되고 처리되게 됩니다. 

 

정말 정말 간단하게 표현하면 위의 그림과 같습니다. WinMain에서 처음 윈도를 생성하고 초기 값을 가진 후 메시지 루프 영역에 도달하게 됩니다.

    while (GetMessage(&msg, nullptr, 0, 0))
    {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
    }

이때부터 사용자가 만든 콜백 함수 WndProc를 호출하여 명령에 맞는 처리를 하게 됩니다.

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

    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: 여기에 hdc를 사용하는 그리기 코드를 추가합니다...
            EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

예를 들어 사용자가 윈도 창에서 마우스 왼쪽 버튼을 클릭했을 때 명령 처리 등 거의 모든 부분이 이 콜백 함수 안에서 진행됩니다.

그래서 WndProc의 부분은 Switch문으로 되어 다양한 명령이 왔을 때 처리하도록 만들어집니다. 

 

 

메시지를 처리하는 구조이다.

결국 WinMain은 프로그램이 시작되는 곳입니다. 그리고 프로그램이 시작된 이후에는 끊임없이 운영체제와 메시지를 주고받는 구조로 되어있습니다. 결국 운영체제에서 어떤 메시지가 들어왔을 때 어떤 처리를 해야 되는 것인가가 Win32 프로그래밍의 핵심이라고 할 수 있습니다. 

 

메시지 루프 영역 이해하기

그렇다면 메세지 루프 영역에서 어떻게 운영체제와 메시지를 주고받는지 이해해 볼 필요가 있습니다. 

실습용 예제 소스코드를 보시면 다음과 같습니다.

    MSG msg;

    // 기본 메시지 루프입니다:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
    }

    return (int) msg.wParam;

MSG구조체 변수 msg를 선언하고 GetMessage함수를 실행합니다. 

BOOL GetMessage(
  [out]          LPMSG lpMsg,
  [in, optional] HWND  hWnd,
  [in]           UINT  wMsgFilterMin,
  [in]           UINT  wMsgFilterMax
);

지금은 단순하게 GetMessage 함수를 통해 &msg 즉 msg구조체 변수에 함수를 통해 메시지를 받고 BOOL타입으로 반환한다고 생각하시면 됩니다.

즉 특정 메세지를 받을 때까지 while루프를 돌겠다는 말입니다.

 

while루프에 진입하면 두 함수를 만나게 됩니다.

BOOL TranslateMessage( CONST MSG *lpMsg); 
LONG DispatchMessage( CONST MSG *lpmsg);

지금은 어렵게 생각하지 말고 다음과 같이만 생각해 봅시다.

TranslateMessage - 사용자가 문자를 입력하는 것인지 확인하는 함수입니다. 단순히 아무 키나 입력하여 키보드를 누른다, 땐다 입력이 아닌 어떠한 특정 문자를 입력했는지 확인하는 함수입니다.

DispatchMessage - 이 부분에서 운영 체제로부터 받은 메시지를 WndProc로 전달하는 함수입니다.

 

결국 다음과 같은 루프로 계속해서 동작할 것입니다.

  • 메세지 루프 진입
    • TranslateMessage함수 
    • DispatchMessage함수
      • WndProc함수가 실행됨 
      • 명령에 따라 처리
  • 위 내용 메시지 루프를 탈출하기 전까지 무한적 반복

WndProc 콜백 함수 해석하기

그럼 이제 WndProc가 실행되면 어떻게 동작하는지 확인해 보겠습니다.

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

    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: 여기에 hdc를 사용하는 그리기 코드를 추가합니다...
            EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

4개의 매개변수를 받고 있습니다. 지금은 결국 운영체제로부터 message를 받아 message에 담긴 명령어를 처리한다고 생각하면 됩니다. 

지금 예제 소스는 2가지 메시지 WM_PAINT, WM_DESTROY만 있지만 다양한 명령이 왔을 때 처리를 하기 위해서는 열심히 명령어에 따른 처리를 해주어야 됩니다.

 

다음 포스트에서는 실제 간단한 몇가지 명령어를 가지고 처리해보도록 하겠습니다.

728x90
반응형

Commnet

G91개발일지

Gon91(지구일)

91년생 공학엔지니어의 개발일지

TODAY :

YESTER DAY :

TOTAL :