解读ATL/WTL/MFC消息映射的实现方式

在我们编写WTL程序的时候,如下的消息映射我们很熟悉:

BEGIN_MSG_MAP(CMainDlg)
  MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
  COMMAND_ID_HANDLER(ID_CATALOG,OnSetCatalog)
  END_MSG_MAP()

在写MFC程序的时候,是如下的消息映射:

BEGIN_MESSAGE_MAP(CUpdateDlg, CDialog)
 ON_WM_PAINT()
 ON_WM_TIMER()
END_MESSAGE_MAP()

然后我们编写相应的消息函数,程序运行的时候就会被调用。

对我们初级程序员来说,我们有可能很少注意这些宏的实现方式,而仅仅关注在了会使用这些宏,并知道这些宏能做什么。

暂且不说它们的实现,看到这种实现方式足以很让我们这些初级程序员感到惊奇。

请闭上眼睛自问:如果让我实现一个有同样功能的程序框架,我会怎么做?

大部分人会首先想到一个结构switch(){case ...},不错,就像我们的哥哥姐姐们写WIN 32程序的时候,有一个大家都很熟悉的函数:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{

switch (message)
 {
 case WM_PAINT:

PAINT_FUN(...);

break;

case WM_MOUSEMOVE:

MOUSEMOVE_FUN(...);

break;

case WM_MOUSELEAVE:

MOUSELEAVE_FUN(...);

break;

....

default:

break;

}

如果再涉及到派生和继承,为了支持多态,就联想到虚函数,也许你会自然而然想到一个这样的类:

class COwnWnd

{

virtual LRESULT PAINT_FUN(...){...}

virtual LRESULT MOUSEMOVE_FUN(...){...}

....

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{

switch (message)
 {
 case WM_PAINT:

PAINT_FUN(...);

break;

case WM_MOUSEMOVE:

MOUSEMOVE_FUN(...);

break;

case WM_MOUSELEAVE:

MOUSELEAVE_FUN(...);

break;

....

default:

break;

}

};

然后在派生类里仅仅需要派生相应的虚函数就OK了。

恩,是的,可以达到要求;但在我们看WTL/MFC的程序的时候,我们发现他们用了来很巧妙的实现了这种方式

这可以通过查看WTL的源代码来查看:

我们发现所有的窗口类都继承了CMessageMap类,而这个类到底做了什么呢?下面是这个类的源代码:

class ATL_NO_VTABLE CMessageMap
{
public:
 virtual BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
  LRESULT& lResult, DWORD dwMsgMapID) = 0;
};

哦,原来它仅仅提供了一个纯虚函数,继续看,我们会发现这个重要的宏:

#define BEGIN_MSG_MAP(theClass) /
public: /
 BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = 0) /
 { /
  BOOL bHandled = TRUE; /
  (hWnd); /
  (uMsg); /
  (wParam); /
  (lParam); /
  (lResult); /
  (bHandled); /
  switch(dwMsgMapID) /
  { /
  case 0:

#define ALT_MSG_MAP(msgMapID) /
  break; /
  case msgMapID:

#define MESSAGE_HANDLER(msg, func) /
 if(uMsg == msg) /
 { /
  bHandled = TRUE; /
  lResult = func(uMsg, wParam, lParam, bHandled); /
  if(bHandled) /
   return TRUE; /
 }

#define MESSAGE_RANGE_HANDLER(msgFirst, msgLast, func) /
 if(uMsg >= msgFirst && uMsg <= msgLast) /
 { /
  bHandled = TRUE; /
  lResult = func(uMsg, wParam, lParam, bHandled); /
  if(bHandled) /
   return TRUE; /
 }

#define COMMAND_HANDLER(id, code, func) /
 if(uMsg == WM_COMMAND && id == LOWORD(wParam) && code == HIWORD(wParam)) /
 { /
  bHandled = TRUE; /
  lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); /
  if(bHandled) /
   return TRUE; /
 }

#define COMMAND_ID_HANDLER(id, func) /
 if(uMsg == WM_COMMAND && id == LOWORD(wParam)) /
 { /
  bHandled = TRUE; /
  lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); /
  if(bHandled) /
   return TRUE; /
 }

#define COMMAND_CODE_HANDLER(code, func) /
 if(uMsg == WM_COMMAND && code == HIWORD(wParam)) /
 { /
  bHandled = TRUE; /
  lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); /
  if(bHandled) /
   return TRUE; /
 }

#define COMMAND_RANGE_HANDLER(idFirst, idLast, func) /
 if(uMsg == WM_COMMAND && LOWORD(wParam) >= idFirst  && LOWORD(wParam) <= idLast) /
 { /
  bHandled = TRUE; /
  lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); /
  if(bHandled) /
   return TRUE; /
 }

#define COMMAND_RANGE_CODE_HANDLER(idFirst, idLast, code, func) /
 if(uMsg == WM_COMMAND && code == HIWORD(wParam) && LOWORD(wParam) >= idFirst  && LOWORD(wParam) <= idLast) /
 { /
  bHandled = TRUE; /
  lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); /
  if(bHandled) /
   return TRUE; /
 }

#define NOTIFY_HANDLER(id, cd, func) /
 if(uMsg == WM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom && cd == ((LPNMHDR)lParam)->code) /
 { /
  bHandled = TRUE; /
  lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); /
  if(bHandled) /
   return TRUE; /
 }

