최근 수정 시각 : 2022-04-21 16:15:17

Windows API

파일:Microsoft 로고.svg
{{{#!wiki style="margin:0 -10px -5px"
{{{#!folding [ 펼치기 · 접기 ]
{{{#!wiki style="margin:-6px -1px -11px"
{{{#000,#e5e5e5
산하 계열사 및 사업부
GitHub · .NET Foundation · Xbox Game Studios · LinkedIn
제품군
하드웨어 Surface · Xbox · HoloLens · PixelSense · Zune
소프트웨어 Windows · Office · Edge · Media Player · Hyper-V · Microsoft Defender · Visual Studio Code · Visual Studio · Windows Terminal · Microsoft PowerToys · Internet Explorer · MS-DOS · Windows Movie Maker · Autoruns
서비스 Microsoft Azure · OneDrive · Skype · MSN · Bing · LinkedIn · Cortana · 테이 · Xbox network · 정품 인증 · MSDN
관련 기술 ASF · ASP · Blazor · COM · DCOM · DirectX · 파일 시스템( FAT · NTFS · ReFS) · MFC · .NET( .NET Core · .NET Standard · C# · F# · Visual Basic .NET · Windows Forms · WPF · Universal Windows Platform · ASP.NET · ML.NET) · OLE · Silverlight · Visual Basic · VBA · WASAPI · Windows 커널 · Windows 디자인 · Windows API · Windows Runtime · WMA · WMV · Xamarin · XNA
관련 인물
빌 게이츠(은퇴) · 폴 앨런(은퇴) · 스티브 발머(퇴사) · 게이브 뉴웰(퇴사) · 사티아 나델라 · 필 스펜서
기타
Microsoft의 제니맥스 미디어 인수 · Microsoft의 액티비전 블리자드 인수 · 빌 게이츠의 굴욕
관련 틀
365 제품군 · 하드웨어 제품군 · Surface 제품군 · Windows 제품군
}}}}}}}}}}}} ||

1. 개요2. 특징
2.1. 하드웨어 독립적2.2. 동적 링크 라이브러리2.3. 메시지 처리2.4. 커널 오브젝트 (Kernel Object)2.5. 리소스
3. Hello, Windows 프로그램
3.1. 메시지 박스3.2. 윈도우
4. COM5. WinRT / UWP6. WinUI7. 그 외8. 관련 문서

1. 개요

Windows API는 Microsoft Windows에서 사용하는 C언어 기반의 API이다. 기본적으로는 C언어 기반이지만, C++에서도 사용 가능하다. 윈도우에서 실행되는 모든 종류의 애플리케이션들은 내부적으로 전부 이 윈도우 API 함수를 호출하는 형태로 바뀐다.[1]

2. 특징

2.1. 하드웨어 독립적

과거의 MS-DOS 환경에서는 프로그래머가 시스템에 연결된 장치의 종류를 모두 알아야 했다. 가령 한컴오피스 한글 같은 워드프로세서를 만든다고 가정해 보자. 문제가 되는 것은 모니터와 프린터인데, 과거에는 이 그래픽 출력 장치 및 프린터에 대한 제어 코드를 일일이 만들어 주어야 했다.[2] 만약 회사나 학교에서 사용 중인 워드 프로세서가 학교에 있는 프린터에 맞추어 설정되어 있다고 생각하여 보자. 누군가가 외국에서 프린터 좋은 거 있다고 해서 사 왔는데, 사용중인 워드 프로세서에서 지원하지 않는 프린터라면 사용이 불가능하거나, 혹은 워드프로세서에서 사용자 정의로 프린터를 설정할 수 있다면, 프린터 매뉴얼을 꺼내들고, 하나 하나 제어코드를 맞추어 워드프로세서에 인식시키면 된다. 귀찮고 시간이 오래 걸릴 뿐이지 하면 된다. 그리고 이렇게 사용하는 것이 기본이었으므로 아무도 불만이 없었다.

그러나 Windows 환경에서는 이런 하드웨어 제어 코드는 디바이스 드라이버가 가져가게 되며, 문자 출력은 DrawText 또는 TextOut 함수 호출로 한큐에 끝내게 된다. 꼭 문자 출력뿐만 아니라 거의 모든 게 이런 식으로 하드웨어의 종류에 영향을 받지 않는다. 거꾸로 윈도우 환경으로 넘어오면서 하드웨어 인터럽트를 직접 건드려 제어하는 방식의 응용 프로그래밍 기법은 완전히 사장되었다.[3] 윈도우에서는 하나의 운영체제 위에 여러 개의 프로세스가 작동하는 멀티태스킹 및 멀티스레딩 환경이기 때문이다.

2.2. 동적 링크 라이브러리

윈도우는 기본적으로 꼭 필요한 기능들을 정적 라이브러리 형태가 아닌 DLL 형태로 만들어 윈도우 운영체제 안에 내장시켜 놓았는데, 보통 %SystemRoot%\\System32 경로에 가 보면 이런 DLL들을 찾아볼 수 있다. 프로그램이 실행될 때 동적으로 불려오는 DLL의 특징상, 프로그램을 한 번 짜 놓으면 윈도우 버전이 올라가면서 윈도우 DLL이 개선되는 경우 그에 맞게 프로그램 기능도 개선되게 된다. 하지만 호환성이 문제

자주 사용하는 DLL은 다음과 같다.
  • ntdll.dll : 가장 핵심적인 라이브러리로 커널 모드(Ring 0, Kernel Mode)와 사용자 모드(Ring 3, User Mode)를 이어주는 시스템 콜 역할을 한다. 모든 윈도우 API들은 최종적으로 ntdll.dll의 함수를 호출하게 된다.
  • kernel32.dll : 메모리 관리, 파일 입/출력, 프로그램 로드/실행 등 기본적인 기능이 내장되어 있다. Windows NT 부터는 Kernel32.dll은 트램폴린 역할만을 하며 실제 기능은 ntdll.dll이 가지고 있다. (Kernel32.dll → KernelBase.dll → ntdll.dll)
  • win32u.dll : 커널와 별개로 그래픽(GDI) 엔진와 메시지 처리 등을 담당하는 커널 드라이버win32k.sys 시스템 콜 역할을 한다. 아래의 gdi32.dll와 user32.dll는 최종적으로 win32u.dll의 함수를 호출한다.
  • gdi32.dll : 화면/프린터의 그래픽 출력을 관리한다.
  • user32.dll : 윈도우[4], 대화 상자, 메뉴 등을 관리한다.

2.3. 메시지 처리

MS-DOS 환경이나 콘솔 응용 프로그램에서는 프로그램의 실행 흐름이 프로그래머가 작성한 코드에 따라서 움직였다면, 윈도우에서는 프로그램 외부에서 발생하는 이벤트들을 메시지의 형태로 전달받을 객체에게 알려 준다. 하드웨어 이벤트[5]가 발생하면, 윈도우의 시스템 메시지 큐에 이것이 쌓이게 되고, 시스템 메시지 큐에 들어온 메시지를 운영체제가 해당하는 객체의 메시지 큐에 넣어 준다. 프로그램은 while문을 돌면서 계속 메시지를 읽어서, switch-case해서 어떤 메시지가 오면 어떻게 처리한다는 로직을 기술하는 형태를 가진다. 메세지는 3가지의 값이 저장되어 있으며 메세지를 구별하기 위한 숫자 데이터, 추가 데이터 2개의[6] 숫자 데이터로 이루어져 있다.[7]

추가적으로 말하면 흔히 OS를 말하는 윈도우가 아니라 UI객체를 프로그래밍 상에서 윈도우라고 부르게 되는데 이 UI개체는 모두 메세지를 받을 수 있다. UI객체는 버튼, 이미지, 창 등 UI를 구성하는 모든 부분이 나뉘어져 있으며 예를 들어서 프로그램 내부의 버튼을 클릭하게 된다면 OS가 프로그램에게 어느부분에 마우스가 눌림 이라는 메세지를 보내게 되고 프로그램은 해당 메세지의 데이터를 보고 좌표값을 계산해서 해당 위치의 UI객체가 있다면 해당 UI객체에게 그 메세지를 전달한다. 버튼을 클릭한다고 했으니 해당 버튼에게 메세지가 전달되게 되고 해당 버튼에서 클릭시 해야될 일을 하게 된다.

2.4. 커널 오브젝트 (Kernel Object)

핸들(Handle) 또는 커널 오브젝트(Kernel Object) 는 윈도우에서 오브젝트에 붙여 주는 숫자로, 가상 메모리의 주소일 수도 있고, 시스템이 전역으로 식별하기 위해 붙인 번호일 수도 있다. 어떤 오브젝트는 주소의 의미를, 어떤 오브젝트는 번호의 의미를 갖는다.[8] 핸들은 각각의 윈도우, 브러시, 펜, 파일, 프로세스, 스레드 등 거의 모든 오브젝트에 붙게 된다. 윈도우 9x 계열에서 말하던 리소스는 커널 오브젝트를 말한다.

2.5. 리소스

윈도우 프로그램을 짜다 보면 메뉴, 대화 상자(다이얼로그 박스), 아이콘, 비트맵 이미지, 커서 등을 많이 사용한다. 그러나 얘네들은 메모리 용량을 많이 잡아먹기 때문에 프로그램이 메모리에 올라올 때 얘네들이 메모리에 전부 다 올라와버리면 메모리가 터져나가게(...) 된다. 그렇기 때문에 이런 것들은 리소스로 취급하며, 리소스 컴파일러를 통해 프로그램 코드와는 별개로 컴파일되고, 이들을 사용할 때는 LoadMenu, LoadIcon, LoadBitmap, LoadCursor 등의 함수를 통해 메모리에 로드하는 과정을 거치게 된다. 프로그램 실행 중 사용하지 않는 리소스는 메모리에서 자동으로 내려간다.

3. Hello, Windows 프로그램

밑의 예시에서 LNK2019 오류가 발생할 경우에는 프로젝트 속성 -> 링커 -> 시스템 ->하위 시스템에서 '콘솔'로 되어있는걸 지우거나 '창'으로 바꾸면 정상적으로 실행이 된다.

3.1. 메시지 박스

이 프로그램은 아무 아이콘도 없고, 확인 버튼이 하나 존재하는 메시지 박스에 "Hello, Windows!"를 출력한다.
#!syntax cpp
#include <tchar.h>
#include <windows.h>

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
    MessageBox(NULL, TEXT("Hello, Windows!"), TEXT("Hello"), MB_OK);
    return 0;
}

