• 技术文章 >运维 >windows运维

    Win32 SDK基础(八)之 关于Windows消息机制的详解(图)

    黄舟黄舟2017-06-06 10:02:15原创3018

    一、 什么是消息

    在解释什么是消息之前,我们先讨论一下程序的执行机制问题。大体上说,程序按照执行机制可以分为两类:
    第一类是过程驱动。比如我们最早接触编程时写的C程序,又或者单片机程序。这类程序往往预先已经设定好了执行流程,我们执行时只是按部就班的执行;
    第二类是事件驱动。事件,相信大家都能够理解。每个事件的发生都是随机的,每个事件都会有发生的时刻,类似生活中的事件。程序中的事件也会有自己的触发点,事件驱动程序就是事先编写好了针对每个事件的处理流程。在Windows的操作系统中,消息就是Windows中的事件。Windows中的几乎每个操作都会触发消息,像我们之前讲过的创建窗口会触发WM_CREATE消息,绘制窗口会触发WM_PAINT消息,我们点击鼠标、键盘、都会触发相应的消息。
    Windows的消息被封装成了一个叫做MSG的结构体,其原型如下:

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

    Hwnd —— 触发消息的窗口的句柄。
    Message —— 消息ID。Windows操作系统为每个消息都分配了一个消息ID,这个ID是唯一的。我们在上文中提到过的WM_CREATE本质就是一个整数,就是消息ID。
    wParam —— 消息可附带的参数。
    lParam —— 消息可附带的参数。
    Time —— 发生消息的时刻。
    Pt —— 发生消息时鼠标所在的位置。
    以上参数对消息来说,缺一不可。
    Windows中就是将一个个消息封装成MSG对象发送消息时,将这些对象放置到消息队列中;获取消息时,也是获取的这些MSG对象。

    二、 消息获取

    2.1 消息队列

    我们说过,在Windows中几乎每个操作都会触发一条消息,这些消息都被发送到消息队列中。何为消息队列?我们可以将其理解为使用了一个存放Msg对象的先进先出的Deque—— Deque<Msg>。消息队列分为两种,一种是系统消息队列,另外一种是进程消息队列。我们在触发消息后,消息先进入系统消息队列。操作系统处理后会根据消息的的窗口句柄hwnd值将消息分配到我们程序自己的消息队列,然后在我们程序内部进行消息的处理。

    2.2 消息循环

    在前面的文章中,我们曾经写过一个消息循环。所谓的消息循环,就是不断的读取我们的进程中的消息队里中的消息,然后在进行处理。

    void Message()  
    {  
        MSG nMsg = { 0 };  
        while (GetMessage(&nMsg, NULL, 0, 0))  
        {  
            TranslateMessage(&nMsg);  
            DispatchMessage(&nMsg);  
        }  
    }

    这里面,GetMessage()不断的在消息队列中抓取消息,其函数原型如下:
    GetMessage(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax)
    lpMsg —— 用来存放消息的MSG类型的指针。
    hWnd —— 指定取得其消息的窗口的句柄。当其值取NULL时,GetMessage为任何属于调用线程的窗口检索消息。
    wMsgFilterMin —— 指定被检索的最小消息值的整数。
    wMsgFilterMax —— 指定被检索的最大消息值的整数。

    GetMessage()获取到消息后,TranslateMessage会将消息进行翻译,主要是把虚拟键消息转换为字符消息。字符消息被寄送到调用线程的消息队列里,当下一次线程调用函数GetMessage或PeekMessage时被读出。Windows中每一个键盘按键,都对应了一个宏,这个键盘按键发出的消息就是虚拟键消息。TranslateMessage的作用就是将虚拟键消息转成字符消息WM_CHAR、WM_SYSCHAR等等。

    三、消息处理

    DispatchMessage的作用就是将消息,分派到我们实现定义好的窗口处理函数中进行处理,下面是我们在之前的文章中定义的窗口处理函数:

    LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)  
    {  
    	switch (uMsg)  
    	{  
    	case WM_DESTROY:  
    		PostQuitMessage(0);//可¨¦以°?使º1GetMessage返¤¦Ì回?0  
    		break;  
    	default:  
    		break;  
    	}  
    	return DefWindowProc(hWnd, uMsg, wParam, lParam);  
    }


    hWnd就是产生消息的窗口句柄,uMsg是传递的消息,wParam和lParam分别是消息携带的两个参数。在上面的窗口处理函数中,我们定只处理了一个消息WM_DESTROY,这是我们在点击窗口的关闭按钮后产生的一个消息。我们说过,我们在创建窗口是,也会产生一个WM_CREATE消息。下面我们在窗口处理函数中处理这个消息:

    LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)  
    {  
    	switch (uMsg)  
    	{  
    	case WM_DESTROY:  
    		PostQuitMessage(0);//可¨¦以°?使º1GetMessage返¤¦Ì回?0  
    		break; 
    	case  WM_CREATE:
    		MessageBox(NULL,"WM_CREATE消息被处理了","消息处理",MB_OK);
    	default:  
    		break;  
    	}  
    	return DefWindowProc(hWnd, uMsg, wParam, lParam);  
    }


    我们在接受到WM_CREATE后,会弹出一个对话框。预期的效果是点击这个对话框的确定按钮后才会显示窗口。如下面所示:

    运行程序,先弹出对话框:


    点击确定按钮后,弹出窗口:

    以上就是Win32 SDK基础(八)之 关于Windows消息机制的详解(图)的详细内容,更多请关注php中文网其它相关文章!

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。
    上一篇:Win32 SDK基础(七)之如何创建一个窗口的子窗口的案例 下一篇:自己动手写 PHP MVC 框架(40节精讲/巨细/新人进阶必看)

    相关文章推荐

    • 重装win7系统的过程 • Win2008 r2下修改mysql data目录的方法详细介绍• 关于负载平衡的详细介绍• windows操作系统 • 连接信息入门教程:10个连接信息零基础入门教程推荐
    1/1

    PHP中文网