Notice
Recent Posts
Recent Comments
Link
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
Archives
Today
Total
관리 메뉴

codingfarm

2. 기본 윈도우 생성 - 윈도우 생성 과정, 메시지 루프 본문

Windows/윈도우즈 API

2. 기본 윈도우 생성 - 윈도우 생성 과정, 메시지 루프

scarecrow1992 2020. 4. 27. 20:43
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <windows.h>
 
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPCTSTR lpszClass = TEXT("First");
 
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance
    , 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)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, 000)) {
        TranslateMessage(&Message);
        DispatchMessage(&Message);
    }
    return 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));
}
cs

 

위 소스코드를 한줄씩 분석해보겠다.

 

WinMain

헤더파일

첫줄에 windows.h하나만 인클루드 되어있다. windows.h 헤더파일은 기본적인 데이터 타입, 함수 원형, 매크로상수 등을 정의하며 그외 윈도우즈프로그래밍에 필요한 보조 헤더파일을 포함하고있다. 

도스 프로그램이 #include<stdio.h> 를 포함하듯이 윈도우즈 프로그램은 #include<windows.h> 로 시작한다 생각하면 된다.

 

 

시작점

도스와 달리 Entry Point가 main이 아닌 Winmain 이다. 모든 윈도우즈 프로그램은 WinMain에서부터 실행을 시작한다. 원형은 아래와 같다.

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

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

 

APIENTRY는 원형이 WINAPI이며 아래와 같이 정의된다.

#define APIENTRY WINAPI

WINAPI는 또한 _stdcall을 #define으로정의한것이다.

즉, 이는 윈도우즈의 표준 호출 규약인 __stdcall을 사용한다는 뜻이다.

 

시작점이 WinMain이므로 main이라는 이름의 함수를 만들고 사용하는것도 가능하나 혼란이 일어날 수 있으므로 추천하진 않는다.

 

각 인수의 의미는 아래와 같다.

인수 의미
hInstance 프로그램의 인스턴스 핸들이다.
hPrevInstance 바로 앞에 실행된 현재 프로그램의 인스턴스 핸들이다. 없을 경우는 NULL이 되며 Win32에서는 항상 NULL이다. 16비트와의 호환성을 위해서만 존재하는 인수이므로 신경쓰지 않아도 된다. 역사가 오래되다 보니 어쩔 수 없이 생기는 일종의 찌거기이다.
lpszCmdParam 명령행으로 입력된 프로그램 인수이다. 도스의 argv인수에 해당하며 보통 실행직후에 열 파일의 경로가 전달된다.
nCmdShow 프로그램이 실행될 형태이며 최소화, 보통 모양 등이 전달된다.

hIntance 이외에는 잘 안쓰인다.

위 예제에서는 2개의 전역변수를 선언하여 사용한다.

1
2
HINSTANCE g_hInst;
LPCTSTR lpszClass = TEXT("First");
cs

g_hInst는 실행중인 프로그램의 인스턴스를 다른 함수에서도 접근가능하도록 hInstance를 대입하였다.(13줄)

lpszClass는 윈도우 클래스를 정의하는 문자열로 윈도우의 타이틀 바에 표시되기도 한다.

 

 

메시지 처리 함수

WndProc함수는 사용자와 시스템이 보내오는 메시지를 처리하는 일을 담당한다. 도스에서는 main 함수만으로 프로그램의 작성이 가능하지만 윈도우즈 에서는 특별한 경우를 제외하고는 WinMain과 WndProc 2개의 함수가 모두 있어야 한다.

WinMain은 메인 윈도우를 만들고 화면에 윈도우를 표시하기만 할뿐이며, 대부분의 실질적인 일은 WndProc에서 이루어진다.

WinMain WndProc
$\bullet$ 메인 윈도우를 만들고 화면에 윈도우를 표시한다.
$\bullet$ 프로그램을 초기화 하고 시작시키기만 하므로 모양이 대체로 일정하다.
$\bullet$ 프로그램에서 발생하는 대부분의 실질적인 일을 담당.
$\bullet$ 실질적인 처리를 담당하므로 프로그램에 따라 형태가 천차만별이다.

함수의 원형은 아래와 같다.

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

CALLBACK 매크로는 APIENTRY아 마찬가지로 __stdcall 로 정의되어있다.

이들 함수호출규약은 호환성과 이식성을 위해 존재하는것으로 지금은 신경쓰지 않도록 한다.

이 함수의 본체에 대해서는 나중에 살펴보겠다.

 

 