3.2. 윈도우

이 프로그램은 흰색 바탕의 클라이언트 영역의 정중앙에 GDI를 사용해 "Hello, Windows!"를 출력하는 윈도우를 하나 띄운다.
#!syntax cpp
#ifndef UNICODE
#  define UNICODE
#endif // UNICODE
#include <stdlib.h> // EXIT_FAILURE
#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int APIENTRY wWinMain(
    HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR lpCmdLine, int nCmdShow)
{
  static wchar_t szAppName[] = L"HELLOWINDOWS";
  HWND           hWnd;
  MSG            msg;
  WNDCLASS       wndclass = {};

  wndclass.style         = CS_HREDRAW | CS_VREDRAW;
  wndclass.lpfnWndProc   = WndProc;
  wndclass.hInstance     = hInstance;
  wndclass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
  wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
  wndclass.hbrBackground = (HBRUSH)GetStockObject(COLOR_WINDOW + 1);
  wndclass.lpszClassName = szAppName;

  if ( !RegisterClass(&wndclass) )
  {
    return EXIT_FAILURE;
  }

  hWnd = CreateWindowW(
      szAppName,
      L"Hello Windows Application",
      WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT,
      CW_USEDEFAULT,
      CW_USEDEFAULT,
      CW_USEDEFAULT,
      NULL,
      NULL,
      hInstance,
      NULL);
  ShowWindow(hWnd, nCmdShow);
  UpdateWindow(hWnd);

  while ( GetMessage(&msg, NULL, 0, 0) )
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }

  return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  HDC         hDC;
  PAINTSTRUCT ps;
  RECT        rect;

  switch ( message )
  {
  case WM_CREATE:
    return 0;
  case WM_PAINT:
    hDC = BeginPaint(hWnd, &ps);
    GetClientRect(hWnd, &rect);
    DrawText(
        hDC,
        TEXT("Hello, Windows!"),
        -1,
        &rect,
        DT_SINGLELINE | DT_CENTER | DT_VCENTER);
    EndPaint(hWnd, &ps);
    return 0;
  case WM_DESTROY:
    PostQuitMessage(0);
    return 0;
  }

  return DefWindowProc(hWnd, message, wParam, lParam);
}

