2020 이전/Win API

Win api32 1일차

이상해C++ 2018. 10. 29. 17:46
콘솔에서의 시작 포인트 : main

window에서의 시작 포인트: WIN MAIN

#define WINAPI      __stdcall
#define WINAPIV     __cdecl
#define APIENTRY    WINAPI

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)

오보에떼~ 이마스까~

<함수호출규약> 뇌자극 sp 챕10 section 4에 나옴
함수 호출시 인자를 전달하는 방법과 stack frame을 반환하는 방식을 약속 해놓은 것을 가리켜 함수 호출 규약

__stdcall : 오른쪽부터 전달되는 이자가 먼저 스택에 쌓이고 반환시 호출된 함수가 stack frame을 반환한다.

__cdecl : c/c++의 디폴트 호출규약. 오른쪽부터 전달되는 인자가 먼저 스택에 쌓이고 반환시 함수를 호출하는 쪽이 stack frame을 반환한다.

__fastcall : 함수 호출을 빠르게 처리하기 위한 규약. 레지스터 ecx, edx, 사용. 2개를 넘어선 인자는 stack을 활용한다.


64비트 기반 윈도우 : 8개 레지스터중 4개를 인자전달에 쓴다.

HINSTANCE hInst;

운영체제는 각각 프로세스를 인식할 방법이 필요하다. 인스턴스는 프로세스의 고유한 식별 번호이다(프로그램당 하나의 인스턴스) 운영체제가 식별 번호를 만들고 wWinMain에 식별 번호를 전달해 준다. 


{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: 여기에 코드를 입력합니다.

    // 전역 문자열을 초기화합니다.
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_WIN32PROJECT1, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // 응용 프로그램 초기화를 수행합니다.
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32PROJECT1));

    MSG msg;

    // 기본 메시지 루프입니다.
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}

LoadStringW(멀티바이트기반은 LoadStringA)

szTitle, szWindowClass 같은 것들은 전부 프로젝트 .rc string table에 있다.


<MyRegisterClass : 창클래스 등록>

MyRegisterClass(hInstance);
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;    //귀찮으면 WNDCLASSEX 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_WIN32PROJECT1));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_WIN32PROJECT1);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}

-윈도우 프로시저 등록

-아이콘 등록

-커서 등록

-윈도우 기본 백그라운드 창 색깔 결정

-메뉴창 알려주고(툴같은거 만들 때)

-RegisterClassEx : 지금 이 구성한 윈도우를 레지스터에 등록한다.

#ifdef UNICODE
typedef WNDCLASSEXW WNDCLASSEX;
typedef PWNDCLASSEXW PWNDCLASSEX;
typedef NPWNDCLASSEXW NPWNDCLASSEX;
typedef LPWNDCLASSEXW LPWNDCLASSEX;
#else
typedef WNDCLASSEXA WNDCLASSEX;
typedef PWNDCLASSEXA PWNDCLASSEX;
typedef NPWNDCLASSEXA NPWNDCLASSEX;
typedef LPWNDCLASSEXA LPWNDCLASSEX;
#endif // UNICODE

#ifdef~#else~#endif 유니코드 설정에 따라서 달라짐


<WndProc : main 창의 메세지를 처리한다. >

//메세지 처리 루프에서 메세지가 들어오면 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);
            // TODO: 여기에 hdc를 사용하는 그리기 코드를 추가합니다.
            EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}
윈도우는 메세지 기반의 운영체제.

이벤트가 발생하면 윈도우OS는 이를 Message로 변환하여 Message큐에 넣는다.

메세지 루프는 무한 루프를 돌면서 메세지 큐에 있는 메세지를 가져온다. 이 때 가져온 메세지를 Window Procedure가 처리한다.

사용자 정의 WndProc을 사용하기 위해 함수 포인터를 사용하며 윈도우 프로시저 함수포인터는 레지스터 등록 때 같이 등록한다. 

MyRegisterClass에 WndProc 등록 부분이 있다. 


<InitInstance : 실제 윈도우 창을 생성한다>

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);    // nCmdShow : 처음 실행했을때 처음 보이게될 창의 방식
   UpdateWindow(hWnd);            // 

   return TRUE;
}
WS_OVERLAPPEDWINDOW : 윈도우 레이아웃 (단축키 최소화키 등등)