윈도우 클래스

WinMain 함수에서 하는 가장 중요한 일은 main window를 만드는 것이다. 윈도우가 있어야 사용자로부터 입력을 받을 수 있고 작업한 결과를 출력할 수도 있기 때문이다. 윈도우를 만들려면 아래의 순서를 따라야 한다.

1) 윈도우 클래스를 등록한다.

2) CreateWindow 함수를 호출한다.

윈도우 클래스는 만들어질 윈도우의 여러가지 특성을 정의하는 구조체이며 모든 윈도우는 윈도우 클래스의 정보를 기반으로 하여 만들어진다.

윈도우 클래스는 windows.h에 아래와 같이 정의된 구조체이다.

1
2
3
4
5
6
7
8
9
10
11
12
typedef struct tagWNDCLASS {
    UINT        style;
    WNDPROC     lpfnWndProc;
    int         cbClsExtra;
    int         cbWndExtra;
    HINSTANCE   hInstance;
    HICON       hIcon;
    HCURSOR     hCursor;
    HBRUSH      hbrBackground;
    LPCSTR      lpszMenuName;
    LPCSTR      lpszClassName;
} WNDCLASS;
cs

10개나 되는 멤버를 가지고 있다. 각 멤버의 의미는 아래와 같다.

 

style

$\bullet$ 윈도우의 스타일을 정의한다.  즉, 윈도우가 어떤 형태를 가질 것인가를 지정하는 멤버이다.

$\bullet$  이 멤버가 가질 수 있는 값은 무척 많지만 가장 많이 사용하는 값은 CS_HREDRAW와 CS_VREDRAW이다.

위 두값을 OR 연산자( | )로 연결하여 사용한다.

$\bullet$  이 스타일은 윈도우의 수직 또는 수평 크기가 변할 경우 윈도우를 다시 그란다는 뜻이다.

$\bullet$  이외에도 많은 값이 올 수 있다.

 

lpfnWndProc

$\bullet$  윈도우의 메시지 처리 함수를 지정한다.

$\bullet$ 메시지가 발생할 때마다 이 멤버가 지정하는 함수가 호출되며 이 함수가 모든 메시지를 처리한다. 메시지 처리함수의 이름은 마음대로 정할 수 있지만 거의 WndProc으로 정해져 있는 편이다.

 

위 예제에서 이 멤버에 WndProc 함수를 대입하고 있으므로 이 윈도우 클래스로부터 만들어지는 윈도우의 메시지는 WndProc 함수가 처리하게 된다.

 

cbClsExtra, cbWndExtra

$\bullet$ 일종의 예약 영역이다.

$\bullet$ 윈도우즈가 내부적으로 사용하며 아주 특수한 목적에 사용되는 여분의 공간이다. 예양 영역을 사용하지 않을 경우는 0으로 지정한다.

 

hInstance

$\bullet$ 이 윈도우 클래스를 등록하는 프로그램의 식별 번호이며 WinMain의 인수로 전달된 hInstance값을 그대로 대입하면 된다.

$\bullet$ 운영체제는 이 윈도우 클래스를 누가 등록했는지 기억해 두었다가 프로그램이 종료될 때 등록을 취소한다.

 

hIcon, hCursor

$\bullet$ 이 윈도우가 사용할 마우스 커서와 아이콘을 지정한다.

$\bullet$ LoadCursor 함수와 CoadIcon 함수를 사용하여 커서, 아이콘을 읽어와 이 멤버에 대입하면 된다.

$\bullet$ 사용자가 직접 이미지를 만들어 사용할 수 있지만 윈도우즈가 디폴트로 제공하는 아이콘과 커서도 있다.

 

hbrBackground

$\bullet$ 윈도우의 배경 색상을 지정한다. 좀더 정확하게 표현하면 윈도우의 배경 색상을 채색할 브러시를 지정하는 멤버이다.

$\bullet$ GetStockObject 라는 함수를 사용하여 윈도우즈에서 기본적으로 제공하는 브러시를 지정하거나 COLOR_WIMDOW 같은 시스템 색상을 지정할 수도 있다.

 

지정가능한 브러시에는 여러 종류가 있지만 이 예제에서는 가장 일반적인 흰색 브러시(WHITE_BRUSH)를 사용하였다.

 

lpszMenuName

$\bullet$ 이 프로그램이 사용할 메뉴를 지정한다.

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

$\bullet$ 메뉴를 사용하지 않을 경우 이 멤버에 NULL을 대입한다.

 