4. COM

Component Object Model
C++의 가상 함수 테이블을 이용하여 기능을 인터페이스로 노출시키고 객체를 사용할 수 있게 한다. C++의 가상 함수 테이블을 사용하지만 COM 인터페이스는 ABI가 C++의 thiscall이 아닌 stdcall이기 때문에 C언어로도 바인딩이 되어 타 언어에서도 사용할 수 있다.
순수 Windows API는 C언어 함수로 구성되지만 DirectX, Media Foundation, Windows Shell 같은 기능들은 COM 인터페이스를 기반으로 제공된다.
COM에서 보이는 프로그래밍 패턴은 WinRT 에서도 유지된다.

5. WinRT / UWP

Windows 8 부터 제공되기 시작한 API셋이다. 이 셋이 등장한 이후부터 새로운 기능들은 WinRT 에서만 사용이 가능하고 이와 동일한 기능을 하는 C기반 표준 Win32 API로는 제공되지 않는다.
파일:상세 내용 아이콘.svg   자세한 내용은 Windows Runtime 문서
번 문단을
부분을
참고하십시오.

6. WinUI

Windows UI Library
Project Reunion라는 이름으로 등장하였다 이후에 Windows UI Library 라는 이름으로 바뀌었다.

Microsoft Windows 8를 함께 발표하면서 WinRT API셋 또한 함께 발표하였고 새로운 기능들은 WinRT 에서만 사용이 가능하였다.
이 API를 주력으로 사용하는 Windows Runtime와 이후 Windows 10에서 나온 Universal Windows Platform이 사실상 망한데다 기존 까지 잘 사용되던 Win32 기반 프로그램들에서 이 WinRT 관련 API를 섞어 쓰는것이 만만치 않게 제약사항이 많았던 터라 WinRT를 Win32 쪽으로 다시 가져온 API 모음이다.

