Directx11 - 메시지 기반 Window 클래스 등록, 윈도우 생성, 창 띄우기, 메시지 루프 PeekMessageW
콘솔에 int main()이라는 메인 함수가 있듯이,
Window 창에도 wWinmain()이라는 메인 함수가 있다.
윈도우는 메시지 기반으로 모든 처리를 한다. 이거는 아래서
좀더 구체적으로 써보겠다. 아래는 wWinmain() 함수이다.
여러 인자가 있는데 생성할때 운영체제에서 받아오는
정보이다. _In_opt_은 옵션이란 뜻으로 그만 없어도 그만임
Window 창을 띄우기 위해서는
1. 윈도우 클래스 등록
2. 윈도우 생성
과정을 해야한다.
윈도우 클래스는 WNDCLASS,
WNDCLASSEX,
WNDCLASSEXW, 등
추가적인 정보를 담는 차이가 있지만
결과적으로 모두 다 사용 가능하다.
다만 WNDCLASS로 클래스를 만들었으면
WNDCLASS로 등록을 해야한다.
나는 이번에 WNDCLASSEXW로 만들어보겠다.
https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexw
윈도우 MSDN를 참고하면
해당 구조체의 내용이 나온다.
이 구조체를 모두 채워서 등록을 해야하나커서, 아이콘처럼 몇몇는 null값으로 두면알아서 기본값이 들아간다.
typedef struct tagWNDCLASSEXW {
UINT cbSize;
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCWSTR lpszMenuName;
LPCWSTR lpszClassName;
HICON hIconSm;
} WNDCLASSEXW, *PWNDCLASSEXW, *NPWNDCLASSEXW, *LPWNDCLASSEXW;
이름만 봐도 어떠한 정보를 관리하는지 알 수 있다.
ZeroMemory로 구조체를 모두 초기화한 후에 필요한 내용을 채워준다.
클래스 이름을 dd로 했다.
이제 윈도우클래스를 등록하면 된다.
등록을 했으면 이제 생성을 해야한다. CreateWindowEXW로 생성한다.
클래스 이름과 같은 이름 dd로 윈도우를 생성한다.
생성한 윈도우를 m_hWnd에 담음
m_hWnd로 ShowWindow해서 윈도우를 보이게 한다.
hWnd 핸들러나, 윈도우 크기나 여러 곳에서 쓰이니
외부변수로 꺼내준다.
이제 윈도우 창 초기화는 끝났다.
윈도우 애플리케이션은 메시지 기반으로 처리한다고 했다.
메시지 루프라는 반복 구조로 큐에 모인 메세지를 하나씩 꺼내
순서대로 처리하는 방식이다.
순서대로 처리하다보니, 하나의 메세지가 오래걸리는 작업이라면
그 시간동안은 다른 작업을 할 수 가 없게 되어 버린다.
그 해결방안으로는 처리를 분할하거나, 멀티스레드를 이용하는 방법이 있다.
메시지를 받는 방식으로 GetMessage 와 PeekMessage가 있는데
GetMessage는 메시지를 꺼내고 큐에서 삭제하는 반면,
PeekMessage API는 메시지가 있는 경우 그 이벤트를 우선처리하고
메시지가 없는 경우에 다른 일을 하게 할 수 있다.
메시지(예를 들어 창닫기, 스크롤, 창 이동 등)가 있다면
메시지를 수행하도록하고 아닐 경우에는 다른 활동을 하게
한다.
//cpp
#include "KWindow.h"
#include <assert.h>
KWindow* g_pWindow = nullptr;
HWND g_hWnd;
RECT g_rtClient;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// 메세지 핸들링
assert(g_pWindow);
return g_pWindow->MsgProc(hWnd, message, wParam, lParam);
}
LRESULT KWindow::MsgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// 1. 윈도우 클래스 등록
// 2. 윈도우 생성
bool KWindow::InitWindows(
HINSTANCE hInstance,
int nCmdShow,
const WCHAR* strWindowTitle)
{
m_hInstance = hInstance;
WNDCLASSEXW wcex;
ZeroMemory(&wcex, sizeof(WNDCLASSEXW));
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc; //메시지 핸들러 등록
wcex.hInstance = hInstance;
wcex.hbrBackground = CreateSolidBrush(RGB(0,0,0));
wcex.lpszClassName = L"dd";
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
if (!RegisterClassExW(&wcex))
{
return false;
}
RECT rc = { 0, 0, 800, 600 };
// 작업영역( 타이틀 바/경계선/메뉴/스크롤 바 등의 영역을 제외한 영역), 윈도우 스타일, 메뉴여부
AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
// 윈도우 생성 함수
m_hWnd = CreateWindowExW(
0,
L"dd",
strWindowTitle,
WS_OVERLAPPEDWINDOW,
0,
0,
rc.right-rc.left,
rc.bottom-rc.top,
NULL,
NULL,
hInstance,
NULL);
if (m_hWnd == NULL)
{
return false;
}
GetWindowRect(m_hWnd, &m_rtWindow);
GetClientRect(m_hWnd, &m_rtClient);
g_hWnd = m_hWnd;
g_rtClient = m_rtClient;
// WM_SHOW
ShowWindow(m_hWnd, nCmdShow);
return true;
}
bool KWindow::Run()
{
GameInit();
MSG msg;
while (m_bGameRun)
{
if (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
m_bGameRun = GameRun();
}
}
GameRelease();
return true;
}
bool KWindow::GameRun()
{
return true;
}
bool KWindow::GameInit()
{
return true;
}
bool KWindow::GameRelease()
{
return true;
}
KWindow::KWindow() : m_bGameRun(true)
{
g_pWindow = this;
}
//h
#pragma once
#include <windows.h>
#include "KDevice.h"
class KWindow : public KDevice
{
public:
RECT m_rtWindow;
RECT m_rtClient;
HINSTANCE m_hInstance;
HWND m_hWnd;
bool m_bGameRun;
public:
bool InitWindows(HINSTANCE hInstance,
int nCmdShow,
const WCHAR* strWindowTitle);
LRESULT MsgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
bool Run();
virtual bool GameInit();
virtual bool GameRun();
virtual bool GameRelease();
public:
KWindow();
};