转载自:http://www.cppblog.com/citywanderer/articles/8660.htmlhttp://www.cppblog.com/citywanderer/articles/8660.html
一、关于DECLARE_MESSAGE_MAP宏定义
使用MFC向导,在ApplicationType页面选择DialogBased,生成一个对话框项目,Dialog类命名为CCapturePacketDlg,在CCapturePacketDlg.cpp中自动产生下列代码:
2 ON_WM_PAINT()
3 END_MESSAGE_MAP()
- 先来分析ON_WM_PAINT(),在头文件“afxmsg.h”有它的宏定义,如下:
2 { WM_PAINT, 0 , 0 , 0 , AfxSig_vv, \
3 (AFX_PMSG)(AFX_PMSGW) \
4 (static_cast < void (AFX_MSG_CALL CWnd:: * )( void ) > ( & ThisClass :: OnPaint)) } ,
2.1 #define WM_PAINT 0x000F
2.2 AfxSig_vv = AfxSig_v_v_v
2.2.1 enum AfxSig::AfxSig_v_v_v = 19
3.1 AFX_PMSG:typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void); //为一个函数指针
3.2 AFX_PMSGW:typedef void (AFX_MSG_CALL CWnd::*AFX_PMSGW)(void); //为一个函数指针
将ON_WM_PAINT()完全展开:
2 0x000F,
3 0,
4 0,
5 0,
6 19,
7 //Converts OnPaint to the type of CCmdTarget finally. Derive Class 's pointer -> Base Class's pointer
8 (AFX_MSG_CALL CCmdTarget::*)((AFX_MSG_CALL CWnd::*)(static_cast< void (AFX_MSG_CALL CWnd::*)(void) >(&ThisClass :: OnPaint))
9 }
2. 再来分析BEGIN_MESSAGE_MAP(CCapturePacketDlg, CDialog),在“afxwin.h”中有定义:
2 PTM_WARNING_DISABLE \
3 const AFX_MSGMAP * theClass::GetMessageMap() const \
4 { return GetThisMessageMap(); } \
5 const AFX_MSGMAP * PASCAL theClass::GetThisMessageMap() \
6 { \
7 typedef theClass ThisClass; \
8 typedef baseClass TheBaseClass; \
9 static const AFX_MSGMAP_ENTRY _messageEntries[] = \
10 {
2.1 PTM_WARNING_DISABLE:
#define PTM_WARNING_DISABLE \
__pragma(warning( push )) \ //#pragma warning( push [ ,n ] ),Where n represents a warning level (1 through 4).
//The pragma warning( push ) stores the current warning state for all warnings.
__pragma(warning( disable : 4867 ))//Do not issue the specified warning message(s).
//http://msdn2.microsoft.com/en-us/2c8f766e.aspx
// Allows selective modification of the behavior of compiler warning messages.
3.1 struct AFX_MSGMAP
{
3.1.1 const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();
3.1.2 const AFX_MSGMAP_ENTRY* lpEntries;
};
3.1.2 struct AFX_MSGMAP_ENTRY
{
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_PTR nSig; // signature type (action) or pointer to message #
3.1.2.1 AFX_PMSG pfn; // routine to call (or special value)
};
3.1.2.1 typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);
5.1 #define PASCAL __stdcall
将BEGIN_MESSAGE_MAP(CCapturePacketDlg, CDialog)完全展开:
2 const struct AFX_MSGMAP * CCapturePacketDlg::GetMessageMap() const
3 {
4 return GetThisMessageMap();
5 }
6 const struct AFX_MSGMAP * __stdcall CCapturePacketDlg::GetThisMessageMap()
7 {
8 typedef CCapturePacketDlg ThisClass;
9 typedef CDialog TheBaseClass;
10 static const struct AFX_MSGMAP_ENTRY _messageEntries[] =
11 {
3 最后分析END_MESSAGE_MAP(),在“afxwin.h”中有定义:
2 {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \
3 }; \
4 static const AFX_MSGMAP messageMap = \
5 { &TheBaseClass::GetThisMessageMap, &_messageEntries[0] } ; \
6 return & messageMap; \
7 } \
8 PTM_WARNING_RESTORE
2.1 AfxSig_end:enum AfxSig.AfxSig_end = 0
2.2 AFX_PMSG:typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);//函数指针
4.1 struct AFX_MSGMAP
{
const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();
const AFX_MSGMAP_ENTRY* lpEntries;
};
8.1 #define PTM_WARNING_RESTORE \
__pragma(warning( pop ))
//pop restores the state of all warnings (including 4705, 4706, and 4707) to what it was at the beginning of the code.
·最后将
2 ON_WM_PAINT()
3 END_MESSAGE_MAP()
2 const struct AFX_MSGMAP * CCapturePacketDlg::GetMessageMap() const
3 {
4 return GetThisMessageMap();
5 }
6 const struct AFX_MSGMAP * __stdcall CCapturePacketDlg::GetThisMessageMap()
7 {
8 typedef CCapturePacketDlg ThisClass;
9 typedef CDialog TheBaseClass;
10 static const struct AFX_MSGMAP_ENTRY _messageEntries[] =
11 {
12 {
13 0x000F,
14 0,
15 0,
16 0,
17 19,
18 //Converts OnPaint to the type of CCmdTarget finally. Derive Class 's pointer -> Base Class's pointer
19 (AFX_MSG_CALL CCmdTarget::*)((AFX_MSG_CALL CWnd::*)(static_cast< void (AFX_MSG_CALL CWnd::*)(void) >(&ThisClass :: OnPaint))
20 },
21 //add others
22 {
23 0,
24 0,
25 0,
26 0,
27 0,
28 (AFX_PMSG)0
29 }
30 }
31 static const struct AFX_MSGMAP messageMap =
32 {
33 &TheBaseClass::GetThisMessageMap,
34 &_messageEntries[0]
35 };
36 return &messageMap;
37 }
38 __pragma(warning( pop ))
39
老办法查看它的定义:
2 protected : \
3 static const AFX_MSGMAP * PASCAL GetThisMessageMap(); \
4 virtual const AFX_MSGMAP * GetMessageMap() const ; \
小结:
每次用MFC类向导生成一个类时,系统会在类的声明部分添加两个方法的声明:GetThisMessageMap(),GetMessageMap()。在类的实现部分.cpp文件中加上这两个方法的定义。
当然这所有的代码都是由系统生成的,如果我们要定义自己的消息处理函数呢,例如,我们要添加一个按钮(ID为:IDC_BUTTON1)的单击处理函数我们可以添加宏ON_NOTIFY(NM_CLICK, IDC_BUTTON1, OnMyClick),OnMyClick为自定义函数,但是他必须与ON_NOTIFY中的函数原型一致。
二、关于DECLARE_DYNCREATE宏
使用MFC向导,在ApplicationType页面选择SingleDocument,生成一个单文档项目,Document类命名为CDynamicDoc,在CDynamicDoc.h中自动产生DECLARE_DYNCREATE(CDynamicDoc),CDynamicDoc.cpp中产生IMPLEMENT_DYNCREATE(CDynamicDoc, CDocument)。
1、展开CDynamicDoc.h中的DECLARE_DYNCREATE(CDynamicDoc):
2 #define DECLARE_DYNCREATE(class_name) \
3 DECLARE_DYNAMIC(class_name) \
4 static CObject * PASCAL CreateObject();
2 #define DECLARE_DYNAMIC(class_name) \
3 protected : \
4 static CRuntimeClass * PASCAL _GetBaseClass(); \
5 public : \
6 static const CRuntimeClass class ##class_name; \
7 static CRuntimeClass * PASCAL GetThisClass(); \
8 virtual CRuntimeClass * GetRuntimeClass() const ; \
2 static CRuntimeClass * PASCAL _GetBaseClass();
3 public :
4 static const CRuntimeClass classCDynamicDoc;
5 static CRuntimeClass * PASCAL GetThisClass();
6 virtual CRuntimeClass * GetRuntimeClass() const ;
7 static CObject * PASCAL CreateObject();
2、展开CDynamicDoc.cpp中的IMPLEMENT_DYNCREATE(CDynamicDoc, CDocument):
2 CObject * PASCAL class_name::CreateObject() \
3 { return new class_name; } \
4 IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF , \
5 class_name::CreateObject, NULL)
2 CRuntimeClass * PASCAL class_name::_GetBaseClass() \
3 { return RUNTIME_CLASS(base_class_name); } \
4 AFX_COMDAT const CRuntimeClass class_name:: class ##class_name = { \
5 #class_name, sizeof(class class_name), wSchema, pfnNew, \
6 &class_name::_GetBaseClass, NULL, class_init } ; \
7 CRuntimeClass * PASCAL class_name::GetThisClass() \
8 { return _RUNTIME_CLASS(class_name); } \
9 CRuntimeClass * class_name::GetRuntimeClass() const \
10 { return _RUNTIME_CLASS(class_name); } \
2 {
3 // Attributes
4 LPCSTR m_lpszClassName;
5 int m_nObjectSize;
6 UINT m_wSchema; // schema number of the loaded class
7 CObject* (PASCAL* m_pfnCreateObject)(); // NULL => abstract class
8 #ifdef _AFXDLL
9 CRuntimeClass* (PASCAL* m_pfnGetBaseClass)();
10 #else
11 CRuntimeClass* m_pBaseClass;
12 #endif
13
14 // Operations
15 CObject* CreateObject();
16 BOOL IsDerivedFrom(const CRuntimeClass* pBaseClass) const;
17
18 // dynamic name lookup and creation
19 static CRuntimeClass* PASCAL FromName(LPCSTR lpszClassName);
20 static CRuntimeClass* PASCAL FromName(LPCWSTR lpszClassName);
21 static CObject* PASCAL CreateObject(LPCSTR lpszClassName);
22 static CObject* PASCAL CreateObject(LPCWSTR lpszClassName);
23
24 // Implementation
25 void Store(CArchive& ar) const;
26 static CRuntimeClass* PASCAL Load(CArchive& ar, UINT* pwSchemaNum);
27
28 // CRuntimeClass objects linked together in simple list
29 CRuntimeClass* m_pNextClass; // linked list of registered classes
30 const AFX_CLASSINIT* m_pClassInit;
31 } ;
2 // Basic object model
3
4 // generate static object constructor for class registration
5 void AFXAPI AfxClassInit(CRuntimeClass * pNewClass);
6 struct AFX_CLASSINIT
7 { AFX_CLASSINIT(CRuntimeClass* pNewClass) { AfxClassInit(pNewClass); } } ;
8 // C:\Program Files\Microsoft Visual Studio 8\VC\atlmfc\src\mfc\objcore.cpp Line157
9 void AFXAPI AfxClassInit(CRuntimeClass * pNewClass)
10 {
11 AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
12 AfxLockGlobals(CRIT_RUNTIMECLASSLIST);
13 pModuleState->m_classList.AddHead(pNewClass);
14 AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
15 }
16 // 可以将AfxClassInit()函数的功能简单的如下表示:
17 AFX_CLASSINIT::AFX_CLASSINIT(CRuntimeClass * pNewClass)
18 {
19 pNewClass->m_pNextClass = CRuntimeClass::pFirstClass;
20 CRuntimeClass::pFirstClass = pNewClass;
21 }
4.1.3 RUNTIME_CLASS如下定义:
“##”——operator ( ##), which is sometimes called the "merging" operator, is used in both object-like and function-like macros.
4.1.8 _RUNTIME_CLASS如下定义:
2 static CObject * PASCAL CDynamicDoc::CreateObject()
3 {
4 return new CDynamicDoc;
5 }
6
7 static CRuntimeClass * PASCAL CDynamicDoc::_GetBaseClass()
8 {
9 return CDocument::GetThisClass()
10 }
11
12 __declspec(selectany) static const CRuntimeClass CDynamicDoc::classCDynamicDoc =
13 {
14 "CDynamicDoc"
15 , sizeof(class CDynamicDoc)
16 , 0xFFFF
17 , CDynamicDoc::CreateObject
18 , &CDynamicDoc::_GetBaseClass
19 , NULL
20 , NULL
21 } ;
22
23 static CRuntimeClass * PASCAL CDynamicDoc::GetThisClass()
24 {
25 return ((CRuntimeClass*)(&CDynamicDoc::classCDynamicDoc));
26 }
27
28 CRuntimeClass * CDynamicDoc::GetRuntimeClass() const
29 {
30 return ((CRuntimeClass*)(&CDynamicDoc::classCDynamicDoc));
31 }
如果你想看这些宏的简化版,可以参考侯老的《深入浅出MFC》,如下:
1//in header file
2class CView : public CWnd
3{
4public:
5 static CRuntimeClass classCView;
6 virtual CRuntimeClass* GetRuntimeClass() const;
7 //……
8};
9//in implementation file
10static char_lpszCView = "CView";
11CRuntimeClass CView::classCView =
12{
13 _lpszCView
14 , sizeof(CView)
15 , 0xFFF
16 , NULL
17 , &CWnd::classCWnd
18 , NULL
19};
20static AFX_CLASSINIT _init_CView(&CView::classCView)
21{
22 (&CView::classCView)->m_pNextClass = CRuntimeClass::pFirstClass;
23 CRuntimeClass::pFirstClass = &CView::classCView;
24}
25CRuntimeClass* CView::GetRuntimeClass() const
26{
27 return &CView::classCView;
28}
其中他将CRuntimeClass简化定义为:
struct CRuntimeClass
{
// Attributes
LPCSTR m_lpszClassName;
int m_nObjectSize;
UINT m_wSchema; // schema number of the loaded class
CObject* (PASCAL* m_pfnCreateObject)(); // NULL => abstract class
CRuntimeClass* m_pBaseClass;
// CRuntimeClass objects linked together in simple list
static CRuntimeClass* pFirstClass; // start of class list
CRuntimeClass* m_pNextClass; // linked list of registered classes
};
2 #define DECLARE_SERIAL(class_name) \
3 _DECLARE_DYNCREATE(class_name) \
4 AFX_API friend CArchive & AFXAPI operator >> (CArchive & ar, class_name * & pOb);
5
6 #define _DECLARE_DYNCREATE(class_name) \
7 _DECLARE_DYNAMIC(class_name) \
8 static CObject * PASCAL CreateObject();
9
10 #define _DECLARE_DYNAMIC(class_name) \
11 protected : \
12 static CRuntimeClass * PASCAL _GetBaseClass(); \
13 public : \
14 static CRuntimeClass class ##class_name; \
15 static CRuntimeClass * PASCAL GetThisClass(); \
16 virtual CRuntimeClass * GetRuntimeClass() const ; \
17 // implement file
18 #define IMPLEMENT_SERIAL(class_name, base_class_name, wSchema) \
19 CObject * PASCAL class_name::CreateObject() \
20 { return new class_name; } \
21 extern AFX_CLASSINIT _init_##class_name; \
22 _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, \
23 class_name::CreateObject, & _init_##class_name) \
24 AFX_CLASSINIT _init_##class_name(RUNTIME_CLASS(class_name)); \
25 CArchive & AFXAPI operator >> (CArchive & ar, class_name * & pOb) \
26 { pOb = (class_name*) ar.ReadObject(RUNTIME_CLASS(class_name)); \
27 return ar; } \
28
29 // generate static object constructor for class registration
30 void AFXAPI AfxClassInit(CRuntimeClass * pNewClass);
31 struct AFX_CLASSINIT
32 { AFX_CLASSINIT(CRuntimeClass* pNewClass) { AfxClassInit(pNewClass); } } ;
33
34 void AFXAPI AfxClassInit(CRuntimeClass * pNewClass)
35 {
36 AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
37 AfxLockGlobals(CRIT_RUNTIMECLASSLIST);
38 pModuleState->m_classList.AddHead(pNewClass);
39 AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
40 }
41
42
43 #define _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew, class_init) \
44 CRuntimeClass * PASCAL class_name::_GetBaseClass() \
45 { return RUNTIME_CLASS(base_class_name); } \
46 AFX_COMDAT CRuntimeClass class_name:: class ##class_name = { \
47 #class_name, sizeof(class class_name), wSchema, pfnNew, \
48 &class_name::_GetBaseClass, NULL, class_init } ; \
49 CRuntimeClass * PASCAL class_name::GetThisClass() \
50 { return _RUNTIME_CLASS(class_name); } \
51 CRuntimeClass * class_name::GetRuntimeClass() const \
52 { return _RUNTIME_CLASS(class_name); } \
53
54 #define _RUNTIME_CLASS(class_name) ((CRuntimeClass*)(&class_name::class##class_name))
55
56 #define RUNTIME_CLASS(class_name) (class_name::GetThisClass())
2 protected :
3 static CRuntimeClass * PASCAL _GetBaseClass();
4 public :
5 static CRuntimeClass classCStroke;
6 static CRuntimeClass * PASCAL GetThisClass();
7 virtual CRuntimeClass * GetRuntimeClass() const ;
8 static CObject * PASCAL CreateObject();
9 AFX_API friend CArchive & AFXAPI operator >> (CArchive & ar, CStroke * & pOb);
10 // implement file
11 // static
12 static CObject * PASCAL CStroke::CreateObject()
13 {
14 return new CStroke;
15 }
16 // static
17 static CRuntimeClass * PASCAL CStroke::GetThisClass();
18 {
19 return ((CRuntimeClass*)(&CStroke::classCStroke))
20 }
21 // static
22 static CRuntimeClass * PASCAL CStroke::_GetBaseClass()
23 {
24 return (CObject::GetThisClass());
25 }
26 // static
27 static AFX_COMDAT CRuntimeClass CStroke::classCStroke =
28 {
29 "CStroke"
30 , sizeof(class CStroke)
31 , 1
32 , CStroke::CreateObject
33 , &class_name::_GetBaseClass
34 , NULL
35 , &_init_CStroke
36 } ;
37 CRuntimeClass * CStroke::GetRuntimeClass() const
38 {
39 return ((CRuntimeClass*)(&CStroke::classCStroke));
40 }
41 extern struct AFX_CLASSINIT _init_CStroke;
42 struct AFX_CLASSINIT _init_CStroke
43 {
44 void AFXAPI AfxClassInit(CRuntimeClass* CStroke)
45 {
46 AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
47 AfxLockGlobals(CRIT_RUNTIMECLASSLIST);
48 pModuleState->m_classList.AddHead(CStroke);
49 AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
50 }
51 } ;
52 CArchive & AFXAPI operator >> (CArchive & ar, class_name * & pOb)
53 {
54 pOb = (CStroke*) ar.ReadObject(RUNTIME_CLASS(CStroke));
55 return ar;
56 }
CStroke::classCStroke =
{
"CStroke"
, sizeof(class CStroke)
, 1
, CStroke::CreateObject
, &class_name::_GetBaseClass
, NULL
, &_init_CStroke
}
其中,由extern AFX_CLASSINIT _initCStroke可知_init_CStroke是一个结构体AFX_CLASSINIT的对象,此结构体有构造函数:
2 struct AFX_CLASSINIT
3 { AFX_CLASSINIT(CRuntimeClass* pNewClass) { AfxClassInit(pNewClass); } } ;
4
5 void AFXAPI AfxClassInit(CRuntimeClass * pNewClass)
6 {
7 AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
8 AfxLockGlobals(CRIT_RUNTIMECLASSLIST);
9 pModuleState->m_classList.AddHead(pNewClass);
10 AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
11 }