이전 단계인 "4. DirectX 창 만들기" 에서는 RenderWindow에서 창을 만들고 메시지를 처리했습니다.
이번 단계에서는 Engine 클래스가 WindowContainer 클래스를 상속받아 창을 초기화하고 메시지를 처리하려고 합니다.
WindowContainer.h
#pragma once
#include "RenderWindow.h"
class WindowContainer
{
public:
LRESULT WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
protected:
RenderWindow render_window;
private:
};
WindowContainer.cpp
#include "WindowContainer.h"
LRESULT WindowContainer::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
/* 처리되지 않은 모든 메시지의 디폴트 처리를 수행 */
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
Engine.h
#pragma once
#include "WindowContainer.h"
/* WindowContainer 클래스 상속 */
class Engine : WindowContainer
{
public:
bool Initialize(HINSTANCE hInstance, string window_title, string window_class, int width, int height); // 창 초기화
bool ProcessMessages(); // 메시지 처리
};
Engine.cpp
#include "Engine.h"
/* RenderWindow 초기화 */
bool Engine::Initialize(HINSTANCE hInstance, string window_title, string window_class, int width, int height)
{
return this->render_window.Initialize(this, hInstance, window_title, window_class, width, height);
}
/* 메시지 처리 */
bool Engine::ProcessMessages()
{
return this->render_window.ProcessMessages();
}
RenderWindow.h
#pragma once
#include "ErrorLogger.h"
class WindowContainer; // 추가
class RenderWindow
{
public:
/* 함수 인자 변경 */
bool Initialize(WindowContainer* pWindowContainer, HINSTANCE hInstance, string window_title, string window_class, int width, int height);
/* 동일 부분 제외 */
};
RenderWindow.cpp
#include "WindowContainer.h" // WindowContainer에서 선언한 RenderWindow가 있기 때문
/* 초기화 -> handle의 마지막 파라미터를 pWindowContainer로 변경 */
bool RenderWindow::Initialize(WindowContainer* pWindowContainer, HINSTANCE hInstance, string window_title, string window_class, int width, int height)
{
/* 동일 부분 제외 */
this->handle = CreateWindowEx(
/* 동일 부분 제외 */
pWindowContainer); // 창을 생성하기 위해
}
/* 동일 함수 제외 */
LRESULT CALLBACK HandleMsgRedirect(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
// 창 종료 시
case WM_CLOSE:
DestroyWindow(hwnd);
return 0;
default:
{
// WindowContainer 클래스로 포인터 검색
WindowContainer* const pWindow = reinterpret_cast<WindowContainer*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
// WindowContainer로 메시지 전달
return pWindow->WindowProc(hwnd, uMsg, wParam, lParam);
}
}
}
LRESULT CALLBACK HandleMessageSetup(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_NCCREATE: // 창이 생성될 때 메시지를 전달해줌
{
const CREATESTRUCTW* const pCreate = reinterpret_cast<CREATESTRUCTW*>(lParam);
WindowContainer* pWindow = reinterpret_cast<WindowContainer*>(pCreate->lpCreateParams);
/* WindowContainer가 생성되었는지 체크 */
if (pWindow == nullptr)
{
ErrorLogger::Log("Critical Error: Pointer to window container is null during WM_NCCREATE.");
exit(-1);
}
// GWLP_USERDATA 유저 데이터를 win32 내에 저장할 수 있는데 이 핸들값을 저장해둠
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pWindow));
// 메시지 처리를 HandleMsgRedirect에 넘김
SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(HandleMsgRedirect));
return pWindow->WindowProc(hwnd, uMsg, wParam, lParam);
}
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
/* 렌더링 할 윈도우 특징 설정 */
void RenderWindow::RegisterWindowClass()
{
WNDCLASSEX wc; // 윈도우 클래스
/* 이 창에서 메시지를 처리하기 위한 WindowProc 함수 포인터 */
wc.lpfnWndProc = HandleMessageSetup;
/* 동일 부분 제외 */
}
main.cpp
#include "Engine.h" // 변경점
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "DirectXTK.lib")
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, // 인스턴스에 대한 핸들
_In_opt_ HINSTANCE hPrevInstance, // 사용 X
_In_ LPWSTR lpCmdLine, // 커맨드 라인을 유니코드 문자열로 포함
_In_ int cCmdShow) // 기본 응용 프로그램 창이 최소화, 최대화 또는 정상적으로 표시되는지 여부를 나타내는 플래그
{
/* 변경점 */
Engine engine;
engine.Initialize(hInstance, "Title", "MyWindowClass", 800, 600);
while (engine.ProcessMessages() == true) {
}
return 0;
}