본문 바로가기
New/MFC 윈도우 프로그래밍

1. 윈도우 프로그래밍의 이해 (2)

by onenewkong 2024. 11. 26.

1.3 간단한 윈도우 애플리케이션의 분석

1) WinMain() 함수

  • 운영체제에 윈도우를 등록함
  • 메모리에 프레임 윈도우를 생성하고 속성을 초기화하여 화면에 표시될 수 있도록 함
  • 메시지 루프를 생성하여 해당 윈도우에 대한 메시지를 메시지 큐로부터 받아와 메시지를 해당 윈도우 프로시저로 보냄

① 윈도우 클래스 등록

WinMain() 함수는 윈도우 클래스 구조체인 WNDCLASSEX 데이터 구조체를 생성하고 구조체 멤버에 값을 채워 초기화한 다음, RegisterClassEx() API 함수를 호출하여 운영체제에 등록함

WndClass.cbSize = sizeof(WNDCLASSEX);        // 구조체 크기
WndClass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;    // 클래스 스타일
WndClass.lpfnWndProc = WndProc;                   // 윈도우 프로시저
WndClass.cbClsExtra = 0;                                   // 윈도우클래스 데이터 영역
WndClass.cbWndExtra = 0;                                 // 윈도우의 데이터 영역
WndClass.hInstance = hInstance;                       // 인스턴스 핸들
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);            // 아이콘 핸들
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);              // 커서 핸들
WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);          // 배경 브러시 핸들
WndClass.lpszMenuName = NULL;                      // 메뉴이름
WndClass.lpszClassName = "EasyText";              // 윈도우 클래스 이름
WndClass.hIconSm = 0;                                        // 기본적인 작은 아이콘

// 윈도우 클래스를 등록함
RegisterClassEx(&WndClass);

② 프레임 윈도우를 생성하고 화면에 표시

윈도우 클래스가 등록되면 WinMain() 함수는 CreateWindow() API 함수를 호출하여 애플리케이션의 프레임 윈도우를 생성하며, CreateWindow() 함수는 윈도우 이름, 윈도우 위치, 윈도우 크기에 대한 정보를 넘겨줌으로써 윈도우의 형태를 좀 더 세부적으로 정의함

// 프레임 윈도우 생성
hwnd = CreateWindow(             // 윈도우 생성 API 함수
    "EasyText",                            // 등록된 윈도우 클래스 이름 (윈도우 클래스에서 정의한 것과 같은 이름)
    "Practice1a",                          // 타이틀 바에 출력될 문자열
    WS_OVERLAPPEDWINDOW,    // 윈도우 스타일
    CW_USEDEFAULT,               // 윈도우 좌측 상단의 x좌표
    CW_USEDEFAULT,               // 윈도우 좌측 상단의 y좌표
    CW_USEDEFAULT,               // 윈도우의 너비 
    CW_USEDEFAULT,               // 윈도우의 높이
    NULL,                                    // 부모 윈도우의 핸들
    NULL,                                    // 메뉴 또는 자식 윈도우의 핸들
    hInstance,                             // 애플리케이션 인스턴스 핸들
    NULL                                     // 윈도우 생성 데이터의 주소
);

윈도우를 생성한 후 ShowWindow() 함수와 UpdateWindow() 함수를 호출하여 윈도우를 화면에 나타나게 함

  • ShowWindow(): 윈도우를 화면에 보이거나 감추는 기능
  • UpdateWindow(): 윈도우의 외관을 다시 그려주는 기능
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

③ 메시지를 윈도우 프로시저로 보냄

메시지 루프는 해당 윈도우에 대한 메시지를 메시지 큐로부터 받아와 메시지를 해당 윈도우 프로시저로 보냄

