#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 |