이제 원하는 윈도우의 메세지 핸들러까지 작성했으니, 실제로 WTL 프로그램의 인스턴스화 작업을 준비해보자. PCH를 사용할 stdafx.h과 윈도우 메세지 핸들러를 구현한 mywnd.h가 준비되었다면, 다음은 MFC를 오랫동안 사용해온 사람에게는 기억에서도 흐릿할 WinMain이다.
#include "stdafx.h"
#include "mywnd.h"
CAppModule _Module;
이제, WTL의 MFC에서의 CWinApp에 해당하는 CAppModule을 전역 변수로 선언한다. CAppModule은 ATL의 CComModule을 상속받은 것이며, CWinApp와 비슷한 역할을 하지만 그 성격은 좀 다르다. VC7 이상에서는 이것을 명시적으로 선언할 필요는 없지만, 메세지 루프를 등록하고 윈도우 메세지 핸들러에서도 사용할 필요가 있기 때문에 선언했다.
#include "stdafx.h"
#include "mywnd.h"
CAppModule _Module;
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance LPTSTR lpCmdLine, int nCmdShow)
{
_Module.Init(0, hInstance);
CMessageLoop msgloop;
_Module.AddMessageLoop(&msgloop);
CMyWnd MyWindow;
if(!MyWindow.Create(0, CWindow::rcDefault, _T("My First WTL Window")))
return 1;
MyWindow.ShowWindow(nCmdShow);
MyWindow.UpdateWindow();
int nReturn = msgloop.Run();
_Module.RemoveMessageLoop();
_Module.Term();
return nReturn;
}
_tWinMain()에서 _t 매크로는 알다시피 유니코드를 위한 매크로이다. 이 매크로를 포함하지 않는다면 링크 에러가 발생할 것이다. _t 매크로를 사용하기 위해서는 windows.h 외에 tchar.h를 포함해야 하지만 atlbase.h에서 내부적으로 처리되기 때문에 굳이 포함시킬 필요는 없다.
WTL에서 메세지 루프를 담당하는 클래스는 CMessageLoop인데, 이 클래스를 인스턴스화하여 CAppModule에 등록시켜주고, 빠져나갈 때 다시 제거해주면 된다. 위에서 _Module.Init(0, hInstance)와 _Module.Term()은 VC7 이상에서는 명시적으로 작성해 줄 필요는 없지만, 내부에서도, 그리고 윈도우 핸들러 내부에서도 CAppModule을 사용할 필요가 있기 때문에 써주는 것이 좋다. 그리고, 여기서 메세지 루프 등록과 윈도우 생성 순서가 중요한데, 나중에 설명할 PreTranslateMessage()와 OnIdle() 메서드를 사용하기 위해서는 해당 윈도우가 반드시 CMessageFilter와 CIdleHandler 클래스를 상속 받아야 한다.
CMessageFilter의 PreTranslateMessage()와 CIdleHandler의 OnIdle()은 순수 가상 함수이기 때문에, 이것을 상속 받은 클래스는 반드시 이들 메서드를 재정의해야 한다. CMessageLoop의 GetMessageLoop() 메서드를 사용하여 CMessageLoop의 인스턴스를 얻고, AddMessageFilter(), AddIdleHandler() 메서드를 사용하여 PreTranslateMessage(), OnIdle()을 재정의한 클래스를 등록해야 한다. 보통 WM_CREATE 메세지를 받을 때 이 것을 처리하게 되는데, 그렇기 때문에 윈도우가 생성되기 전에 메세지 루프가 등록되어 있어야 한다. 메세지 루프가 등록되어 있지 않다면 당연히 이 과정은 실패한다.
자, 이 과정을 모두 거쳤다면 프로젝트 설정에서 WTL 폴더가 정상적으로 include 되어 있는지 확인하고 컴파일해보자. 윈도우가 정상적으로 나타났다면, 성공적으로 WTL 프로그램을 하나 만든 것이다.
Contraturation!
#include "stdafx.h"
#include "mywnd.h"
CAppModule _Module;
이제, WTL의 MFC에서의 CWinApp에 해당하는 CAppModule을 전역 변수로 선언한다. CAppModule은 ATL의 CComModule을 상속받은 것이며, CWinApp와 비슷한 역할을 하지만 그 성격은 좀 다르다. VC7 이상에서는 이것을 명시적으로 선언할 필요는 없지만, 메세지 루프를 등록하고 윈도우 메세지 핸들러에서도 사용할 필요가 있기 때문에 선언했다.
#include "stdafx.h"
#include "mywnd.h"
CAppModule _Module;
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance LPTSTR lpCmdLine, int nCmdShow)
{
_Module.Init(0, hInstance);
CMessageLoop msgloop;
_Module.AddMessageLoop(&msgloop);
CMyWnd MyWindow;
if(!MyWindow.Create(0, CWindow::rcDefault, _T("My First WTL Window")))
return 1;
MyWindow.ShowWindow(nCmdShow);
MyWindow.UpdateWindow();
int nReturn = msgloop.Run();
_Module.RemoveMessageLoop();
_Module.Term();
return nReturn;
}
_tWinMain()에서 _t 매크로는 알다시피 유니코드를 위한 매크로이다. 이 매크로를 포함하지 않는다면 링크 에러가 발생할 것이다. _t 매크로를 사용하기 위해서는 windows.h 외에 tchar.h를 포함해야 하지만 atlbase.h에서 내부적으로 처리되기 때문에 굳이 포함시킬 필요는 없다.
WTL에서 메세지 루프를 담당하는 클래스는 CMessageLoop인데, 이 클래스를 인스턴스화하여 CAppModule에 등록시켜주고, 빠져나갈 때 다시 제거해주면 된다. 위에서 _Module.Init(0, hInstance)와 _Module.Term()은 VC7 이상에서는 명시적으로 작성해 줄 필요는 없지만, 내부에서도, 그리고 윈도우 핸들러 내부에서도 CAppModule을 사용할 필요가 있기 때문에 써주는 것이 좋다. 그리고, 여기서 메세지 루프 등록과 윈도우 생성 순서가 중요한데, 나중에 설명할 PreTranslateMessage()와 OnIdle() 메서드를 사용하기 위해서는 해당 윈도우가 반드시 CMessageFilter와 CIdleHandler 클래스를 상속 받아야 한다.
CMessageFilter의 PreTranslateMessage()와 CIdleHandler의 OnIdle()은 순수 가상 함수이기 때문에, 이것을 상속 받은 클래스는 반드시 이들 메서드를 재정의해야 한다. CMessageLoop의 GetMessageLoop() 메서드를 사용하여 CMessageLoop의 인스턴스를 얻고, AddMessageFilter(), AddIdleHandler() 메서드를 사용하여 PreTranslateMessage(), OnIdle()을 재정의한 클래스를 등록해야 한다. 보통 WM_CREATE 메세지를 받을 때 이 것을 처리하게 되는데, 그렇기 때문에 윈도우가 생성되기 전에 메세지 루프가 등록되어 있어야 한다. 메세지 루프가 등록되어 있지 않다면 당연히 이 과정은 실패한다.
자, 이 과정을 모두 거쳤다면 프로젝트 설정에서 WTL 폴더가 정상적으로 include 되어 있는지 확인하고 컴파일해보자. 윈도우가 정상적으로 나타났다면, 성공적으로 WTL 프로그램을 하나 만든 것이다.
Contraturation!