출처 : www.soen.kr
#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)); } |
4헤더 파일
우선 제일 첫행을 보면 windows.h 하나만 인클루드되어 있다. 도스에서는 사용하는 함수에 따라 여러 개의 헤더 파일을 포함하지만 윈도우즈에서는 하나의 헤더 파일에 모든 API 함수들의 원형과 사용하는 상수들을 죄다 정의하고 있기 때문에 windows.h만 포함해 주면 된다. stdio.h나 conio.h, graphics.h 등을 포함해 줄 필요가 없다. 물론 특별한 경우에는 해당하는 헤더 파일을 포함해야 하지만 예제 수준에서는 windows.h만 포함시키면 거의 문제가 없다. windows.h 헤더 파일은 기본적인 데이터 타입, 함수 원형 등을 정의하며 그 외 필요한 헤더 파일을 포함하고 있다. 그래서 윈도우즈 프로그램의 첫 줄은 거의 항상 #include <windows.h> 로 시작된다.
4 시작점
다음으로 차이나는 점은 프로그램의 시작점인 엔트리 포인트(Entry Point)가 main 함수가 아니라 WinMain이라는 점이다. 윈도우즈 프로그램의 시작점은 main이 아닌 WinMain이다. 원형은 다음과 같다.
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance ,LPSTR lpszCmdParam,int nCmdShow)
도스에서의 main 함수는 인수 사용여부에 따라 여러 가지 원형이 있지만 WinMain의 원형은 위와 같이 고정되어 있다. APIENTRY 지정자는 __stdcall형 호출 규약을 사용한다는 뜻인데 일단은 없다고 생각해도 무방하다. 4개의 인수를 취하는데 각 인수의 의미는 다음과 같다.
인수 |
의미 |
hInstance |
프로그램의 인스턴스 핸들 |
hPrevInstance |
바로 앞에 실행된 현재 프로그램의 인스턴스 핸들. 없을 경우는 NULL이 되며 WIN32에서는 항상 NULL이다. 호환성을 위해서만 존재하는 인수이므로 신경쓰지 않아도 된다. |
lpCmdLine |
명령행으로 입력된 프로그램 인수이다. 도스의 argv인수에 해당한다. |
nCmdShow |
프로그램이 실행될 형태이며 최소화, 보통모양 등이 전달된다. |
이 중 hInstance 이외에는 잘 사용되지 않는다. 인스턴스(Instance)라는 말은 클래스가 메모리에 실제로 구현된 실체를 의미한다. 윈도우즈용 프로그램은 여러개의 프로그램이 동시에 실행되는 멀티태스킹 시스템일 뿐만 아니라 하나의 프로그램이 여러 번 실행될 수도 있다. 이때 실행되고 있는 각각의 프로그램을 프로그램 인스턴스라고 하며 간단히 줄여서 인스턴스라고 한다. 예를 들어 다음과 같이 메모장이 두번 실행되어 있다고 해 보자.
이 때 두 프로그램은 모두 메모장(Notepad.exe)이지만 운영체제는 각각 다른 메모리를 사용하는 다른 프로그램으로 인식한다. 이때 각 메모장은 서로 다른 인스턴스 핸들을 가지며 운영체제는 이 인스턴스 핸들값으로 두 개의 메모장을 서로 구별한다.
hInstance란 프로그램 자체를 일컫는 정수값이며 API 함수에서 수시로 사용된다. 그래서 이 예제에서는 WinMain의 인수로 전달된 hInstance값을 전역 변수 g_hInst에 대입해 두었다. hInstance 인수는 기억부류가 지역 변수이기 때문에 WinMain의 밖에서는 사용할 수 없기 때문이다. 이 예제에서는 g_hInst 값을 당장 사용하지 않고 있지만 앞으로의 예제에서는 이 값을 사용하게 될 것이다.
그리고 lpszClass라는 전역 문자열이 정의되어 있는데 이 문자열은 윈도우 클래스를 정의하는데 사용된다. 잠시 후에 이 문자열이 사용되는 곳에서 설명을 하도록 한다.
HINSTANCE g_hInst;
LPSTR lpszClass="First";
4 메시지 처리 함수
이 프로그램을 자세히 보면 두개의 함수만 있다. 하나는 프로그램의 시작점인 WinMain이며 나머지 하나는 WndProc이다. 도스에서는 main 함수만으로도 프로그램을 작성할 수 있지만 윈도우즈에서는 아주 특별한 경우를 제외하고는 이 두개의 함수가 모두 있어야 한다.
WinMain에서는 윈도우를 만들고 화면에 출력하기만 할 뿐이며 대부분의 일은 WndProc에서 이루어진다. WinMain은 프로그램을 시작시키기만 하며 실질적인 처리는 대부분 WndProc에서 이루어진다. WinMain의 모양은 대체로 일정하며 특별한 일을 하지 않지만 WndProc는 프로그램에 따라 천차만별로 달라진다. 그래서 소스를 분석할 때 주의깊게 봐야 할 부분은 WinMain이 아니라 WndProc이다. WinMain 바로 윗부분에 WndProc 함수의 원형이 선언되어 있다.
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
그리고 소스의 뒷부분에는 이 함수의 본체가 정의되어 있다.