MFC中的消息映射(Message Mapping)

      Windows靠消息的流动来维持运行。MFC里有消息映射表,这个消息映射表,把消息和处理消息的程序关联起来。

      当我们的类库建立成功后,如果其中与消息相关的类(姑且叫做“消息标志类”,在MFC之中就是 CCmdTarget) 都是一条线式地继承,我们应该为每一个“消息标记类”准备一个消息映射表,并且将基类与派生类的消息映射表连接起来。然后,当窗口函数作消息的比较时,我们就可以想办法引导它沿着这条路走过去:

MFC中的消息映射(Message Mapping)_第1张图片

         但是,MFC中用来处理消息的C++类,并不是呈单线发展。作为Application FrameWork的重要结构之一的Document/View,也具有处理消息的能力。消息不仅可以纵向流动(从子类到父类),还可以横向流动(从左兄弟到右兄弟)。

         消息如何流动,我们暂时先不管。是直线前进,或是中途换跑道,我们都暂时不管,本案例先把消息的纵向流动,弄清楚。

        这个消息的流动,就是消息映射表。也可以把它比作一张地图,或者一根多叉树。如果将消息与消息映射表中的元素进行比较,然后调用对应的处理程序,我们把这种比较就叫做“消息映射”(Message Mapping)。

        MFC中消息的纵向流动,如图(3-5)所示:

MFC中的消息映射(Message Mapping)_第2张图片

        为了验证整个消息映射表,我必须在映射表中做点记号,等全部构建完成之后,再一一追踪将记号显示出来。我将为每一个类的消息映射表加上这个项目:

  ON_COMMAND(ClassId ,0)

      这样就可以吧ClassId 镶嵌到映射表中作为记号。正式用途(与MFC中)当然不是这样,这只不过是权宜之计。

        在main 函数中,我先产生4个对象(分别是 CMyWinApp、CMyFrameWnd、CMyDoc、CMyView 对象):

      

CMyWinApp theApp; //theApp是CMyWinApp对象
void main()
{

    CWinApp* pApp = AfxGetApp();

    pApp->InitApplication();
    pApp->InitInstance();
    pApp->Run();

    CMyDoc* pMyDoc = new CMyDoc;
    CMyView* pMyView = new CMyView;
    CFrameWnd* pMyFrame = (CFrameWnd*)pApp->m_pMainWnd;

    ...
}

       然后,分别取其消息映射表,一路追踪上去,把每一个消息映射表中的类的标记打印出来:

void main()
{
    ...

    AFX_MSGMAP* pMessageMap = pMyView->GetMessageMap();
    cout << endl << "CMyView Message Map : " << endl;
    MsgMapPrinting(pMessageMap);

    pMessageMap = pMyDoc->GetMessageMap();
    cout << endl << "CMyDoc Message Map : " << endl;
    MsgMapPrinting(pMessageMap);

    pMessageMap = pMyFrame->GetMessageMap();
    cout << endl << "CMyFrameWnd Message Map : " << endl;
    MsgMapPrinting(pMessageMap);

    pMessageMap = pApp->GetMessageMap();
    cout << endl << "CMyWinApp Message Map : " << endl;
    MsgMapPrinting(pMessageMap);
}
    自定义两个函数,来打印出消息映射表中的class标记:void MsgMapPrinting(AFX_MSGMAP* pMessageMap) 和 void  printlpEntries(AFX_MSGMAP_ENTRY* lpEntry)


void  printlpEntries(AFX_MSGMAP_ENTRY* lpEntry)
{
struct {
  int classid;
  char* classname;
} classinfo[] = {
                    CCmdTargetid ,  "CCmdTarget   ",
                    CWinThreadid ,  "CWinThread   ",
                    CWinAppid    ,  "CWinApp      ",
                    CMyWinAppid  ,  "CMyWinApp    ",
                    CWndid       ,  "CWnd         ",
                    CFrameWndid  ,  "CFrameWnd    ",
                    CMyFrameWndid,  "CMyFrameWnd  ",
                    CViewid      ,  "CView        ",
                    CMyViewid    ,  "CMyView      ",
                    CDocumentid  ,  "CDocument    ",
                    CMyDocid     ,  "CMyDoc       ",
                    0            ,  "             "
                };

  for (int i=0; classinfo[i].classid != 0; i++)
  {
      if (classinfo[i].classid == lpEntry->nID)
      {
          cout << lpEntry->nID << "    ";
          cout << classinfo[i].classname << endl;
          break;
      }
  }
}

