본문 바로가기

Windows/_Windows Programming

윈도우 기초 프로그래밍

#include <windows.h>

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

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;
        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));
}




#include <windows.h> :

윈도우즈에서는 하나의 헤더 파일에 모든 API 함수들의 원형과 사용하는 상수들(매크로), 기본적인 데이터 타입, 그 외 윈도우즈 프로그래밍에 필요한 헤더 파일을 거의 포함하고 있기 때문에 이 헤더 하나만 포함하면 된다.(특별한 경우에는 해당 헤더 파일을 포함해야 한다)


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

: 함수의 원형과 전역 변수를 선언한다



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

: 윈도우즈 프로그램의 엔트리 포인트(Entry Point : 프로그램의 시작점)이다.
APIENTRY 지정자는 __stdcall 형 호출 규약을 사용한다.

 파라미터  의미
 hInstance  프로그램의 인스턴스 핸들
 hPrevInstance  바로 앞에 실행된 현재 프로그램의 인스턴스
 핸들. 없을 경우 NULL이며 Win32에서는 항
 상 NULL이다. 호환성을 위해서 존재하는
 파라미터다.
 IpszCmdParam  명령행으로 입력된 프로그램 파리미터다.
 도스의 argv인수에 해당한다.
 nCmdShow  프로그램이 실행될 형태이며 최소화, 보통
 모양 등이 전달된다. 

(참고 : 인스턴스(Instance) : 클래스가 메모리에 실제로 구현된 실체를 의미. 윈도우즈 프로그램은 하나의 프로그램이 여러 번 실행될 수도 있다. 이때 실행되고 있는 각각의 프로그램을 인스턴스라고 한다.
예를 들어 그림판을 두 번 실행했다고 하면 각각의 프로그램은 모두 그림판이지만 운영체제는 각각 다른 메모리를 사용하는 다른 프로그램으로 인식한다. 이때 각 그림판은 서로 다른 인스턴스 핸들을 가지며 운영체제는 이 인스턴스 핸들값으로 두 개의 그림판을 구별한다)

hInstance : 프로그램 자체를 일컫는 정수값이며 프로그램 내부에서 자기 자신을 가리키는
1인칭 대명사다. WinMain의 파라미터로 전달된 hInstace 값은 지역변수이기 때문에 WinMain 안에서만 쓸 수 있다 때문에 다른 곳에서 쓰기 위해 전역변수에 대입해놓는다.


윈도우 클래스 :

윈도우가 있어야 사용자로부터 입력을 받을 수 있고 출력을 보여 줄수도 있다. 윈도우를 만들려면 윈도우 클래스를 먼저 등록한 후 CreateWinodw 함수를 호출한다. 윈도우 클래스는 만들어질 윈도우에 여러가지 특성을 정의하는 구조체이며 모든 윈도우는 윈도우 클래스의 정보를 기반으로 만든다.

typedef struct tagWNDCLASS
{
         UINT style;
         WNDPROC lpfnWndProc;
         int cbClsExtra;
         int cbWndExtra;
         HINSTANCE hInstance;
         HICON hIcon;
         HCURSOR hCursor;
         HBRUSH hbrBackground;
         LPCSTR lpszMenuName;
         LPCSTR lpszClassName;
} WNDCLASS;

1. style : 윈도우가 어떤 형태를 가질 것인가를 지정한다. 가장 많이 사용하는 값은CS_HREDRAW 와 CS_VREDRAW 이다. 이 두 값을 OR 연산자(|)로 연결하여 사용한다. 이 값은 윈도우의 수직(or 수평) 크기가 변할 경우 윈도우를 다시 그린다.

2. lpfnWndProc : 메시지 처리 함수를 지정한다. 메시지가 발생할 때마다 이 멤버가 지정하는 함수가 호출되며 이 함수가 모든 메시지를 처리한다.

3. cbClsExtra, cbWndExtra : 에약 영역이다. 특수한 목적에 사용되는 여분의 공간이다.
사용하지 않을 경우 0으로 지정한다.

4. hInstance : 윈도우 클래스를 등록하는 프로그램의 번호이며 이 값은 WinMain의 파라미터로 전달된 hInstance 값을 그대로 대입한다.

5. hIcon, hCursor : 사용할 마우스 커서와 아이콘을 지정한다. LoadCursor 함수와 LoadIcon 함수를 사용하여 커서, 아이콘을 읽어와 이 멤버에 대입한다. 사용자가 직접 아이콘과 커서를 만들어 사용할 수도 있다.

6. hbrBackground : 윈도우의 배경 색상을 채색할 브러시를 지정한다.GetStockObject 함수를 사용하여 기본적으로 제공하는 브러시를 지정하거나 시스템 색상을 지정할 수도 있다.

