일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- UI
- 언리얼 엔진
- gas
- 유니티
- gravity direction
- map design
- Unreal Engine
- Replication
- 게임 개발
- dirty cow
- os
- photon fusion2
- ability task
- MAC
- gameplay ability system
- local prediction
- unity
- gameplay tag
- 언리얼엔진
- ret2libc
- Aegis
- rpc
- CTF
- 게임개발
- gameplay effect
- nanite
- attribute
- animation
- listen server
- Multiplay
- Today
- Total
Replicated
Windows API로 진입점 만들기 본문
https://github.com/Lagooneng/DirectX11Study
GitHub - Lagooneng/DirectX11Study: DirectX11 공부
DirectX11 공부. Contribute to Lagooneng/DirectX11Study development by creating an account on GitHub.
github.com
#pragma once
#include "DirectXMath.h"
using int8 = __int8;
using int16 = __int16;
using int32= __int32;
using int64 = __int64;
using uint8 = unsigned __int8;
using uint16 = unsigned __int16;
using uint32 = unsigned __int32;
using uint64 = unsigned __int64;
using Vec2 = DirectX::XMFLOAT2;
using Vec3 = DirectX::XMFLOAT3;
using Vec4 = DirectX::XMFLOAT4;
using Color = DirectX::XMFLOAT4;
#pragma once
#include "Types.h"
const int32 GWinSizeX = 800;
const int32 GWinSizeY = 600;
일단 이런식으로 필요한 헤더 선언해주고
미리 컴파일된 헤더 사용 설정
헤더 이름은 pch.h로 해주고
pch.cpp 속성 가서 pch에는 미리 컴파일된 헤더에서 만들기로 설정
#pragma once
#include "Types.h"
#include "Values.h"
#include "Struct.h"
//STL
#include <vector>
#include <list>
#include <map>
#include <unordered_map>
using namespace std;
// WIN
#include <Windows.h>
#include <assert.h>
// DX
#include <d3d11.h>
#include <d3dcompiler.h>
#include <wrl.h>
#include <DirectXMath.h>
#include <DirectXTex/DirectXTex.h>
#include <DirectXTex/DirectXTex.inl>
using namespace DirectX;
using namespace Microsoft::WRL;
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d3dcompiler.lib")
#ifdef _DEBUG
#pragma comment(lib, "DirectXTex\\DirectXTex_debug.lib")
#else
#pragma comment(lib, "DirectXTex\\DirectXTex.lib")
#endif // _DEBUG
pch에는 필요한 거 다 넣어놓기
추가 파일, 링크할 라이브러리 파일 디렉터리 연결
필요한 거 다 넣어주기
// GameCoding.cpp : 애플리케이션에 대한 진입점을 정의합니다.
//
#include "pch.h"
#include "framework.h"
#include "GameCoding.h"
#include "Game.h"
#define MAX_LOADSTRING 100
// 전역 변수:
HINSTANCE hInst; // 현재 인스턴스입니다.
HWND hWnd;
// 이 코드 모듈에 포함된 함수의 선언을 전달합니다:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
// 윈도우 창 정보 등록
MyRegisterClass(hInstance);
// 윈도우 창 생성
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
Game game;
game.Init(hWnd);
MSG msg = {};
// 기본 메시지 루프입니다:
while (msg.message != WM_QUIT)
{
if ( ::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
game.Update();
game.Render();
}
}
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_GAMECODING));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = L"GameCoding";
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
//
// 함수: InitInstance(HINSTANCE, int)
//
// 용도: 인스턴스 핸들을 저장하고 주 창을 만듭니다.
//
// 주석:
//
// 이 함수를 통해 인스턴스 핸들을 전역 변수에 저장하고
// 주 프로그램 창을 만든 다음 표시합니다.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // 인스턴스 핸들을 전역 변수에 저장합니다.
RECT windowRect = { 0, 0, GWinSizeX, GWinSizeY };
::AdjustWindowRect(&windowRect, WS_OVERLAPPEDWINDOW, false);
hWnd = CreateWindowW(L"GameCoding", L"Client", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, 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_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: 여기에 hdc를 사용하는 그리기 코드를 추가합니다...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
이거 만들면 나오는 거 조금 변경된 코드
메뉴 창 같은 거 날리고 게임이랑 연결
1. 진입점
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
// 윈도우 창 정보 등록
MyRegisterClass(hInstance);
// 윈도우 창 생성
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
Game game;
game.Init(hWnd);
MSG msg = {};
// 기본 메시지 루프입니다:
while (msg.message != WM_QUIT)
{
if ( ::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
game.Update();
game.Render();
}
}
return (int) msg.wParam;
}
이 부분은 진입점 코드
hInstance : 프로그램의 인스턴스 핸들. 윈도우를 만들거나 리소스 로딩 시 필요
lpCmdLine : 명령줄 인자 문자열
nCmdShow : 윈도우가 시작 시 어떤 상태로 보여줄지(최소화, 최대화 등)
MyRegisterClass(hInstance);
윈도우의 클래스 정보 등록
if (!InitInstance (hInstance, nCmdShow)) {
return FALSE;
}
윈도우 실제 생성 및 화면 표시
Game game;
game.Init(hWnd);
게임 초기화
MSG msg = {};
while (msg.message != WM_QUIT)
{
if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
game.Update();
game.Render();
}
}
게임 루프
PeekMessage() : 마우스 클릭, 키보드 입력 등을 확인하고 처리
메시지가 없을 때만 Update랑 Render를 돌리는 구조
return (int) msg.wParam;
프로그램 종료 시 종료 코드 리턴
2. 클래스 등록
윈도우를 만들기 전 창이 어떤 모습인지 정의할 필요가 있음
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
WNDCLASSEXW : 윈도우 창의 속성을 정의하는 구조체
그 밑에는 구조체 사이즈 지정
wcex.style = CS_HREDRAW | CS_VREDRAW;
창이 바뀌면 다시 그려라
CS_HREDRAW: 가로 크기 바뀌면 다시 그림
CS_VREDRAW: 세로 크기 바뀌면 다시 그림
wcex.lpfnWndProc = WndProc;
윈도우 메시지를 처리할 함수 지정
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
클래스/윈도우에 추가적인 메모리를 붙일 건지 설정
wcex.hInstance = hInstance;
현재 실행 중인 앱 인스턴스 핸들
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_GAMECODING));
앱 아이콘 로딩
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
마우스 커서 모양 지정 (IDC_ARROW는 기본 화살표)
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
배경색 설정. 시스템 기본 윈도우 배경색
wcex.lpszMenuName = NULL;
메뉴 안 씀
wcex.lpszClassName = L"GameCoding";
이 클래스의 이름. CreateWindow()에서 이 이름으로 창을 생성함
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
작은 아이콘 (작업 표시줄용)
return RegisterClassExW(&wcex);
이걸 호출하면 OS에 “이런 스타일의 창을 만들 거야” 하고 등록하는 거고,
나중에 CreateWindow(L"GameCoding", ...) 이런 식으로 이 클래스를 써서 창을 만듦.
3. 실제 윈도우 창 만들기
hInst = hInstance;
전달받은 앱 인스턴스 핸들을 전역 변수 hInst에 저장. → 나중에 리소스 로딩 등에 사용될 수 있음.
RECT windowRect = { 0, 0, GWinSizeX, GWinSizeY };
::AdjustWindowRect(&windowRect, WS_OVERLAPPEDWINDOW, false);
원하는 클라이언트 영역 크기를 가진 창을 만들기 위해 윈도우 전체 크기를 계산
GWinSizeX, GWinSizeY는 전역 상수로 가로세로 크기
AdjustWindowRect() - WS_OVERLAPPEDWINDOW 설정을 통해 타이틀바, 테두리 포함된 실제 창 크기로 조정해줌
hWnd = CreateWindowW(
L"GameCoding", // 윈도우 클래스 이름 (MyRegisterClass에서 등록한 이름)
L"Client", // 윈도우 타이틀
WS_OVERLAPPEDWINDOW, // 윈도우 스타일 (타이틀, 크기 조절 등 포함)
CW_USEDEFAULT, 0, // 기본 위치
windowRect.right - windowRect.left, // 너비
windowRect.bottom - windowRect.top, // 높이
nullptr, nullptr, // 부모 윈도우, 메뉴 없음
hInstance, // 앱 인스턴스 핸들
nullptr); // 추가 데이터 없음
윈도우 생성
성공하면 hWnd에 윈도우 핸들이 들어감
if (!hWnd) {
return FALSE;
}
창 생성 실패하면 FALSE 반환해서 wWinMain()에서 바로 종료하도록 함
::ShowWindow(hWnd, nCmdShow);
::UpdateWindow(hWnd);
ShowWindow: 윈도우를 화면에 표시 (최소화/최대화 방식은 nCmdShow에 따라)
UpdateWindow: 윈도우를 강제로 즉시 다시 그림 (WM_PAINT 메시지 발생)
4. 이벤트 수신
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
hWnd: 이벤트가 발생한 윈도우의 핸들
message: 어떤 메시지가 왔는지 (예: 마우스 클릭, 키 입력, 윈도우 닫힘 등)
wParam, lParam: 메시지에 따라 달라지는 추가 정보
case WM_COMMAND:
{
int wmId = LOWORD(wParam); // 어떤 메뉴/컨트롤인지 구분
switch (wmId)
{
case IDM_EXIT:
DestroyWindow(hWnd); // 윈도우 파괴 요청 → WM_DESTROY 발생함
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam); // 기본 처리
}
}
break;
명령 발생 시
일단 종료 명령만 구분하고
그 외는 DefWindowProc에 맡겨서 OS 기본 동작 수행하게 함
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// hdc(디바이스 컨텍스트)로 그리기 작업 가능
EndPaint(hWnd, &ps);
}
break;
윈도우 다시 그려야 하는 경우
여기서 hdc를 사용해서 텍스트, 도형, 이미지 등을 직접 그릴 수 있음
case WM_DESTROY:
PostQuitMessage(0); // 메시지 루프에 WM_QUIT 전송 → 앱 종료 신호
break;
DestroyWindow() 호출하면 이 메시지가 옴
앱 종료 마무리 동작
default:
return DefWindowProc(hWnd, message, wParam, lParam);
위에서 처리하지 않은 메시지는 모두 Windows OS 기본 동작에 맡김
#include "pch.h"
#include "Game.h"
Game::Game()
{
}
Game::~Game()
{
}
void Game::Init(HWND hand)
{
_hwnd = hand;
_width = GWinSizeX;
_height = GWinSizeY;
}
void Game::Update()
{
}
void Game::Render()
{
}
이제 기본 세팅 끝나서 Game 클래스만 조정하면 됨
'DirectX 11' 카테고리의 다른 글
그래픽스 개요 (1) | 2025.04.06 |
---|