● First 예제
#include <windows.h> LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM); HINSTANCE g_hInst; LPSTR lpszClass="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,0,0,0)) { 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)); }
아무런 기능도 없으며 단지 윈도우를 하나 만들었을 뿐이다. 그러나 간단해 보여도 완전히 온전한 하나의 윈도우이므로 표준 윈도우가 가진 모든
기능을 다 발휘할 수 있다.
● First 예제 분석
- 헤더파일
도스에서는 사용하는 함수의 종류에 따라 여러 개의 헤더 파일을 포함하지만 윈도우즈에서는 하나의 헤더 파일에 모든 API 함수들의
원형과 사용하는 상수들이 죄다 정의되어 있기 때문에 windows.h만 포함하면 된다.
- 시작점
다음으로 차이나는 점은 프로그램의 시작점인 엔트리 포인트(EntIy Point)가 main이 아니라 WinMain이라는 점이다. 윈도우즈 프로그램의 시작점은 main이 아닌 WinMain이며 모든 윈도우즈 프로그램은 WinMain에서부터 실행을 시작한다.
※ APIENTRY 지정자는 윈도우즈의 표준 호출 규약인 _stdcall 을 사용한다는 뜻
1. hlnstance
프로그램의 인스턴스 핸들이다.
2. hPrevlnstance
바로 앞에 실행된 현재 프로그램의 인스턴스 핸들이다. 없을 경우는 NULL이 되며 Win32에서는 항상 NULL이다. 16비트와의 호환성을 위해서만 존재하는 인수이므로 신경쓰지 않아도 된다 역사가 오래되다 보니 어찔 수 없이 샘기는 일종의 찌꺼기이다.
3. IpszCmdParam
영령행으로 입럭된 프로그램 인수이다. 도스 의 argv인수에 해당하며 보통 실행
직후에 열 파일의 경로가 전달된다
4. nCmdShow
프로그램이 실행될 형태이며 최소화,보통 모앙 등이 전달된다.
5. Instance란?
인스턴스(instance)라는 말은 실행중인 프로그램 하나를 칭하는 용어이다. 윈도우즈는 여러 개의 프로그램이 동시에 실행되는 멀티 태스킹 시스템일 뿐만 아니라 하나의 프로그램 이 여러 번 실행될 수도 있다. 이때 실행되고 있는 각각의 프로그램을 프 로그램 인스턴스라고 하며 간단히 줄여서 인스턴스라고 한다.
- 메시지 처리 함수
WndProc은 사용자와 시 스템 이 보내오는 메시지 를 처리하는 아주 중요한 일을 한다 WinMain은 메인 윈도우를 만들고 화면에 윈도우를 표시하기만 할 뿐이며 대부분의 일은 WndProc 에서 이루어진다. WinMain은 프로그램을 초기화하고 시작시키기만 하므로 모양이 대체 로 일정한데
비해 WndProc은 프로그램의 실질적이고도 고유한 처리를 하는 곳이므로 프로그램 에 따라 천차만별 로 달라진다.
- 윈도우 클래스
윈도우를 만들려면 윈도우클래스를 먼저 등록한 후 CreateWindow 함수를 호출해야 한다. 윈도우 클 래 스는 만들어질 윈도우의 여러 가지 특성을 정의하는 구조체이며 모든 윈도우는 윈도우 클래스의 정보를 기반으로 하여 만들어진다.
윈도우 클래스는 windows.h에 다음과 같이 정의되어 있는 구조체이다.
typedef struct tagWNDCLASS
{
UINT style;
WNDPROC IpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hlnstance;
HICON hlcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCSTR IpszMenuName;
LPCSTR IpszClassName;
} WNDCLASS;
1. style : 윈도우의 스타일을 정의한다. 즉 윈도우가 어떤 형태를 가질 것인가를 지정하는 멤버이다.
2. IpfnWndProc :이 멤버는 윈도우의 메시지 처리 함수를 지정한다. 메시지가 발생할 때마다 이 멤버가 지정하는 함수가 호출되며 이 함수가 모
든 메시지를 처리한다.
3. cbCIsExtra, cbWndExtra : 일종의 예약 영역이다. 윈도우즈가 내부적으로 사용하며 아주 특수한 목적에 사용되는 여분의 공간이다. 예약 영역
을 사용하지 않을 경우는 0으로 지정한다,
4. hInstance : 이 윈도우 클래스를 등록하는 프로그램의 번호. 운영체제는 이 윈도우 클래스를 누가 등록했는지 기억해 두었다가 프로그램이 종
료될 때 등록을취소한다
5. hIcon, hCursor : 윈도우가 사용할 마우스 커서 와 아이콘을 지 정 한다.
6. hbrBackground : 윈도우의 배경 색상을 지정한다. 좀 더 정확하게 표현하면 윈도우의 배경 색상을 채색할 브러시를 지정하는 멤버이다.
7. lpszMenuName: 이 프로그램이 사용할 메뉴를 지정한다.
8. lpszClassName : 윈도우 클래스의 이 름을 문자열로 정의한다. 여기서 지정한 이 름은 CreateWindow 함수에 전달되며 CreateWindow 함수
는 윈도우 클래스에서 정의한 특성값을 참조하여 윈도우를 만든다.
9 ATOM RegisterClass : RegisterClass 함수의 인수로 WNDCLASS 구조체의 번지 를 전달한다. 이런 이런 특성을 가진 윈도우를 앞으로 사용
하겠다는 등록 과정이며 운영체제는 이 윈도우 클래스의 특성을 잘 기억해 놓는다.
- 윈도우 생성
윈도우 클래스를 등록한 후에는 이 윈도우 클래 스를 기본으로 실제 윈도우를 생성한다. 윈도우를 생성할 때는 CreateWindow 함수를 사용한다.
HWND CreateWindow(lpszClassName, IpszWindowName, dw5tyle, x, y, nWidth, nHeight, hwndParent, hmenu, hinst, Ipvparam);
1. IpszClassName : 생성하고자 하는 윈도우의 클래스를 지정하는 문자열이다.
2. IpszWindowName : 윈도우의 타이틀 바에 나타날 문자열이다. 여기서 지정한 문자열이 윈도우의 타이 툴 바에 나타난다.
3. dwStyle : 만들고자 하는 윈도우의 형 태 를 지정하는 인수이다. 일종의 비 트 필드값이며 거의 수십 개를 헤아리 는 매 크로 상수들이 정의되
어 있고 이 상수틀을 OR연산자로 연결하여 윈도우의 다양한 형태를 지정한다.
4. X, Y, nWidth, nHeight : 인수의 이 름이 의미하듯이 윈도우의 크기와 위치 를 지정하며 픽셀 단위를 사용한다.
5. hWndParent: 부모 윈도우가 있을 경우 부모 윈도우의 핸들을 지정한다.
6. hmenu : 윈도우에서 사용할 메뉴의 핸들을 지정한다.
7. hinst : 윈도우를 만드는 주체, 즉 프로그램의 핸들을 지정한다.
8. IpvParam : CREATESTRUCT라는 구조체의 번지이며 여 러 개의 윈도우를 만들 때 각 윈도우에 고유의 파라미터를 전달하는 특수한 목적에 사
용된다 보통은 M凡L값을 사용하며 잘 사용되지 않으므로 일단은무시하자.
9 . BOOL ShowWindow(hWnd, nCmdShow)
메모리에 만들어진 윈도우를 화면으로 보이게 하려면 다음 함수를 사용해야한다.
SW HIDE 윈도부를 숨긴다.
SW MINIMIZE 윈도우를 최소화하고 활성화시키지 않는다.
SW RESTORE 윈도우를 활성화시킨다.
SW SHOW 윈도우를 활성화하여 보여준다
SW SHOWNORMAL 윈도우를 활성화하여 보여준다.
- 윈도우를 만드는 과정
- 메시지 루프
윈도우즈 프로그램에서 메시지 를 처리하는 부분을 메시지 루프(Message Loop)라고 하며 보통 WinMain 함수의 끝에 다음과 같은 형식으로 존재한다, 메인 윈도우를 만든 직후 WinMain은 메시지 루프를 실행한다.
while (GetMessage(&Message,NULL,0,0)) {
TranslateMessage( &Message);
DispatchMessage( &Message);
}
1. BOOL GetMessage(LPMSG IpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax);
메시지 큐(Message Queue)는 시스템이나 사용자로 부터 발생된 메시지가 잠시 대기하는 일종의 메시지 임시 저장 영역이다. 읽어들인 메
시지는 첫 번째인수가 지정하는 MSG 구조체에 저장된다. 이 함수는 읽어들인 메시지가 프로그램을 종료하라는 WM_QUIT일 경우 FALSE를 리턴하며 그 외의 메시지이변 TRUE를 리턴한다. 따라서 WM_QUIT 메시지가 읽혀질 때까지, 즉 프로그램이 종료될 때까지 전체 while 루프가 계속 반복된다. 나머지 세 개 의 인수는 읽어들일 메시지의 범위를 지정하는데 잘 사용되지 않으므로 일단 무시하기로 한다
2. BOOL TranslateMessage(CONST MSG *lpMsg);
이 함수는 키보드 입력 메시지를 가공하여 프로그램에서 쉽게 쓸 수 있도록 한다. 윈도우즈는 키보드의 어떤 키가 눌러지거나 떨어졌을 때 키보드 메시지를 발생시키는데 TranslateMessage 함수는 키보드의 눌림 (WM_KEYDOWN) 메시지가 발생할 때 문자가 입력되었다는 메시지(WM_CHAR)를 만드는 역할을 한다.
3. LONG DispatchMessage(CONST MSG *Ipmsg);
이 함수는 메시지 큐에서 꺼낸 메시지를 윈도우의 메시 지 처리 함수(WndProc)로 전달한다 이 함수에 의해 메시지가 윈도우로 전달되며 프로그램(정확하게 표현하면 윈도우 프로시저)에서는 전달된메시지 를 점검하여 다읍 동작을 결정한다. 이 함수가 메시지 를 전달하면 다시 루프의 선두로 돌아가 다음 메시지를 기다린다.
메시지 루프의 세 함수는 공통적으로 MSG라는 구조체를 사용하는데 이 구조체는 메시지에 대한 정보를 정의한다.
typedef struct tagMSG
{
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM IParam;
DWORD time;
POINT pt;
} MSG;
1. hwnd : 메시지를 받을 윈도우 핸틀이다
2. message : 어떤 종류의 메시지인가를 Lf 타낸다. 가장 중요한 값이다.
3. wParam : 전달된 메시지에 대한 부가적인 정보를 가진다. 어떤 의미를 가지는가는 메시지열로 다르다 32 비트 값이다
4. IParam : 전달된 메시지에 대한 부가적인 정보를 가진다 어떤 의미를 가지는가는 메시지별로 다르다 32 비트 값이다
5. time : 메 시지가 발생한 시간이 다
6. 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)이며 이 프로그램을 실행시킨 운영체제로 리턴된다.
- 윈도우 프로시저
윈도우 프로시저(Window Procedure)라는 뜻이지만 통상 읽을 때는 콩글리쉬로 “윈드프록”이라고 읽는다. WndProc은 WinMain에서 호출하는
것이 아니라 운영체제에 의해 호출된다. WinMain내의 메시지 루프는 메시지를 메시지 처리 함수로 보내기만 할 뿐이며 WndProc은 메시지가 입
력되면 운영체제에 의해 호출되 어 메시지를 처리한다.
메시지를 처리하는 WndProc의 구조는 대체로 다음과 같은 형태를 가진다. 다양한 종류의 메시지가 전달될 수 있는데 전달된 메시지의 종류에 따
라 다중 분기하여 운영체제로부터 전달된 신호에 반응하는 형식이다.
switch (iMessage) {
case Msg1:
처리 1;
return 0;
case Msg2:
처리 2'
return 0;
case Msg3:
처리 3;
return 0;
default:
return DefWindowProc( ... );
}
제일 끝에 있는 DefWindowProc 함수는 WndProc 에서 처리하지 않은 나머지 메시지에 관한 처리를 한다 예를 들어 시스템 메뉴를 더블클릭하면
프로그램이 종료되는데 이런 처리는 별도로 하지 않아도 DefWindowProc 함수에서 알아서 한다. 그래서 윈도우의 이동이나 크기 변경 따위의 처
리는 프로그램이 직접 할 필요없이 DefWindowProc으로 넘기기만 하면 된다
● 메시지 루프와 메시지 처리 함수의 전체 적 인 순서도
● 배경색 바꾸기
WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
여기서 사용된 GetStockObject함수는 윈도우즈가 기본적으로 제공하는 브러시, 펜 등의 핸들을 구 하는 함수인 데 이 함수의 인수로 WHITE_BRUSH를 지정했기 때문에 배경색을 칠하는 데 흰색 브러시가 사용되었다. 이 값을 BLACK BRUSH로 변경하면 검정색이 배경색으로 사
용되며LTGAY BRUSH로 변경 하면 열은 회색 배경이 만들어진다.
● 커서 바꾸기
WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
hCursor 멤버는 윈도우가 기본적으로 사용할 커서를 지정하며 LoadCursor 함수는 커서를 읽어 오는함수이다.
● 윈도우 타이틀 바꾸기
CreateWindow 함수의두 번째 인수로 지정한 lpszClass 문자열이며 이는 또한 윈도우 클래스의 이름이기도 하다. 타이틀 바에 나타나는 윈도우의 이
름을 변경하려면 CreateWindow 함수의 두 번째 인수를 원하는 문자열로 변경하면 된다.
hWnd=CreateWindow(lpszClass, TEXT("My First program"),WS_OVERLAPPEDWINDOW, CW_USEOEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,CW USEOEFAULT,NULL,(HMENU)NULL,hlnstance,NULL);
● 윈도우 스타일
CreateWindow함수의 세 번째 인수 dwStyle은 윈도우의 모양과 동작 방식을 결정하는 여러 가지 속성을 지정한다. 여러 가지 스타일값을 가지는 32
비트 정수값이며 이 값을 변경함에 따라 다양한 모양의 윈도우를 만들 수 있다. 일단 dwStyle에 사용될 수 있는 값들을 보자. 이 값들을 OR연산자로
연결하여 여러 가지 속성을 한꺼번에 지정한다,
WS OVERLAPPEDWINDOW는 다음과 같이 정의되어 있다
#define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED I WS_CAPTION I WS_SYSMENU | WS_THICKFRAME I WS_MINIMIZEBOX I WS_MAXIMIZEBOX)