7. lpszMenuName : 사용할 메뉴를 지정한다. 메뉴는 프로그램 코드에서 실행중에 만드는 것이 아니라 리소스 에디터에 의해 별도로 만들어진 후 링크시에 합쳐진다. 메뉴를 사용하지 않을 경우 NULL(0)을 대입한다.

8. lpszClassName : 윈도우 클래스의 이름을 문자열로 정의한다. 지정한 이름은 CreateWinodw 함수에 전달된다. 클래스의 이름은 마음대로 정할수 있으나 관습상 실행 파일의 이름과 일치시켜 전역변수 lpszClass에 정의하며 이 전역변수를 대입시켜준다.

이 중 가장 중요한 멤버는 윈도우 클래스의 이름을 정의하는 lpszClassName과 메시지 처리함수를 지정하는 lpfnWndProc이다. 나머지 멤버는 디폴트나 0, NULL 같은 값을 주면 무난하다.


ATOM RegisterClass(CONST WNDCLASS *lpWndClass);

: 파라미터로  정의한 WNDCLASS 구조체의 번지를 넘겨준다.
정의한 윈도우 클래스 구조체를 운영체제에 등록한다.


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

: 윈도우 클래스를 기본으로 실제 윈도우를 생성하는 함수이다.
윈도우에 관한 모든 정보를 메모리에 만든 후 윈도우 핸들을 리턴값으로 넘겨준다.

1. lpszClassName : 생성하고자 하는 윈도우의 클래스를 지정하는 문자열이다. 윈도우 클래스의 lpszClassName에 대입했던 전역변수를 이 값에 넣어주면 된다.

2. lpszWinodowName : 윈도우 타이틀 바에 나타날 문자열을 지정한다.

3. dwStyle : 만들고자 하는 윈도우의 형태를 지정하는 값이다. 비트 필드값이며 매크로 상수들이 정의되어 있고 필요한 매크로 상수를 OR 연산자로 연결하여 다양한 형태를 지정한다.
WS_OVERLAPPEDWINDOW 스타일을 사용하면 가장 무난한 윈도우 설정 상태가 된다.

4. x, y, nWidth, nHeight : 윈도우의 크기와 위치를 픽셀 단위로 지정한다. 정수값을 바로 지정해도 되며 CW_USEDEFAULT를 사용하면 화면 크기에 맞게 적당한 크기와 위치를 설정한다

5. hWndParent : 부모 윈도우가 있을 경우 부모 윈도우의 핸들을 지정한다. 윈도우끼리 수직적인 상하관계를 가져 부자 관계(parent-child)가 성립되는데 이 관계를 지정해 주는 파라미터다. 없을 경우 NULL(0)로 지정한다.

6. hmenu : 사용할 메뉴의 핸들을 지정한다. 윈도우 클래스에서 지정한 메뉴를 그대로 사용하려면 이 값을 NULL로 다른 메뉴를 사용하려면 원하는 메뉴 핸들을 넣는다.

7. lpvParam : CREATESTRUCT 라는 구조체의 번지이며 특수한 목적에 사용된다. 보통은 NULL값을 대입한다.


BOOL ShowWindow(hWnd,nCmdShow);

: hWnd 파라미터는 화면으로 출력하고자 하는 윈도우의 핸들이며 CreateWindow 함수가 리턴한 핸들을 그대로 넘겨준다. nCmdShow는 화면에 출력하는 방법을 지정하며 다음의 매크로 상수들이 정의되있다.

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

nCmdShow 파라미터에는 WinMain 함수의 파라미터로 전달한 nCmdShow를 그대로 넣어주면 된다. 따라서 거의 호출 형식이 정해져있다.


메시지 루프 : 윈도우즈를 메시지 구동 시스템(Message Driven System)이라고도 하며
순서를 따르지 않고 주어진 메시지에 대한 반응을 정의하는 방식으로 프로그램이 실행된다.
윈도우즈 프로그램에서는 메시지 처리 부분을 while문으로 묶어서 무한히 반복시킨다.

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

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

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

: 메시지 큐에서 메시지를 읽어들인다. 메시지 큐(Message Queue)는 시스템이나 사용자로부터 발생된 메시지가 잠시 대기하는 메시지 임시 저장 영역이다. 읽어들인 메시지는 첫 번째 파라미터가 지정하는 MSG 구조체에 저장된다. 읽어들인 메시지가 WM_QUIT일 경우 FALSE를 리턴하여 루프가 종료되며, 그 외 메시지에는 TURE를 리턴하여 루프가 계속된다.
나머지 세 개의 파라미터는 읽어들일 메시지의 범위를 지정하는데 잘 사용되지 않는다.

