ATL程序框架

stdafx.h

#define STRICT
#define VC_EXTRALEAN

#include <atlbase.h>        //基本的ATL类
extern CComModule _Module;
#include <atlwin.h>         //ATL窗口类

CMyWindow.h

#pragma once
#include "stdafx.h"
#include "resource.h"

class CAboutDlg : public CDialogImpl<CAboutDlg>
{
public:
    enum { IDD = IDD_ABOUT };

    BEGIN_MSG_MAP(CAboutDlg)
        MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
        MESSAGE_HANDLER(WM_CLOSE, OnClose)
        COMMAND_ID_HANDLER(IDOK, OnOKCancel)
        COMMAND_ID_HANDLER(IDCANCEL, OnOKCancel)
    END_MSG_MAP()

    LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
    {
        CenterWindow();
        return TRUE;
    }

    LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
    {
        EndDialog(IDCANCEL);
        return 0;
    }

    LRESULT OnOKCancel(WORD wNotifyCode, WORD wID, HWND hWndCtrl, BOOL& bHandled)
    {
        EndDialog(wID);
        return 0;
    }
};

template<class T, COLORREF t_crBrushColor>
class CPaintBkgnd : public CMessageMap
{
public:
    CPaintBkgnd() { m_hbrBkgnd = CreateSolidBrush(t_crBrushColor); }
    ~CPaintBkgnd() { DeleteObject(m_hbrBkgnd); }

    BEGIN_MSG_MAP(CPaintBkgnd)
        MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
    END_MSG_MAP()

    LRESULT OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
    {
        T* pT = static_cast<T*>(this);
        HDC dc = (HDC)wParam;
        RECT rcClient;

        pT->GetClientRect(&rcClient);
        FillRect(dc, &rcClient, m_hbrBkgnd);
        return 1;
    }

protected:
    HBRUSH m_hbrBkgnd;
};



//typedef CWinTraits<WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, WS_EX_APPWINDOW> CMyWindowTraits;

class CMyWindow : public CWindowImpl<CMyWindow, CWindow, CFrameWinTraits>,
                  public CPaintBkgnd<CMyWindow, RGB(0, 0, 255)>
{
public:
    DECLARE_WND_CLASS(_T("My Window Class"));

    typedef CPaintBkgnd<CMyWindow, RGB(0, 0, 255)> CPaintBkgndBase;

    BEGIN_MSG_MAP(CMyWindow)
        MESSAGE_HANDLER(WM_CREATE, OnCreate)
        MESSAGE_HANDLER(WM_CLOSE, OnClose)
        MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
        COMMAND_ID_HANDLER(IDC_ABOUT, OnAbout)
        CHAIN_MSG_MAP(CPaintBkgndBase)
    END_MSG_MAP()

    LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
    {
        HMENU hMenu = LoadMenu(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_MENU1));
        SetMenu(hMenu);
        return 0;
    }

    LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
    {
        DestroyWindow();
        return 0;
    }

    LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
    {
        PostQuitMessage(0);
        return 0;
    }

    LRESULT OnAbout(WORD wNotifyCode, WORD wID, HWND hWndCtrl, BOOL& bHandled)
    {
        CAboutDlg dlg;
        dlg.DoModal();
        return 0;
    }

};

main.cpp

#include "CMyWindow.h"

