消息映射机制的简单实现

项目中使用了消息通信机制,因为消息类型非常多,相应的,处理消息的地方代码也非常多。  
自然而然想到MFC中的消息映射:  
创建一个缺省MFC框架程序的解决方案Test,在Test.h中看到以下内容:  
class Ctest_mfcApp : public CWinApp
{
public:
    Ctest_mfcApp();  
// 重写
public:
    virtual BOOL InitInstance();  
// 实现
    afx_msg void OnAppAbout();
    DECLARE_MESSAGE_MAP()
};  
 
其中,最紧要的就是DECLARE_MESSAGE_MAP()这个宏,相关内容展开如下:  
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 #
    AFX_PMSG pfn;    // routine to call (or special value)
};  
struct AFX_MSGMAP
{
    const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();
    const AFX_MSGMAP_ENTRY* lpEntries;
};  
#define DECLARE_MESSAGE_MAP() /
protected: /
    static const AFX_MSGMAP* PASCAL GetThisMessageMap(); /
    virtual const AFX_MSGMAP* GetMessageMap() const; /  
其中AFX_PMSG不再解析下去,我们认为这是一个指向特定消息对应的实现函数函数指针,这几个宏的作用可简单理解成为Test这个项目定义了一个静态的消息映射表。当消息到来时,从消息队列中弹出消息并分发到具有入口实现的上层CWnd派生窗口。用户只需要注册消息,实现消息入口函数就够了,这在MFC中一般放在.cpp文件头部。Test.cpp中头部有以下内容:  
BEGIN_MESSAGE_MAP(CTest, CWinApp)
    ON_COMMAND(ID_APP_ABOUT, &CTest::OnAppAbout)
    // 基于文件的标准文档命令
    ON_COMMAND(ID_FILE_NEW, &CWinApp::OnFileNew)
    ON_COMMAND(ID_FILE_OPEN, &CWinApp::OnFileOpen)
    // 标准打印设置命令
    ON_COMMAND(ID_FILE_PRINT_SETUP, &CWinApp::OnFilePrintSetup)
END_MESSAGE_MAP()  
这里是为消息枚举值与消息实现函数建立映射,其中涉及到的宏的展开如下:
#define ON_COMMAND(id, memberFxn) /
    { WM_COMMAND, CN_COMMAND, (WORD)id, (WORD)id, AfxSigCmd_v, /
        static_cast<AFX_PMSG> (memberFxn) },  
#define BEGIN_MESSAGE_MAP(theClass, baseClass) /
    PTM_WARNING_DISABLE /
    const AFX_MSGMAP* theClass::GetMessageMap() const /
        { return GetThisMessageMap(); } /
    const AFX_MSGMAP* PASCAL theClass::GetThisMessageMap() /
    { /
        typedef theClass ThisClass;                           /
        typedef baseClass TheBaseClass;                       /
        static const AFX_MSGMAP_ENTRY _messageEntries[] =  /
        {  
#define END_MESSAGE_MAP() /
        {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } /
    }; /
        static const AFX_MSGMAP messageMap = /
        { &TheBaseClass::GetThisMessageMap, &_messageEntries[0] }; /
        return &messageMap; /
    }                                  /
    PTM_WARNING_RESTORE  
按照上述思路得到的相似代码如下:
// Test.h
typedef void (* funCall)(void*);        // 消息执行函数类型  
struct tagMsgEntry                      // 消息入口结构
{
    int            nMsgType;            // 消息类型
    funCall        MsgRun;              // 消息执行函数
};  
struct tagMsgMap                        // 消息映射表结构
{
    const tagMsgMap* (__stdcall* funGetBaseMsgMap)();
    const tagMsgEntry* pMsgEntries;     // 消息入口集
};  
class CMessage
{
    // ...
protected:
    static const tagMsgMap* __stdcall GetThisMsgMap();
    virtual const tagMsgMap* GetMsgMap() const;
};  
// Test.cpp
const tagMsgMap* CMessage::GetMsgMap() const
{
    return GetThisMsgMap();
}  
const tagMsgMap* __stdcall CMessage::GetThisMsgMap()
{
    static const tagMsgEntry MsgEntries[] =
    {
        { MSG_SOME_ONE, SomeOneFunc },
        { MSG_SOME_TWO, SomeTwoFunc },
        { MSG_NULL, NULL }
    };
    static const tagMsgMap msgMap =
    {
        &CBaseMessage::GetThisMsgMap,    // 父类消息映射表
        &MsgEntries[0]
    };
    return &msgMap;
}
int CMessage::MsgProc(int nMsgType)
{
    switch( nMsgType )
    {
    case MSG_SOME_ONE:
        {  
        }
        break;
    }
    return CBaseMessage::MsgProc(nMsgType);
}  
这种处理的优点在于,子类没有定义的消息实现接口,可以使用父类接口实现。不过在现在的消息处理中,我们一般不需要由基类来完成,因此可以不依赖基类接口,使用宏可以使代码看上去更加简洁。  
___________________________________________________________  
简化版本的消息映射采用以下方式,简单清晰:  
// Test.h
#define REG_MSG_FUNC(nMsgType, MsgFunc) /
    CMessge::RegisterCallFunc(nMsgType, MsgFunc); /  
typedef void (* function)(void*);  
typedef std::map<int, function> MSG_MAP;
typedef MSG_MAP::const_iterator MSG_CITR;  
class CMessage
{
    // ...
public:
    static const MSG_MAP& GetMsgMap();
    static void RegisterCallFunc(int nMsgType, void(* Func)(void *))
    {
        s_MsgMap[nMsgType] = Func;
    }  
    int CMessage::Run(int nMsgType)                // 消息公用执行函数
    {
        MSG_ITR itr = s_MsgMap.find(nMsgType);
        if( s_MsgMap.end() != itr )
        {
            itr->second(this);
        }
    }  
protected:
    static MSG_MAP            s_MsgMap;            // 消息映射表
};  
// UserTest.cpp -- 用户在使用时对自己关心的消息予以注册, 入口函数予以实现即可
REG_MSG_FUNC(MSG_SOME_ONE, SomeOneFunc)  
void SomeOneFunc(CBaseMessage *pMsg)
{
    return;
}  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值