F.R.I.D.A.Y.

Win32 프로그램 생성하기 5 본문

DEV/C C++

Win32 프로그램 생성하기 5

F.R.I.D.A.Y. 2021. 4. 2. 19:05
반응형

 

 윈도우 프로시저를 이제 작성해보겠습니다.


윈도우 프로시저

 윈도우 프로시저는 Windows에서 수신한 정보를 토대로 그에 알맞은 행동을 정의해놓은 공간이라고 생각할 수 있습니다. 윈도우 프로시저는 아래의 모양을 가지고 있습니다.

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

 뭐 하나 알만한 것이 없습니다. 그렇지만 차근차근 알아가면 못할 것도 없죠. 함수의 자세한 설명은 이 포스트를 참고하세요. 작성하면 기본으로 반환해줄 값이 하나 있습니다. DefWindowProc 함수를 이용하는 것인데요.

 

DefWindowProc

 윈도우에서는 기본으로 처리하는 작업이 있습니다. 윈도우의 이동이 타이틀바에 존재하는 시스템 메뉴[# 최대/최소화 버튼, 창닫기 버튼]의 행동을 담당하는 것들이 있죠. 원래대로라면 이런 작업도 전부 우리 개발자가 담당해서 개발해야하는 내용입니다. 그렇지만 공통적인 부분이기 때문에 Windows에서는 DefWindowProc라는 함수를 이용해 기본 사항들을 처리할 수 있게 됩니다.

LRESULT LRESULT DefWindowProcA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);

 구조는 윈도우 프로시저와 동일합니다. 윈도우의 기본적인 부분을 담당하는 함수이다보니, 프로시저의 공통작업을 그대로 엮어온 것이라고 보면 되겠습니다.

 

필수 처리할 메시지

 이렇게 만들면 다음은 필수 처리할 메시지를 알아보겠습니다.

WM_CLOSE

 시스템 메뉴의 창닫기 버튼을 클릭하는 등 윈도우를 닫으려 할 때 발생하는 이벤트입니다. 이 메시지가 들어온 시점에서는 윈도우를 닫을 것인지 선택할 수 있습니다. 이 메시지에 대한 자세한 내용은 다음 문서를 참고하세요.

 

WM_CLOSE message (Winuser.h) - Win32 apps

WM_CLOSE message In this article --> Sent as a signal that a window or an application should terminate. A window receives this message through its WindowProc function. #define WM_CLOSE 0x0010 Parameters wParam This parameter is not used. lParam This parame

docs.microsoft.com

 

WM_DESTROY

 이 메시지가 들어온 시점에는 윈도우를 닫을 것인지 말 것인지는 결정할 수 없습니다. 이미 윈도우를 없애겠다고 선언된 시점이기 때문입니다. 대신 이 시점엔 완전히 파괴되기 전에 할 작업을 처리할 수 있습니다. 예컨데 프로그램에서 수정된 파일을 임시 저장하는 것입니다.

 

WM_DESTROY message (Winuser.h) - Win32 apps

Sent when a window is being destroyed. It is sent to the window procedure of the window being destroyed after the window is removed from the screen.

docs.microsoft.com

 

 

프로시저 구성하기

 프로시저는 이렇게 구성할 수 있습니다.

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	switch (uMsg) {
		case WM_CLOSE:{
				PostQuitMessage(0);
				return 0;
			}

		case WM_DESTROY: {
				DestroyWindow(hwnd);
				return 0;
			}
	}

	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

 저는 주로 switch 구문을 활용해 프로시저를 구성합니다. if 구문에 비해서 편하니까요.

 

엔트리 포인트에 바인딩하기

 이전 엔트리 포인트를 작성할 때 남겨둔 부분이 있습니다. 

wc.lpfnWndProc = nullptr;

 이 부분의 nullptr을 WindowProc로 변경해줍니다.

wc.lpfnWndProc = WindowProc;

 

중간 점검

 여태 작성한 코드를 나열하면 다음과 같습니다.

더보기

# 중간 코드 점검

#include <Windows.h>

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	switch (uMsg) {
		case WM_CLOSE:{
				PostQuitMessage(0);
				return 0;
			}

		case WM_DESTROY: {
				DestroyWindow(hwnd);
				return 0;
			}
	}


	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR, int nCmdShow) {
	WNDCLASS wc{};

	wc.lpfnWndProc = nullptr;
	wc.lpszClassName = L"Hello world";
	wc.hInstance = hInstance;

	RegisterClass(&wc);

	HWND hWnd = CreateWindow(L"Hello world", L"My First Win32 Program", WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT,
		CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, hInstance, nullptr);

	if (!hWnd) return -1;

	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);

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

 

코드 다듬기

 실행하고 기본 작업을 살펴보겠습니다. 사이즈 조정을 한번 해보세요. 어떻게 되나요?

 조정을 하면 이렇게 검은 칸이 생길 수 있습니다. 줄였다 늘리면 하얀색 공간이 줄어들기도 하구요. 사이즈 조절하고 나서 마우스 커서를 보면 다시 화살표로 돌아오지 않을 수도 있습니다.

 

 우리가 WNDCLASS 등록을 할 때 비워두었던 속성이 있습니다.

wc.hCursor;
wc.hbrBackground;

 다른 항목도 있지만 여기에서는 이 두 항목이 문제의 원입니다. 아무것도 지정하지 않았으니 이리 되는 것입니다. 아래처럼 wc 초기화에 코드를 추가해 등록하겠습니다.

wc.lpfnWndProc = WindowProc;
wc.lpszClassName = L"Hello world";
wc.hInstance = hInstance;

// 추가된 항목
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;

 

 이제 크기를 늘리거나 줄여도 정상적으로 출력이 되는 것을 알 수 있습니다.

최종 코드

 

더보기

# 최종 코드

#include <Windows.h>

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	switch (uMsg) {
		case WM_CLOSE:{
				PostQuitMessage(0);
				return 0;
			}

		case WM_DESTROY: {
				DestroyWindow(hwnd);
				return 0;
			}
	}

	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR, int nCmdShow) {
	WNDCLASS wc{};

	wc.lpfnWndProc = WindowProc;
	wc.lpszClassName = L"Hello world";
	wc.hInstance = hInstance;
	wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)COLOR_WINDOW;

	RegisterClass(&wc);

	HWND hWnd = CreateWindow(L"Hello world", L"My First Win32 Program", WS_OVERLAPPEDWINDOW,
    	CW_USEDEFAULT, CW_USEDEFAULT,
		CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, hInstance, nullptr);

	if (!hWnd) return -1;

	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);

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

 


 이것으로 Win32 프로그래밍을 위한 기본적인 틀이 잡혔습니다. 다음으로는 Window Hello의 사진암호와 비슷한 실행을 가지는 프로그램을 구현해보겠습니다.

# index

728x90
반응형
Comments