linux에서 win api를 대치하는 것은 무엇일까?
QT같은 GUI를 쓴다면 QT의 api를 알아봐야한다고 하는데(https://unix.stackexchange.com/a/25607), 그보다 더 근본적으로 하드웨어 콜을 통한 방법은 없을까?(https://stackoverflow.com/a/14162435/8106257)
class
{
public:
bool Init(); //초기화
bool Frame(); //실시간 연산
bool Render(); //실시간 렌더링
bool Release(); //해제, 소멸, 삭제
};
구현이 비어있더라도 꼭 선언
#include <Windows.h>
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
// WNDCLASSEXW의 lpszClassName과 CreateWindowW의 lpClassName은 동일해야 함
LPCWSTR name = L"TEST";
WNDCLASSEXW wcex;
// WNDCLASSEX를 전부 지정하지 않을 경우 초기화 하는것이 좋음
// 초기화하지 않을 경우 예측할 수 없는 행동 발생
ZeroMemory(&wcex, sizeof(wcex));
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
//윈도우 메시지를 받아서 처리하는 콜백 함수
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
//wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
//내가 등록하고자 하는 이름
// 이 값을 통해 OS는 창 클래스를 식별
wcex.lpszClassName = name;
// WNDCLASSEXW를 통해 운영체제에 생성하고자 하는 Window의 설계를 등록
//1개의 HInstance를 가지고 여러개 등록 가능
//다만 굳이 여러개를 만들 이유는 없을 듯
RegisterClassExW(&wcex);
// HWND
// 생성된 window의 Handle
// CreateWindowW
// RegisterClassExW를 통해 운영체제에 등록한 Window를 생성
// 첫번째 매개변수는 lpszClassName과 동일해아함
// WS_OVERLAPPEDWINDOW -> dwStyle
// 메뉴, 프레임, 최대화, 최소화 여부 등 설정
// WS_SYSMENU를 설정하지 않으면 최대화, 최소화, 창닫기 버튼 비활성화 -> 일부 의존적인 속성이 있는 듯
HWND hWnd = CreateWindowW(name, L"Title", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
//실제로 window를 그리는 함수
ShowWindow(hWnd, nCmdShow);
//무효화 영역을 바로 갱신시켜주는 함수라고는 하는데 주석처리 후 resize를 해도 별 문제 없이 수행되는 듯 함. 아직 차이를 모르겠음
UpdateWindow(hWnd);
MSG msg;
// 메세지 큐에 메세지가 존재한다면 True
// 읽은 메세지가 WM_QUIT이면 False
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
// WndProc에 번역된 메세지 전달
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
// 내가 생성한 msg를 받을수도 있지만, OS가 생성한 msg도 받을 수 있음
// GetMessage()와 WndProc()에 breakPoint를 설정할 경우 GetMessage는 걸리지 않지만 WndProc에는 걸리는 경우를 확인할 수 있음
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
// WM_DESTROY 처리 필수
// close box를 누르더라도 실제로 종료되는 것이 아닌 close box를 눌렀음을 알리는 이벤트만 전송
case WM_DESTROY:
// 이 함수를 통해 실질적으로 프로그램이 종료됐음을 알림
PostQuitMessage(0);
break;
default:
// 최대화, 최소화, 창이동, 화면크기 변경 등 불필요하다고 판단되는 event를 위임 가능
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
w = 유니코드, 없다면 멀티바이트
WinMain = WinAPI에서 main역할
LP = long pointer
C = const
W = 유니코드
STR = 문자열
H = 핸들, 운영체제에서 넘겨주는 ID
WND = windows
EX = extention, 확장, WNDCLASSEX도 존재
W = 유니코드
lp = long pointer
fn = function
Wnd = window
Proc = procedure
윈도우 프로시저 함수 포인터
Message Queue에 msg가 올 때까지 대기
/*
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
// WndProc에 WM_DESTROY msg 전송
DispatchMessage(&msg);
}
*/
// 이런 구조로 수행
MSG msg = { 0, };
while (WM_QUIT != msg.message)
{
// 장점 : 메세지큐에 메세지가 없어도 반환됨.
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg); // 메세지 번역
DispatchMessage(&msg); // 메세지 프로시져에 전달한다.
}
else
{
Frame();
Render();
}
}
Game에서는 Window Message가 없을 때 작동해야 함(Idle Time, 유휴시간)
대신 PeekMessage함수 사용
GetWindowRect(); // 메뉴, 타이틀, 프레임, close box등 모든 것을 포함한 크기
GetClientRect(); // 부가적인 것을 제외한 화면의 크기
DX작업 시 Client영역의 값을 중요하게 사용
AdjustWindowRect(); // 원하는 client화면에 맞도록 window style을 포함하는 window 화면 계산
GetWindowLong(); // 해당하는 WindowHandle의 Stlye을 알 수 있음
SetWindowLong(); // 해당하는 WindowHandle의 Stlye 설정 가능
Long계열 함수는 GWL_에 따라 원하는 값을 얻을 수 있음(GWL_Style)
GetSystemMetrix(); // system의 전체 해상도 등 조회 가능
MoveWindow(); // 화면 이동, 크기 조절 가능