[C++] Win32 API 튜토리얼

Posted at 2012.02.04 13:44 | Posted in 프로그래밍

원문 출처: C++ Win32 API Tutorial. Baran Ornarli. At INFERNO DEVELOPMENT

글 내용이 너무 좋아서 부족한 실력으로 번역하여 블로그에 옮깁니다. 오역이 다수 있을 수 있으니 양해바랍니다.

 

여러분은 이미 C++으로 콘솔 프로그램을 만든 경험이 있을 겁니다. 그러나 여러분은 검정색화면이 아닌 GUI(Graphical User Interfaces)프로그램 만드는 방법을 궁금해 할 것입니다. 이러한 GUI 프로그램을 Win32 API 프로그램이라고 합니다. 윈도우 32 프로그래밍으로 단추와 창, 글자 상자, 그 외 GUI 개체를 만드는 방법을 배워봅시다.

윈도우 32 프로그래밍은 근본적으로 윈도우 XP 혹은 Vista와 같은 윈도우 운영체제와 상호작용을 함을 뜻하는 윈도우 32비트 응용 프로그램 인터페이스(Windows 32-bit Application programming interface)를 사용합니다. 이 튜토리얼에서, 여러분은 멋진 윈도우 응용프로그램 제작을 위한 Win32 API C++의 사용법을 배웁니다.

윈도우 프로그램은 운영체제에 자기자신을 등록하고 메시지 순환으로 작동합니다. 게다가, 메시지 순환(Message Loop)은 모든 윈도우의 메시지를 처리하고 사용자나 운영체제의 요구를 운반하는 작업 기능을 통과합니다.

가장 많이 쓰이는 윈도우 메시지들은 WM_CREATEWM_DESTROY, WM_COMMAND 입니다. WM은 윈도우 메시지(Windows Message)를 줄인 것입니다. CREATE는 윈도우 운영체제의 작업 목록에 프로그램을 등록하는 중 프로그램이 받는 첫 메시지를 처리합니다. 여러분은 대부분의 GUI 코드 또는 프로그램을 초기화하는 코드를 WM_CREATE안에 삽입할 수 있습니다. WM_DESTROY는 여러분이 메모리 누수를 방지하기 위해 지워야 할 변수 또는 GUI를 위한 것입니다. 이것은 프로그램의 상태 등 최근 몇 분간의 설정을 저장하는 데에도 사용됩니다. WM_COMMAND는 동작 처리기의 기본이며, 여러분의 단추나 GUI, 그리고 다른 프로그램으로의 메시지나 다른 사용자 입력 등 모든 메시지 종류를 처리합니다.

첫 예제로 누르면 메시지 상자를 띄우는 단추를 포함한 창을 만들어 보겠습니다.

#include <windows.h>

/* 윈도우 프로시저 선언 */
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);

자, 우리는 제일 먼저 여러분의 프로그램과 Win32 API를 연결하는 주요 헤더인 windows.h를 포함시켰습니다.

우리는 이어서 어떤 함수를 위한 자료 형식인 LRESULT CALLBACK으로 정의된 프로토타입 WndProc 함수를 선언합니다. 프로토타입은 처음에 선언됐지만 프로그램의 나중에 정의될 함수입니다. 따라서 여러분은 똑같은 함수를 볼 것이지만 실제 코드는 뒤에 있는 것입니다. 우리는 HWND와 UINT, WPARAM, LPARAM 같은 함수를 위한 인수를 정의합니다.

HWND는 보통 GUI 요소를 위해 사용됩니다. 이것은 실제 윈도우나 프로그램의 윈도우 요소를 대표합니다. UINT는 부호 없는 정수(unsigned integer)이고 WPARAM과 LPARAM은 윈도우가 메시지에 자료를 추가하는데 사용하는 매개변수입니다.

#define IDBUTTON 102

/* 클래스 이름을 전역 변수로 생성 */
TCHAR szClassName[] = TEXT("MyFirstProgram");
HINSTANCE g_hInst;

