API에 대한 마지막 수업을 들었다.
메시지 루프
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WINDOWSPROJECT1));
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
GetMessage
- 메시지 큐에서 메시지를 하나씩 가져온다 ( 메시지 큐에 데이터 입력이 들어가면 루프가 돌면서 메시지를 하나씩 꺼내서 처리함 )
- 메시지가 들어오지 않으면 대기 상태로 진입, 그렇기에 게임에 사용하지 않음 ( 입력이 없으면 멈추기 때문 )
- 게임에는 PeekMessage 사용 권장
TranslateMessage
- 키보드 입력을 분석해 문자 메시지를 메시지 큐에 추가 덧붙힌다
- 없어도 동작하지만, 키 입력 처리를 개선한다.
DispatchMessage ( 중요 )
- 메시지를 등록된 윈도우 프로시저(WndProc)로 전달합니다.
윈도우 초기화
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;
}
CreateWindowW
- 윈도우 생성 함수. 핸들(hWnd)을 반환하며, 실패 시 NULL 반환.
- CreateWindowW 들어가는 변수중 hMenu에 대한 것으로
HMENU hWnd = LoadMenu(hInstance, MAKEINTRESOURCEW(IDC_WINDOWSPROJECT8));
이렇게 해도 매뉴는 만들어 짐 ( 점점 개발하면서 잔재가 남은 것 ) - 핸들을 만드는 방법 2가지 Load, Create
Load :리소스 불러옴 , create : 리소스가 없어 만들어야함 - 단축키를 눌렀을때 ID가 아닌 NAME이 있다면 MAKEINTRESOURCEW로 감싸서 넣어야함
szWindowClass
- 윈도우 클래스 이름
szTitle
- 창 제목
WS_OVERLAPPEDWINDOW
- 창 스타일
ShowWindow
- 창을 특정 방식으로 표시 (nCmdShow 값에 따라 달라짐).
- hwnd : 창에 대한 핸들
- hCmdShow : 창을 표시하는 방법을 제어 ( define으로 해서 0 ~ 11까지 각각의 값이 있어 각각 의미는 다름 )
- nCmdShow를 사용할때 매뉴얼을 봐야함
UpdateWindow
- 창을 강제로 갱신
윈도우 프로시저 (WndProc)
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);
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
wParam
- 주로 정수 값을 전달하며, 메시지에 대한 추가 정보를 나타냄
- WPARAM은 32비트 시스템에서 unsigned int, 64비트 시스템에서 unsigned long long 이다
lParam
- 주로 포인터 값이나 두 개의 16비트 값으로 구성된 32비트 정보를 전달, 하위 16비트와 상위 16비트로 나누어 각각 다른 데이터를 저장
- LPARAM은 32비트 시스템에서 long, 64비트 시스템에서 long long이다
WM_COMMAND
- 메뉴 항목 선택, 단축키 입력 ( 엑셀러레이터 키 입력 ) ,컨트롤 부모 창에 알림 메시지 발생 시 호출
- 이 항목이 없으면 위에 3가지 기능이 먹통이 됨
WM_PAINT
- 창이 다시 그려질 때 호출
WM_DESTROY
- 창이 종료될 때 호출. 메시지 루프 종료를 위해 PostQuitMessage 호출
DefWindowProc
- 처리되지 않은 메시지를 기본 윈도우 프로시저로 전달
- 호출하지 않으면 프로그램이 동작하지 않음
대화상자 프로시저
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;
}
역할
- 대화 상자 창의 메시지 처리. 메뉴 선택 시 대화 상자 표시 등
[ 기본 API 창 만드는 법 ]
- WCHAR 스트링 테이블 삭제
- class name, title 직접 입력
- MyRegisterClass 함수 내용 main으로 이동, 함수 삭제 ( return 조심할것 )
- Initlnastance 함수 내용 main 이동, 함수 삭제
- menu, accelerator 삭제
- WM_COMMAND삭제
- about함수 삭제
- 전역변수 삭제 정리
- 리소스 정리 ( 아이콘 말고 전부 삭제 )
#include "framework.h"
#include "WindowsProject9.h"
#define MAX_LOADSTRING 100
LRESULT CALLBACK WndProc(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);
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_WINDOWSPROJECT9));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = 0; // 게임에는 메뉴가 필요없기에 지움
wcex.lpszClassName = L"name";
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
RegisterClassExW(&wcex);
HWND hWnd = CreateWindowW(L"name", 0, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
'C++' 카테고리의 다른 글
[강의] 1월 20일 수업정리 (1) | 2025.01.20 |
---|---|
[강의] 1월 17일 수업정리 (0) | 2025.01.17 |
[강의] 1월 15일 수업정리 (0) | 2025.01.16 |
[강의] 1월 13일 수업정리 (0) | 2025.01.13 |
[강의] 1월 3일 수업정리 (1) | 2025.01.03 |