lpszClassName

$\bullet$ 윈도우 클래스의 이름을 문자열로 정의한다.

 

$\bullet$ 여기서 지정한 이름은 CreateWindow 함수에 전달되며 이 함수는 윈도우 클래스에서 정의한 특성값을 참조하여 윈도우를 만든다.

$\bullet$ 아무 이름이나 설정 가능하지만 보통 실행 파일의 이름과 일치시켜 작성한다.

 

 

ATOM RegisterClass(CONST WNDCLASS *lpWndClass);

위 함수의 인수로 WNDCLASS 구조체의 번지를 전달한다.  그리고 함수를 호출하여 윈도우 창의 특성을 등록한다.

위코드에서 WNDCLASS를 초기화 하는 코드만을 가저와 아래에 정리하였다.

1
2
3
4
5
6
7
8
9
10
11
12
WNDCLASS WndClass;
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)WndProc;
WndClass.lpszClassName = lpszClass;
WndClass.lpszMenuName = NULL;
WndClass.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&WndClass);
cs

가장 일반적인 윈도우를 만들 수 있는 무난한 값들이다.

흰색 배경에(5줄) 커서와 아이콘은 OS가 제공하는 것을 사용했다.(6,7줄) 메뉴는 사용하지 않는다.(11줄)

이 윈도우 클래스를 등록한 프로그램은 hInstance 이며(8줄) 전달되는 메시지는 WndProc 함수가 처리하도록 했다.(9줄)

 

WNDCLASS는 멤버가 좀 많은 구조체일 뿐이므로 선언과 동시에 초기화 하는것도 가능하다.

멤버의 초기화 방법은 각자 편한방법을 쓰도록 한다.

 

 

윈도우 생성

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

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

HWND CreateWindow(lpszClassName, lpszWindowName, dwStyle, x, y, nWidth, nHeight, hwndParent, hmenu, hinst, lpvParam)

마찬가지로 인수가 굉장히 많다. 하나하나 의미를 살펴보자

 

lpszClassName

$\bullet$ 생성하고자 하는 윈도우의 클래스를 지정하는 문자열이다. 등록하고자 할 WNDCLASS 구조체의 lpszClassName 멤버의 이름을 여기에 기입한다.

$\bullet$ RegisterClass 함수를 통해 등록된 구조체 정보를 이 매개변수를 통해 찾게된다.

 

위 예제에서는 lpszClass 전역변수에 윈도우의 클래스 이름을 기억시켜 두었다.(5줄)

 

lpszWindowName

$\bullet$ 윈도우 타이틀 바에 나타날 문자열이다. 

 

dwStyle

$\bullet$ 만들고자 하는 윈도우의 형태를 지정하는 인수이다.

$\bullet$ 일종의 비트 필드값이며 거의 수십개를 헤아리는 매크로 상수들이 정의되어 있고 이 상수들을 OR 연산자로 연결하여 윈도우의 다양한 형태를 지정한다.

$\bullet$ 크기 조절이 가능하게 할것인가, 타이틀 바를 가질것인가, 스크롤 바의 유무 등등을 지정 가능하다.

WS_OVERLAPPEDWINDOW 스타일을 넣으면 가장 무난한 윈도우가 된다.(메모장과 비슷하다)

 

X, Y, nWidth, nHeight

$\bullet$ 윈도우의 크기와 위치를 지정하며 픽셀 단위를 사용한다.

예제처럼 CW_USEDEFAULT를 사용하면 운영체제가 화면 크기에 맞게 적당한 크기와 위치를 알아서 설정한다.

 

hWndParent

$\bullet$ 부모 윈도우가 있을 경우 부모 윈도우의 핸들을 지정한다.

$\bullet$ MDI 프로그램이나 팝업 윈도우는 윈도우끼리 수직적인 상하관계를 가져 부모(parent-child) 관계가 성립되는데, 이 관계를 지정하는 인수이다. 자식 윈도우는 부모 윈도우의 창 안에서만 존재 할 수 있다.

$\bullet$ 부모 윈도우가 없을경우, 즉 자신이 최상위 윈도우일 경우는 이 값을 NULL로 지정한다. 이경우 데스크 탑을 부모로 가져 바탕화면 어디나 돌아다닐 수 있는 윈도우가 된다.

 

hmenu

$\bullet$ 윈도우에서 사용할 메뉴의 핸들을 지정한다.

$\bullet$ 윈도우 클래스의 메뉴는 그 윈도우 클래스를 기반으로 하는 모든 윈도웅에서 공통적으로 사용된다.

