消息和事件的传递、分发、相应
既然没有真实的窗口,那么也就不能使用windows的根据句柄来分发消息的方式了,我们需要创建自己的消息和事件分发体系。主要应该包括这几个方面:
1. 接收真实窗口的消息,并将其转化虚窗口体系中的处理
2. 虚窗口体系内有一套独立的消息分发机制,可以讲系统消息发至该接收的控件
3. 虚窗口需要能够抛出事件的能力,因为虚窗口之间也需要有相互的通知和相应的能力,那么就需要虚窗口可以对于指定窗口抛出事件
4. 对于3中所抛出的事件,可以传递到指定的控件,并且控件内部应该有一套指定额相应体系
在CBkDialogViewImpl中使用WTL的消息分发方法用于系统消息的分发:
BEGIN_MSG_MAP_EX(CBkDialogViewImpl)
MESSAGE_RANGE_HANDLER_EX(WM_MOUSEFIRST, WM_MOUSELAST,OnToolTipEvent)
MSG_WM_SIZE(OnSize)
MSG_WM_PRINT(OnPrint)
MSG_WM_PAINT(OnPaint)
//……从略
NOTIFY_CODE_HANDLER_EX(BKINM_INVALIDATERECT, OnBKINMInvalidateRect)
REFLECT_NOTIFY_CODE(NM_CUSTOMDRAW)
MESSAGE_HANDLER_EX(WM_NOTIFY, OnChildNotify)
MESSAGE_HANDLER_EX(WM_COMMAND, OnChildNotify)
MESSAGE_HANDLER_EX(WM_VSCROLL, OnChildNotify)
MESSAGE_HANDLER_EX(WM_HSCROLL, OnChildNotify)
REFLECT_NOTIFICATIONS_EX()
END_MSG_MAP()
下面的是对于WM_SIZE消息的分发过程:
在CBkWindow类中创建了用于发送通知的函数:
// Send a message to BkWindow
LRESULT BkSendMessage(UINT Msg, WPARAM wParam =0, LPARAM lParam= 0)
{
LRESULT lResult= 0;
if ( Msg < WM_USER
&&Msg != WM_DESTROY
&&Msg != WM_CLOSE
)
{
TestMainThread();
}
SetMsgHandled(FALSE);
ProcessWindowMessage(NULL, Msg, wParam, lParam,lResult);
return lResult;
}
这个函数很像windows的消息发送函数SendMessage,
LRESULT SendMessage(HWND hWnd, UINT Msg,WPARAM wParam, LPARAM IParam)
需要向那个对象发送消息,那么首先需要获取这个对象,然后调用这个对象的BkSendMessage函数,用消息类型和附属参数填充,就可以完成事件通知的过程了。
在这个函数中调用了ProcessWindowMessage方法,但是我们并没有看见这个函数的实现,我们来找一下哈~~
我们点击调用栈里面的ProcessWindowMessage方法,程序转到了CBkWindow类的这块:
BKWIN_BEGIN_MSG_MAP()
MSG_WM_CREATE(OnCreate)
MSG_WM_PAINT(OnPaint)
MSG_WM_DESTROY(OnDestroy)
MSG_WM_WINDOWPOSCHANGED(OnWindowPosChanged)
MSG_WM_NCCALCSIZE(OnNcCalcSize)
MSG_WM_SHOWWINDOW(OnShowWindow)
BKWIN_END_MSG_MAP_BASE()
难道就是这串宏实现了实现了通知的相应机制,我们来分析一下这个几个宏的实现。
// BkWindow Message MapDefine
// Use WTL Message Map Ex(include atlcrack.h)
#define BKWIN_BEGIN_MSG_MAP() \
protected: \
virtual BOOL ProcessWindowMessage( \
HWND hWnd,UINT uMsg,WPARAM wParam, \
LPARAM lParam,LRESULT& lResult) \
{ \
#define BKWIN_END_MSG_MAP() \
if (!IsMsgHandled()) \
return__super::ProcessWindowMessage( \
hWnd,uMsg, wParam,lParam, lResult); \
return TRUE; \
} \
#define BKWIN_END_MSG_MAP_BASE() \
return TRUE; \
} \
上面的是自定义的,而其他则是使用的WTL的宏,如:
// intOnCreate(LPCREATESTRUCT lpCreateStruct)
#define MSG_WM_CREATE(func)\
if (uMsg == WM_CREATE) \
{\
SetMsgHandled(TRUE);\
lResult = (LRESULT)func((LPCREATESTRUCT)lParam); \
if(IsMsgHandled())\
return TRUE; \
}
我们将宏展开看一下就是:
protected:
virtualBOOL ProcessWindowMessage(
HWND hWnd, UINT uMsg, WPARAM wParam,
LPARAM lParam, LRESULT& lResult)
{
if(uMsg == WM_CREATE)
{
SetMsgHandled(TRUE);
lResult= (LRESULT) OnCreate ((LPCREATESTRUCT)lParam);
if(IsMsgHandled())
returnTRUE;
}
//......此处略去其他分发函数
return TRUE;
}
可见就是给每个虚窗口类增加了一个函数ProcessWindowMessage,而这个函数的作用就是根据发送通知的不同来选择处理的函数,也就是BkSendMessageàProcessWindowMessageà根据消息的不同选择不同的处理函数,并且这个函数和消息我们可以自己进行搭配的,可能是为了简便使用了系统消息宏,其实我们也可以自己进行定义的。比如定义一个消息为BKM_CREATE,那么定义一个宏:
#define MSG_BKM_CREATE(func)\
if (uMsg == BKM_CREATE) \
{\
SetMsgHandled(TRUE);\
lResult = (LRESULT)func((LPCREATESTRUCT)lParam); \
if(IsMsgHandled())\
return TRUE; \
}
就可以自己来定义通知的类型了。
对于CBkWindow,因为它是所有虚窗口的基类,所以消息处理到此为止,ProcessWindowMessage函数最后什么都没做,使用了BKWIN_END_MSG_MAP_BASE宏。
在CBkWindow子类中,我们将BKWIN_END_MSG_MAP_BASE替换为BKWIN_END_MSG_MAP,那么宏展开了就是:
protected:
virtualBOOL ProcessWindowMessage(
HWND hWnd, UINT uMsg, WPARAM wParam,
LPARAM lParam, LRESULT& lResult)
{
if(uMsg == WM_CREATE)
{
SetMsgHandled(TRUE);
lResult= (LRESULT)func((LPCREATESTRUCT)lParam);
if(IsMsgHandled())
returnTRUE;
}
//......此处略去其他分发函数
if (!IsMsgHandled())
return__super::ProcessWindowMessage(
hWnd, uMsg, wParam, lParam,lResult);
return TRUE;
}
__super::ProcessWindowMessage完整的链式消息传递啊~~,对于子类处理之后的消息还行传递给父类进行处理就可以这么搞了~~~