void MsgMapPrinting(AFX_MSGMAP* pMessageMap)
{
    for(; pMessageMap != NULL; pMessageMap = pMessageMap->pBaseMessageMap) {
        AFX_MSGMAP_ENTRY* lpEntry = pMessageMap->lpEntries;
        printlpEntries(lpEntry);
    }
}

效果如下:

MFC中的消息映射(Message Mapping)_第3张图片

图(4)Frame7中消息的纵向流动

  工程Frame7的详细代码如下:

//mfc.h

#define TRUE 1
#define FALSE 0

typedef char* LPSTR;
typedef const char* LPCSTR;

typedef unsigned long  DWORD;
typedef int            BOOL;
typedef unsigned char  BYTE;
typedef unsigned short WORD;
typedef int            INT;
typedef unsigned int   UINT;
typedef long           LONG;

#define WM_COMMAND             0x0111
#define CObjectid              0xffff
#define   CCmdTargetid         1
#define     CWinThreadid       11
#define       CWinAppid        111
#define         CMyWinAppid    1111
#define     CWndid             12
#define       CFrameWndid      121
#define         CMyFrameWndid  1211
#define       CViewid          122
#define         CMyViewid      1221
#define     CDocumentid        13
#define       CMyDocid         131

#include 

///
// Window message map handling

struct AFX_MSGMAP_ENTRY;       // declared below after CWnd

struct AFX_MSGMAP
{
        AFX_MSGMAP* pBaseMessageMap;
        AFX_MSGMAP_ENTRY* lpEntries;
};

#define DECLARE_MESSAGE_MAP() \
        static AFX_MSGMAP_ENTRY _messageEntries[]; \
        static AFX_MSGMAP messageMap; \
        virtual AFX_MSGMAP* GetMessageMap() const;

