DirectX11 - Window 초기화

Sungsik Bae·2024년 1월 14일

DirectX11

목록 보기
2/6
post-thumbnail

Window 초기화

Window 창을 띄어 보겠다.
Cpp 기본 솔루션 설정으로 띄우는 방법도 있지만 직접 하나하나 구현해보고자 한다.

Register window class


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

int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
	// Register Window class.
	constexpr wchar_t CLASS_NAME[] = L"Sample Window Class";

	WNDCLASS wc = {};
	wc.lpfnWndProc = WindowProc;
	wc.hInstance = hInstance;
	wc.lpszClassName = CLASS_NAME;

	RegisterClass(&wc);

	return 0;
}

WNDCLASS 구조체를 생성해서 Register한다.
WNDCLASS의 전체를 설정하지 않았는데, 이런식으로 해도 Window를 생성하는 것에는 문제가 없나보다.

어디에 Register를 하는 것일까..?
공식문서에 따르면 CreateWindowCreateWindowEx 함수에서 사용하기 위해서 Register한다고 하는데, 어떤 방식으로 내가 생성한 구조체를 알아올까?

Create & Show window

	// Create Window
	HWND hwnd = CreateWindowEx(
		0,								// Optional window styles
		CLASS_NAME,						// Window class
		L"Learn to Program Windows",	// Window text
		WS_OVERLAPPEDWINDOW,			// Window style

		// Size and position
		CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,

		nullptr,	// Parent window
		nullptr,	// Menu
		hInstance,	// Instance handle
		nullptr		// Additional application data
	);

	if (hwnd == nullptr)
	{
		return 0;
	}

	ShowWindow(hwnd, nCmdShow);

CreateWindowEx 함수를 보니 CLASS_NAME을 통해서 Register 된 WNDCLASS 구조체를 가져오나 보다.

파라미터들 또한 주석이 달려있어서 쉽게 이해했다.

Message loop

	// Run the message loop
	MSG msg = {};
	while (GetMessage(&msg, nullptr, 0, 0) > 0)
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

Message loop란 무엇일까?
공식 문서에는 이렇게 되어있다.

응용 프로그램은 실행 중에 수천개의 메세지를 받는다(키보드나 마우스 클릭 등). 또한 응용 프로그램은 여러 개의 윈도우를 가질 수 있으며, 각각의 윈도우는 절차(procedure)를 가진다. 프로그램은 이 모든 메세지를 수신하여 올바른 창에 절차대로 전달할 수 있을까?

이 것의 해결 방법이 Message loop이다.

각 윈도우를 생성하는 각각의 스레드에서 OS는 메세지를 위한 Queue를 생성하고 이 Queue에는 해당 스레드에서 생성된 모든 메세지가 저장된다. 사용자는 Queue를 조작할 수 없으나 GetMessage 함수를 통해서 Queue에서 Message를 가져올 수 있다.

TranslateMessage함수는 어떠한 역할을 할까? 함수 이름과 같이 OS로부터 받은 Message를 번역하는 것일까?
안타깝게도 아닌것 같다. 공식 문서에 따르면 Keyboard와 같은 입력을 character값으로 바꿔주는 역할을 한다.

DispatchMessage함수는 어떤 역할을 할까? 이름을 통해 추측해보자면 Message를 어딘가로 전송하는 것 같다.
공식 문서를 살펴보자.
이번에는 비슷하게 맞는 듯 하다. GetMessage를 통해 받은 Message를 Window Procedure에 전송한다.

그렇다면 Window Procedure는 뭘까?
위에 WNDCLASS 구조체에 정보를 입력할 때, 설정해주었다.

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
	...
	wc.lpfnWndProc = WindowProc;
    ...
}

WinProc Callback 함수

언제나 그렇듯 공식 문서를 보자.

DispatchMessage를 통해 메세지가 전송될 때 호출되는 Callback 함수이다.
파라미터가 4개나 있는데, 뭔지 알아보자.

  • HWND hWnd : 메세지를 받을 Window Handle
  • UINT uMsg : 메세지의 종류
  • WPARAM wParam : 메세지에 따른 추가 정보
  • LPARAM lParam : 메세지에 따른 추가 정보

작성된 WindowProc Callback 함수

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_SIZE: // Handle window resizing
	{
		const int width = LOWORD(lParam); // Macro to get the low-order word
		const int height = HIWORD(lParam); // Macro to get the high-order word

		// Respond to the message:
		OnSize(hWnd, static_cast<UINT>(wParam), width, height);
	}
	break;
	default:;
	}

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

void OnSize(HWND hWnd, UINT flag, int width, int height)
{
	// Handle resizing
}

LOWORD 매크로는 width값을 lParam으로부터 받음
HIWORD 매크로는 height값을 lParam으로부터 받음

WinProc 함수에서 처리하지 않은 Message는 DefWindowProc함수를 통해 전달한다.
이 함수는 메세지 종류에 따라 기본적인 작업을 수행한다.


이렇게 대충 Window 함수에 기본적인 정보를 알았으니, 다음 장부터는 DirectX에서 사용할 수 있도록 Window 함수를 조금 수정하도록 해야겠다.

profile
Game Developer

0개의 댓글