C++

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

k-codestudy 2025. 1. 13. 17:32

오늘은 API에 대한 수업을 들었다.

 

1. API

1.1 설명 

  • API(Application Program Interface)란 응용 프로그램에서 운영 체제나 프로그래밍 언어가 제공하는 기능을 제어하거나 상호작용할 수 있도록 설계된 인터페이스이다.
  • 일반적으로 파일 제어, 창 제어, 화상 처리, 문자 제어 등을 위한 인터페이스를 제공한다.
  • Application Program (응용 프로그램) + Interface (인터페이스)를 조합한 개념으로, 쉽게 말해 프로그램 간 연결 역할을 한다.

1.2 코드 설명 

#include "framework.h"
#include "WindowsProject1.h"

#define MAX_LOADSTRING 100

HINSTANCE hInst;                              
WCHAR szTitle[MAX_LOADSTRING];                
WCHAR szWindowClass[MAX_LOADSTRING];           

ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(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);

    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_WINDOWSPROJECT1, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    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);
        }
    }

    return (int) msg.wParam;
}

ATOM MyRegisterClass(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_WINDOWSPROJECT1));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_WINDOWSPROJECT1);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}

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;
}

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;
}

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를 처음 만들게 되면 나오게 되는 코드이다.

 

전역 변수

HINSTANCE hInst;                                // 현재 인스턴스
WCHAR szTitle[MAX_LOADSTRING];                  // 제목 표시줄 텍스트
WCHAR szWindowClass[MAX_LOADSTRING];            // 기본 창 클래스 이름
  • WCHAR : Wide Character (확장형 문자, 2 bytes), 아스키코드 이외에 유니코드 문자까지 포함된다.

 

프로젝트 내의 함수들 

ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

 

wWinMain

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

    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_WINDOWSPROJECT1, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    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);
        }
    }

    return (int) msg.wParam;
}

 

UNREFERENCED_PARAMETER

UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);

 

  • 프로그램 작성 시 변수나 인자를 선언만 해놓고 참조를 하지 않은 경우 컴파일러는 C4100번 오류를 내게 되는데, 이때 오류를 지워주는 매크로이다.
  • 즉, 인자 값이나 로컬 변수가 선언되지 않았을 때 컴파일러 경고를 발생시키지 않기 위해 사용하는 매크로이다. 
    ( 참조한 적이 없는 파라미터 )
  • UNREFERENCED_PARAMETER(hPrevInstance); 는 hPrevInstance와 동일한 의미 

 LoadStringW

LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_WINDOWSPROJECT1, szWindowClass, MAX_LOADSTRING);

// 문자열 리소스를 메모리에 로드.

// hInstance: 인스턴스 핸들.
// IDS_APP_TITLE, IDC_WINDOWSPROJECT1: 리소스 ID.
// szTitle, szWindowClass: 문자열을 저장할 버퍼.
// MAX_LOADSTRING: 버퍼 크기.

API는 클래스 개념이 아닌 핸들 개념을 사용한다. 

이 핸들을 꼽아서 명령을 하면 이 핸들에 대한 객체가 움직이는 방식으로 예를 들어 버튼을 만들어 주세요라고 요청을 하게 되면 API가 어딘가에 메모리를 잡게 되고 그렇게 되면 포인터가 나오기에 버튼 포인터를 우리에게 주게 되는데 이때, HBTM이라는 것만 주게 되는데 이때 해당 버튼에는 명령을 못 내린다.

그렇기에 API는 버튼이라는 행위에 대한 요청이 따로 전부 존재하게 된다. 

즉, 해당 명령어에 누구를 조립하게 되냐에 따라 수행이 달라지며 대상 따로 명령어 따로 해줘야 한다.

 

여기서 알아야 하는 부분이 인스턴스와 핸들이라는 개념을 알아야 한다.

 

1. 인스턴스

  • 일반적으로 실행 중인 임의의 프로세스, 클래스의 현재 생성된 오브젝트를 가리킨다 ( 존재하는 객체 )
  • 응용 프로그램 (application)을 메모리에 띄운 것, 예를 들어 메모장을 바탕화면에 띄웠을 때 그것은 하나의 인스턴스이며, 바탕화면에 메모장을 여러 개 띄울 수 있는데 그때 인스턴스는 여러 개가 되는 것이다.
  • 객체 지향 프로그래밍에서 인스턴스는 해당 클래스의 구조를 컴퓨터 저장 공간에서 할당된 실체를 의미
  • 즉, 인스턴스는 존재를 만들어 메모리에 얹는 것을 인스턴스 ( 메모리에 올라가 있는 덩어리 )라 하며 메모리의 포인터라고 볼 수 있다 ( 그렇기에 고유 ID라는 의미는 맞는 의미 )

 

2. 핸들 (H 시리즈)

  • 핸들이란 구체적인 어떤 대상에 붙여진 번호이다. ( 운영체제가 무언가를 식별하기 위한 키값)
  • 핸들은 정수값이며 대부분의 경우 32비트 값이다. ( 정수형이 비교가 제일 빠르기 때문 )
  • 운영체제가 발급하며 사용자는 쓰기만 한다.
  • 같은 종류의 핸들끼리는 절대로 중복된 값을 가지지 않는다 ( 식별을 위한 것이므로 중복은 절대 허용하지 않음 )
  • 핸들은 정수형이므로 값을 가지겠지만 그 실제 값이 무엇인지는 몰라도 상관없다.

 

3. HINSTANCE

  • 핸들 인스턴스로 프로그램의 인스턴스 식별자로 쉽게 보면 프로그램 자제의 실체화된 주소 ( 즉, 프로그램 자체의 핸들 

4. HWND 

  • 핸들 윈도 약자로 윈도의 핸들 번호를 저장해서 사용하며 하나의 프로그램에서 많은 양의 윈도우 창을 띄울 수 있는 것 즉, 윈도우 창의 번호들(HWND)로 구분함 

 

'C++' 카테고리의 다른 글

[강의] 1월 16일 수업정리  (0) 2025.01.16
[강의] 1월 15일 수업정리  (0) 2025.01.16
[강의] 1월 3일 수업정리  (1) 2025.01.03
[강의] 1월 2일 수업정리  (0) 2025.01.02
[강의] 12월 31일 수업정리  (0) 2024.12.31