BOOL TranslateMessage( CONST MSG *lpMsg);

: 키보드 입력 메시지를 가공하여 프로그램에서 쉽게 쓸 수 있도록 해준다. 키보드를 눌러서 키보드 메시지를 발생시키면 문자가 입력되었다는 메시지로 바꿔준다.
(WM_KEYDOWN -> WM_CHAR)

LONG DispatchMessage( CONST MSG *lpmsg);

: 메시지 큐에서 꺼낸 메시지를 윈도우의 메시지 처리 함수(WndProc)로 전달한다. WndProc는 메시지를 윈도우로 전달하고 윈도우에서 전달된 메시지를 점검하여 다음 동작을 결정한다.

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

typedef struct tagMSG
{
      HWND       hwnd;
      UINT         message;
      WPARAM   wParam;
      LPARAM   lParam;
      DWORD     time;
      POINT       pt;
} MSG;

 멤버  의미
 hwnd  메시지를 받을 윈도우 핸들
 message  메시지 종류를 나타낸다. 가장 중요하다
 wParam  전달된 메시지에 대한 부가적인 정보 32비트
 lParam  전달된 메시지에 대한 부가적인 정보 32비트
 time  메시지가 발생한 시간
 pt  메시지가 발생했을 때의 마우스 위치

message 멤버를 읽어서 메시지의 종류를 파악하며 message 값에 따라 프로그램의 반응이 달라진다. wParam, lParam은 메시지의 부가적인 정보를 가지되 메시지별로 의미가 다르다. GetMessage 는 읽은 메시지를 MSG 형의 구조체에 대입해 주며 DispatchMessage 에 의해 WndProc 로 전달된다.(WM_QUIT 메시지가 올때까지)

메시지는 실제로 하나의 정수값으로 표현되는데 종류가 무척많아 windows.h 에 메시지 별
매크로 상수를 정의해 두었다.(접두어 WM_)

 메시지  의미 
 WM_QUIT  프로그램을 끝낼 때 발생하는 메시지
 WM_LBUTTONDOWN  마우스의 좌측 버튼을 누를 경우 발생
 WM_CHAR  키보드로부터 문자가 입력될 때 발생
 WM_PAINT  화면을 다시 그려야 할 필요가 있을때 발생
 WM_DESTORY  윈도우가 메모리에서 파괴될 때 발생
 WM_CREATE  윈도우가 처음 만들어질 때 발생

메시지 루프가 종료되면 프로그램은 마지막으로 Message.wParam 을 리턴하고 종료한다.
이 값은 WM_QUIT 메시지로부터 전달된 탈출 코드(exit code)이다.


WinMain에서 한일을 정리해보면

WndClass 정의  ->   CreateWindow               ->   ShowWindow                
윈도우 클래스 정의    메모리상에 윈도우를 만든다   윈도우를 화면에 표시한다.

-> 메시지 루프
사용자로부터 메시지를 처리한다.



윈도우 프로시저 :

메시지가 발생할 때 프로그램의 반응을 처리하는 일을 한다. WndProc 은 WinMain 에서 호출하는 것이 아니라 메시지가 입력되면 운영체제에 의해 호출되어 메시지를 처리한다.
(참고 : 운영체제에 의해 호출되는 응용 프로그램 내의 함수를 콜백(CallBack)함수라 한다)

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)

WndProc의 파라미터는 4개이며 MSG 구조체의 멤버 4개와 동일하다(iMessage = message)

WndProc의 구조는 다음과 같으며 메시지의 종류에 따라 다중 분기하여 메시지별로 처리한다.

switch (iMessage)
{
       case Msg1 :
               처리 1;
               return 0;
       case Msg2 :
               처리 2;
               return 0;
}
return(DefWindowProc(hWnd,iMessage,wParam,lParam));

Msg1 메시지가 전달 되면 처리 1을 한 후 리턴하고 Msg2 메시지가 전달되면 처리 2를 한 후 리턴하는 식이다. 이 외에 메시지가 전달되면 DefWindowProc 함수에서 디폴트 처리한다.
(주의 : 메시지 처리 후 반드시 0을 리턴해야한다. 또한 DefWindowProc에서 메시지를 처리한 경우에 DefWindowProc에서 리턴한 값을 WndProc가 다시 리턴해야한다)



메시지 처리 순서도 :

'Windows > _Windows Programming' 카테고리의 다른 글

타이머(Timer)  (0) 2009.12.23
입력하기  (0) 2009.12.01
출력하기  (2) 2009.11.28
윈도우즈(Windows) 프로그래밍의 기초  (0) 2009.11.27
.xxx 파일 만들기  (2) 2009.11.24