~~~~終於快到MFC的6大關鍵技術的盡頭了~~
Windows程序的活動依靠消息的流動,在前面我們已經很簡單的看過了消息的處理方式,即一個一般化的switch/case比較操作,判斷是否有對應的消息再執行處理對應的程序,爲了讓switch/case的操作簡化,爲了簡化這一過程且爲了後來更方便的添加消息,MFC中提供了一種消息映射表的做法。
消息映射表的建立其實就是統一的在需要處理消息的類之中加入了一些用來記錄消息的定義,然後爲了保證類的編寫的方便化,統一地使用宏定義來降低代碼的冗餘~~.
這過程中還考慮到一些消息的傳遞,所以還要建立一些獨特的聯繫保證消息的傳遞的執行,其實具體做法就和之前的自動類型識別很是相似
接下來讓我們一個一個的來看一看:
首先聲明一個這樣的數據結構,其中包含下一個消息條目的指針和本身消息條目的指針,具體如下:
struct AFX_MSGMAP
{
AFX_MSGMAP* pBaseMessageMap;
AFX_MSGMAP_ENTRY* lpEntries;
};
其中AFX_MSGMAP_ENTRY是這樣一個數據結構:
struct AFX_MSGMAP_ENTRY
{
UINT nMessage;
UINT nCode;
UINT nID;
UINT nLastID;
UINT nSig;
AFX_PMSG pfn;
};
該數據結構主要用來儲存消息條目,在這個數據結構中AFX_PMSG是一個函數指針,可以指向CCmdTarget的一個無參數無返回值的成員函數,具體定義如下:
typedef void (CCmdTarget::*AFX_PMSG)(void);
有了這些基礎材料之後,我們就可以開始着手實現我們消息映射表了,首先我們需要在需要處理消息的類中加入如下的宏:
#define DECLARE_MESSAGE_MAP() \
static AFX_MSGMAP_ENTRY _messageEntries[]; \
static AFX_MSGMAP messageMap; \
virtual AFX_MSGMAP* GetMessageMap() const;
宏的第一部分是一個數組,用來保存對應類的所有的消息條目,第2個則是特定的數據結構用來儲存父類的該結構索引和本身條目的索引,第3個方法則是爲了獲取第2個成員,該組宏的具體實現宏如下:
#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 } \
};
在這組宏之中,我們還可以添加一些消息條目,例如:
BEGIN_MESSAGE_MAP(CWinApp, CCmdTarget)
ON_COMMAND(CWinAppid, 0)
END_MESSAGE_MAP()
在我們需要處理消息的對象之中加入了消息之後,我們的對象便擁有了對應的消息映射表
且我們可以通過我們創建的結構AFX_MSGMAP來實現消息的流動,將一消息從子類對象傳遞到父類對象
對了,在實際編碼中我們設定了消息的最終節點爲CCmdTarget,所以對於該節點的消息映射表我們需要特殊處理一下,同時還有一點要注意的是WinApp的消息傳遞的下一級就是CCmdTarget,而不是CWinThread,,
整個消息傳遞網形成之後如下所示:
以上內容均爲作者讀《深入淺出MFC》有感
作者在後面爲了保證搭建出來的正確性,還做了一些特殊標記以輸出消息傳遞的過程
在這我貼出代碼:
運行平臺:VS2013
代碼:
//MFC.h
#pragma once
#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<iostream>
using namespace std;
struct AFX_MSGMAP_ENTRY;
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 } \
};
#include<afxmsg_.h>
class CObject
{
public:
CObject::CObject() {}
CObject::~CObject() {}
};
class CCmdTarget : public CObject
{
public:
CCmdTarget::CCmdTarget() {}
CCmdTarget::~CCmdTarget(){}
DECLARE_MESSAGE_MAP()
};
typedef void (CCmdTarget::*AFX_PMSG)(void);
struct AFX_MSGMAP_ENTRY
{
UINT nMessage;
UINT nCode;
UINT nID;
UINT nLastID;
UINT nSig;
AFX_PMSG pfn;
};
class CWinThread :public CCmdTarget
{
public:
CWinThread::CWinThread() {}
CWinThread::~CWinThread(){}
virtual BOOL InitInstance()
{
cout << "CWinThread::InitInstance" << endl;
return TRUE;
}
virtual int Run() {
cout << "CWinThread::Run" << endl;
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" << endl;
return TRUE;
}
virtual BOOL InitInstance() {
cout << "CWinApp::InitInstance" << endl;
return TRUE;
}
virtual int Run()
{
cout << "CWinApp::Run" << endl;
return CWinThread::Run();
}
DECLARE_MESSAGE_MAP()
};
typedef void (CWnd::*AFX_PMSGW)(void);
//時間隊列指針
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()
};
//全局函數用以獲取全局對象
CWinApp* AfxGetApp();
//MFC.cpp
#include"MY.h"
extern CMyWinApp theApp;
BOOL CWnd::Create()
{
cout << "CWnd::Create" << endl;
return TRUE;
}
BOOL CWnd::CreateEx()
{
cout << "CWnd::CreateEx" << endl;
PreCreateWindow();
return TRUE;
}
BOOL CWnd::PreCreateWindow()
{
cout << "CWnd::PreCreateWindow" << endl;
return TRUE;
}
BOOL CFrameWnd::Create()
{
cout << "CFrameWnd::Create" << endl;
CreateEx();
return TRUE;
}
BOOL CFrameWnd::PreCreateWindow()
{
cout << "CFrameWnd::PreCreateWindow" << endl;
return TRUE;
}
CWinApp* AfxGetApp()
{
return theApp.m_pCurrentWinApp;
}
AFX_MSGMAP* CCmdTarget::GetMessageMap() const
{
return &CCmdTarget::messageMap;
}
AFX_MSGMAP CCmdTarget::messageMap = {
NULL,
&CCmdTarget::_messageEntries[0]
};
AFX_MSGMAP_ENTRY CCmdTarget::_messageEntries[] = {
//{0,0,0,0,AfxSig_end ,0} ,
{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
#pragma once
#include<iostream>
#include"MFC.h"
using namespace std;
class CMyWinApp : public CWinApp
{
public:
CMyWinApp::CMyWinApp() {}
CMyWinApp::~CMyWinApp() {}
virtual BOOL InitInstance();
DECLARE_MESSAGE_MAP()
};
class CMyFrameWnd :public CFrameWnd
{
public:
CMyFrameWnd::CMyFrameWnd();
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()
};
//MF.cpp
#include"MY.h"
CMyWinApp theApp;
BOOL CMyWinApp::InitInstance()
{
cout << "CMyWinApp::InitInstance" << endl;
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,"CWndid",
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);
}
}
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;
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);
system("pause");
}
效果圖如下: