C++

[강의] 1월 16일 수업정리

k-codestudy 2025. 1. 16. 17:41

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 창 만드는 법 ]

  1. WCHAR 스트링 테이블 삭제
  2. class name, title 직접 입력
  3. MyRegisterClass 함수 내용 main으로 이동, 함수 삭제 ( return 조심할것 )
  4. Initlnastance 함수 내용 main 이동, 함수 삭제 
  5. menu, accelerator 삭제
  6. WM_COMMAND삭제
  7. about함수 삭제
  8. 전역변수 삭제 정리
  9. 리소스 정리 ( 아이콘 말고 전부 삭제 )
#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