windows的消息机制总结

DOS靠过程来驱动,而windows靠消息驱动。

MFC/QT是一个广泛使用的变成类库,对windows的消息机制进行了很好的封装。

1、消息的概念:

消息是指windows操作系统发给应用程序的一个通告,告诉程序某个特定的事件发生了。比如用户点击鼠标,会引发相关的消息,并交给相应的程序去处理。最终处理消息的是应用程序的窗口函数,如果程序不负责处理的话,系统会作出默认的处理。

从数据结构的角度来说,消息是一个结构体,包含了消息的类型标识符以及其他的一些附加消息。

系统定义的结构体MSG用于表示消息,MSG具有如下形式:

typedef struct tagMSG

{

  HWND hwnd;

 UINT message;

WPARAM wParam;

LPARAM IParam;

DWORD time;

POINT pt;

}MSG;

 

其中hwnd是窗口的句柄,这个参数决定哪个窗口过程函数对消息进行处理;message是一个消息常量,用来表示消息的类型;wParam lParam 都是32 位的附加信息,具体表示什么内容,要视消息的类型而定;time是消息发送的时间;pt是消息发送时鼠标所在的位置。

2、windows编程原理

Windows 是一消息(Message)驱动式系统,Windows 消息提供了应用程序与应用程序之间、应用程序与Windows 系统之间进行通讯的手段。应用程序要实现的功能由消息来触发,并靠对消息的响应和处理来完成。Windows 系统中有两种消息队列,一种是系统消息队列,另一种是应用程序消息队列。计算机的所有输入设备由 Windows 监控,当一个事件发生时,Windows 先将输入的消息放入系统消息队列中,然后再将输入的消息拷贝到相应的应用程序队列中,应用程序中的消息循环从它的消息队列中检索每一个消息并发送给相应的窗口函数中。一个事件的发生,到达处理它的窗口函数必须经历上述过程。

 

用程序队列中,应用程序中的消息循环从它的消息队列中检索每一个消息并发送给相应的窗口函数中。一个事件的发生,到达处理它的窗口函数必须经历上述过程。所谓消息就是描述事件发生的信息,Windows程序是事件驱动的,用这一方法编写程序

避免了死板的操作模式,因为Windows程序的执行顺序将取决于事件的发生顺序,具有不可预知性。Windows操作系统,计算机硬件,应用程序之间具有如下图所示的关系:

 

箭头1 说明操作系统能够操纵输入输出设备,例如让打印机打印;箭头2说明操作系统能够感知输入输出设备的状态变化,如鼠标单击,按键按下等,这就是操作系统和计算机硬件之间的交互关系,应用程序开发者并不需要知道他们之间是如何做到的,我们需要了解的操作系统与应用程序之间如何交互。箭头3是应用程序通知操作系统执行某个具体的操作,这是通过调用操作系统的API来实现的;操作系统能够感知硬件的状态变化,但是并不决定如何处理,而是把这种变化转交给应用程序,由应用程序决定如何处理,向上的箭头4说明了这种转交情况,操作系统通过把每个事件都包装成一个称为消息结构体MSG来实现这个过程,也就是消息响应,要理解消息响应,首先需要了解消息的概念和表示。

3、windows消息循环

 

消息循环Windows应用程序存在的根本,应用程序通过消息循环获取各种消息,并通过相应的窗口过程函数,对消息加以处理;正是这个消息循环使得一个应用程序能够响应外部的各种事件,所以消息循环往往是一个Windows应用程序的核心部分。Windows 的消息机制如图2所示:


