WinMain 함수에서 하는 가장 중요한 일은 메인 윈도우를 만드는 일이다. 윈도우를 만들려면 윈도우 클래스를 먼저 등록한 후 CreateWindow 함수를 호출해야 한다. 윈도우 클래스는 만들어질 윈도우의 여러가지 특성을 정의하는 구조체이며 모든 윈도우는 윈도우 클래스의 정보를 기반으로 하여 만들어진다. 윈도우 클래스는 windows.h 에 다음과 같이 정의되어 있는 구조체이다.
typedef struct tagWNDCLASS
{
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCSTR lpszMenuName;
LPCSTR lpszClassName;
} WNDCLASS;
이제부터 이 멤버가 어떤 역학을 하는 멤버인지 알아보자.
style : 윈도우의 스타일을 정의한다. 즉 위도우가 어떤 형태를 가질 것인가를 지정하는 멤버이다. 이 멤버가 가질 수 있는 값은 무척 많지만 가장 많이 사용하는 값이 CS_HREDRAW 와 CS_VREDRAW이다. 이 두 값을 OR 연산자로 연결하여 사용한다. 이 스타일은 윈도우의 수직(수평) 크기가 변할 경우 윈도우를 다시 그린다는 뜻이다. 이 밖에도 많은 값이 올 수 있다.
lpfnWndProc : 윈도우의 메시지 처리 함수를 지정한다. 메시지가 발생할 때마다 이 멤버가 지정하는 함수가 호출되며 이 함수가 모든 메시지를 처리한다.
Tip.메시지 호출 함수 이름은 WndProc 로 정해져있다.(거의)
cbClsExtra, cbWndExtra : 일종의 예약 영역이다. 윈도우즈가 내부적으로 사용하며 아주 특수한 목적에 사용되는 여분의 공간이다. 사용하지 않을 경우는 0으로 지정한다.
hInstance : 이 윈도우 클래스를 등록하는 프로그램의 번호이며 이 값은 WinMain의 인수로 전달된 hInstance 값을 그대로 대입해 주면 된다.
hIcon, hCursor : 이 윈도우가 사용할 마우스 커서와 아이콘을 지정한다. LoadCursor 함수와 LoadIcon함수를 사용하여 커서, 아이콘을 읽어와 이 멤버에 대입해 주면 된다. 사용자가 직접 아이콘과 커서를 만들어 사용할 수 도 있다.
hbrBacground : 윈도우의 배경 색상을 지정한다. (채색할 브러시) GetStockObject라는 함수를 사용하여 윈도우즈에서 기본적으로 제공하는 브러시를 지정하거나 아니면 시스템 색상을 지정할 수도 있다.
lpszMenuName : 이 프로그램이 사용할 메뉴를 지정한다. 메뉴는 프로그램 코드에서 실행 중에 만드는 것이 아니라 리소스 에디터에 의해 별도로 만들어진 후 링크시에 같이 합쳐진다. 메뉴를 사용하지 않을 경우 널을 대입해주면 된다.
lpszClassName : 윈도우 클래스의 이름을 문자열로 정의한다. 여기서 지정한 이름은 CreateWindow 함수에 전달되며 CreateWindow 함수는 윈도우 클래스에서 정의한 특성값을 참조하여 윈도우를 만든다. 어디까지나 이름일 뿐이므로 변수명이나 함수명을 만들 듯이 마음대로 작성할 수 있다. 그러나 윈도우 클래스의 이름은 실행 파일의 이름과 일치시켜 작성하는 것이 보통이다.
이렇게 윈도우 클래스 구조체를 정의한 후 RegisterClass 함수를 호출하여 윈도우 클래스를 등록한다.
ATOM RegisterClass(CONST WNDCLASS *lpWndClass);
RegisterClass 함수의 인수로 WndCLASS 구조체의 번지를 넘겨주면 된다. 이런 특성을 가진 윈도우를 앞으로 사용하겠다는 등록 과정이며 운영체제는 이 윈도우 클래스의 특성을 잘 기억해 놓는다. WinMain의 앞부분을 보면 WNDCLASS 구조체의 각 멤버에 값을 대입하고 윈도우 클래스를 등록하는 코드가 있다. 단순한 대입문의 연속인데 어떤 값들이 대입되었는지 잘 보자.
이제 윈도우 클래스를 기본으로 실제 윈도우를 생성해야 한다. 윈도우를 생성할 때는 CreateWindow 함수를 사용한다.
HWND CreateWindow(lpszClassName, lpszWindowName, dwStyle, x, y, nWidth, nHeight, hwndParent,hmenu,hinst,lpvParam)
원형은 다음과 같고 이제 인수를 알아보자.
lpszClassName : 생성하고자 하는 윈도우의 클래스를 지정한 문자열이다. CreateWindow함수는 윈도우 클래스에 정의된 속성대로 우니도우를 생성한다. 앞에서 등록한 WNDCLASS 구조체의 lpszClassName 멤버의 이름을 여기에 기입해준다. 우리의 예제에서는 lpszClass 전역변수에 윈도우 클래스 이름을 기억시켜 두었으므로 이 문자열을 그대로 넘겨주면 된다.
lpszWindowName : 윈도우의 타이틀 바에 나타날 문자열이다. 여기서 지정한 문자열이 윈도우의 타이틀 바에 나타난다. 프로그래머가 마음대로 지정할 수 있는데 예제의 프로젝트명을 타이틀 바에 나타내고 있다.
dwStyle : 만드려는 윈도우 형태를 지정하는 인수이다. 여러가지 값들을 OR 연산자로 나타낼 수 있는데 WS_OVERLAPPEDWINDOW 가 가장 무난하다.
x,y,nWidth,nHeight : 인수의 이름대로 윈도우의 크기와 위치를 지정한다.(픽셀단위) CW_USERDEFAULT를 사용하면 윈도우즈가 화면 크기에 맞게 적당한 크기와 위치를 설정해준다.
hWndParent : 부모 윈도우를 설정해준다.(부모에 대한 의미를 모른다면 C++을 공부하고 오길.)
부모 윈도우가 없을 경우는 NULL로 지정하면 된다.
hmenu : 윈도우에서 사용할 메뉴 핸들을 지정한다. 윈도우 클래스에도 메뉴를 지정하는 멤버가 있는데 윈도우 클래스의 메뉴는 그 윈도우 클래스를 기반으로 하는 모든 윈도우에서 사용되는 반면 이 인수로 지정된 메뉴는 현재 CreateWindwo 함수로 만들어지는 윈도우에서만 사용된다. 윈도우 클래스에서 지정한 메뉴를 그대로 사용하려면 이 인수를 NULL로 지정하면 되고, 다른 메뉴를 사용하려면 이 인수에 원하는 메뉴 핸들을 주면 된다.
hinst : 윈도우를 만드는 주체, 즉 프로그램의 핸들을 지정한다.
lpvParam : CREATESTRUCT 라는 구조체의 번지이며 특수한 목적에 사용된다. 보통은 NULL값을 사용한다.
이렇게 쓴 CreateWindow 함수는 윈도우 핸들을 리턴값으로 넘겨준다. 넘겨지는 윈도우 핸들은 hWnd라는 지역변수에 저장되었다가 이 윈도우를 참조하는 모든 함수으 ㅣ인수로 사용된다. CreateWindow 함수로 만든 윈도우는 메모리상에만 있을 뿐이며 아직까지 화면에 출력되지 않았다. 메모리에 만들어진 윈도우를 화면으로 보이게 하려면 다음 함수를 사용해야 한다.
BOOL ShowWindow(hWnd,nCmdShow);
hWnd 인수는 화면으로 출력하고자 하는 윈도우의 핸들이며 CreateWindow 함수가 리턴한 핸들을 그대로 넘겨주면 된다. nCmdShow는 윈도우를 화면에 출력하는 방법을 지정하며 다음과 같은 매크로 상수들이 정의되어 있다.
SW_HIDE : 윈도우를 숨긴다.
SW_MINIMIZE : 윈도우를 최소화시키고 활성화시키지 않는다.
SW_RESTORE : 윈도우를 활성화시킨다.
SW_SHOW : 윈도우를 활성화시켜 보여준다.
SW_SHOWNORMAL : 윈도우를 활성화시켜 보여준다.
nCmdShow 인수에 어떤 값을 넘겨줄 것인가는 전혀 고민할 필요가 없으며 WinMain 함수의 인수로 전달된 nCmdShow를 그대로 넘겨주기만 하면 된다. 그래서 ShowWindow(hWnd,nCmdShow);와 같이 거의 호출 형식이 정햊 있는 셈이다.