windows 截取消息

先概述一下消息:

在API中:在消息隊列中GetMessage,然後調用TranslateMessage,再然後分發消息DispatchMessage

在MFC中:由於它把很多過程都封裝了,所以我們都看不到了。但是它爲我們留下了藉口供我們調用,例如:PreTranslateMessage,我們在系統處理消息前,截取這個消息;

在編程的過程中,我們可能經常去琢磨windows的內部實現,它是如何封裝的。在這裏我把這幾天的東西梳理一下,是關於消息的。

從產生消息開始:

消息的來源:

1.系統  就是在合適的時候,系統發送給程序的消息  例如 發送WM_CREATE

2.程序員  程序員通過調用函數,發送消息 調用:SendMessage,PostMessage

3.用戶  用戶通過與程序交互產生消息  。點擊控件

這些消息都被送入消息對列(某些消息不進對列,不說了,還有SendMessage不進隊列)

獲取消息:

調用GetMessage,從消息隊列中獲取消息,之後就該處理了

轉換消息

TranslateMessage:該函數將虛擬鍵消息轉換爲字符消息。字符消息被寄送到調用線程的消息隊列裏,當下一次線程調用函數GetMessage或PeekMessage時被讀出.(這個東西沒有遇到過關於這方面的問題,所以不太關注)。

分發消息:

調用DispatchMessage,這個函數值得深度解析一下

我看windows核心編程的時候,看到部分關於這個函數的代碼,它調用過程函數,處理消息。那麼在過程函數中,程序是如何處理的呢?

查看MFC消息宏的時候,我們可以看出它是一個2維數組,記錄相關的信息。

 

#define ON_NOTIFY(wNotifyCode, id, memberFxn) \
	{ WM_NOTIFY, (WORD)(int)wNotifyCode, (WORD)id, (WORD)id, AfxSigNotify_v, \
		(AFX_PMSG) \
		(static_cast< void (AFX_MSG_CALL CCmdTarget::*)(NMHDR*, LRESULT*) > \
		(memberFxn)) },

#define ON_NOTIFY_RANGE(wNotifyCode, id, idLast, memberFxn) \
	{ WM_NOTIFY, (WORD)(int)wNotifyCode, (WORD)id, (WORD)idLast, AfxSigNotify_RANGE, \
		(AFX_PMSG) \
		(static_cast< void (AFX_MSG_CALL CCmdTarget::*)(UINT, NMHDR*, LRESULT*) > \
		(memberFxn)) },
 ON_NOTIFY(TVN_SELCHANGED, IDC_TREE_DIR, &CFileManagerDlg::OnTvnSelchangedTreeDir)
 ON_NOTIFY(NM_DBLCLK, IDC_LIST_INFO, &CFileManagerDlg::OnDblclkListInfo)
 ON_BN_CLICKED(IDC_BUTTON_OK, &CFileManagerDlg::OnBnClickedButtonOk)
 ON_NOTIFY(NM_RCLICK, IDC_LIST_INFO, &CFileManagerDlg::OnRclickListInfo)
 

看到這個宏,我們可以看出後面的東西懂事被存儲到數組裏面。等待過程函數來查詢處理。我之前寫了一個日誌:關於消息與通知關係。看看這裏的定義可以知道,通知只是WM_NOTIFY消息中的一個變量(MSG的一個成員),來標識通知類型。

在過程函數處理消息的時候,會根據消息的類型,把MSG的信息進行分類處理,然後把調用函數消息函數,並把處理的信息通過參數傳入。就OK了。

好了,應該就這麼多了

PS:昨天回去之後,突然又想到,窗口是如何處理控件消息的?

我找了一個宏定義查看了一下:

ON_NOTIFY(NM_RCLICK, IDC_LIST_INFO, &CFileManagerDlg::OnRclickListInfo)
 
#define ON_NOTIFY(wNotifyCode, id, memberFxn) \
	{ WM_NOTIFY, (WORD)(int)wNotifyCode, (WORD)id, (WORD)id, AfxSigNotify_v, \
	(AFX_PMSG) \
	(static_cast< void (AFX_MSG_CALL CCmdTarget::*)(NMHDR*, LRESULT*) > \
	(memberFxn)) },

結合一下可以看出: 當子控件產生一個WM_NOTIFY(NM_RCLICK通知類型)消息時,被髮送到主窗口,儘管是控件產生的消息,但是卻不是這個控件處理的,由主窗口處理。

說個有意思的事,本來打算通過鼠標的位置,獲取被指的CListCtrl的項。然後我就在主窗口添加了一個WM_MOUSEMOVE消息。這個消息的句柄就是主窗口,我在列表上怎麼移動都不會執行我關聯的函數,很是鬱悶。我仔細想了一下,原因就是:鼠標放在控件上,只會發生WM_NOTIFY消息,所以主窗口當然無法接收到鼠標移動的消息了。於是我想了一個損招。在PreTranslateMessage消息中,截取WM_MOUSEMOVE消息(這個消息實際上是子控件的消息),把句柄修改爲主窗口的句柄。然後主窗口就可以處理這個消息了,不過Point是基於控件的。



 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章