Windows App (구 Project Reunion)에서 WinUI 3를 사용한다.

7. 그 외

  • A함수와 W함수가 나뉘어 있다. 예시로 MessageBox()매크로를 예로 들면 컴파일 옵션에 따라 최종적으로 MessageBoxA() 또는 MessageBoxW() 로 변환되게 되는데 전자의 경우 시스템 로케일을 사용하며 (ANSI의 A) 후자는 유니코드 (UTF-16LE, Wide의 W)를 사용하게 된다.
    • 이러한 특징으로 TCHAR 이라는 매크로 자료형이 사용된다. 명시적으로 A 또는 W를 프로그래머가 알고서 사용하는 경우는 아무 문제가 되지 않지만 이해 없이 섞어 쓰는 경우 런타임 오류를 내기 때문.
  • Windows 98과 같이 Windows NT 커널이 탑재되기 이전의 OS의 경우 이 Wide 버전을 지원하지 않았으며 별도의 호환성 레이어를 설치해야 이런 유니코드 기반 프로그램을 동작시킬 수 있었다.
  • A 버전의 함수를 호출해도 커널 내부적으로는 W 함수를 최종으로 실행하게 된다. (A()->MultiByteToWideChar()->W();)
  • Windows API라는것 자체는 Windows 1.0 때부터 이어져 온 것이다 보니 시대가 지나며 기능이 추가되거나 없어진것도 있고 아무 의미 없이 존재하는것이 있다. 대표적으로 엔트리포인트인 WinMain()hPrevInstance가 있다.[9]
  • 마찬가지로 원형과 Ex 버전이 별도로 존재한다. 기능이 추가되었지만 하위호환성을 위해 원형을 남겨 둔 것으로 CreateWindow()가 있다. 본래 함수였으나 현 SDK는 매크로로 되어 있으며 실제로는 CreateWindowEx()를 실행시킨다.

8. 관련 문서


[1] MFC, 비주얼 베이식, 델파이 등 윈도우에서 사용할 수 있는 모든 라이브러리는 실행 시 전부 내부적으로 어떻게든 변환을 거치게 된다. [2] 허큘리스, CGA, EGA, VGA같은 그래픽 드라이버와 각각의 프린터에 대한 제어 코드를 일일이 다 만들어서 워드프로세서 프로그램 안에 내장시켜 주어야 했다. [3] 다만 산업용으로 ISA 버스 등 하드웨어를 직접 건드려야 하는 곳에서는 여전히 사용한다. 응용프로그램이 아닌 드라이버 개발을 하는 경우에도 마찬가지. [4] "창"의 의미로 사용하는 그 윈도우를 의미한다. [5] 사용자가 키보드를 누르거나 마우스를 움직였다거나, 기타 여러 가지의 자잘한 이벤트를 의미한다. [6] LPARAM, WPARAM [7] 예를 들어서 마우스를 클릭하면 메세지로, 마우스 클릭 이벤트 메세지, x좌표, y좌표라고 메세지가 날라온다. [8] 특정 종류의 오브젝트를 가리키는 핸들이 주소인지 번호인지는 마이크로소프트에서 공식적으로 문서화하지 않았다. 즉 언제든 바뀔 수 있다. [9] 첫번째 창을 띄운뒤 두번째 창부터 클래스 등록을 생략하고 기존 클래스를 재사용하기 위한 용도였으나 32비트 윈도우부터 무조건 클래스를 등록하는 것으로 변경되며 그 역할이 사라졌다.