본문 바로가기

Programming Study/Win32 API

윈도우즈 프로그래밍 한번 알아보기

아래 소스 프로그램은 윈도우즈 API를 통해 만들어진 예제 소스이다.

아무 하는 일 없이 만든 후 종료되는 그런 프로그램이다.

#include <windows.h>

 

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPCTSTR lpszClass=TEXT("First");

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance,
    LPSTR lpszCmdParam, int nCmdShow)
{
    HWND hWnd;
    MSG Message;
    WNDCLASS WndClass;
    g_hInst = hInstance;

    WndClass.cbClsExtra = 0;
   WndClass.cbWndExtra = 0;
    WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
    WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    WndClass.hInstance = hInstance;
    WndClass.lpfnWndProc= WndProc;
    WndClass.lpszClassName = lpszClass;
    WndClass.lpszMenuName = NULL;
    WndClass.style = CS_HREDRAW | CS_VREDRAW;
    RegisterClass(&WndClass);

    hWnd = CreateWindow(lpszClass, lpszClass, WS_OVERLAPPEDWINDOW,
               CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
               NULL, (HMENU)NULL, hInstance, NULL);
    ShowWindow(hWnd, nCmdShow);
 
    while(GetMessage(&Message, NULL, 0,0))
    {
         TranslateMessage(&Message);
         DispatchMessage(&Message);
    }
    return (int)Message.wParam;
}

 

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
    switch(iMessage)
    {
    case WM_DESTROY :
     PostQuitMessage(0);
     return 0;
    }
    return(DefWindowProc(hWnd, iMessage, wParam, lParam));

실행하면 아래의 그림과 같이 나온다.

 

이제부터는 소스를 차근 차근 분석해 보면서 도스 또는 콘솔 프로젝트와의 차이점을 짚어보자.

 

1. WinMain

헤더파일 

#include <windows.h>

도스에서는 사용하는 함수의 종류에 따라 여러 개의 헤더 파일을 포함하지만 윈도우즈에서는 하나의 헤더 파일에

모든 API 함수들의 원형과 사용하는 상수들이 죄다 정의되어 있기 때문에 windows.h만 포함하면 된다.

물론 특별한 경우에는 해당하는 헤더 파일을 포함해야 한다.

윈도우즈 프로그램의 첫 줄은 거의 항상 #include <windows.h>로 시작된다.

마치 모든 도스 프로그램이 #include <stdio.h>를 포함하는 것과 같다.

 

시작점

프로그램의 시작점인 엔트리포인트(Entry Point)가 main이 아니라 WinMain이라는 점이 차이난다.

윈도우즈 프로그램의 시작점은 main이 아닌 WinMain이며 모든 윈도우즈 프로그램은 WinMain에서부터 실행을 시작한다.

원형은 다음과 같다.

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance,
    LPSTR lpszCmdParam, int nCmdShow)

도스에서의 main 함수는 인수 사용 여부에 따라 여러 가지 원형이 있지만 WinMain의 원형은 위와 같이 고정 되어 있다.

APIENTRY 지정자는 윈도우즈 표준 호출 규약인 _stdcall을 사용한다는 뜻이다.

WinMain함수는 4개의 인수를 취하는데 각 인수의 의미는 다음과 같다.

이 중 hInstance 이외에는 잘 사용되지 않는다.

인스턴스(Instance)라는 말은 실행중인 프로그램 하나를 칭하는 용어이다.

 

메시지 처리 함수

위 프로그램은 두 개의 함수만 정의하고 있다.

하나는 프로그램의 시작점인 WinMain이며 나머지 하나는 WndProc이다.

WndProc사용자와 시스템이 보내오는 메시지를 처리하는 아주 중요한 일을 한다.

도스에서는 main 함수만으로도 프로그램을 작성할 수 있지만 윈도우즈에서는 아주 특별한 경우를 제외하고는

이 두 개의 함수가 모두 있어야 한다.

WndProc함수의 원형을 살펴보자

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

 

함수 원형에 CALLBACK이라는 매크로가 사용되었는데 이 매크로도 APIENTRY와 마찬가지로 _stdcall로 정의 되어 있다.

 

 

2. 윈도우 클래스

WinMain 함수에서 하는 가장 중요한 일은 메인 윈도우를 만드는 일이다.

윈도우를 만들려면 윈도우 클래스를 먼저 등록한 후 CreateWindow 함수를 호출해야 한다.

윈도우 클래스는 만들어질 윈도우의 여러 가지 특성을 정의하는 구조체이며

모든 윈도우는 윈도우 클래스의 정보를 기반으로 만들어 진다.

 

윈도우 클래스의 멤버들을 간략하게 살펴보자.

style

  - 윈도우의 스타일을 정의

lpfnWndProc

  - 윈도우의 메시지 처리 함수를 지정

cbClsExtra, cbWndExtra

  - 일종의 예약 영역

hInstance

  - 이 윈도우 클래스를 등록하는 프로그램의 번호

hIcon, hCursor

  - 이 윈도우가 사용할 마우스 커서와 아이콘을 지정

hbrBackground

  - 윈도우의 배경 색상을 지정

  - 좀 더 정확하게 표현하면 윈도우의 배경 색상을 채색할 브러시를 지정하는 멤버

