12
24

콘솔에 int main()이라는 메인 함수가 있듯이, 

 

Window 창에도 wWinmain()이라는 메인 함수가 있다.

윈도우는 메시지 기반으로 모든 처리를 한다. 이거는 아래서

좀더 구체적으로 써보겠다. 아래는 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

 

WNDCLASSEXW (winuser.h) - Win32 apps

Contains window class information.

docs.microsoft.com

 

윈도우 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로 구조체를 모두 초기화한 후에 필요한 내용을 채워준다.

 

채워줌, lpfnWndProc는 메세지 핸들러를 등록하는 것.

 

클래스 이름을 dd로 했다.

이제 윈도우클래스를 등록하면 된다.

 

등록

 

등록을 했으면 이제 생성을 해야한다. CreateWindowEXW로 생성한다.

 

EX로도 생성이 된다. EXW랑 호환이 되나보다.

 

클래스 이름과 같은 이름 dd로 윈도우를 생성한다.

생성한 윈도우를 m_hWnd에 담음

m_hWnd로 ShowWindow해서 윈도우를 보이게 한다.

 

 

 

hWnd 핸들러나, 윈도우 크기나 여러 곳에서 쓰이니 

외부변수로 꺼내준다.

 

이제 윈도우 창 초기화는 끝났다.

 


 

윈도우 애플리케이션은 메시지 기반으로 처리한다고 했다.

메시지 루프라는 반복 구조로 큐에 모인 메세지를 하나씩 꺼내

순서대로 처리하는 방식이다. 

 

순서대로 처리하다보니, 하나의 메세지가 오래걸리는 작업이라면

그 시간동안은 다른 작업을 할 수 가 없게 되어 버린다.

 

그 해결방안으로는 처리를 분할하거나, 멀티스레드를 이용하는 방법이 있다.

 

메시지를 받는 방식으로 GetMessage 와 PeekMessage가 있는데

GetMessage는 메시지를 꺼내고 큐에서 삭제하는 반면,

 

PeekMessage API는 메시지가 있는 경우 그 이벤트를 우선처리하고

메시지가 없는 경우에 다른 일을 하게 할 수 있다.  

 

Run
PeekMessageW

메시지(예를 들어 창닫기, 스크롤, 창 이동 등)가 있다면 

메시지를 수행하도록하고 아닐 경우에는 다른 활동을 하게

한다. 

 

더보기
//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();
};

 

COMMENT