위 처럼 프로젝트를 생성하시면
// BrickOut.cpp : 애플리케이션에 대한 진입점을 정의합니다.
//
#include "framework.h"
#include "BrickOut.h"
#define MAX_LOADSTRING 100
// 전역 변수:
HINSTANCE hInst; // 현재 인스턴스입니다.
WCHAR szTitle[MAX_LOADSTRING]; // 제목 표시줄 텍스트입니다.
WCHAR szWindowClass[MAX_LOADSTRING]; // 기본 창 클래스 이름입니다.
// 이 코드 모듈에 포함된 함수의 선언을 전달합니다:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: 여기에 코드를 입력합니다.
// 전역 문자열을 초기화합니다.
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_BRICKOUT, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// 애플리케이션 초기화를 수행합니다:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_BRICKOUT));
MSG msg;
// 기본 메시지 루프입니다:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// 함수: MyRegisterClass()
//
// 용도: 창 클래스를 등록합니다.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_BRICKOUT));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_BRICKOUT);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
//
// 함수: InitInstance(HINSTANCE, int)
//
// 용도: 인스턴스 핸들을 저장하고 주 창을 만듭니다.
//
// 주석:
//
// 이 함수를 통해 인스턴스 핸들을 전역 변수에 저장하고
// 주 프로그램 창을 만든 다음 표시합니다.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // 인스턴스 핸들을 전역 변수에 저장합니다.
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// 함수: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// 용도: 주 창의 메시지를 처리합니다.
//
// WM_COMMAND - 애플리케이션 메뉴를 처리합니다.
// WM_PAINT - 주 창을 그립니다.
// WM_DESTROY - 종료 메시지를 게시하고 반환합니다.
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// 메뉴 선택을 구문 분석합니다:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: 여기에 hdc를 사용하는 그리기 코드를 추가합니다...
// 윈도우 핸들
// 윈도우 좌표
// HDC?
// 화면 가운데에 사각형 그리기 테스트
RECT rc;
int centerX, centerY;
if (GetClientRect(hWnd, &rc))
{
centerX = (rc.left + rc.right) / 2;
centerY = (rc.bottom + rc.top) / 2;
Rectangle(hdc, centerX - 20, centerY + 20, centerX + 20, centerY - 20);
}
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// 정보 대화 상자의 메시지 처리기입니다.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
위와 같이 프로젝트가 만들어집니다.
wWinMain
처음 호출되게 되면 wWinMain함수가 호출되게 됩니다.
_In_과 같은 부분들은 SAL이라는 주석언어 입니다. 실제로는 많이 사용하지 않는거 같습니다.
뒤에 UNREFERENCED_PARAMETER라는 메크로는 말 그대로 참조되지 않는 파라미터인데
아마 이전 윈도우와의 호환 때문에 남겨둔 것으로 생각이 됩니다.
wWinMain의 인자들 중에 hInstance는 방금 만든 프로그램이 실행이 되면 메모리에 올라가게 되는데
메모리에 올라간 시작 주소를 의미합니다.
hPrevInstance는 초창기의 윈도우 때문에 남겨진 매개변수입니다.
윈도우가 발전하게 되면서 필요없어진 매개변수라 SAL주석으로도 Optional이라는 주석이 달린 것을 확인 할 수 있습니다.
또한 윈도우는 가상메모리 시스템을 사용하기 때문에 hInstance의 값이 다 같이 나옵니다.
(실제 메모리에 올라간 물리적인 주소는 다릅니다.)
lpCmdLine은 추가 명령어를 받는 인자입니다. (게임을 만들 때는 딱히 필요하지는 않습니다)
MyRegisterClass
해당 함수는 wcex라는 구조체의 멤버 변수들을 채우는 함수입니다.
다채우고 나서 RegisterClassExW에 전달해주는데 해당함수는 윈도우에서 제공하는 함수인데 선언만 볼 수 있고 실제 구현은 볼 수 없습니다.
위의 함수는 윈도우 정보를 등록하는 용도로 사용됩니다.
InitInstance
위의 함수에서 CreateWindowW를 통해 윈도우를 생성한다음에
아래의 while문 -> 메세지 루프를 통해서 메세지 큐에 메세지를 받습니다.
해당 while문은 WM_QUIT이라는 메세지가 발생하면 윈도우창을 닫고 프로그램을 종료를 합니다.
그 이외의 메세지들은 계속해서 입력을 받습니다.
WM_QUIT이라는 메세지가 발생하기 전까지 목이 빠지게 대기를 합니다.
게임을 만들기 위해서는 해당 while문을 수정하여 게임에 적법하게 로직을 수정해야합니다.
http://www.directxtutorial.com/Lesson.aspx?lessonid=11-1-3
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!