$\bullet$ 이 인수로 지정된 메뉴는 현재 CreateWindow 함수로 만들어지는 윈도우에서만 사용된다.

윈도우 클래스에서 지정한 메뉴를 그대로 사용하려면 이 인수를 NULL로 지정하며 다른 메뉴를 사용하려면 이 인수에 원하는 메뉴 핸들을 지정한다.

위 예제에서는 윈도우 클래스와 CrateWindow 함수의 인수 모두 메뉴를 지정하지 않았으므로 메뉴없는 윈도우가 만들어진다.

 

hinst

$\bullet$ 윈도우를 만드는 주체, 즉 프로그램의 핸들을 지정한다.

$\bullet$ 주로 WinMain의 인수로 전달된 hInstance를 대입한다.

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

 

lpvParam

$\bullet$  CREATESTRUCT라는 구조체의 번지이며 여러개의 윈도우를 만들 때 각 윈도우에 고유의 파라미터를 전달하는 특수한 목적에 사용된다.

$\bullet$ 보통은 NULL값을 사용하며 잘 사용되지 않으므로 일단은 무시하자.

 

 

CreateWindow 함수는 윈도우에 관한 모든 정보를 메모리에 만든 후 윈도우를 대표하는 번호인 윈도우 핸들을 리턴한다.

반환된 윈도우 핸들은 hWnd라는 변수에 저장되었다가(27줄) 이 윈도우를 참조하는 모든 함수의 인수로 사용된다.

 

 

ShowWindow

CreateWindow 함수를 호출하여 만든 윈도우는 메모리상에만 존재할 뿐 아직 화면에 출력되지 않는다.

메모리에 만들어진 윈도우를 화면에 보이게 하기 위해선 ShowWindow 함수를 호출해야 한다.

BOOL ShowWindow(hWnd, nCmdShow);

hWnd : 화면으로 출력하고자 하는 윈도우의 핸들, CreateWindow 함수가 리턴한 핸들을 넘긴다.

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

 

매크로 상수 의미
SW_HIDE 윈도우를 숨긴다.
SW_MINIMIZE 윈도우를 최소화하고 활성화 시키지 않는다.
SW_RESTORE 윈도우를 활성화시킨다.
SW_SHOW 윈도우를 활성화하여 보여준다.
SW_SHOWNORMAL 윈도우를 활성화하여 보여준다.

nCmdShow 인수에는 WinMain 함수의 인수로 전달된 nCmdShow를 그대로 전달하면 된다.

이값은 프로그램을 쉘로부터 전달된것이며 곧 사용자가 프로그램 등록 정보 대화상자에서 지정한 값이다. 그래서 ShowWindow(hWnd, nCmdShow);와 같이 거의 호출형식이 정해져 있는 셈이다.

예제에서는 27~30번재 줄에서 윈도우를 만들고 화면에 나타낸다.

 

 

여기까지 실행하면 화면에 윈도우가 출력된다. 이후에는 메시지 루프가 시작되며 프로그램이 사용자와 윈도우즈, 그리고 다른 프로그램과 정보를 상호 교환하며 실행된다.

 

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

이 과정은 거의 정형화되어 있으며 WinMain에서 반드시 해야 할 과정들이다. 그래서 WinMain의 모양은 대부분의 프로그램에서 거의 유사하다.

 


메시지 루프

  • 윈도우즈를 메시지 구동 시스템(Message Driven System)이라 하며, 이 점이 도스와 가장 뚜렷한 대비를 이루는 윈도우즈의 특징이다.
    • 도스에서는 프로그래머에 의해 미리 입력된 일련의 명령들을 순서대로 실행하는 순차적 방법을 사용한다.
    • 윈도우즈는 프로그램의 실행순서가 명확하게 정해져 있지 않으며 상황에 따라 달라진다.
      • 상황이란 어떤 메시지가 발생했는가를 의미한다.
  • 메시지란 사용자나 시스템의 내부적인 동작에 의해 발생된 일체의 변화에 대한 정보이다.
  • 가령 마우스 버튼의 클릭, 키모드 버튼 누름, 위노우 최소화 등의 변화에 대한 정보들이 메시지이다.
  • 메시지를 받은 프로그램은 메시지가 어떤 정보를 담고 있는가를 분석하여 무슨 동작을 할것인가를 결정한다.
  • 즉, 순서를 따르지 않고 주어진 메시지에 대한 반응을 정의하는 방식으로 프로그램이 실행된다.
  • 메시지 루프(Message Loop) : 윈도우즈 프로그램에서 메시지를 처리하는 부분을 지칭
    • 보통 WinMain 함수의 끝에 아래 형식으로 존재한다.