#define BEGIN_MESSAGE_MAP(theClass, baseClass) \
        AFX_MSGMAP* theClass::GetMessageMap() const \
                { return &theClass::messageMap; } \
        AFX_MSGMAP theClass::messageMap = \
        { &(baseClass::messageMap), \
                (AFX_MSGMAP_ENTRY*) &(theClass::_messageEntries) }; \
        AFX_MSGMAP_ENTRY theClass::_messageEntries[] = \
        {

#define END_MESSAGE_MAP() \
        { 0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \
        };

// Message map signature values and macros in separate header
#include "afxmsg_.h" //注意是“”,不是<>

class CObject
{
public:
  CObject::CObject()  {
                      }
  CObject::~CObject() {
                      }
};

class CCmdTarget : public CObject
{
public:
  CCmdTarget::CCmdTarget()  {
                            }
  CCmdTarget::~CCmdTarget() {
                            }
  DECLARE_MESSAGE_MAP()       // base class - no {{ }} macros
};

typedef void (CCmdTarget::*AFX_PMSG)(void);

struct AFX_MSGMAP_ENTRY  // MFC 4.0
{
    UINT nMessage; // windows message
    UINT nCode;    // control code or WM_NOTIFY code
    UINT nID;      // control ID (or 0 for windows messages)
    UINT nLastID;  // used for entries specifying a range of control id's
    UINT nSig;     // signature type (action) or pointer to message #
    AFX_PMSG pfn;  // routine to call (or special value)
};

class CWinThread : public CCmdTarget
{
public:
  CWinThread::CWinThread()  {
                            }
  CWinThread::~CWinThread() {
                            }

  virtual BOOL InitInstance() {
                                cout << "CWinThread::InitInstance \n";
                                return TRUE;
                              }
  virtual int Run() {
                      cout << "CWinThread::Run \n";
                      return 1;
                    }
};

class CWnd;

class CWinApp : public CWinThread
{
public:
  CWinApp* m_pCurrentWinApp;
  CWnd* m_pMainWnd;

public:
  CWinApp::CWinApp()  {
                        m_pCurrentWinApp = this;
                      }
  CWinApp::~CWinApp() {
                      }

  virtual BOOL InitApplication() {
                                   cout << "CWinApp::InitApplication \n";
                                   return TRUE;
                                 }
  virtual BOOL InitInstance()    {
                                   cout << "CWinApp::InitInstance \n";
                                   return TRUE;
                                 }
  virtual int Run() {
                      cout << "CWinApp::Run \n";
                      return CWinThread::Run();
                    }

  DECLARE_MESSAGE_MAP()
};

typedef void (CWnd::*AFX_PMSGW)(void);
        // like 'AFX_PMSG' but for CWnd derived classes only

class CDocument : public CCmdTarget
{
public:
  CDocument::CDocument()   {
                           }
  CDocument::~CDocument()  {
                           }
  DECLARE_MESSAGE_MAP()
};

class CWnd : public CCmdTarget
{
public:
  CWnd::CWnd()   {
                 }
  CWnd::~CWnd()  {
                 }

  virtual BOOL Create();
  BOOL CreateEx();
  virtual BOOL PreCreateWindow();

  DECLARE_MESSAGE_MAP()
};

class CFrameWnd : public CWnd
{
public:
  CFrameWnd::CFrameWnd()   {
                           }
  CFrameWnd::~CFrameWnd()  {
                           }
  BOOL Create();
  virtual BOOL PreCreateWindow();

  DECLARE_MESSAGE_MAP()
};

class CView : public CWnd
{
public:
  CView::CView()   {
                   }
  CView::~CView()  {
                   }
  DECLARE_MESSAGE_MAP()
};

// global function
CWinApp* AfxGetApp();

//mfc.cpp

#include "my.h"  // it should be mfc.h, but for CMyWinApp definition, so...

extern CMyWinApp theApp;

BOOL CWnd::Create()
{
	cout << "CWnd::Create \n";
	return TRUE;
}

BOOL CWnd::CreateEx()
{
	cout << "CWnd::CreateEx \n";
	PreCreateWindow();
	return TRUE;
}

BOOL CWnd::PreCreateWindow()
{
	cout << "CWnd::PreCreateWindow \n";
	return TRUE;
}

BOOL CFrameWnd::Create()
{
	cout << "CFrameWnd::Create \n";
	CreateEx();
	return TRUE;
}

BOOL CFrameWnd::PreCreateWindow()
{
	cout << "CFrameWnd::PreCreateWindow \n";
	return TRUE;
}

CWinApp* AfxGetApp()
{
	return theApp.m_pCurrentWinApp;
}

AFX_MSGMAP* CCmdTarget::GetMessageMap() const  // JJHOU: in MFC 40 cmdtarg.cpp
{
	return &CCmdTarget::messageMap;
}

AFX_MSGMAP CCmdTarget::messageMap =   // JJHOU: in MFC 40 cmdtarg.cpp
{
	NULL,
        &CCmdTarget::_messageEntries[0]
};

AFX_MSGMAP_ENTRY CCmdTarget::_messageEntries[] = // JJHOU: in in MFC 40 cmdtarg.cpp
{
	// { 0, 0, 0, 0, AfxSig_end, 0 }     // nothing here
	{ 0, 0, CCmdTargetid, 0, AfxSig_end, 0 }
	
};

BEGIN_MESSAGE_MAP(CWnd, CCmdTarget)
ON_COMMAND(CWndid, 0)
END_MESSAGE_MAP()

BEGIN_MESSAGE_MAP(CFrameWnd, CWnd)
ON_COMMAND(CFrameWndid, 0)
END_MESSAGE_MAP()

BEGIN_MESSAGE_MAP(CDocument, CCmdTarget)
ON_COMMAND(CDocumentid, 0)
END_MESSAGE_MAP()

BEGIN_MESSAGE_MAP(CView, CWnd)
ON_COMMAND(CViewid, 0)
END_MESSAGE_MAP()

BEGIN_MESSAGE_MAP(CWinApp, CCmdTarget)
ON_COMMAND(CWinAppid, 0)
END_MESSAGE_MAP()

//my.h

#include 
#include "mfc.h"

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

class CMyFrameWnd : public CFrameWnd
{
public:
	CMyFrameWnd();
	~CMyFrameWnd()  {
	}
	DECLARE_MESSAGE_MAP()
};

class CMyDoc : public CDocument
{
public:
	CMyDoc::CMyDoc()  {
	}
	CMyDoc::~CMyDoc() {
	}
	DECLARE_MESSAGE_MAP()
};

class CMyView : public CView
{
public:
	CMyView::CMyView()   {
	}
	CMyView::~CMyView()  {
	}
	DECLARE_MESSAGE_MAP()
};



//my.cpp

#include "my.h"

CMyWinApp theApp;

BOOL CMyWinApp::InitInstance()
{
    cout << "CMyWinApp::InitInstance \n";
    m_pMainWnd = new CMyFrameWnd;
    return TRUE;
}

CMyFrameWnd::CMyFrameWnd()
{
    Create();
}

BEGIN_MESSAGE_MAP(CMyWinApp, CWinApp)
ON_COMMAND(CMyWinAppid, 0)
END_MESSAGE_MAP()

BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
ON_COMMAND(CMyFrameWndid, 0)
END_MESSAGE_MAP()

BEGIN_MESSAGE_MAP(CMyDoc, CDocument)
ON_COMMAND(CMyDocid, 0)
END_MESSAGE_MAP()

BEGIN_MESSAGE_MAP(CMyView, CView)
ON_COMMAND(CMyViewid, 0)
END_MESSAGE_MAP()

void  printlpEntries(AFX_MSGMAP_ENTRY* lpEntry)
{
struct {
  int classid;
  char* classname;
} classinfo[] = {
                    CCmdTargetid ,  "CCmdTarget   ",
                    CWinThreadid ,  "CWinThread   ",
                    CWinAppid    ,  "CWinApp      ",
                    CMyWinAppid  ,  "CMyWinApp    ",
                    CWndid       ,  "CWnd         ",
                    CFrameWndid  ,  "CFrameWnd    ",
                    CMyFrameWndid,  "CMyFrameWnd  ",
                    CViewid      ,  "CView        ",
                    CMyViewid    ,  "CMyView      ",
                    CDocumentid  ,  "CDocument    ",
                    CMyDocid     ,  "CMyDoc       ",
                    0            ,  "             "
                };

  for (int i=0; classinfo[i].classid != 0; i++)
  {
      if (classinfo[i].classid == lpEntry->nID)
      {
          cout << lpEntry->nID << "    ";
          cout << classinfo[i].classname << endl;
          break;
      }
  }
}

void MsgMapPrinting(AFX_MSGMAP* pMessageMap)
{
    for(; pMessageMap != NULL; pMessageMap = pMessageMap->pBaseMessageMap) {
        AFX_MSGMAP_ENTRY* lpEntry = pMessageMap->lpEntries;
        printlpEntries(lpEntry);
    }
}

//------------------------------------------------------------------
// main
//------------------------------------------------------------------
void main()
{

    CWinApp* pApp = AfxGetApp();

    pApp->InitApplication();
    pApp->InitInstance();
    pApp->Run();

    CMyDoc* pMyDoc = new CMyDoc;
    CMyView* pMyView = new CMyView;
    CFrameWnd* pMyFrame = (CFrameWnd*)pApp->m_pMainWnd;

    // output Message Map construction
    AFX_MSGMAP* pMessageMap = pMyView->GetMessageMap();
    cout << endl << "CMyView Message Map : " << endl;
    MsgMapPrinting(pMessageMap);

    pMessageMap = pMyDoc->GetMessageMap();
    cout << endl << "CMyDoc Message Map : " << endl;
    MsgMapPrinting(pMessageMap);

    pMessageMap = pMyFrame->GetMessageMap();
    cout << endl << "CMyFrameWnd Message Map : " << endl;
    MsgMapPrinting(pMessageMap);

    pMessageMap = pApp->GetMessageMap();
    cout << endl << "CMyWinApp Message Map : " << endl;
    MsgMapPrinting(pMessageMap);
}

//afxmsg_.h

enum AfxSig
{
	AfxSig_end = 0,     // [marks end of message map]
        AfxSig_vv,
};

#define ON_COMMAND(id, memberFxn) \
{ WM_COMMAND, 0, (WORD)id, (WORD)id, AfxSig_vv, (AFX_PMSG)memberFxn },


你可能感兴趣的:(C++,MFC)