MFC 프레임워크 안에 숨겨진 윈도우 프로그램의 기본 구조를 이해해보자.
Windows에서 실행되는 애플리케이션의 종류
윈도우에서 실행되는 애플리케이션은 크게 콘솔 애플리케이션과 GUI 애플리케이션으로 나눌 수 있다.
콘솔 앱 또는 데스크톱 애플리케이션 만들기
프로젝트 생성 시 콘솔 또는 데스크톱 애플리케이션을 지정하여 생성할 수 있으며, 이미 생성한 프로젝트를 콘솔 또는 GUI 애플리케이션으로 변경하려면 프로젝트 우클릭 - 속성 - 링커 - 시스템 - 하위 시스템에서 변경 가능하다.
Windows C/C++ 애플리케이션의 진입점
프로그램이 실행될 때 가장 먼저 호출되는 함수를 프로그램의 진입점(entry point)라고 하고, 이 진입점을 호출하는 함수는 C/C++ 런타임(CRT) 초기화를 담당하는 함수로 다양한 초기화 작업을 수행 한 뒤 main함수를 호출하는 역할을 한다.
프로그램이 GUI냐 콘솔이냐에 따라 다른 CRTStartup 함수가 사용되며 이는 프로젝트 설정에 의해 지정된다.
✔ GUI 응용 프로그램에서 콘솔창을 띄우려면 다음의 컴파일러 지시문을 추가하면 된다.
#ifdef _DEBUG
#pragma comment(linker, "/entry:WinMainCRTStartup /subsystem:console")
#endif
Win32 API를 사용해 작성된 간단한 윈도우 프로그램
#include <Windows.h>
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR LpszCmdLine, int nCmdShow)
{
HWND hwnd; // 윈도우 핸들
MSG msg; // 메시지 구조체
WNDCLASSEX WndClass; // 윈도우 클래스 구조체
// 윈도우 클래스 구조체 WndClass에 값을 채워 윈도우 클래스를 등록한다.
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);
// 프레임 윈도우를 생성한다.
hwnd = CreateWindow( // 윈도우 생성 API 함수
"EasyText", // 등록된 윈도우 클랫 ㅡ이름
"WindowProgram", // 타이틀 바에 출력될 문자열
WS_OVERLAPPEDWINDOW, // 윈도우 스타일
CW_USEDEFAULT, // 윈도우 좌측 상단의 x 좌표
CW_USEDEFAULT, // 윈도우 좌측 상단의 y 좌표
CW_USEDEFAULT, // 윈도우의 너비
CW_USEDEFAULT, // 윈도우의 높이
NULL, // 부모 윈도우의 핸들
NULL, // 메뉴 또는 자식 윈도우의 핸들
hInstance, // 애플리케이션 인스턴스 핸들
NULL // 윈도우 생성 데이터의 주소
);
// 프레임 윈도우를 화면에 표시한다.
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// 메시지 큐로부터 메시지를 받아와 해당 윈도우 프로시저로 보낸다.
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc; // 디바이스 컨텍스트
RECT rect;
PAINTSTRUCT ps;
LPCSTR szMsg1 = "간단한 윈도우 프로그램";
LPCSTR szMsg2 = "키보드가 눌러졌습니다.";
LPCSTR szMsg3 = "키보드가 떼어졌습니다.";
// 커널에서 들어온 메시지를 switch 문을 이용하여 처리
switch (message)
{
case WM_CREATE:
break;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
TextOut(hdc, 10, 10, szMsg1, strlen(szMsg1));
EndPaint(hwnd, &ps);
break;
case WM_KEYDOWN:
hdc = GetDC(hwnd);
GetClientRect(hwnd, &rect);
DrawText(hdc, szMsg2, strlen(szMsg2), &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
ReleaseDC(hwnd, hdc);
break;
case WM_KEYUP:
hdc = GetDC(hwnd);
GetClientRect(hwnd, &rect);
DrawText(hdc, szMsg3, strlen(szMsg3), &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
ReleaseDC(hwnd, hdc);
break;
case WM_LBUTTONDBLCLK:
MessageBox(hwnd, "마우스 더블 클릭", "마우스 메시지", MB_OK | MB_ICONASTERISK);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
모든 윈도우 프로그램과 마찬가지로 MFC 애플리케이션도 WinMain()과 윈도우 프로시저를 가지고 있지만 프레임워크 안에 숨겨져 있기 때문에 전체적인 구조를 파악하기가 어렵다.
코드출처 :
Visaul C++ 2022 MFC 윈도우 프로그래밍, 정일홍 저
'프로그래밍 > C++' 카테고리의 다른 글
C++ 에서 구조체와 클래스의 차이 (0) | 2024.02.14 |
---|---|
C++ ] 벡터의 최대값과 최소값 찾기, max_element, min_element (0) | 2024.02.10 |
C/C++ ] 윈도우 콘솔 프로그램 아이콘 변경하기 + 무료 아이콘 찾기 (0) | 2023.12.09 |
C/C++ ] start 명령어 사용 새로운 프롬프트 창에서 시스템 명령 사용하기 (0) | 2023.12.08 |
C/C++ ] 키보드 메시지 후킹을 사용한 간단 키로거 (0) | 2023.11.21 |