Windows 操作系统为每个线程维持一个消息队列,当事件产生时,操作系统感知这一事件的发生,并包装成消息发送到消息队列,应用程序通过GetMessage()函数取得消息并存于一个消息结构体中,然后通过一个TranslateMessage()DispatchMessage()解释和分发消息,下面的代码描述了Windows 的消息循环。
while(GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
TranslateMessage(&msg)
对于大多数消息而言不起作用,但是有些消息,比如键盘按键按下和弹起(分别对于KeyDown KeyUp 消息),却需要通过它解释,产生一个WM_CHAR消息。DispatchMessage(&msg)负责把消息分发到消息结构体中对应的窗口,交由窗口过程函数处理。GetMessage()在取得WM_QUIT 之前的返回值都为TRUE,也就是说只有获取到WM_QUIT 消息才返回FALSE,才能跳出消息循环。

 

 

 

4、消息的处理

 

取得的消息将交由窗口处理函数进行处理,对于每个窗口类Windows为我们预备了一个默认的窗口过程处理函数DefWindowProc(),这样做的好处是,我们可以着眼于我们感兴趣的消息,把其他不感兴趣的消息传递给默认窗口过程函数进行处理。每一个窗口类都有一个窗口过程函数,此函数是一个回调函数,它是由Windows操作系统负责调用的,而应用程
序本身不能调用它。以switch语句开始,对于每条感兴趣的消息都以一个case引出。
LRESULT CALLBACK WndProc
(
HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam
)
{

switch(uMsgId)
{

caseWM_TIMER//WM_TIMER 定时器消息的处理过程
return 0;
case WM_LBUTTONDOWN
//对鼠标左键单击消息的处理过程
reurn 0;
. …
default:
return DefWindowProc(hwnd,uMsgId,wParam,lParam);
}
}

对于每条已经处理过的消息都必须返回0,否则消息将不停的重试下去;对于不感兴趣

 

的消息,交给DefWindowProc()函数进行处理,并需要返回其处理值。

 

5、 MFC 消息映射的实现

 

MFC 的框架结构下,消息映射是通过巧妙的宏定义,形成一张消息映射表格来进行的。这样一旦消息发生,Framework 就可以根据消息映射表格来进行消息映射和命令传递。首先在需要进行消息处理的类的头文件(.H)里,都会含有DECLARE_MESSAGE_MAP()声明该类拥有消息映射表格。然后在类应用程序文件(.CPP)实现这一表格

 

BEGIN_MESSAGE_MAP(CInheritClass, CBaseClass)
//{{AFX_MSG_MAP(CInheritClass)
ON_COMMAND(ID_EDIT_COPY,OnEditCopy)
………
//}}AFX_MSG_MAP

 

END_MESSAGE_MAP()

这里主要进行消息映射的实现,把它和消息处理函数联系在一起。其中出现三个宏,第一个宏是BEGIN_MESSAGE_MAP 有两个参数,分别是拥有消息表格的类,及其父类。第二个宏是ON_COMMAND 指定命令消息的处理函数名称。第三个是
END_MESSAGE_MAP()作为结尾符号。DECLARE_MESSAGE_MAP 宏定义里包含了MFC 定义的两个新的数据结构;
AFX_MSGMAP_ENTRY AFX_MSGMAP;其中AFX_MSGMAP_ENTRY结构包含了一个消息的所有相关信息,AFX_MSGMAP 主要作用有两个,一是用来得到基类的消息映射入口地址。二是得到本身的消息映射入口地址。

AFX_MSGMAP_ENTRYAFX_MSGMAP;其中AFX_MSGMAP_ENTRY结构包含了一个消息的所有相关信息,AFX_MSGMAP主要作用有两个,一是用来得到基类的消息映射入口地址。二是得到本身的消息映射入口地址。实际上,MFC 把所有的消息一条条填入到AFX_MSGMAP_ENTRY结构中去,形成一个数组,该数组存放了所有的消息和与它们相关的参数。同时通过AFX_MSGMAP能得到该数组的首地址,同时得到基类的消息映射入口地址。当本身对该消息不响应的时候,就可

以上溯到基类的消息映射表寻找对应的消息响应。

MFC 通过钩子函数_AfxCbtFilterHook()截获消息,并在此函数中把窗口过程函数设置为AfxWindProc,而原来的窗口过程函数被保存在成员变量m_pfnSuper中。MFC 框架下,通过下面的步骤来对消息进行映射

1 函数AfxWndProc接收Windows操作系统发送的消息。

2 函数AfxWndProc调用函数AfxCallWndProc进行消息处理,这里一个进步是把对句柄的操作转换成对CWnd 对象的操作。

 

3 函数AfxCallWndProc调用CWnd 类的方法WindowProc进行消息处理。

4 WindowProc 调用OnWndMsg进行正式的消息处理,即把消息派送到相关的方法中去处理。

5 如果OnWndMsg方法没有对消息进行处理的话,就调用DefWindowProc对消息进行处理。
这就是MFC 对消息调用过程的巧妙封装。

6、MFC消息分类

 

1 命令消息(WM_COMMAND)
比如菜单项的选择,工具栏按钮点击等发出该消息。所有派生自CCmdTarget的类都有
能力接收WM_COMMAND消息。


2 标准消息(WM_XXX)
比如窗口创建,窗口销毁等。所有派生自CWnd的类才有资格接收标准消息。


3 通告消息(WM_NOTIFY)
这是有控件向父窗口发送的消息,标示控件本身状态的变化。比如下拉列表框选项的改
CBN_SELCHANGE和树形控件的TVN_SELCHANGED消息都是通告消息。
Window 9x 版及以后的新控件通告消息不再通过WM_COMMAND传送,而是通过
WM_NOTIFY 传送,但是老控件的通告消息,比如CBN_SELCHANGE还是通过
WM_COMMAND 消息发送。


4 自定义消息
利用MFC 编程,可以使用自定义消息。使用自定义消息需要遵循一定的步骤,并需要
自己编写消息响应函数

 

 

 

 

 

 

 

 

 

 

 

 

 

 

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页