while(GetMessage(&Message, NULL, 0, 0)){
    TranslateMessage(&Message);
    DispatchMessage(&Message);
}
  • 메시지 루프는 세개의 함수가 while문으로 싸여저, 무한히 반복되는 구조를 가진다.
  • 메시지 루프는 윈도우즈의 멀티태스킹을 지원하는 굉장히 중요한 역할을 하며 따라서 윈도우즈를 이해하기 위한 핵심루프이다.

추후 13장에서 상세히 배우지만 우선 대략적으로 알아보자.

 

BOOL GetMessage(LPMSG lgMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax);
  • 메시지큐에서 메시지를 읽어들인다.
  • 메시지큐(Message Queue) : 시스템이나 사용자로부터 발생된 메시지가 잠시 대기하는 일종의 메시지 임시 저장 영역
  • 읽어들인 메시지는 매개변수 lpMsg구조체에 저장된다.
  • 반환값 : 읽어들인 메시지가 프로그램을 종료하라는 WM_QUIT이면 FALSE를 반환하며, 그 외의 메시지면 TRUE를 반환한다.

 

BOOL TranslateMessage(CONST MSG *lpMsg);
  • 키보드 입력 메시지를 가공하여 프로그램에서 쉽게 쓸 수 있도록 한다.
  • 키보드의 눌림(WM_KEYDOWN) 메시지가 발생할 때 문자가 입력되었다는 메시지(WM_CHAR)을 만드는 역할을 한다.

 

LONG DispatchMessage(CONST MSG *lpmsg);
  • 이 함수는 메시지 큐에서 꺼낸 메시지를 윈도우의 메시지 처리 함수(WndProc)으로 전달한다.
  • 이 함수에 의해 메시지가 윈도우로 전달되며 프로그램(정확히는 윈도우 프로시저)에서는 전달된 메시지를 점검하여 다음 동작을 결정한다.

 

  • 메시지 루프에서 하는 일은 메시지를 꺼내고, 필요한 경우 약간 형태를 바꾼 후 응용 프로그램으로 전달하는 것뿐이다.
  • 실제 메시지 처리는 별도의 메시지 처리 함수(WndProc)에서 수행한다.
  • 메시지 루프의 세 함수는 공통적으로 MSG라는 구조체를 사용하는데 이 구조체는 메시지에 대한 정보를 정의한다.
  • MSG 구조체는 아래와 같이 정의된다.
typedef struct tagMSG {
  HWND   hwnd;
  UINT   message;
  WPARAM wParam;
  LPARAM lParam;
  DWORD  time;
  POINT  pt;
  DWORD  lPrivate;
} MSG, *PMSG, *NPMSG, *LPMSG;

각 멤버의 의미는 아래와 같다.

멤버 의미
hwnd 메시지를 받을 윈도우 핸들이다.
message 어떤 종류의 메시지인가를 나타낸다. 가장 중요한 값이다.
wParam 전달된 메시지에 대한 부가적인 정보를 가진다.
어떤 의미를 가지는가는 메시지별로 다르다.
32bit 크기이다.
lParam 전달된 메시지에 대한 부가적인 정보를 가진다.
어떤 의미를 가지는가는 메시지별로 다르다.
32bit 크기이다.
time 메시지가 발생한 시간이다.
pt 메시지가 발생햇을 때의 마우스 위치이다.
  • message 멤버를 읽음으로써 메시지의 종류를 파악하며 message 값에 따라 프로그램의 반응이 달라진다.
  • wParam, lParam은 메시지에 대한 부가적인 정보를 가지되 메시지별로 의미가 다르다.
  • GetMessage 함수는 읽은 메시지를 MSG형의 구조체에 대입하며 이 구조체는 DispatchMessage 함수에 의해 응용프로그램의 메시지 처리 함수(WndProc)로 전달된다.

 

  • 메시지는 하나의 정수값으로 표현되는데, 일일이 암기 할 수는 없으므로 레퍼런스를 참고하여 사용한다.
