Windows API

  • 관련 문서 : API

1 개요

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

2 특징

2.1 하드웨어 독립적

과거의 MS-DOS 환경에서는 프로그래머가 시스템에 연결된 장치의 종류를 모두 알아야 했다. 가령 한/글 같은 워드프로세서를 만들어야 한다고 가정해 보자. 문제가 되는 것은 모니터랑 프린터인데, 과거에는 이 그래픽 출력 장치 및 프린터에 대한 제어 코드를 일일이 만들어 주어야 했다.[2] 만약 회사나 학교에서 사용 중인 워드 프로세서가 아래아 한글이고, 지원하는 프린터가 정해져 있다고 생각해 보자. 누군가가 외국에서 프린터 좋은 거 있다고 해서 사 왔는데, 아래아 한글에서 지원하지 않는 프린터라면 더 이상의 자세한 설명은 생략한다.
그러나 Windows 환경에서는 그러한 하드웨어 제어 코드는 장치 드라이버가 가져가게 되며, 문자 출력은 DrawText 또는 TextOut 함수 호출로 한큐에 끝내게 된다. 꼭 문자 출력뿐만 아니라 거의 모든 게 이런 식으로 하드웨어의 종류에 영향을 받지 않는다.
거꾸로 윈도우 환경으로 넘어오면서 하드웨어 인터럽트를 직접 건드려 제어하는 방식의 프로그래밍 기법은 완전히 사장되었다. 그도 그럴 것이, 윈도우에서는 하나의 운영체제 위에 여러 개의 프로세스가 작동하는 멀티태스킹 및 멀티스레딩 환경이기 때문.

2.2 동적 링크 라이브러리

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

  • kernel32.dll : 메모리 관리, 파일 입/출력, 프로그램 로드/실행 등 기본적인 기능이 내장되어 있다.
  • gdi32.dll : 화면/프린터의 그래픽 출력을 관리한다.
  • user32.dll : 윈도우[3], 대화 상자, 메뉴 등을 관리한다.

2.3 메시지 처리

MS-DOS환경이나 콘솔 응용 프로그램에서는 프로그램의 실행 흐름이 프로그래머가 작성한 코드에 따라서 움직였다면, 윈도우에서는 프로그램 외부에서 발생하는 이벤트들을 메시지의 형태로 전달받을 객체에게 알려 준다. 하드웨어 이벤트[4]가 발생하면, 윈도우의 시스템 메시지 큐에 이것이 쌓이게 되고, 시스템 메시지 큐에 들어온 메시지를 운영체제가 해당하는 객체의 메시지 큐에 넣어 준다. 프로그램은 while문을 돌면서 계속 메시지를 읽어서, switch-case해서 어떤 메시지가 오면 어떻게 처리한다는 로직을 기술하는 형태를 가진다. 메세지는 3가지의 값이 저장되어 있으며 메세지를 구별하기 위한 숫자 데이터, 추가 데이터 2개의 숫자 데이터로 이루어져 있다.[5]
추가적으로 말하면 흔히 OS를 말하는 윈도우가 아니라 UI객체를 프로그래밍 상에서 윈도우라고 부르게 되는데 이 UI개체는 모두 메세지를 받을수 있다. UI객체는 버튼, 이미지, 창 등 UI를 구성하는 모든 부분이 나뉘어져 있으며 예를 들어서 프로그램 내부의 버튼을 클릭하게 된다면 OS가 프로그램에게 어느부분에 마우스가 눌림 이라는 메세지를 보내게 되고 프로그램은 해당 메세지의 데이터를 보고 좌표값을 계산해서 해당 위치의 UI객체가 있다면 해당 UI객체에게 그 메세지를 전달한다. 버튼을 클릭한다고 했으니 해당 버튼에게 메세지가 전달되게 되고 해당 버튼에서 클릭시 해야될 일을 하게 된다.

2.4 커널 오브젝트 (Kernel Object)

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

2.5 리소스

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

3 Hello, Windows 프로그램

3.1 메시지 박스

이 프로그램은 아무 아이콘도 없고, 확인 버튼이 하나 존재하는 메시지 박스에 "Hello, Windows"를 출력한다.

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

3.2 윈도우

이 프로그램은 흰색 바탕의 클라이언트 영역의 정중앙에 "Hello, Windows"를 출력하는 윈도우를 하나 띄운다.

#include 
#include 
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
static TCHAR szAppName[] = TEXT("HELLOWINDOWS");
HWND hWnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{   
MessageBox(NULL, TEXT("This program requires Windows 2000 or upper."),
szAppName, MB_OK | MB_ICONERROR);
return 0;
}
hWnd = CreateWindow(szAppName, TEXT("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);
}

  1. MFC, 비주얼 베이식, 델파이, 등 윈도우에서 사용할 수 있는 모든 라이브러리는 실행 시 전부 내부적으로 어떻게든 변환을 거치게 된다.
  2. 모니터 출력의 경우 허큘리스, CGA, EGA, VGA ... 그리고 프린터의 경우 각각의 프린터에 대한 제어 코드를 일일이 다 만들어서 위드프로세서 프로그램 안에 내장시켜 주어야 했다.
  3. "창"의 의미로 사용되는 그 윈도우를 의미한다
  4. 사용자가 키보드를 누르거나 마우스를 움직였다거나, 기타 여러 가지의 자잘한 이벤트를 의미한다.
  5. 예를 들어서 마우스를 클릭하면 메세지로, 마우스클릭이벤트메세지, x좌표, y좌표라고 메세지가 날라온다.
  6. 특정 종류의 오브젝트를 가리키는 핸들이 주소인지 번호인지는 마이크로소프트에서 공식적으로 문서화하지 않았다. 즉 언제든 바뀔 수 있다.