#define NOTIFY_ID_HANDLER(id, func) /
 if(uMsg == WM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) /
 { /
  bHandled = TRUE; /
  lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); /
  if(bHandled) /
   return TRUE; /
 }

#define NOTIFY_CODE_HANDLER(cd, func) /
 if(uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code) /
 { /
  bHandled = TRUE; /
  lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); /
  if(bHandled) /
   return TRUE; /
 }

#define NOTIFY_RANGE_HANDLER(idFirst, idLast, func) /
 if(uMsg == WM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) /
 { /
  bHandled = TRUE; /
  lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); /
  if(bHandled) /
   return TRUE; /
 }

#define NOTIFY_RANGE_CODE_HANDLER(idFirst, idLast, cd, func) /
 if(uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) /
 { /
  bHandled = TRUE; /
  lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); /
  if(bHandled) /
   return TRUE; /
 }

#define CHAIN_MSG_MAP(theChainClass) /
 { /
  if(theChainClass::ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult)) /
   return TRUE; /
 }

#define CHAIN_MSG_MAP_MEMBER(theChainMember) /
 { /
  if(theChainMember.ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult)) /
   return TRUE; /
 }

#define CHAIN_MSG_MAP_ALT(theChainClass, msgMapID) /
 { /
  if(theChainClass::ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult, msgMapID)) /
   return TRUE; /
 }

#define CHAIN_MSG_MAP_ALT_MEMBER(theChainMember, msgMapID) /
 { /
  if(theChainMember.ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult, msgMapID)) /
   return TRUE; /
 }

#define CHAIN_MSG_MAP_DYNAMIC(dynaChainID) /
 { /
  if(CDynamicChain::CallChain(dynaChainID, hWnd, uMsg, wParam, lParam, lResult)) /
   return TRUE; /
 }

#define END_MSG_MAP() /
   break; /
  default: /
   ATLTRACE(ATL::atlTraceWindowing, 0, _T("Invalid message map ID (%i)/n"), dwMsgMapID); /
   ATLASSERT(FALSE); /
   break; /
  } /
  return FALSE; /
 }

这个宏,会提供一个具体的ProcessWindowMessage函数,来重写那个纯虚函数。

如果有一个这样的类:

class test:public CMessageMap
{

//当你写下这对宏的时候,你已经提供了一个具体的ProcessWindowMessage函数

BEGIN_MSG_MAP(test)

//添加相应的消息映射

END_MSG_MAP()

}

哦,原来如此,那就让我们模拟一下这种实现方式吧!

//msg
#define OWN_MSG_1 0x1
#define OWN_MSG_2 0x2
#define OWN_MSG_3 0x3
//cmd
#define OWN_CMD_1 0x4
#define OWN_CMD_2 0x5
#define OWN_CMD_3 0x6

class COwnMessageMap//
{
public:
 virtual int DefaultWinProc(unsigned int uMsg,char* wParam,char* lParam)=0;//关键的纯虚函数
 void _Run()
 {
  int i=0;
  char str[3]={0};
  while(1)//模拟GetMsg
  {
   _sleep(1000);
   sprintf(str,"%d",i);
   DefaultWinProc(i,str,str);
   i++;
   if(i>10)
    break;
  }
 }
}; 

#define BEGIN_OWN_MAP(theClass) /
 int DefaultWinProc(unsigned int uMsg,char* wParam,char* lParam) /
 {/

  #define MSG_HANDLER(msg,function) /
   if(uMsg==msg) /
   {/
    return function(wParam,lParam); /
   }/

  #define CMD_HANDLER(msg,function) /
   if(uMsg==msg) /
   {/
    return function(uMsg,wParam,lParam); /
   }/

  #define END_OWN_MAP()/
   return 1;/
 }

class COwnWnd:public COwnMessageMap
{
 BEGIN_OWN_MAP(COwnWnd)
  MSG_HANDLER(OWN_MSG_1,OnMsg1)
  MSG_HANDLER(OWN_MSG_3,OnMsg3)
  CMD_HANDLER(OWN_CMD_1,OnCmd1)
  CMD_HANDLER(OWN_CMD_2,OnCmd)
  CMD_HANDLER(OWN_CMD_3,OnCmd)
 END_OWN_MAP()
 int OnMsg1(char* wp,char* lp)
 {
  printf("Msg/t");
  printf(wp);
  printf("/n");
  return 1;
 }
 int OnMsg3(char* wp,char* lp)
 {
  printf("MSG/t");
  printf(wp);
  printf("/n");
  return 1;
 }
 int OnCmd1(unsigned int id,char* wp,char* lp)
 {
  printf("command id:%x/t",id);
  printf("CMD/t");
  printf(wp);
  printf("/n");
  return 1;
 }
 int OnCmd(unsigned int id,char* wp,char* lp)
 {
  printf("command id:%d/t",id);
  printf("CMD/t");
  printf(wp);
  printf("/n");
  return 1;
 }
};

int _tmain(int argc, _TCHAR* argv[])
{
 COwnWnd Wnd;
 Wnd._Run();
 getchar();
 return 0;
}

运行结果:

Msg    1

Msg    3

command id:4   CMD   4

command id:5   CMD   5

command id:6   CMD   6

宏特别是对C/C++程序员来说,是值得学习的啊

猜你喜欢

转载自blog.csdn.net/lvxb_tiger/article/details/2160022
今日推荐