정의와 전역 변수를 프로그램의 첫 부분에 선언하는 것은 중요합니다. IDBUTTON은 102라고 정의했는데, 이것은 GUI 컨트롤 ID를 위한 기본 정의입니다. 우리는 이 정의를 단추가 클릭되었을 때 일어날 일을 처리하기 위한 일을 연결하는데 사용합니다. HINSTANCE는 프로그램의 인스턴스입니다. 이것은 GUI가 어느 프로그램의 소속됐는지 정의하기 위해 사용합니다. 우리는 프로그램 안에서 계속 사용할 것이기 때문에 이것을 전역 변수로 정의했습니다. szClassName은 윈도우 운영 체제에서 프로그램 등록에 필요한 클래스 이름입니다.

WINAPI WinMain 함수

int WINAPI WinMain (HINSTANCE hInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR lpCmdLine,
                    int nCmdShow)
{
  HWND hWnd;                    /* 윈도우를 위한 처리기 */
  MSG msg;                      /* 프로그램에 전송된 메시지가 저장 */
  WNDCLASSEX wcex;              /* windowclass를 위한 자료 구조체 */

  /* 윈도우 구조체 */
  g_hInst = hInstance;
  wcex.hInstance = hInstance;
  wcex.lpszClassName = szClassName;
  wcex.lpfnWndProc = WndProc;   /* 이 함수는 윈도우에 의해 호출됩니다 */
  wcex.style = CS_DBLCLKS;      /* 더블 클릭을 잡아냄 */
  wcex.cbSize = sizeof (WNDCLASSEX); 

  /* 기본 아이콘과 포인터 사용 */
  wcex.hIcon = LoadIcon (NULL, IDI_APPLICATION); 
  wcex.hIconSm = LoadIcon (NULL, IDI_APPLICATION); 
  wcex.hCursor = LoadCursor (NULL, IDC_ARROW); 
  wcex.lpszMenuName = NULL;     /* 메뉴 사용안함 */
  wcex.cbClsExtra = 0;          /* 윈도우 클래스 뒤에 여우 바이트 없음 */
  wcex.cbWndExtra = 0;          /* 윈도우 인스턴스 또는 구조체 */
  /* 창의 배경으로 윈도우의 기본 색상 사용 */
  wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);

  /* 윈도우 클래스 등록. 실패 시 프로그램 종료 */
  if (!RegisterClassEx (&wcex))
    return 0;

우리는 윈도우 OS가 인정한 특별한 함수인 WinMain 프로그램을 정의했습니다. 우리는 프로그램의 주 창인 프로그램의 HWND를 선언했습니다. 우리는 이어서 윈도우 메시지 순환을 만들기 위한 MSG를 선언합니다. 게다가, 우리는 윈도우 OS에서 프로그램에 대한 약간의 정보를 등록하는데 쓰이는 구조체인 WNDCLASSEX 개체를 만듭니다.

윈도우를 위한 메시지 이벤트 순환

자료 정의를 다 하고 나서, 우리는 클래스를 등록하고 오류 확인을 한다.

  /* 클래스는 등록되었다. 이제 프로그램을 만들자 */
  hWnd = CreateWindowEx (0,     /* 변화를 위한 확장 가능성 */
    szClassName,                /* 클래스 이름 */
    TEXT("MyFirstProgram v1.0.0.0"),  /* 제목 */
    WS_OVERLAPPEDWINDOW,        /* 기본 창 */
    CW_USEDEFAULT,              /* 프로그램이 화면에 표시 될 때의 */
    CW_USEDEFAULT,              /* 윈도우 위치 선언 */
    230,                        /* 프로그램 너비와 */
    85,                         /* 높이 (pixel 단위) */
    HWND_DESKTOP,               /* 이 창은 바탕화면의 자식 창이다 */
    NULL,                       /* 메뉴 없음 */
    hInstance,                  /* 프로그램 인스턴스 처리 */
    NULL);                      /* 윈도우 생성 자료 없음 */

  /* 윈도우를 화면에 보이게 */
  ShowWindow (hWnd, SW_SHOW);
  UpdateWindow(hWnd);

  /* 메시지 순환 실행. GetMessage()가 0을 반환 할 때 까지 작동 */
  while (GetMessage (&msg, NULL, 0, 0))
  {
    /* 가상의 키 메시지를 문자 메시지로 해석 */
    TranslateMessage(&msg);
    /* 메시지를 WndProc으로 전송 */
    DispatchMessage(&msg);
  }
  /* 프로그램 반환 값은 0 입니다. (PostQuicMessage()에서 받은 값) */
  return msg.wParam;
}

