3.MFC基础(三)消息映射

一、消息映射机制

 1.消息映射机制的使用

  (1)类必须派生自CCmdTarget

  (2)类内必须添加声明宏:DECLARE_MESSAGE_MAP( )

  (3)类外必须添加实现宏:BEGIN_MESSAGE_MAP( theClass, baseClass )

                              END_MESSAGE_MAP( )

 2.消息映射机制的实现

  (1)数据结构    

      struct  AFX_MSGMAP_ENTRY
      {
        UINT           nMessage;   // 消息ID
        UINT           nCode;       // 控件通知码(只有控件的WM_COMMAND消息有通知码)
        UINT           nID;           // 命令ID、控件ID
        UINT           nLastID;     // 最后一个控件ID
        UINT_PTR    nSig;         // 消息处理函数类型
        AFX_PMSG   pfn;          // 消息处理函数的指针(地址)
      };    

      struct AFX_MSGMAP
      {
        const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)( );
        const AFX_MSGMAP_ENTRY* lpEntries;
      };

  (2)宏展开的代码

     见代码

  (3)宏展开各部分的作用

      _messageEntries[ ] - 静态数组

       数组中每个元素保存了消息ID和处理消息的函数地址等

     messageMap - 静态变量

       保存父类静态变量地址(负责连接链表)

       保存了本类静态数组首地址

     GetMessageMap( )

       获取本类静态变量地址(获取链表头结点)

  (4)关系

     GetMessageMap( )

        |->CMyFrameWnd::messageMap

                |->&CMyFrameWnd::_messageEntries[ ]

                                 |->消息ID ... 处理函数

                |->&CFrameWnd::messageMap

                      |->&CFrameWnd::_messageEntries[ ]

                                     |->消息ID ... 处理函数

                      |->&CWnd::messageMap

                            |->&CWnd::_messageEntries[ ]

                                    |->消息ID ... 处理函数

                            |->&CCmdTarget::messageMap

                                       |->&CCmdTarget::_messageEntries[ ]

                                                                      |->消息ID ... 处理函数

                                       |->NULL  

三、执行过程

 1.获取和窗口句柄绑定的框架类对象pFrame

 2.利用pFrame调用宏展开的虚函数GetMessageMap获取本类静态变量地址(链表头结点)pMessageMap

 3.利用pMessageMap(静态变量)的第二个成员获取相应类的静态数组并到数组中匹配查找消息ID和对应的处理函数

  如果找到,执行5

 4.如果没找,用pMessageMap的第一个成员获取父类静态变量地址,如果为NULL,结束查找;如果不为NULL,执行3

 5.用找到的数组元素的第六个成员保存的函数地址并调用,完成消息处理

  伪代码:

  //以WM_CREATE消息为例(同时注意WM_COMMAND / WM_PAINT)

  AfxWndProc( HWND  hWnd, UINT  nMsg, WPARAM  wParam, LPARAM  lParam )

  {

    CWnd*  pWnd  =  CWnd::FromHandlePermanent( hWnd );  //获取和窗口句柄绑定的框架类对象pFrame

    return  AfxCallWndProc( pWnd,  hWnd,  nMsg,  wParam,  lParam )  //参数的pWnd就是pFrame

    {

      lResult  =  pWnd->WindowProc( nMsg,  wParam,  lParam )  //函数内部this为pFrame

      {

        LRESULT  lResult  =  0;

        OnWndMsg( message,  wParam, lParam,  &lResult )  //函数内部this为pFrame

        {

          union MessageMapFunctions  mmf;

          AFX_MSGMAP*  pMessageMap  =  GetMessageMap( )  //获得链表头结点

          {

            return GetThisMessageMap( );  //返回链表头结点地址

          }

          AFX_MSGMAP_ENTRY*  lpEntry;

          //遍历链表

          for (  ; pMessageMap->pfnGetBaseMap != NULL; pMessageMap = ( *pMessageMap->pfnGetBaseMap)( ) )

          {        

            lpEntry = AfxFindMessageEntry( pMessageMap->lpEntries, message, 0, 0 ) );

            if  ( lpEntry  !=  NULL )

            {

              goto  LDispatch;  //找到跳出for循环

            }

          }

          LDispatch:

            mmf.pfn  =  lpEntry->pfn;  //将OnCreate保存到联合体的所有成员中

            switch( lpEntry->nSig )

            {

              case  AfxSig_l_w_l:
                lResult  =  ( this->*mmf.pfn_l_w_l )( wParam, lParam );
                break;

            }

        }

      }

    }  

  }

 相关代码: 

#include "stdafx.h"
#include "T10_MFCMsg.h"

class CMyFrameWnd : public CFrameWnd
{
    DECLARE_MESSAGE_MAP()
/*
protected:
    static const AFX_MSGMAP* PASCAL GetThisMessageMap();
    virtual const AFX_MSGMAP* GetMessageMap() const;
*/
public:
    LRESULT OnCreate(WPARAM wParam, LPARAM lParam);
    LRESULT OnPaint(WPARAM wParam, LPARAM lParam);
    LRESULT OnMouseMove(WPARAM wParam, LPARAM lParam);
private:
    int m_x;
    int m_y;
public:
    CMyFrameWnd();
};

BEGIN_MESSAGE_MAP( CMyFrameWnd, CFrameWnd )
    ON_MESSAGE(WM_CREATE, OnCreate)
    ON_MESSAGE(WM_PAINT, OnPaint)
    ON_MESSAGE(WM_MOUSEMOVE, OnMouseMove)
END_MESSAGE_MAP()

