코딩하는 나귀

저자 : hanburn

날짜 : 2007.08.13

환경 : WTL7.5, VS-2003

 

 

지난시간에는 WTL에 대해서 간략하게 알아보고 설치하고 환경 설정하는 것 까지 알아보았다. 이제 WTL로 간단한 프로젝트를 만들어 보자. VS를 열면 WTL application wizard가 보일 것이다. 이것을 선택하여 시작하도록 하자.

사용자 삽입 이미지

그런 다음에는 너무나도 익숙한 화면이다. SDI, MDI, Dialog base 등 초기의 프로그램 형태를 선택할 수 있는 창이 나온다. MFC wizard와 상당히 유사한 모습이다. 아래 그림처럼 Dialog Base를 선택하고 Generate .CPP Files를 체크한 뒤에 Finish를 선택하면 된다.


사용자 삽입 이미지

이렇게 하면 위저드가 기본 골격 코드를 생성하는데, 생성된 코드를 한번 살펴 보면서 시작하자.

먼저 프로젝트이름.cpp 파일을 살펴보면 아래와 같은 코드가 보일 것이다.

 

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)

{

        HRESULT hRes = ::CoInitialize(NULL);

        ...

        hRes = _Module.Init(NULL, hInstance);

        ATLASSERT(SUCCEEDED(hRes));

 

        int nRet = Run(lpstrCmdLine, nCmdShow);

 

        _Module.Term();

        ::CoUninitialize();

 

        return nRet;

}


우리가 잘 알고있는 WinMain 함수이다. 여기서 살펴볼 것은 _Module 이라 전역객체 인데, MFC theApp 와 비슷한 놈이다. MFC에서는 CWinApp를 상속받아서 각 프로그램마다 한 개씩 있던 것을 보았을 것이다. WTL에서는
CAppModule클래스의 전역객체인데, 쉽게 생각하면 전체 프로그램의 관리자 역할로 보면 것이다. _Module.Init()/Term() 사이에 있는 Run() 이라는 함수가 윈도우 시스템의 메시지를 가지고 와서 배분을 해주는(DispatchMessage) 역할을 하는 부분이다. 전역함수인 Run 함수에 대해서 조금 자세히 알아보자

 

int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT)

{

        CMessageLoop theLoop;

        _Module.AddMessageLoop(&theLoop);

 

        CMainDlg dlgMain;

        if(dlgMain.Create(NULL) == NULL)

        {

               ATLTRACE(_T("Main dialog creation failed!\n"));

               return 0;

        }

        dlgMain.ShowWindow(nCmdShow);

 

        int nRet = theLoop.Run();

        _Module.RemoveMessageLoop();

        return nRet;

}

 

웬지 MFC에서 InitInstance 부분과 유사한 느낌을 받을 것이다. 메인 다이얼로그를 생성하고 메시지루프를 처리하고..  WTL MFC보다 역할의 구분을 클래스로 잘 구분을 해놓은 느낌이다. Design Pattern Explained에서 말하는 역할 중심의 설계랄까? ^^

Run함수에서 CMessageLoop 객체를 만들고 _Module에 추가를 해주어서 메시지 펌핑을 받도록 처리하고 있다. CMessageLoop run함수에 우리가 익숙하게 보는 다음과 같은 코드가 들어있다.

 

bRet = ::GetMessage(&m_msg, NULL, 0, 0);

if(!PreTranslateMessage(&m_msg))

{

::TranslateMessage(&m_msg);

::DispatchMessage(&m_msg);

}

 

이렇게 함으로써 Dialog의 기본 골격 코드를 살펴 보았다. 그리고 WTL의 위자드에서 Dialog를 선택하고 DoModal을 체크하게 되면 더 간단하게 아래처럼 Dialog DoModal을 호출해 준다.

 

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)

{

        HRESULT hRes = ::CoInitialize(NULL);

        ...

        hRes = _Module.Init(NULL, hInstance);

 

        int nRet = 0;

        {

               CMainDlg dlgMain;

               nRet = dlgMain.DoModal();

        }

 

        _Module.Term();

        ::CoUninitialize();

 

        return nRet;

}

 

보통 WTL으로 프로그래밍을 할 때, 기본적으로 생성되는 Dialog를 사용하지 않을 때는 첫번째 처럼 기본 틀을 생성하고, Dialog대신 내가 만든 윈도우를 Create 하고 Show를 해주게 되어서, 보통은 Domodal을 체크 않하고 많이 사용한다. (이것은 개인적인 취향이다. )

 

다음으로는 MainDlg.h 를 살펴보자. 실제적인 Dialog에 대핸 메시지 처리 및 기타 주요한 부분을 담당하는 부분이다.

 

class CMainDlg :       public CDialogImpl<CMainDlg>,

public CUpdateUI<CMainDlg>,

                       public CMessageFilter,

public CIdleHandler

{

public:

        enum { IDD = IDD_MAINDLG };

 

        virtual BOOL PreTranslateMessage(MSG* pMsg);

        virtual BOOL OnIdle();

 

        BEGIN_UPDATE_UI_MAP(CMainDlg)

        END_UPDATE_UI_MAP()

 

        BEGIN_MSG_MAP(CMainDlg)

               MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)

               COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)

               COMMAND_ID_HANDLER(IDOK, OnOK)

               COMMAND_ID_HANDLER(IDCANCEL, OnCancel)

        END_MSG_MAP()

 

        LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);

        LRESULT OnAppAbout(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);

        LRESULT OnOK(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/);

        LRESULT OnCancel(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/);

 

        void CloseDialog(int nVal);

};

 

여기서 조금 낯설 수가 있다. 평소에 잘 사용 안하던 다중상속을 사용한 것이다. 전형적인 ATL 스타일인 것이다. 여러가지 template class 로부터 상속을 받고 있는데, 이것들은 다음 시간에 알아보도록 하겠습니다.