C++
[강의] 1월 22일 수업정리
k-codestudy
2025. 1. 22. 17:20
오늘은 API 클래스화에 대한 수업을 들었다.
api.h
#pragma once
#include <windows.h>
#include "msgProc.h"
class C_API
{
private:
static C_API* m_pApi;
HWND m_hWnd;
HINSTANCE m_hInstance;
C_MSGPROC m_cMsgProc;
private:
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
C_API() = default;
public:
static void createApi();
static C_API* getApi();
static void releaseApi();
bool init(HINSTANCE hInstance);
void Msg();
};
api.cpp
#include "api.h"
#include "resource.h"
C_API* C_API::m_pApi = nullptr;
void C_API::createApi()
{
if (!m_pApi)
m_pApi = new C_API{};
}
C_API* C_API::getApi()
{
return m_pApi;
}
void C_API::releaseApi()
{
if (m_pApi)
{
delete m_pApi;
m_pApi = nullptr;
}
}
bool C_API::init(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_WINAPI));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = 0;
wcex.lpszClassName = L"TEST";
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
RegisterClassExW(&wcex);
m_cMsgProc.init();
HWND hWnd = CreateWindowW(L"TEST", 0, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
return FALSE;
ShowWindow(hWnd, SW_SHOWDEFAULT);
UpdateWindow(hWnd);
return true;
}
void C_API::Msg()
{
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
LRESULT CALLBACK C_API::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return m_pApi->m_cMsgProc.apiProc(hWnd, message, wParam, lParam);
}
C_API 클래스는 윈도우 애플리케이션을 초기화하고 메시지 루프를 관리하며, Singleton 패턴을 사용하여 애플리케이션 내에서 단일 인스턴스만 유지된다.
createApi()
- C_API 클래스의 인스턴스를 생성한다
- 이미 인스턴스가 존재하면 아무 작업도 수행하지 않는다
getApi()
- 생성된 C_API 인스턴스를 반환한다
releaseApi()
- C_API 인스턴스를 삭제하고 메모리를 해제한다
init(HINSTANCE hInstance)
- 윈도우 클래스를 등록하고, 윈도우를 생성 및 초기화한다
- 성공하면 true, 실패하면 false를 반환한다
Msg()
- 메시지 루프를 실행한다
- GetMessage 함수로 메시지를 대기 및 처리한다
WndProc
- 윈도우 프로시저 콜백 함수이다
- 메시지가 발생할 때 호출되며, C_MSGPROC의 메시지 처리 함수로 위임한다
msgProc.h
#pragma once
#include <windows.h>
class C_MSGPROC
{
private:
LRESULT(C_MSGPROC::* m_arProc[WM_USER]) (HWND, UINT, WPARAM, LPARAM); // WM_USER 여기까지 쓸꺼라고 예약이 되어있음 그렇기에 값을 WM_USER까지라고 하면 됨
LRESULT onPaint(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT onDestroy(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT onKeyDown(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
public:
void init();
LRESULT apiProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
};
msgProc.cpp
#include "msgProc.h"
LRESULT C_MSGPROC::onPaint(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
return 0;
//return LRESULT(); // 함정 : 이게 뭘까 -> 메시지 처리의 서명된 결과 ( 성공이 0 이다. )
}
LRESULT C_MSGPROC::onDestroy(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PostQuitMessage(0);
return 0;
}
LRESULT C_MSGPROC::onKeyDown(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (wParam == VK_ESCAPE)
DestroyWindow(hWnd);
return 0;
}
void C_MSGPROC::init()
{
m_arProc[WM_PAINT] = &C_MSGPROC::onPaint;
m_arProc[WM_DESTROY] = &C_MSGPROC::onDestroy;
m_arProc[WM_KEYDOWN] = &C_MSGPROC::onKeyDown;
}
LRESULT C_MSGPROC::apiProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message >= WM_USER || !m_arProc[message])
return DefWindowProc(hWnd, message, wParam, lParam);
return (this->*m_arProc[message])(hWnd, message, wParam, lParam);
}
C_MSGPROC 클래스는 개별 메시지(WM_PAINT, WM_DESTROY, WM_KEYDOWN)에 대한 처리 로직을 정의하고 이를 관리합니다.
init()
- 처리할 메시지를 배열 m_arProc에 등록한다
- 각 메시지는 해당 메시지에 대응하는 멤버 함수 포인터로 매핑된다
apiProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
- 전달된 메시지를 처리한다
- 등록된 메시지인지 확인한 후, 해당 메시지 처리 함수를 호출한다
- 등록되지 않은 메시지는 기본 윈도우 프로시저(DefWindowProc)로 처리한다
onPaint()
- WM_PAINT 메시지를 처리합니다. 창을 다시 그릴 때 호출된다
onDestroy()
- WM_DESTROY 메시지를 처리합니다. 창이 종료될 때 호출되며 메시지 루프를 종료한다
onKeyDown()
- WM_KEYDOWN 메시지를 처리합니다. 키보드 입력(예: ESC 키)을 처리한
main.cpp
#include "framework.h"
#include "winAPI.h"
#include "api.h"
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
C_API::createApi();
C_API::getApi()->init(hInstance);
C_API::getApi()->Msg();
C_API::releaseApi();
}
윈도우 애플리케이션의 진입점으로, C_API의 생명주기를 관리
- C_API::createApi()로 C_API 인스턴스를 생성한다
- init(hInstance)로 윈도우 초기화 및 생성에 성공하면, 메시지 루프(Msg())를 실행한다
- 애플리케이션 종료 후 C_API::releaseApi()로 메모리를 해제한다