Window 系统是以消息形式驱动并运行的,作为一个Window程序员,编程时对系统消息的控制应该已经讳莫如深了,但是只使用系统消息,编程时势必受到束缚,为了满足我们程序灵活自由的编写程序,MS为我们提供了PostMessage和SendMessage两个函数开放程序员自定义消息的编程方式。
关于发送和寄送消息
MS为我们提供的PostMessage和SendMessage这两个函数,前者采用了寄送消息的方式,后者采用发送消息的方式。两者的区别就是发送消息后,等待该消息的处理结果返回后才运行下一步程序,而寄送消息则是当消息寄送到消息队列之后,如果寄送成功就返回TURE,否则返回FALSE。
为此一般在比较笨重的函数内部,我们一般采用寄送消息的模式。不过我们也不建议使用笨重的函数体。
具体发送自定义消息的过程实现
实现自定义消息常见的又可分为两种,一种是SDK形式的LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam)和BOOL PostMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam),另一种是CWnd类的成员函数LRESULT SendMessage(UINT Msg,WPARAM wParam,LPARAM lParam)和BOOL PostMessage(UINT message,WPARAM wParam = 0,LPARAM lParam = 0)。两者从函数体上我们就可以看出他们的区别了,即一个是在一个基于CWnd类派生对象内发送或寄送隶属于该对象的消息,而另一个则是在一个基于CWnd类派生对象内或者在任何一个函数过程中向另外一个对象发送或寄送属于那个对象的消息。(运行时是对象,但是编程时我们都是在类内实现的,所以下一步讲解中我不言明是在类内编程的)
以下我采用第一种形式的发送消息方式具体讲一下自定义消息的过程:
一、定义消息
一般在发送该消息的代码的头文件中定义消息,或者干脆在stdAfx.h头文件中定义消息。
定义形式为:#define WM_XXXX WM_USER+100
注:MS推荐我们自定义的消息一般在WM_USER+100以上,因为考虑到你的程序中可能要加进一些新的控件,而这些控件又常有自己的消息。当然你确信不用新的控件或者确信新的控件没有自定义消息或者自定义消息值不与你的定义干扰的化,你也完全可以采用WM_USER顺次往上加1来定义你的消息的值。
二、发送消息
即在你要在发送消息的时候填写该代码,假如你在一个对话框内要发一个消息到另一个对话框,那么你只要潜移默化的在发送对话框内取得目的对话框的句柄,加入为m_hWnd,那么你只要如下填写代码就可以了:
::SendMessage(m_hWnd,WM_XXXX, wParam, lParam)
注:wParam, lParam是发送时要传送的参数,如果该消息发送时不传递参数的话,那就使用默认为零就可以了。
三、声明消息处理函数
在目标对象类的头文件中我们声明消息处理函数,具体函数名随程序员的喜好,但是消息处理函数名通用形式为OnXXXX,而且一般放在头文件的固定位置,即//{{AFX_MSG(CXXX)和 //}}AFX_MSG之间,形式如下:
//{{AFX_MSG(CMainFrame)
afx_msg void OnXXXX();
//}}AFX_MSG
注:CXXX是目标类名,之所以这么做是为了编程的规范,你也可以不这么做。如果需要返回的话,void类型改为你需要返回的类型,通常情况为LPESULT类型。
四、添加消息映射关系
在目标类的代码文件的消息映射块内添加如下代码:
BEGIN_MESSAGE_MAP(CXXX, CXX)
//{{AFX_MSG_MAP(CXXX)
ON_MESSAGE(WM_XXXX, OnXXXX)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
完成消息映射对应关系。
注:在这里就没有那么自由,程序必须按照规范来做,顶多可以删掉注释给IDE看的//{{AFX_MSG_MAP(CXXX)和//}}AFX_MSG_MAP两句话,但是干吗要去删掉呢,放在那边跟你又没仇对吧?
五、实现消息处理函数
这个步骤不用我多做解释了吧,你只要按照你一般的函数代码编程来写就可以了,顶多就是对传递过来的值wParam, lParam进行判断处理就可以了。
补充:相对应发送和寄送消息,MS也为我们提供了两个接收消息API函数,他们分别是GetMessage()和PeekMessage(),前者原理和发送消息一样需要等待接收的消息处理完,再返回,后者只要把消息送到消息队列之后就可以返回了。