우리는 CreateWindowEx를 주 윈도우 GUI를 만드는데 사용합니다. 우리가 만들고 있는 창의 종류에 대한 약간 정보를 정의합니다.

우리는 이어서 창을 보이게 하고, 창을 업데이트하며, 프로그램이 실제로 운영 체제와 대화할 수 있도록 메시지 순환을 시작합니다.

윈도우 프로시저 콜백

LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  HWND hWndButton; 
  switch (message) {        /* 모든 윈도우 메시지를 처리 */
    case WM_COMMAND: {
      if (((HWND)lParam) && (HIWORD(wParam) == BN_CLICKED)) {
        int iMID; 
        iMID = LOWORD(wParam); 
        switch(iMID) {
          case IDBUTTON: {
            MessageBox(hWnd, TEXT("클릭되었슴돠!"), TEXT("내 프로그램!"), MB_OK|MB_ICONEXCLAMATION); 
            break; 
            }
          default: 
            break; 
        }
      }
      break; 
    } 
    case WM_DESTROY: {
      PostQuitMessage (0);  /* 메시지 처리기에 프로그램을 종료하라는 WM_QUIT를 보냄 */
      break; 
      }

윈도우 프로시저 함수는 WM_으로 선언된 윈도우 메시지를 보내고 받는 일종의 Win32 API입니다.

우리는 앞에서 프로그램에 선언한 프로토타입의 실제 함수를 정의했습니다. 우리는 HWND를 단추를 위해 만들고, 각각의 윈도우 메시지를 선언하고 처리합니다.

WM_COMMAND에서, 우리는 LPARAM WPARAM의 인수를 확인하기 위해 switch를 사용했고, 어떤 컨트롤이 우리에게 보낸 명령을 결정했습니다. 만약 단추가 클릭되어서 보낸 메시지를 정확하게 받아냈다면, 우리는 메시지 상자를 볼 수 있습니다.

WM_DESTROY에서, 우리는 프로그램을 종료하기 위해서 PostQuitMessage(0)을 선언했습니다. 이 메시지는 제목표시줄의 X 단추를 누를 때 활성화됩니다.

윈도우 메시지 생성
    case WM_CREATE: {
      hWndButton = CreateWindowEx(0,  /* 더 또는  '확장된' 모양 */
        TEXT("BUTTON"),             /* 만들고픈 GUI '클래스' */
        TEXT("날 눌러줘!"),          /* GUI 자막(Caption) */
        WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON, /* 컨트롤 모양은 |로 분할 */
        10,                         /* 좌측 위치 (좌측으로부터의 위치) */
        10,                         /* 상단 위치 (상단으로부터의 위치) */
        200,                        /* 컨트롤의 너비 */
        30,                         /* 컨트롤의 높이 */
        hWnd,                       /* 부모 창 처리 */
        (HMENU)IDBUTTON,            /* WM_COMMAND를 위한 컨트롤의 ID */
        g_hInst,                    /* 응용프로그램 인스턴스 */
        NULL); 
      break; 
      }
    default:             /* 작동하지 않았을 때의 메시지 */
      return DefWindowProc (hWnd, message, wParam, lParam); 
  }

  return 0;
}

WM_CREATE에서 우리는 그래픽 컨트롤인 단추를 만들기 위해 CreateWindowEx를 사용했습니다. 우리는 사용할 글자와 모양, 위치, 크기, 부모 창, WM_COMMAND에서 쓴 메뉴 ID를 정의했고, HINSTANCE로 이 컨트롤의 기원을 선언했습니다.

Default는 우리가 처리하고 싶지 않은 메시지가 발생하면 호출됩니다. 우리가 이 함수를 정수로 선언했기 때문에, 윈도우는 0이 반환되기를 기다립니다. 따라서 프로그램의 끝에는 0을 반환합니다.

약간의 C++과 Win32의 자료유형

자료유형