메시지 의미
WM_QUIT 프로그램을 끝낼 때 발생하는 메시지이다.
WM_LBUTTONDOWN 마우스의 좌측 버튼을 누를 경우 발생한다.
WM_KEYDOWN 키보드의 키를 눌렀다.
WM_CHAR 키보드로부터 문자가 입력될 때 발생한다.
WM_PAINT 화면을 다시 그려야할 필요가 있을 때 발생한다.
WM_CREATE 윈도우가 처음 만들어질 때 발생한다.
WM_DESTROY 윈도우가 메모리에서 파괴될 때 발생한다.

 

 

  • 메시지 루프가 종료되면 프로그램은 마지막으로 Message.wParam을 리턴하고 종료한다.
  • 이 값은 WM_QUIT 메시지로부터 전달된 탈출 코드(exit code)이며 이 프로그램을 실행시킨 운영체제로 리턴된다.
  • 도스에서 사용하는 탈출 코드와 동일한 의미를 가지며 사용하는 경우가 거의 없다.

 


윈도우 프로시저

  • WndProc은 메시지 처리함수로써, 메시지가 발생할때 프로그램의 반응을 처리하는 일을 한다.
  • WinMain이 아니라 OS에 의해 호출된다.
  • WndProc은 메시지가 입력되면 OS에 의해 호출되어 메시지를 처리한다.
  • OS내에서 호출되는 응용프로그램 내의 함수를 콜백(CallBack) 함수라 한다. (4장에서 자세히 배울것)
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));
}
  • 매개변수
변수 기능
hwnd 메시지를 받을 윈도우 핸들이다.
iMessage 어떤 종류의 메시지인가를 나타낸다. 가장 중요한 값이다.
wParam 전달된 메시지에 대한 부가적인 정보를 가진다.
어떤 의미를 가지는가는 메시지별로 다르다.
32bit 크기이다.
lParam 전달된 메시지에 대한 부가적인 정보를 가진다.
어떤 의미를 가지는가는 메시지별로 다르다.
32bit 크기이다.
  • 각 매개변수의 역할은 MSG 구조체 앞쪽 멤버 4개와 동일하다
  • wParam, lParam은 부가적인 요소이다.
    • 화면의 어디에 마우스 버튼이 눌렸는가
    • 키보드의 어떤 문자가 입력되었는가

 

  • WndProc 맨 끝의 DefWindowProc 함수는 WndProc에서 처리하지 않은 나머지 메시지에 관한 처리를 한다.
    • 가령 시스템 메뉴를 더블클릭하면 프로그램이 종료되는데 이런 처리는 별도로 하지 않아도 DefWindowProc 함수에서 알아서 한다.
    • 그러므로 윈도우의 이동이나 크기 변경 따위의 처리는 프로그램이 직접 할 필요없이 DefWindowProc으로 넘기기만 하면 된다.

 

 

 

Window와 Dos의 차이

DOS는 콘솔 기반의 텍스트 출력만을 보여주지만 윈도우는 OS에서 제공해주는 다양한 기능들을 활용한 GUI 출력을 보여준다.

윈도우 창의 라이프 사이클을 실행하기 위한 WinMain 함수와 입력된 메시지를 처리하기 위한 WndProc 함수로 이루어짐

 

 

 

 

 

 

요약

  • 윈도우 프로그램의 기초적인 구성요소
    • 진입함수(WinMain)
    • 메시지처리함수(WndProc)
  • 윈도우의 생성 과정
    1. WndClass 클래스 정의
    2. 윈도우 클래스 등록 (RegisterClass)
    3. 메모리상에 윈도우 생성(CreateWindow)
    4. 화면에 윈도우 표시 (ShowWindow)
    5. 메시지 루프
  • 윈도우 메시지
    • 사용자나 시스템의 내부적인 동작에 대한 정보
    • Window는 메시지 구동 시스템(Message Driven System)이라 불릴 정도로 메시지에 지배적이다.
  • 메시지 발생 조건
    • 사용자 조작
    • 시스템 변화
  • 메시지 루프의 루틴
    • GetMessage : 메시지큐에서 메시지를 읽어들인다.
    • TranslateMessage : 키보드 입력 메시지를 가공하여 프로그램에서 쉽게 쓸 수 있게끔 한다.
    • DispatchMessage : 메시지를 메시지처리함수(WndProc)으로 전달한다.

 

 

 

 

 

'Windows > 윈도우즈 API' 카테고리의 다른 글

3. 그래픽 출력  (0) 2020.11.19
3. 문자열의 출력(TextOut, DrawText)  (0) 2020.11.19
3. DC(Device Context)  (0) 2020.11.19
2. 다양한 변형  (0) 2020.11.17
1. 윈도우즈 프로그래밍  (0) 2020.04.27
Comments