while (GetMessage(&msg, NULL, 0, 0))
{
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}
  • GetMessage(): 메시지 큐에서 메시지를 꺼내와 MSG 데이터 구조체에 저장
  • TranslateMessage(): 가상 키 메시지를 문자 메시지로 변환함
  • DispatchMessage(): 내부적으로 윈도우 프로시저 함수를 호출하여 윈도우 프로시저 함수에 메시지를 전달함
  • WM_QUIT 메시지를 받을 때 GetMessage() 함수는 0을 리턴하며, WinMain() 함수가 끝나면서 프로그램이 종료됨

2) WinProc() 함수

윈도우 프로시저는 윈도우가 클라이언트 영역에 표시해야 할 것과 사용자 입력에 대하여 반응하는 방법을 결정함

디폴트 윈도우 프로시저 DefWindowProc() 함수는 윈도우의 아이콘 표시나 화면 복귀, 전체 화면 표시, 메뉴 리소스 표시 등 일반적인 Win32 애플리케이션의 많은 행위를 구현함

윈도우 애플리케이션은 각각 다른 이름을 갖는 하나 이상의 윈도우 프로시저를 포함할 수 있음

  • WM_CREATE: 윈도우가 처음 생성될 때 발생하는 메시지
  • WM_KEYDOWN, WM_KEYUP: 각각 키보드의 키 하나를 누르거나 뗄 때 발생하는 메시지
  • WM_LBUTTONDBLCLK: 왼쪽 마우스를 더블 클릭할 때 발생하는 메시지
  • WM_DESTROY: 윈도우가 종료될 때 발생하는 메시지

3) 윈도우에서 문자열 표현 방식

LP: Long Pointer

C: Constant, 함수 내부에서 인자 값을 변경할 수 없음

STR: String, 내부적으로 char 배열로 마지막 종료 값 null을 가지고 있음

W: Wide Char, 유니코드를 의미함

T: TChar

  • char 형식은 1바이트를 사용하고 wide char 형식은 2바이트를 사용하기 때문에 호환성의 문제가 많다고 판단하여 컴파일러가 precompile option을 보고 환경에 맞게 컴파일할 수 있도록 만든 형식
  • 프로젝트 세팅에 유니코드가 정의되어 있으면 유니코드 문자열 wchar_t형으로 변환되고 그렇지 않으면 ANSI 문자열 (멀티바이트 포함) char형으로 자동 변환됨
문자열 형식 의미
LPSTR (long pointer string) char*
LPCSTR (long pointer constant string) const char*
LPWSTR (long pointer wide string) wchar_t*
LPCWSTR (long pointer constant wide string) const wchar_t*
LPTSTR (long pointer t_string) TCHAR*
LPCTSTR (long pointer costant t_string) const TCHAR*

4) 윈도우에 문자열을 출력하는 방법

  • 윈도우에 문자영을 출력하기 위해서는 반드시 디바이스 컨텍스트 핸들을 얻어와야 함
  • 디바이스 컨텍스트를 얻은 후 윈도우에 문자열을 출력하기 위해서는 TextOut() 함수나 DrawText() 함수를 사용
  • TextOut(): 화면의 지정된 위치에 문자열을 출력하는 함수
  • DrawText(): 영역을 정하고 이 영역에 출력 형식에 맞게 문자열을 출력하는 함수
  • GetClientRect(): 윈도우의 클라이언트 영역의 크기를 알아내는 함수
    • CWnd 클래스의 함수이며 윈도우의 클라이언트 영역을 RECT 구조체로 반환

5) MFC에서의 WinMain() 함수와 윈도우 프로시저

  • MFC 애플리케이션에 WinMain() 함수를 작성할 필요가 없음
  • WinMain() 함수는 프레임워크에서 제공되며 애플리케이션이 시작될 때 호출됨
  • MFC는 클래스가 생성하는 대부분의 메시지를 처리하는 내부적인 메시징 시스템을 갖고 있음
  • MFC 안에서 메시지를 처리할 수 없을 때 애플리케이션은 디폴트 윈도우 프로시저, 즉 DefWindowProc() 함수를 호출하여 해당 메시지를 처리함