windows 截取消息

来源:互联网 发布:leetcode题解 java版 编辑:程序博客网 时间:2024/06/10 01:55
先概述一下消息:

在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是基于控件的。



 

 

 

原创粉丝点击