看看MFC自动的宏

来源:互联网 发布:ubuntu软件安装 编辑:程序博客网 时间:2024/06/06 16:58

面对MFC自动生成的宏,我需要深刻的理解其内容。

摘自: http://blog.csdn.net/strmagic/archive/2007/11/19/1892785.aspx

 

一、关于DECLARE_MESSAGE_MAP宏定义

使用MFC向导,在ApplicationType页面选择DialogBased,生成一个对话框项目,Dialog类命名为CCapturePacketDlg,在CCapturePacketDlg.cpp中自动产生下列代码:

 

1  BEGIN_MESSAGE_MAP(CCapturePacketDlg, CDialog)

2     ON_WM_PAINT()

3 END_MESSAGE_MAP() 

先来分析ON_WM_PAINT(),在头文件“afxmsg.h”有它的宏定义,如下: 

1  #define  ON_WM_PAINT() / 

2        { WM_PAINT,  0 ,  0 ,  0 , AfxSig_vv, /

3         (AFX_PMSG)(AFX_PMSGW) /

4         (static_cast <   void  (AFX_MSG_CALL CWnd:: * )( void )  >  (  & ThisClass :: OnPaint)) } , 说明:层次序号x.y.z表示x为根节点也就是上面代码中的行号,y、z为上一级的定义展开。

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()完全展开:

1{

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”中有定义:

 

 

 1#define BEGIN_MESSAGE_MAP(theClass, baseClass) /

 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)完全展开:

 

 

 1__pragma(warning( push )) __pragma(warning( disable : 4867 ))

 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”中有定义:

 

 

1#define END_MESSAGE_MAP() /

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.

 

·最后将

 

1BEGIN_MESSAGE_MAP(CCapturePacketDlg, CDialog)

2    ON_WM_PAINT()

3END_MESSAGE_MAP()完全展开为:

 1__pragma(warning( push )) __pragma(warning( disable : 4867 ))

 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其中GetMessageMap()是在哪里声明的呢?在CCapturePacketDlg的定义中有一个这样的宏:DECLARE_MESSAGE_MAP()

老办法查看它的定义:

1#define DECLARE_MESSAGE_MAP() /

2protected: /

3    static const AFX_MSGMAP* PASCAL GetThisMessageMap(); /

4    virtual const AFX_MSGMAP* GetMessageMap() const; /注意函数为static,即它们是类的函数。函数中的static变量实际也在类对象未生成之前已经存在。(这种说法不知道是否正确?)

小结:

每次用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):

1// not serializable, but dynamically constructable

2    #define DECLARE_DYNCREATE(class_name) /

3        DECLARE_DYNAMIC(class_name) /

4        static CObject* PASCAL CreateObject();3.1如下定义:

1#ifdef _AFXDLL

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; /so the result(DECLARE_DYNCREATE(CDynamicDoc)) of combining the above two is following:

1protected: 

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):

1#define IMPLEMENT_DYNCREATE(class_name, base_class_name) /

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)4.1如下定义:

 1#define IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew, class_init) /

 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); } /4.1.2 CRuntimeClass如下定义:

 1struct CRuntimeClass

 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    };4.1.2.30 AFX_CLASSINIT如下定义:(这个变量非常重要,它完成了将新的类加在List头部的功能,List中的节点类型就是CRuntimeClass)

 1/**//////////////////////////////////////////////////////////////////////////////

 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如下定义:

1#define RUNTIME_CLASS(class_name) (class_name::GetThisClass())4.1.4 AFX_COMDAT如下定义:

1#define AFX_COMDAT __declspec(selectany)说明:“#”——operator (#) converts macro parameters to string literals without expanding the parameter definition.

“##”——operator (##), which is sometimes called the "merging" operator, is used in both object-like and function-like macros. 

4.1.8 _RUNTIME_CLASS如下定义:

1#define _RUNTIME_CLASS(class_name) ((CRuntimeClass*)(&class_name::class##class_name))so the result(IMPLEMENT_DYNCREATE(CDynamicDoc, CDocument)) of combining the aboves is following:

 1//CDynamicDoc, CDocument->class_name, base_class_name

 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    }小结:注意了,上面的成员变量、很多函数都是static

如果你想看这些宏的简化版,可以参考侯老的《深入浅出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

};

三、宏DECLARE_SERIAL(CStroke)、IMPLEMENT_SERIAL(CStroke, CObject, 1),给出它们的宏定义及结果:

 1//declaration file

 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())

 1//header file

 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    }总结,一旦RUNTIME_CLASS(CStroke)由#define RUNTIME_CLASS(class_name) (class_name::GetThisClass())也就是CStroke::GetThisClass() 即

CStroke::classCStroke = 

 {

  "CStroke"

  , sizeof(class CStroke)

  , 1

  , CStroke::CreateObject

  , &class_name::_GetBaseClass

  , NULL

  , &_init_CStroke 

 }

其中,由extern AFX_CLASSINIT _initCStroke可知_init_CStroke是一个结构体AFX_CLASSINIT的对象,此结构体有构造函数:

 1void AFXAPI AfxClassInit(CRuntimeClass* pNewClass);

 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    }所以一旦返回classCStroke,也就调用了_init_CStroke的构造函数即将类CStroke添加到了全局变量m_classList类的List中了,同时在变量classCStroke中,也可以得到类CStroke的名称、大小、一个CStroke的对象、类CStroke的基类以及AFX_CLASSINIT结构的一个对象。   

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/strmagic/archive/2007/11/19/1892785.aspx

原创粉丝点击