windows消息机制

Windows 操作系统为每个进程维持一个消息队列,当事件产生时,操作系统感知这一事件的发生,并包装成消息发送到消息队列,应用程序通过GetMessage()函数取得消息并存于一个消息结构体中,然后通过一个TranslateMessage()和DispatchMessage()解释和分发消息

1 引言

Windows 在操作系统平台占有绝对统治地位,基于Windows 的编程和开发越来越广泛。Dos 是过程驱动的,而Windows 是事件驱动的[6],这种差别的存在使得很多Dos 程序员不能习惯Windows 的程序开发。而很多Windows 程序开发人员也只是对消息运行机制一知半解,想要掌握Windows 编程的核心,必须深刻理解消息机制。事件驱动围绕着消息的产生与处理展开,事件驱动是靠消息循环机制来实现的。也可以理解为消息是一种报告有关事件发生的通知,消息是Windows 操作系统的灵魂,掌握了消息运行机制就掌握了Windows 编程的神兵利器。本文将首先阐述Windows 的编程原理,继而对Windows 的消息运行机制进行分析,并讲述对消息的处理。MFC 是一个广为使用的编程类库,对Windows 的消息机制进行了良好的封装,所以,在第二部分将着重讨论MFC 的消息映射,最后结合编程实际,通过对MFC 消息映射的分析,非常巧妙的加以应用,以帮助解决实际问题

2 Windows 消息运行机制

消息(Message)指的就是Windows 操作系统发给应用程序的一个通告[5],它告诉应用程序某个特定的事件发生了。比如,用户单击鼠标或按键都会引发Windows 系统发送相应的消息。最终处理消息的是应用程序的窗口函数,如果程序不负责处理的话系统将会作出默认处理。

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

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

typedef struct tagMSG
{
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
}MSG;

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

2.2 Windows 编程原理

Windows 是一消息(Message)驱动式系统,Windows 消息提供了应用程序与应用程序之间、应用程序与Windows 系统之间进行通讯的手段。应用程序要实现的功能由消息来触发,并靠对消息的响应和处理来完成。Windows 系统中有两种消息队列,一种是系统消息队列,另一种是应用程序消息队列。计算机的所有输入设备由 Windows 监控,当一个事件发生时,Windows 先将输入的消息放入系统消息队列中,然后再将输入的消息拷贝到相应的应用程序队列中,应用程序中的消息循环从它的消息队列中检索每一个消息并发送给相应的窗口函数中。一个事件的发生,到达处理它的窗口函数必须经历上述过程。所谓消息就是描述事件发生的信息,Windows 程序是事件驱动的,用这一方法编写程序避免了死板的操作模式,因为Windows 程序的执行顺序将取决于事件的发生顺序,具有不可预知性。Windows 操作系统,计算机硬件,应用程序之间具有如图1 所示的关系

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

2.3 Windows 消息循环

消息循环[1]是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,才能跳出消息循环。

2.4 消息的处理

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

LRESULT CALLBACK WndProc(
                HWND hwnd,
                UINT message,
                WPARAM wParam,
                LPARAM lParam
                )
{
    …
    switch(uMsgId)
    {

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

对于每条已经处理过的消息都必须返回0,否则消息将不停的重试下去;对于不感兴趣的消息,交给DefWindowProc()函数进行处理,并需要返回其处理值。

3 关于TranslateMessage(&msg)

TranslateMessage内部对已经转换的消息是不处理的。比如A消息到了,TranslateMessage判断A消息是虚拟键消息(virtual-key messages),就转换为B消息。B消息本身并不是virtual-key messages,TranslateMessage不做处理,就直接返回了。

虚拟键指WINDOWS编程的一个概念。实际的键盘输入每按下一个件要有对应的键值,最初的电子信号是根据键盘的矩阵代码确定是什么来确定哪个键,原来在DOS时代也要直接查询操作系统返回的值键来确定是哪个键按下。WINDOWS对每个键都定义了一个宏,就称做虚拟键,例如VK_ESC,VK_RETURN,VK_ENTER,这些宏可以直接引用,判断按键的时候直接和宏比较就可以,而不必关心具体的键值是什么。软键盘就是一个使用虚拟键的例子,通过向窗口发送键盘消息,消息里面封闭了虚拟键值,实际上键盘并没有按键按下。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值