여러분은 Win32 API를 공부하면서 다음부터 나오는 자료유형을 알 필요는 없습니다. 대부분의 Win32 자료유형이 C++ 자료유형과 같지 않더라도 비슷하기 때문입니다. 여러분은 명시된 모든 Win32 자료유형을 기본 C++ 자료유형으로 사용해도 됩니다. Win32 API의 매우 많은 자료유형은 동의어이고 정확히 알지 못해도 됩니다만, 어쨌거나 여러분에게 빠른 참조를 제공하겠습니다.

  • BOOL은 C++에서 쓰이는 간단한 bool과 같은 것을 표시하는 윈도우 자료유형입니다. 이것의 값은 true 혹은 false가 올 수 있습니다.
  • WORD는 long과 비슷한 16비트 정수(16-bit integer)입니다. 이것은 특별히 몇몇 윈도우 함수에서 쓰입니다. 이것은 C++의 unsigned short와 같습니다.
  • FLOAT는 C++의 float과 같습니다.
  • UINT는 C++의 unsigned int와 같습니다.
  • WINAPI, APIENTRY, CALLBACK, APIPRIVATE, STDCALL은 C++에서 standard calling convention이라고 하는 __stdcall과 같습니다.
  • CDECL, WINAPIV는 모두 C++의 __cdecl calling convention과 같습니다.
  • FASTCALL은 C++의 __fastcall calling convention과 같습니다.
  • PASCAL은 C++의 __pascal calling convention과 같습니다.
  • WPARAMunsigned int pointer와 같고, 윈도우 메시지에서 쓰입니다.
  • Win32 API의 LPARAM은 WM_으로 시작하는 윈도우 메시지에 쓰입니다만, 정확하게는 long의 포인터입니다.
  • LRESULT는 HRESULT 또는 LONG/long과 같습니다만, long의 포인터입니다.
  • INT는 기본 정수 자료유형이고, C++의 int(부호 있음)와 같습니다.
  • BYTE는 C++의 unsigned char와 동의어입니다. 이것은 글자 특성에 쓰입니다.
  • DWORD는 C++의 LONG 혹은 long과 같습니다.
  • LONGINT를 대체합니다.

  • HRESULT는 C++의 long과 같습니다.
  • HANDLE은 Win32 API의 기본 long이지만, 보통 GUI 개체 혹은 그래픽 개체, 다른 win32 개체를 나타내는데 쓰입니다.
  • HINSTANCE는 윈도우 프로그램의 인스턴스를 선언하는데 사용된다는 것만 제외하면 HANLE과 매우 비슷합니다.
  • HWND의 자료유형은 long입니다. 이것은 윈도우 개체 자신을 표시하고, H-Wind(ow) 이름을 금후 하는데 사용됩니다.
  • LPSTR은 Win32에서 string 포인터입니다.
  • LPCSTR은 상수 문자열(constant string)의 long pointer입니다.
  • LPTSTRLPSTR과 같습니다. 이 자료유형은 두 가지 버전이 존재하는데, 하나는 ANSI 문자열을 가지고, 다른 하나는 Unicode 문자열을 가집니다.
  • LPCTSTRTCHARLPTSTR를 짬뽕한 것입니다. UnicodeANSI를 포함할 수 있습니다.

Win32 API C++ 프로그래밍을 배우면서

당연히 우리가 처리할 수 있는 윈도우 메시지와 메시지 상자를 보여주는 것을 포함하여 더 많은 GUI함수를 포함한 프로그램에서 사용할 수 있는 CreateWindowEx 클래스는 더 많이 있습니다. 메시지에 대해 더 많이 공부하고 싶다면 이 튜토리얼과 http://msdn.microsoft.com/library 를 즐겨 찾기에 추가하길 추천합니다.

저는 초보자들이 보기에 가장 간단하게 따라올 수 있고 충분한 예제와 함께 윈도우 프로그램의 구조를 이해할 수 있도록 튜토리얼을 제작하려고 노력했습니다. 하지만, 전 아직도 여러분이 다양한 함수와 자료유형에 대해 질문을 던질 것이라 확신합니다.

여러분은 이미 C++으로 콘솔 프로그램을 만든 경험이 있을 겁니다. 그러나 여러분은 검정색화면이 아닌 GUI(Graphical User Interfaces)프로그램 만드는 방법을 궁금해 할 것입니다. 이러한 GUI 프로그램을 Win32 API 프로그램이라고 합니다.

  1. Exh
    수고하셨습니다!
  2. 23123213
    window프로시저 선언할 때 변수를 선언하지 않았습니다.

Name __

Password __

Link (Your Website)

Comment