/*
const AFX_MSGMAP* CMyFrameWnd::GetMessageMap() const
{
    return GetThisMessageMap();
}
const AFX_MSGMAP* PASCAL CMyFrameWnd::GetThisMessageMap()
{
    typedef CMyFrameWnd ThisClass;
    typedef CFrameWnd TheBaseClass;
    static const AFX_MSGMAP_ENTRY _messageEntries[] =
    {
        { WM_CREATE, 0, 0, 0, AfxSig_lwl,
        (AFX_PMSG)(AFX_PMSGW)
        (static_cast<LRESULT(AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM)> (&OnCreate)) },
        { 0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 }
    };
    static const AFX_MSGMAP messageMap = { &TheBaseClass::GetThisMessageMap, &_messageEntries[0] };
    return &messageMap;
}
*/

CMyFrameWnd::CMyFrameWnd()
{
    m_x = 100;
    m_y = 100;
}
LRESULT CMyFrameWnd::OnMouseMove(WPARAM wParam, LPARAM lParam)
{
    m_x = LOWORD(lParam);
    m_y = HIWORD(lParam);
    ::InvalidateRect(m_hWnd, NULL, TRUE);
    return 0;
}
LRESULT CMyFrameWnd::OnPaint(WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps = { 0 };
    HDC hdc = ::BeginPaint(m_hWnd, &ps);
    ::TextOut(hdc, m_x, m_y, L"hello", 5);
    ::EndPaint(m_hWnd, &ps);
    return 0;
}
LRESULT CMyFrameWnd::OnCreate(WPARAM wParam, LPARAM lParam)
{
    AfxMessageBox(L"CMyFrameWnd::OnCreate");
    return 0;
}

class CMyWinApp : public CWinApp
{
public:
    virtual BOOL InitInstance();
};

CMyWinApp theApp;

BOOL CMyWinApp::InitInstance()
{
    CMyFrameWnd *pFrame = new CMyFrameWnd;
    pFrame->Create(NULL, L"MFCMsg");
    m_pMainWnd = pFrame;
    pFrame->ShowWindow(SW_SHOW);
    pFrame->UpdateWindow();
    return TRUE;
}
View Code

 运行结果:

  

四、MFC消息分类

 1.windows的标准消息(键盘/鼠标/定时器...)

   ON_WM_XXX

   ON_WM_CREATE

   ON_WM_PAINT

   ON_WM_MOUSEMOVE

   ......

 2.自定义消息

   #define  WM_MYMESSAGE  WM_USER + n(1 - 31743)

   消息宏:ON_MESSAGE

 3.命令消息(WM_COMMAND)   

   消息宏:ON_COMMAND

 4.通知消息(WM_COMMAND)

   消息宏:ON_通知码     例如:ON_EN_CHANGE / ON_BN_CLICKED

 相关代码:

#include "stdafx.h"
#include "T11_MFCCmd.h"

#define WM_MYMESSAGE WM_USER+1001

class CMyFrameWnd : public CFrameWnd
{
    DECLARE_MESSAGE_MAP()
public:
    afx_msg int OnCreate(LPCREATESTRUCT pcs);
    afx_msg void OnPaint();
    afx_msg LRESULT OnMyMsg(WPARAM wParame, LPARAM lParam);
    afx_msg void OnOk();
    afx_msg void OnEnChange();
    afx_msg void OnBnClick();
};

BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
    ON_WM_CREATE()  //基本消息
    ON_WM_PAINT()
    ON_MESSAGE(WM_MYMESSAGE, OnMyMsg)  //自定义消息
    //ON_COMMAND(1001, OnOk)  //命令消息
    ON_EN_CHANGE(1002, OnEnChange)  //通知消息
    ON_BN_CLICKED(1001, OnBnClick)
END_MESSAGE_MAP()

void CMyFrameWnd::OnBnClick()
{
    AfxMessageBox(L"OK按钮被点击");
}

void CMyFrameWnd::OnEnChange()
{
    AfxMessageBox(L"内容被修改");
}

void CMyFrameWnd::OnOk()
{
    AfxMessageBox(L"OK按钮被点击");
}

LRESULT CMyFrameWnd::OnMyMsg(WPARAM wParame, LPARAM lParam)
{
    AfxMessageBox(L"处理自己定义的消息");
    return 0;
}

void CMyFrameWnd::OnPaint()
{
    PAINTSTRUCT ps = { 0 };
    HDC hdc = ::BeginPaint(m_hWnd, &ps);
    ::TextOut(hdc, 100, 100, L"hello", 5);
    ::EndPaint(m_hWnd, &ps);
}

int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs)
{
    ::CreateWindowEx(0, L"BUTTON", L"OK", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 
        100, 100, 100, 40, m_hWnd, (HMENU)1001, AfxGetInstanceHandle(), NULL);
    ::CreateWindowEx(0, L"EDIT", L"", WS_BORDER | WS_VISIBLE | WS_CHILD, 
        400, 100, 100, 100, m_hWnd, (HMENU)1002, AfxGetInstanceHandle(), NULL);
    AfxMessageBox(L"CMyFrameWnd::OnCreate");
    ::PostMessage(m_hWnd, WM_MYMESSAGE, 1, 2);
    return CFrameWnd::OnCreate(pcs);
}

class CMyWinApp : public CWinApp
{
public:
    virtual BOOL InitInstance();
};

CMyWinApp theApp;

BOOL CMyWinApp::InitInstance()
{
    CMyFrameWnd *pFrame = new CMyFrameWnd;
    m_pMainWnd = pFrame;
    pFrame->Create(NULL, L"MFCCmd");
    pFrame->ShowWindow(SW_SHOW);
    pFrame->UpdateWindow();
    return TRUE;
}
View Code

 运行结果:

 

 

   

posted @ 2016-07-18 15:13  甩锅侠  阅读(368)  评论(0编辑  收藏  举报