프로그래밍/C++

Win32 API ] 윈도우 프로그램의 기본 구조

eteo 2023. 12. 13. 22:02

 

 

 

 

MFC 프레임워크 안에 숨겨진 윈도우 프로그램의 기본 구조를 이해해보자.

 

 

 

Windows에서 실행되는 애플리케이션의 종류

 

 

윈도우에서 실행되는 애플리케이션은 크게 콘솔 애플리케이션과 GUI 애플리케이션으로 나눌 수 있다.

 

 

 

 

콘솔 앱 또는 데스크톱 애플리케이션 만들기

 

 

 

 

 

프로젝트 생성 시 콘솔 또는 데스크톱 애플리케이션을 지정하여 생성할 수 있으며, 이미 생성한 프로젝트를 콘솔 또는 GUI 애플리케이션으로 변경하려면 프로젝트 우클릭 - 속성 - 링커 - 시스템 - 하위 시스템에서 변경 가능하다.

 

 

 

 

 

 

 

Windows C/C++ 애플리케이션의 진입점

 

프로그램이 실행될 때 가장 먼저 호출되는 함수를 프로그램의 진입점(entry point)라고 하고, 이 진입점을 호출하는 함수는 C/C++ 런타임(CRT) 초기화를 담당하는 함수로 다양한 초기화 작업을 수행 한 뒤 main함수를 호출하는 역할을 한다.

프로그램이 GUI냐 콘솔이냐에 따라 다른 CRTStartup 함수가 사용되며 이는 프로젝트 설정에 의해 지정된다.

 

 

https://i.stack.imgur.com/VG9RO.jpg

 

 

 

 

✔ 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 윈도우 프로그래밍, 정일홍 저