lpszMenuName

  - 이 프로그램이 사용할 메뉴를 지정

  - 메뉴는 프로그램 코드에서 실행중에 만드는 것이 아니라 리소스 에디터에 의해 별도로 만들어져 링크시에 같이 합쳐짐

  - 메뉴를 사용하지 않을 경우에 NULL을 대입

lpszClassName

  - 윈도우 클래스의 이름을 문자열로 정의

 

이 멤버들 중에서 제일 중요한 멤버는 윈도우 클래스의 이름을 정의하는 lpszClassName과

메시지 처리 함수를 지정하는 lpfnWndProc이다.

윈도우 클래스 구조체를 정의한 후 RegisterClass 함수를 호출하여 윈도우 클래스를 등록한다.

 

ATOM RegisterClass(CONST WNDCLASS *lpWndClass); 

RegisterClass 함수의 인수로 WNDCLASS 구조체의 번지를 전달.

 

 

3. 윈도우 생성

윈도우 클래스를 동록한 후에는 이 윈도우 클래스를 기본으로 실제 윈도우를 생성한다.

윈도우를 생성할 때는 CreateWindow 함수를 사용한다.

HWND CreateWindow(lpszClassName, lpszWindowName, dwStyle, x, y, nWidth, nHeight,

    hwndParent, hmenu, hinst, lpvParam)

인수들을 살펴보자

lpszClassName

  - 생성하고자 하는 윈도우의 클래스를 지정하는 문자열

lpszWindowName

  - 윈도우의 타이틀 바에 나타날 문자열이다.

dwStyle

  - 만들고자 하는 우니도우의 형태를 지정하는 인수

  - OR연산자로 연결하여 다양한 형태 지정

X, Y, nWidth, nHeight

  - 윈도우의 크기와 위치를 지정하며 픽셀 단위를 사용

  - 정수 값을 바로 지정해도 되며 CW_USEDEFAULT를 사용하면 운영체제가 화면 크기에 맞게 적당한 크기와 위치를 알아서 설정

hWndParent

  - 부모 윈도우가 있을 경우 부모 윈도우의 핸들을 지정

hmenu

  - 윈도우에서 사용할 메뉴의 핸들을 지정

hinst

  - 윈도우를 만드는 주체, 즉 프로그램의 핸들을 지정

  - 운영체제는 누가 윈도우를 만들었는지 기억해 두었다가 프로그램이 종료될 때 파괴되지 않은 윈도우를 자동을 파괴

lpvParam

  - CREATESTRUCT라는 구조체의 번지이며 여러 개의 윈도우를 만들 때 각 윈도우에 고유의 파라미터를 전달하는

    특수한 목적에 사용

  - 보통은 NULL값을 사용하며 잘 사용되지 않음

 

BOOL ShowWindow(hWnd, nCmdShow); 

메모리에 만들어진 윈도우를 화면에 보이게 하는 함수이다.

hWnd 인수는 화면으로 출력하고자 하는 윈도우의 핸들이며 CreateWindow 함수가 리턴한 핸들을 그대로 넘기면 된다.

nCmdShow는 윈도우를 화면에 출력하는 방법을 지정하며 다음과 같은 매크로 상수들이 정의되어 있다.

 

 

윈도우를 만드는 과정을 간단하게 정리해 보자. 

 

 

4. 메시지 루프

윈도우를 메시지 구동 시스템(Message Driven System)이라고 하는데 이 점이 도스와 가장 뚜렷한 대비를 이루는 특징이다.

메시지란?

  - 사용자나 시스템의 내부적인 동작에 의해 발생된 일체의 변화에 대한 정보

메시지 루프는 세 개의 함수 호출로 이루어져 있으며 전체 루프는 whlie문으로 싸여져 있어 무한히 반복되는 구조를 가진다.

 

각 함수들이 어떤 동작을 하는지 살펴보자.

BOOL GetMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax);

이 함수는 메시지 큐에서 메시지를 읽어들인다.

메시지 큐(Message Queue)는 시스템이나 사용자로부터 발생된 메시지가 잠시 대기하는 일종의 메시지 임시 저장 영역.

 

BOOL TranslateMessage(CONST MSG *lpMsg);

이 함수는 키보드 입력 메시지를 가공하여 프로그램에서 쉽게 쓸 수 있도록 한다.

 

LONG DispatchMessage(CONS MSG *lpmsg);

이 함수는 메시지 큐에서 꺼낸 메시지를 윈도우의 메시지 처리 함수(WndProc)로 전달

 

메시지 루프의 세 함수는 공통적으로 MSG라는 구조체를 사용한다.

 

5. 윈도우 프로시저

메시지 처리 함수

메시지 처리 함수란 메시지가 발생할 때 프로그램의 반응을 처리하는 일을 하며

WinMain 함수와는 별도로 WndProc이라는 이름으로 존재한다.

WndProc은 WinMain에서 호출하는 것이 아니라 운영체제에 의해 호출된다.

운영체제에 의해 호출되는 응용 프로그램 내의 함수를 콜백(CallBack) 함수라고 한다.

 

다음은 메시지 루프와 메시지 처리 함수의 전체적인 순서도이다.

 

- 윈도우즈 API 정복 中 -

 

'Programming Study > Win32 API' 카테고리의 다른 글

입력_타이머  (0) 2014.09.10
입력_마우스  (0) 2014.09.10
입력_키보드  (0) 2014.09.10
출력  (0) 2014.09.06
윈도우즈 프로그래밍  (0) 2014.09.06