在我们编写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++程序员来说,是值得学习的啊