MFC的消息处理如何工作?
当你的窗口收到一个消息的时候,MFC将会调用你的类中的成员函数。但是MFC是如何知道那个函数应该被调用的呢?
MFC用了一个叫做消息映射的技术。消息映射是一张用来联系消息和函数的表。当你收到一个消息的时候,MFC将会通过你的消息映射表来查找对应的消息响应。我已经在第一章展示了你应该如何利用Classwizard来添加消息响应的,但是真正的代码做了些什么。
MFC利用了大量的而且相当复杂的宏来添加到你的消息映射到你的类中。当你用Classwizard去创建消息响应的时候,它首先添加函数到你的类中,然后添加响应宏到你的消息映射表中。例如,观察利用Classwizard生成WM_CLOSE的消息响应。
消息映射表:在你的类实现中。
函数声明:在类声明处
函数的实现:在类的实现处
通过增加
所有可能的ON_MESSAGE
有时候你会发现你试图添加的消息处理是Classwizard不支持的,它都没有消息映射宏。MFC有一个通用宏ON_MESSAGE来应对这种情况。ON_MESSAGE允许你处理任何存在的消息。消息处理ON_MESSAGE的原型是
有的时候,你需要在你的应用程序的两个窗口中,或者是在不同的应用程序中通信。一种简单的方式就是通过用户自定义消息。开始的时候,名字是“用户自定义”会造成迷惑,你定义一个用户自定义消息,而不是你的程序的用户。我在第一章已经描述过了消息是是数字定义的,Windows可以预先定义一些标准的消息。这种预先定义的消息是用数字来标识的。为了确保你定义的用户自定义消息不会和系统预定义好的消息冲突,你应该在WM_APP的范围通过0xBFFF:
当你的窗口收到一个消息的时候,MFC将会调用你的类中的成员函数。但是MFC是如何知道那个函数应该被调用的呢?
MFC用了一个叫做消息映射的技术。消息映射是一张用来联系消息和函数的表。当你收到一个消息的时候,MFC将会通过你的消息映射表来查找对应的消息响应。我已经在第一章展示了你应该如何利用Classwizard来添加消息响应的,但是真正的代码做了些什么。
MFC利用了大量的而且相当复杂的宏来添加到你的消息映射到你的类中。当你用Classwizard去创建消息响应的时候,它首先添加函数到你的类中,然后添加响应宏到你的消息映射表中。例如,观察利用Classwizard生成WM_CLOSE的消息响应。
消息映射表:在你的类实现中。
- BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
- //{{AFX_MSG_MAP(CAboutDlg)
- ON_WM_CLOSE()
- //}}AFX_MSG_MAP
- END_MESSAGE_MAP()
- BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
- //{{AFX_MSG_MAP(CAboutDlg)
- ON_WM_CLOSE()
- //}}AFX_MSG_MAP
- END_MESSAGE_MAP()
- void CAboutDlg::OnClose()
- {
- // TODO: Add your message handler code here and/or call default
- CDialog::OnClose();
- }
DECLARE_MESSAGE_MAP宏 到类的声明中,MFC增加了必须的的代码来声明消息映射表。
BEGIN_MESSAGE_MAP宏告诉MFC消息映射表从那里开始,同时识别出你的类和其基类。它需要基类的原因是消息响应也是通过C++的继承来的,就像其他函数一样。
END_MESSAGE_MAP宏显示的告诉MFC消息映射表从哪里结束。在这两个宏之中就是你的消息映射的入口。MFC有很多预先定义的宏,用来联系你的成员函数。用
ON_WM_CLOSE
宏当个例子:它联系了
WM_CLOSE消息和你的
OnClose()成员函数。这个宏没有带参数,因为它总是可以预料得到去调用OnClose(),一个是
afx_msg void OnClose()
原型的函数。这种想法有两个好处:
1.可以很容易联系消息和消息处理
2.MFC可以筛选出来不相干的,可以接散开lParam和wParam 参数到相关的消息
同时返回值也很简单,消息处理是相对于消息的雏形。例如:如果返回值总是0,MFC简化了这个过程,要求你把函数声明为void类型,同时MFC将会响应返回0.为了正确的找到消息处理宏对应消息响应的名字,你应该查看MFC的文档。
这里有一些消息是Classwizard不支持的,但是你可以手动添加消息处理,通过添加如上面所叙述的函数和消息映射宏来实现。如果你手动添加消息映射入口,你可能不能再用Classwizard进行编辑。如果你添加他们到
//{{AFX_MSG_MAP(classname)
and
//}}AFX_MSG_MAP的外面
,那么你的Classwizard将会不能够编辑了。注意:处于同样原因Classwizard都将不能够得到你写在注解外面入口,如果你不想它们被修改,那么就把消息加载到任意地方。消息不能够被Classwizard识别出来,比如消息映射的范围,肯定会被加到注解的外面。
所有可能的ON_MESSAGE
有时候你会发现你试图添加的消息处理是Classwizard不支持的,它都没有消息映射宏。MFC有一个通用宏ON_MESSAGE来应对这种情况。ON_MESSAGE允许你处理任何存在的消息。消息处理ON_MESSAGE的原型是
- afx_msg LRESULT OnMessage(WPARAM wParam, LPARAM lParam);
当OnMessage是你的消息处理函数的时候。这个ON_MESSAGE带有两个参数:处理器的地址,和需要处理的消息。例如:有如下的映射
WM_GETTEXTLENGTH到
OnGetTextLength()
:
- ON_MESSAGE (WM_GETTEXTLENGTH, OnGetTextLength)
OnGetTextLength的原型是
- afx_msg LRESULT OnGetTextLength(WPARAM wParam, LPARAM lParam);
用户自定义消息
有的时候,你需要在你的应用程序的两个窗口中,或者是在不同的应用程序中通信。一种简单的方式就是通过用户自定义消息。开始的时候,名字是“用户自定义”会造成迷惑,你定义一个用户自定义消息,而不是你的程序的用户。我在第一章已经描述过了消息是是数字定义的,Windows可以预先定义一些标准的消息。这种预先定义的消息是用数字来标识的。为了确保你定义的用户自定义消息不会和系统预定义好的消息冲突,你应该在WM_APP的范围通过0xBFFF:
- #define WM_DELETEALL WM_APP + 0x100
- //...
pYourDialog->SendMessage(WM_DELETEALL, 0, 0);
处理用户自定义那消息也是用ON_MESSAGE宏来实现的:
- #define WM_DELETEALL WM_APP + 0x100
- //...
- //Message Map entry:
- ON_MESSAGE (WM_DELETEALL, OnDeleteAll)
- //OnDeleteAll is prototyped as
- afx_msg LRESULT OnDeleteAll(WPARAM wParam, LPARAM lParam);
- //And is implemented as
- LRESULT OnDeleteAll(WPARAM wParam, LPARAM lParam){
- //Do What ever you want
- return somevalue;
- }
注册Windows 消息
RegisterWindowMessage
函数是用来通过系统把一个新的消息来授权成为唯一的。这个宏
ON_REGISTERED_MESSAGE用来处理消息。这个宏可以来接受包含着窗口消息ID的UINT型的变量。例如:
- class CMyWnd : public CMyParentWndClass
- {
- public:
- CMyWnd();
- //{{AFX_MSG(CMyWnd)
- afx_msg LRESULT OnFind(WPARAM wParam, LPARAM lParam);
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
- };
- static UINT WM_FIND = RegisterWindowMessage("YOURAPP_FIND_MSG");
- BEGIN_MESSAGE_MAP(CMyWnd, CMyParentWndClass)
- //{{AFX_MSG_MAP(CMyWnd)
- ON_REGISTERED_MESSAGE(WM_FIND, OnFind)
- //}}AFX_MSG_MAP
- END_MESSAGE_MAP()
用户自定义消息的这种方式将会在
0xC000 to 0xFFFF这个范围能,你可以用
SendMessage()方法来发送它。
- static UINT WM_FIND = RegisterWindowMessage("YOURAPP_FIND_MSG");
- //...
- pFindWindow->SendMessage(WM_FIND, lParam, wParam);
License
This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.
A list of licenses authors might use can be found here
About the Author
Daniel Kopitchinski |
|