[MFC 기본] WinMain과 윈도우 응용 프로그램 기본 구조

Jin Hur·2022년 6월 19일
0

Win32

Win32는 32비트 버전의 마이크로소프트 윈도에서 사용하는 윈도우 OS API

cf) 자료형 형 재선언
1) typedef
2) #define
Win32에서 선언된 대부분의 형들은 재선언된 것이다.
-> 'F12' 키를 눌러 선언된 형을 확인하면 된다.

Win32 아키텍처

WinMain()

기존의 C언어에서의 엔트리 포인트는 main() 함수이다.
윈도우로 넘어가면 엔트리 포인트가 WinMain()이 된다.
WinMain의 구조는 간략히 다음과 같다.

WinMain() {
    1) 초기화 코드
        - 윈도우 등록
        - 윈도우 생성
    2) Main Message Loop 코드
    3) 해제 코드
}

아래 코드는 Win32 프로젝트의 메인함수이다.

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: 여기에 코드를 입력합니다.

    // 전역 문자열을 초기화합니다.
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_WIN32PROJ, szWindowClass, MAX_LOADSTRING);
    
    // WndProc을 등록하는 부분이 있다. 
    // 윈도우를 WndProc과 매칭시켜 이벤트 처리를 담당하도록 함.
    MyRegisterClass(hInstance); 

    // 애플리케이션 초기화를 수행합니다:
    // 윈도우를 생성하고 초기화한다.
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32PROJ));

    MSG msg;
    /*
    * Message structure
    
    typedef struct tagMSG {
        HWND        hwnd;       // 어떤 윈도우에게 
        UINT        message;    // 어떤 메시지를
        WPARAM      wParam;     // 메시지 관련 정보1
        LPARAM      lParam;     // 메시지 관련 정보1
        DWORD       time;
        POINT       pt;         // 윈도우의 (x, y)좌표
        						// 마우스 클릭 위치 등에 필요
    #ifdef _MAC
        DWORD       lPrivate;
    #endif
    } MSG, * PMSG, NEAR* NPMSG, FAR* LPMSG;
    */

    // 기본 메시지 루프입니다:
    // 메시지 큐에서 메시지를 루프를 돌며 가져와 처리(WndProc 호출)한다.
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        // 키보드 입력, 마우스 클릭과 같은 이벤트가 발생하면,
        // 이벤트에 따라 메시지가 발생하고,
        // 해당 메시지는 큐 형태의 자료구조에 추가됨
        // 루프를 돌면서 큐에서 메시지를 하나씩 가져와 
        // 각 메시지에 대한 처리를 한다. 처리는 '윈도우 프로시저(WndProc)'에서 진행
        // == callback (WndProc 호출) 
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}

윈도우 메시지 큐

source: https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=kater102&logNo=122545087

WndProc

WndProc 함수의 구조는 아래와 같다.

						// 윈도우 핸들: 윈도우 식별자(값 또는 포인터)
						// HWND, 윈도우 핸들(값)
                        // 윈도우 식별을 위해 필요한 값이다. 
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // 메뉴 선택을 구문 분석합니다:
            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:
        {
            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;
}

0개의 댓글