CComModule _Module;

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
    _Module.Init(NULL, hInst);

    CMyWindow wndMain;
    MSG msg;

    if(NULL == wndMain.Create(NULL, CWindow::rcDefault, _T("My First ATL Window")))
    {
        return 1;
    }
    wndMain.ShowWindow(nCmdShow);
    wndMain.UpdateWindow();

    while(GetMessage(&msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    _Module.Term();

    return msg.wParam;
}

resource.h

//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by ATLWindow.rc
//
#define IDR_MENU1                       101
#define IDD_ABOUT                       102
#define IDC_ABOUT                       40002

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        103
#define _APS_NEXT_COMMAND_VALUE         40003
#define _APS_NEXT_CONTROL_VALUE         1001
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif

ATLWindow.rc

// Microsoft Visual C++ generated resource script.
//
#include "resource.h"

#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"

/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS

/////////////////////////////////////////////////////////////////////////////
// Chinese (P.R.C.) resources

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
#ifdef _WIN32
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
#pragma code_page(936)
#endif //_WIN32

#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//

1 TEXTINCLUDE 
BEGIN
    "resource.h\0"
END

2 TEXTINCLUDE 
BEGIN
    "#include ""afxres.h""\r\n"
    "\0"
END

3 TEXTINCLUDE 
BEGIN
    "\r\n"
    "\0"
END

#endif    // APSTUDIO_INVOKED


/////////////////////////////////////////////////////////////////////////////
//
// Menu
//

IDR_MENU1 MENU 
BEGIN
    POPUP "About"
    BEGIN
        MENUITEM "About",                       IDC_ABOUT
    END
END


/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//

IDD_ABOUT DIALOGEX 0, 0, 222, 103
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
    DEFPUSHBUTTON   "OK",IDOK,108,82,50,14
    PUSHBUTTON      "Cancel",IDCANCEL,165,82,50,14
END


/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//

#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO 
BEGIN
    IDD_ABOUT, DIALOG
    BEGIN
        LEFTMARGIN, 7
        RIGHTMARGIN, 215
        TOPMARGIN, 7
        BOTTOMMARGIN, 96
    END
END
#endif    // APSTUDIO_INVOKED

#endif    // Chinese (P.R.C.) resources
/////////////////////////////////////////////////////////////////////////////



#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//


/////////////////////////////////////////////////////////////////////////////
#endif    // not APSTUDIO_INVOKED

ATL程序的基本要点是:
首先,采用了下面的模板技术来避免使用虚函数却实现了虚函数的功能:

template <class T>
class B1
{
public: 
    void SayHi() 
    {
        T* pT = static_cast<T*>(this);   

        pT->PrintClassName();
    }
protected:
    void PrintClassName() { cout << "This is B1"; }
};

class D1 : public B1<D1>
{
    // No overridden functions at all
};

class D2 : public B1<D2>
{
protected:
    void PrintClassName() { cout << "This is D2"; }
};

main()
{
    D1 d1;
    D2 d2;

    d1.SayHi();    // prints "This is B1"
    d2.SayHi();    // prints "This is D2"
}

其次,主程序的框架必须是这样的:

//第一步:必须先定义一个名字叫_Module的CComModule的对象(有且仅有一个)
CComModule _Module;         

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
    //第二步:调用_Module的Init()方法,如果不含COM组件,第一个参数为NULL
    _Module.Init(NULL, hInst);      

    //第三步,定义窗口C++对象并创建和显示窗口
    CMyWindow wndMain;
    MSG msg;

    if(NULL == wndMain.Create(NULL, CWindow::rcDefault, _T("My First ATL Window")))
    {
        return 1;
    }
    wndMain.ShowWindow(nCmdShow);
    wndMain.UpdateWindow();

    //第四步:设置消息循环
    while(GetMessage(&msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    //第五步:调用_Module的Term()方法
    _Module.Term();

    return msg.wParam;
}

再次,ATL创建窗口时(调用Create())时注册了窗口类,窗口类通过宏DECLARE_WND_CLASS(_T(“My Window Class”));来声明,如下:

#define DECLARE_WND_CLASS(WndClassName) \
static ATL::CWndClassInfo& GetWndClassInfo() \
{ \
    static ATL::CWndClassInfo wc = \
    { \
        { sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, StartWindowProc, \
          0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName, NULL }, \
        NULL, NULL, IDC_ARROW, TRUE, 0, _T("") \
    }; \
    return wc; \
}

在_wndMain.Create()中注册窗口类,并将窗口过程函数设置为WindowProc():

class ATL_NO_VTABLE CWindowImpl : public CWindowImplBaseT< TBase, TWinTraits >
{
public:
    HWND Create(HWND hWndParent, _U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
            DWORD dwStyle = 0, DWORD dwExStyle = 0,
            _U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
    {
        if (T::GetWndClassInfo().m_lpszOrigName == NULL)
            T::GetWndClassInfo().m_lpszOrigName = GetWndClassName();
        ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc);

        dwStyle = T::GetWndStyle(dwStyle);
        dwExStyle = T::GetWndExStyle(dwExStyle);

        // set caption
        if (szWindowName == NULL)
            szWindowName = T::GetWndCaption();

        return CWindowImplBaseT< TBase, TWinTraits >::Create(hWndParent, rect, szWindowName,
            dwStyle, dwExStyle, MenuOrID, atom, lpCreateParam);
    }
};

第四点,ATL消息处理通过宏来实现:

BEGIN_MSG_MAP(CMyWindow)
        MESSAGE_HANDLER(WM_CREATE, OnCreate)
        MESSAGE_HANDLER(WM_CLOSE, OnClose)
        MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
        COMMAND_ID_HANDLER(IDC_ABOUT, OnAbout)
        CHAIN_MSG_MAP(CPaintBkgndBase)
END_MSG_MAP()

展开之后实际上是一个大大的switch语句:

BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = 0) \
    { \
        BOOL bHandled = TRUE; \
        (hWnd); \
        (uMsg); \
        (wParam); \
        (lParam); \
        (lResult); \
        (bHandled); \
        switch(dwMsgMapID) \
        { \
        case 0:

#define ALT_MSG_MAP(msgMapID) \
        break; \
        case msgMapID:

#define MESSAGE_HANDLER(msg, func) \
    if(uMsg == msg) \
    { \
        bHandled = TRUE; \
        lResult = func(uMsg, wParam, lParam, bHandled); \
        if(bHandled) \
            return TRUE; \
    }

由于窗口过程是CWindowImplBaseT::WindowProc(),当消息产生时
调用:

LRESULT CALLBACK CWindowImplBaseT< TBase, TWinTraits >::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

在WindowProc()调用:

BOOL bRet = pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, 0);

在ProcessWindowMessage中根据switch语句中消息类型,调用对应的消息处理函数,如OnCreate()/OnClose().

第五点,一般消息处理函数中最后一个参数为bHandled,如果处理完消息后还需要调用默认的消息处理过程处理,则bHandled设置为FALSE。

最后,对话框显示仍然使用DoModal()函数,如:

CAboutDlg dlg;
dlg.DoModal();

参考:http://www.winmsg.com/wtl/Part1.htm

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值