精华内容
下载资源
问答
  • windows消息机制详解

    千次阅读 2015-04-09 00:10:47
    1. 引言 Windows 在操作系统平台占有绝对统治地位,基于Windows 的编程...而很多Windows 程序开发人员也只是对消息运行机制一知半解, 想要掌握Windows 编程的核心,必须深刻理解消息机制。事件驱动围绕着消息
    1. 引言

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

     

    2. Windows 消息运行机制
    在介绍Windows 消息运行机制之前,首先介绍一下消息的概念。
    2.1 消息的概念和表示
    消息(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. MFC 的消息映射
    MFC 是Windows 下编程的微软基础类库,封装了大部分Windows API 和Windows 控件,
    提供了一套消息映射和命令响应机制,方便了应用程序的开发。MFC 只是通过对Windows
    消息映射的进行封装,使得添加消息响应变得更为简单,但深究起来,与Windows 消息机
    制有一样的底层实现。


    3.1 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 主要作用有两个,一是用来得到基类的消息映
    射入口地址。二是得到本身的消息映射入口地址。
    实际上,MFC 把所有的消息一条条填入到AFX_MSGMAP_ENTRY 结构中去,形成一
    个数组,该数组存放了所有的消息和与它们相关的参数。同时通过AFX_MSGMAP 能得到
    该数组的首地址,同时得到基类的消息映射入口地址。当本身对该消息不响应的时候,就可
    以上溯到基类的消息映射表寻找对应的消息响应。
    MFC 通过钩子函数_AfxCbtFilterHook()截获消息,并在此函数中把窗口过程函数设置为

    AfxWindProc,而原来的窗口过程函数被保存在成员变量m_pfnSuper 中。
    在MFC 框架下,通过下面的步骤来对消息进行映射[7]。
    1 函数AfxWndProc 接收Windows 操作系统发送的消息。
    2 函数AfxWndProc 调用函数AfxCallWndProc 进行消息处理,这里一个进步是把对句柄的
    操作转换成对CWnd 对象的操作。
    3 函数AfxCallWndProc 调用CWnd 类的方法WindowProc 进行消息处理。
    4 WindowProc 调用OnWndMsg 进行正式的消息处理,即把消息派送到相关的方法中去处理。
    5 如果OnWndMsg 方法没有对消息进行处理的话,就调用DefWindowProc 对消息进行处理。
    这就是MFC 对消息调用过程的巧妙封装。


    3.2 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 编程,可以使用自定义消息。使用自定义消息需要遵循一定的步骤[2]并需要
    自己编写消息响应函数

     


    4. MFC 消息的灵活运用
    在此,我们给出一个示例程序,演示对MFC 消息的灵活运用,通过此例的剖析,将加
    深我们对MFC 消息的理解。


    4.1 示例功能描述
    本示例程序将演示这样一种效果:
    对话框上有一个CTabCtrl 控件,一个CComboBox 控件,两个按钮Button1 和Button2。
    CTabCtrl 控件有两个标签页Tab1 和Tab2;CComboxBox 有两个选项:选项1 和选项2;通
    过按钮(Button1 和Button2)单击,分别发送CTabCtrl 控件的TCN_SELCHANGE 消息和
    下拉列表框的CBN_SELCHANGE 消息,在各自的消息响应函数中只是简单的对控件选项做
    切换和给出提示信息。
    单击Button1 将选中标签页Tab1 和下拉列表框的选项1,并弹出提示信息;单击Button2
    将选中标签页Tab2 和下拉列表框的选项2,并弹出提示信息。


    4.2 程序设计思路
    TCN_SELCHANGE 消息和CBN_SELCHANGE 消息都属于通告消息,此消息由子控件

    发送给父窗口,在MSDN 中查询发现TCN_SELCHANGE 消息是以WM_NOTIFY 消息的形
    式发送,在MSDN 中查询WM_NOTIFY 消息:
    idCtrl = (int) wParam;
    pnmh = (LPNMHDR) lParam;
    也就是说,WPARAM 参数传递发送此消息的控件标识,LAPAM 参数一个指向NMHDR
    结构体的指针。NMHDR 结构体定义如下:
    typedef struct tagNMHDR
    {
    HWND hwndFrom;
    UINT idFrom;
    UINT code;
    }
    NMHDR; 其中hwndFrom 标识发送消息控件的句柄,idFrom 是发送消息控件的ID,code
    则是消息码,如果要发送TCN_SELCHANGE 消息,则以TCN_SELCHANGE 填充。
    查询MSDN 发现, 由CComboBox 控件发送的CBN_SELCHANGE 消息以
    WM_COMMAND 消息发送,WPARAM 的高字节传递CComboBox 控件的ID,低字节发送
    消息码CBN_SELCHANGE,而LPARAM 则传送发送此消息的控件句柄。
    所以我们可以通过在按钮控件的单击响应函数里分别发送WM_NOTIFY 和
    WM_COMMAND 消息来引起TCN_SELCHANGE 和CBN_SELCHANGE 消息响应函数的调
    用,分别在两控件消息响应函数中实现选项改变和消息提示即可,遵照这种思路,我们就可
    以实现我们想要的功能。


    4.3 程序实现步骤
    启动VC++6.0,新建基于对话框的应用程序MsgTest.
    在对话框上添加1 个CTabCtrl 控件,一个CComboBox 控件,2 个按钮Button1 和Button2;
    给IDC_TAB1 和IDC_COMBO1 分别关联控件成员变量m_tab1 和m_cb1;为两按钮分
    别添加按钮单击响应函数。
    在对话框的OnInitDlg()函数中为CTabCtrl 控件添加两个标签页,Tab1 和Tab2;为
    ComboBox 添加选项1 和2;代码如下:
    m_tab1.InsertItem(0,"Tab1");
    m_tab1.InsertItem(1,"Tab2");
    m_cb1.AddString("选项1");
    m_cb1.AddString("选项2");
    用ClassWizard 为CTabCtrl 添加消息响应TCN_SELCHANGE,为CComboBox 添加消息
    响应CBN_SELCHANGE。在OnSelchangeTab1()函数中添加代码
    int nIndex=m_tab1.GetCurSel();
    CString str;
    str.Format("%d",nIndex+1);
    MessageBox("Tab"+str+" selected!");
    在OnSelchangeCombo1()函数中添加代码:
    int nIndex=m_cb1.GetCurSel();
    CString str;
    str.Format("%d",nIndex+1);

     

    MessageBox("ComboBox 选项"+str+" selected!");
    在按钮1 的响应函数OnButton1()中添加代码:
    m_tab1.SetCurSel(0);
    NMHDR nmhdr;
    nmhdr.code=TCN_SELCHANGE;
    nmhdr.hwndFrom=GetDlgItem(IDC_TAB1)->m_hWnd;
    nmhdr.idFrom=IDC_TAB1;
    SendMessage(WM_NOTIFY,(WPARAM)IDC_TAB1,(LPARAM)&nmhdr);
    m_cb1.SetCurSel(0);
    WPARAM wParam=0;
    WPARAM lParam=0;
    wParam=IDC_COMBO1;
    wParam= wParam | (CBN_SELCHANGE<<16);
    lParam=(WPARAM)(GetDlgItem(IDC_COMBO1)->m_hWnd);
    SendMessage(WM_COMMAND, wParam, lParam);
    在按钮2 的响应函数OnButton2()中添加类似代码,只需要把m_tab1.SetCurSel(0)和
    m_cb1.SetCurSel(0)分别改成m_tab1.SetCurSel(1)和m_cb1.SetCurSel(1)。
    通过SendMessage() 函数向控件的父窗口也就是对话框窗口发送相应的消息,
    TCN_SELCHANGE 是以WM_NOTIFY 消息的形式发送,参数WPARAM 标识发送
    TCN_SELCHANGE 消息的控件ID,LPARAM 是一个NMHDR 结构体的指针,此结构体的
    成员code 标识发送什么通告消息,此处是TCN_SELCHANGE,hwndFrom 是发送消息的控
    件句柄, 程序中用GetDlgItem()->m_hWdn 获得, idFrom 是发送消息的控件ID 。
    CBN_SELCHANGE 以WM_COMMAND 消息的形式发送,同样的,通过查阅MSDN,可以
    对此消息的两个参数进行赋值,以保证消息的正确发送。
    通过上面的5 个步骤,我们的程序就编写完成了,单击Button1,可以发现,CTabCtrl
    切换到了Tab1 标签页,CComboBox 选择了“选项1”,并弹出消息对话框。由此可见确实引
    起了消息响应函数的调用,完成了预定的功能。
    通过查阅MSDN,可以得到其他消息的发送和包装形式,我们可以方便的加以利用,完
    成更为复杂的功能,可以说,掌握了Windows 的消息机制,就掌握了Windows 编程的核心。

     


    5. 总结
    Windows 消息机制是Windows 编程的本质和核心,对Windows 消息机制的理解能提高
    我们Windows 程序开发的能力。本文首先阐述Windows 的消息机制,然后讲解了MFC 的
    消息映射,消息分类,最后通过示例程序,讲解如何借助MSDN,灵活运用消息编程,解
    决实际问题。本文对Windows 下的程序开发具有一定的参考和借鉴意义。


    展开全文
  • Windows消息机制详解

    2018-10-15 09:40:00
    Windows消息机制详解 转载于:https://www.cnblogs.com/endenvor/p/9789345.html

    Windows消息机制详解

    转载于:https://www.cnblogs.com/endenvor/p/9789345.html

    展开全文
  • Windows 消息机制详解

    千次阅读 2012-07-11 13:16:47
    Windows系统有一个系统消息队列 每个线程都有一个自己的消 息队列(由于发送消息MSG需 要提供一个窗口HWnd,而基 本有窗口的线程,都是UI线 程),因此基本上如果线程使用了GDI函数,则windows给该线程分配一个线程...
    总的来说:
    
    MSG包括:
    窗口句柄,指示MSG发送的目的窗口
    消息标识
    lPARAM、wParam
    发送时间
    发送时的鼠标位置
     
    关于消息队列:
    Windows系统有一个系统消息队列
    每个线程都有一个自己的消 息队列(由于发送消息MSG需 要提供一个窗口HWnd,而基 本有窗口的线程,都是UI线 程),因此基本上如果线程使用了GDI函数,则windows给该线程分配一个线程消息队列,这个消息队列负责该线程的所有窗口的消息。
     
    所有的窗口都有自己的句柄(HWND),消息被发送时,这个句柄就已经被指定了。所以 当子窗口收到一个消息时,其父窗口不会也收到这个消息,除非子窗口手 动的转发。
     
    消息分为:
    实际上MSDN把消息分为队列型(Queued Message)和非队列型(Non-queued Message),这只是不同的路由方式, 但最终都会由消息处理函数来处理。
    队 列型消息包括硬件的输入(WM_KEY*等)、WM_TIMER消 息、WM_PAINT消息等;非队列型的一些例子有WM_SETFOCUS, WM_ACTIVE, WM_SETCURSOR等,它们被直接发送给处理函数。
    其实,按照MSDN的说法和消息的路由过程可以理 解为,Posted Message Queue里的消息是真正的队列型消 息,而通过SendMessage()发送到消息,即使它进入了Sent Message Queue,由于SendMessage要求的同步处理,这些消息也 应该算非队列型消息。也许,Windows系统会特殊处理,使消息强行绕 过队列。
     
      

    =====================

    一节详细描述消息和消息队列以及如何在 你程序中使用他们。 
    关于消息和消息 队列
    与传统的应用程序不 同,Microsoft Windows应用程序并不显式地用一个函数的调用(如c运行库)来获取输入,而是,等待windows系统把输入传给它们。 
    windows系统把应用程序 的所有输入传给应用程序的窗口,每个窗口都有一个称之为窗口过程的函数.当窗口有输入时windows系统要调用它,窗口过程处理输入并把控制返回 windows系统。有关窗口过程,参见 “窗口过程”。 这一章讲述消息及消息队列,并说明在应用程序中如何使用它们。 
    消息
    windows系统以消息的形式把输入传给窗口过程,消息是由windows系 统或应用程序产生的.windows系统对每一个输入事件都要产生消息,例如,用户按键盘、移动鼠标或单击一个滚动条控制框。windows系统为了响应 应用程序给系统带来的变化也会产生消息,比如应用程序改变了系统字体资源池或是改变了一个窗门的大小。应用程序可通过产生消息指导它自己的窗口来完成某个 任务,或是与其它应用程序的窗口进行通信。 
    windows 系统把消息发送给窗口过程.窗口过程有四个参数:窗口句柄、消息标识以及两个叫做消息参数的32位值。窗口句柄决定消息将发送到哪—个窗 口,windows系统则用它来确定向哪一个窗口过程发送消息。 
    消息标识是一个命名的常量,由它来标明消息的目的。如果窗口过程接收到一条消息,它就通过消息标识来决定如何处理这条 消息。例如,消息标识WM_PAINT 通知窗口过程,窗口的客户区被改变了,需要重画。 
    消息参数指定窗口过程在处理消息时所用的数据或数据的位 置,消息的意图及数值取决了消息本身。消息参数可以是一个整数、紧缩的位标志、一个含有附加数据结构的指针等等。如果消息不使用消息参数,一般就都设置成NULL 、 窗口过程必须检查消息标识以确定如何解释消息参数。 
    消息路由
    windows系统用两种方式向窗口过程发送消息:把消息投递到一个先进先出的消息队列中,它是一个系统定义的内存块用于临时存储消息;或是把消 息直接发给窗口过程。 
    投递到 消息队列中的消息叫排队消息,它们主要是用户通过鼠标或键盘的输入结果.如WM_MOUSEMOVE, WM_LBUTTONDOWN, WM_KEYDOWN, and WM_CHAR 消息。其它的排队消息包括定时器、绘制和退出消息:WM_TIMER, WM_PAINT, and WM_QUIT 。所有直接发送到窗口过程的其它消息称之为非排队消息。 
    排队消息
    windows系统在同一时间可显示多个窗口,要发送鼠标和键盘输入到相应 的窗口,windows系统要用到消息队列,它要管理一个系统消息队列和任意数目线程消息队列,每一个队列对应于一个线程。 
    不管什么时候,只要用户移动鼠标或是敲键盘.鼠标或键盘的 设备驱动器都要把输入转换成消息,并把它们放到系统消息队列中去。windows从系统队列中每次移走一条消息,确定目的窗口,再把它们投递到创建目的窗 口的线程的消息队列中,线程消息队列接收所有由该线程创建的窗口的鼠标和键盘消息。线程从它的队列中移走消息并指导windows系统将它们发送到相应的 窗口过程进行处理。有关线程,参见 “进程和线程”。 
    WM_PAINT 消息有点特别,windows系统总是把这条消息放在消息队列的最后,这样 可保证窗口按先进先出次序接收它的输入消息,WM_PAINT 消息被保持在队列中,只有在队列中没有其它消息时才发送 到窗口过程。同一个窗口的多个WM_PAINT 消息被合并成一个WM_PAINT 消 息,把客户区所有无效部分合并成一个区域.合并WM_PAINT 消息节约了窗口必须重画客户区内容的时间。 
    系统向线程消息队列投递消息是通过填充 一个MSG 结构,再把它复制到消息队列中,MSG 结构中的信息包括接收消息的窗口 句柄、消息标识、两个消息参数、消息时间以及鼠标的位置,线程可把消息投递到它自己的消息队列中或是通过函数 PostMessage 和PostThreadMessage 把 消息投递到其它线程的队列中去。 
    应 用程序可通过函数GetMessage 从它的队列中移走一条消息,应用程序还可用函数PeekMessage 来 检查队列中的某个消息但并不移走它,这个函数用有关这条消息的信息填充MSG 结构。 
    把一条消息从它的队列中移走后.应用程序可用函数DispatchMessage 指 导windows系统把这条消息发送到窗口过程进行处理。DispatchMessage 利用前面调用函数GetMessage 或PeekMessage 时 填充的MSG 结构的指针,把窗口句柄、消息标识及两个消息参数传给窗口过程,但它并不传送时间或鼠标光标的位置.应用 程序可以在处理一条消息时,通过调用函数GetMessageTime 和GetMessagePos 来 获取这些信息。 
    一个线程可以 用函数WaitMessage 当他没有其他消息在其队列里时,产生对其他线程的控制。此函数将终止线程,直到一个新消 息被放入该线程的消息队列里,然后返回。 
    你 可以调用函数SetMessageExtraInfo 来设置当前线程消息队列的附加信息。是和当前线程的消息队列联系 的32位值。用户可以用函数GetMessageExtraInfo 来获得附加信息,该信息将会保留到下次调用函数GetMessage 或PeekMessage 之 前。 
    非排队消息
    非 排队消息是直接发送到目标窗口过程的,而不通过系统消息队列和线程消息队列。windows系统一般通过发送非排队消息把影响某窗口的事件通知窗口。例 如,如果用户激活一个新的应用程序窗口.windows系统就会向该窗口发送一系列的消息,包括:WM_ACTIVATE ,WM_SETFOCUS 和WM_SETCURSOR ,这些消息分别通知窗口: 它被激活了;将通过这个窗口进行键盘输入;鼠标已移到这个窗口边 框的里面了 。非排队消息也有可能发生在 应用程序调用一个windows系统函数时,例如,在应用程序用函数SetWindowPos 来移动一个窗口之 后,windows系统发送一条WM_WINDOWPOSCHANGED 消息。 
    应用程序是调用函数SendMessage 、SendNotifyMessage 或SendDlgItemMessage 发 送消息的。 
    消息处理
    应用程序必须删除和处理投递到它的线 程消息队列中的消息,单一线程的应用程序一般是在它的WinMain函数中使用一个消息环来删除消息,并把消息发送到相应的窗口过程进行处理。具有多重线 程的应用程序在创建窗口的每一个线程中使用一个消息环,下一节将讲述消息环是如何工作的,另外还解释了窗口过程的一般规则。 
    消息环
    一个简单的消息环含有一个对下列函数的调 用:GetMessage, TranslateMessage和DispatchMessage。函数GetMessage从队列中检取一条消息并把它复制到一个MSG结构 中.GetMessage应返回TRUE,但如果它得到的是WM_QUIT消息,它就返回FALSE并结束循环。在单一线程的应用程序中,结束消息循环通 常是关闭应用程序的第一步。一般在应用程序主窗口的窗口过程中响应WM_DESTROY消息时,应用程序通过函数PostQuitMessage关闭它自 己的消息环。 
    如果在 GetMessage中指定窗口句柄,那么从队列中检取的只是指定窗口的消息。GetMessage 也能过滤队列中的消息,这种情况下检取的只是指定范围内的消息。有关过滤消息,参见 “消息过滤”。 
    如果某个线程想接收键盘的字符输入,那么线程消息环中必须含有 TranslateMessage。Windows系统在用户每按一次键时会产生一个虚键消息(WM_KEYDOWN和WM_KEYUP),虚键消息含有 一个标识哪一个键被按过的虚键码,但不是它的字符值,要得到这个值,消息环中必须含有TranslateMessage,由它来把虚键消息翻译成字符消息 (WM_CHAR),再把它放回到应用程序的消息队列中去.这样字符消息才能在消息环的下一轮循环中被发送到窗口过程。 
    函数DispatchMessage把消息发送到与MSG结构 中指定的窗口句柄相应的窗口过程,如果窗口句柄是HWND_TOPMOST ,DispatchMessage就把消息发送到系统中所有顶层窗口的窗口过程。如果窗口句柄是NULL,对于这条消息DispatchMessage则 什么也不做。 
    应用程序的主线 程在初始化应用程序并且至少创建了一个窗口之后就开始了消息循环,一旦开始,消息环就连续不断地从线程的消息队列中校取消息并把它们分发到相应的窗口,函 数GetMessage从消息队列中检取到WM_QUIT消息时,消息环就结束了。 
    一个消息队列只需要有一个消息环,而不管应用程序有多少个窗口,因为队列中的每一条消息是一个 MSG结构,其中含有接收消息的窗口句柄,DispatchMessage总能把消息发送到相应的窗口。 
    应用程序可以有多种方法修改它的消息环,例如,它可以从队列中检取消息但并不 发送到任何窗口,这对那些投递不指定窗口的消息的应用程序是很有用的,(这些消息是提供给应用程序的,而不是某个窗口,因为它们含有NULL窗口句柄)。 应用程序也能指导GetMessage来搜索队列中一个特定的消息,而不管其它消息,这对那些有时不按消息队列先进先出次序检取消息的应用程序来说是很有 用的。 
    使用键盘加速键的应用 程序必须能够把键盘消息转换成命令消息,要这样做,应用程序的消息环必须调用函数TranslateAccelerator有关加速键,参见 “键盘加速键”。 
    窗口过程
    窗口过程是一个函数,用来接收和处理 所有发送到该窗口的消息,每个窗口类都有一个窗口过程,同一窗口类所创建的窗口共用同一个窗口过程来响应消息。 
    系统通过把消息数据作为过程的参数来向窗口过程发送消息,再由窗口过程 完成与消息相应的活动。它需要检查消息的标识,在处理消息时要使用由消息参数指定的这个信息。 
    窗口过程一般不会忽略—条消息,如果它不处理某条消息,它就必须把这条消息传回系统进行 默认处理,窗口过程是调用函数DefWindowProc 来完成的,由它完成一个默认的操作并返回消息结果。绝大多数 窗口过程只处理几种类型的消息,其它的则通过调用DefWindowProc 传给了系统。 
    因为窗口过程是由所有属于同类窗口共享的,所以它能处理 几个不同窗口的消息,要识别受消息影响的某个窗口,窗口过程可以检查消息所带的窗口句柄。有关窗口过程,参见 “窗口过程”。 
    传递和发送消息
    任何应用程序都能投递和发送消息,就跟系统一样,应用程序投递一 条消息是通过把它复制到消息队列,发送消息则是通过把消息数据作为窗门过程的参数。要投递消息,应用程 序需 要用到函数PostMessage ,要发送消息,程序使用函数SendMessage, BroadcastSystemMessage, SendMessageCallback, SendMessageTimeout, SendNotifyMessage 或SendDlgItemMessage 。 
    应用程序通常投递—条消息来通知某个窗口去完成 一个任务。PostMessage 为消息创建一个MSG 结构并把消息拷到消息队列 中,最后由应用程序的消息环检取这条消息再把它发送到相应的窗口过程。 
    应用程序一般是通过发送一条消息通知窗口过程立即完成某项任务,函数SendMessage 把 消息发送到与给定窗口相应的窗口过程,这个函数要等待窗口过程完成处理井返回消息的结果。父窗口与子窗口之间也是通过发送消息来进行相互间的通信,例如, 某个父窗口有一个编辑控制框作为它的子窗口,就可通过向它发送消息设置控制框的正文,这个控制框则通过向父窗口发送消息来把用户对正文的改变通知其父窗 口。 
    函数SendMessageCallback 也 能发送消息到指定窗口的窗口过程里,但是,这函数是立即返回,当窗口过程函数处理完消息后,系统调用指定的回调函数,有关更多回调函数信息,参考函数SendAsyncProc 。 
    有时,应用程序也有可能要求 向系统中的所有顶层窗口发送或投递一条消息,例如,如果应用程序改变了系统的时间,它必须通过发送WM_TIMECHANGE 消 息来通知所有顶层窗口,应用程序向所有顶层窗口发送或投递一条消息是调用函数SendMessage 或PostMessage , 并在hwnd 参数中指定HWND_TOPMOST 。你同样通过函数BroadcastSystemMessage 指 定参数lpdwRecipients 的值为BSM_APPLICATIONS 来 广 播消息给所有程序 
    应用程序能 够投递一条消息而不指定窗口,在调用PostMessage 时应用程序提供NULL 窗 口句柄,这条消息就被投递到与当前线程相应的队列中。因为没有指定窗口句柄,应用程序就必须在处理消息环中的这条消息,这也是一种创建消息的方法.此类消 息适用于整个应用程序,而不只是指某个窗口。 
    使用函数InSendMessage 窗口过程能够确定它所处理的消息是从另一个线程发来的,这种能力 在需要根据消息源进行消息处理时是很有用的。 
    经常出现的一个编程错误是假设函数PostMessage 总能成功地投递一条消息,这在消息队列是满 的时候是不对的,应用程序应该检查函数PostMessage 的返回值以确认消息是否已经被投递,否则要重新投递这条 消息。 
    消息种类
    这部分将两种类型windows消 息;系统定义的消息,程序定义的消息 
    系 统消息
    系统使用系统定义的 消息来控制应用程序的操作,并给应用程序提供输入或其他信息进行处理。系统在与应用程序进行通信是时是发送系统消息的。应用程序也能发送或投递系统消息, 应用程序通常用这些消息来控制预注册类创建的控制窗口的操作。 
    每条系统消息都有一个唯一的消息标识,对应于一个符号常量(在Windows系统头文件中定义),它表明了消息的目的, 例如,常量WM_PAINT 要求窗口绘制它的内容。 
    符号常量指定了系统消息所属的类别,常量的前缀标识能够解释和处理消息的亩口的类型。下表列出 了前缀及相应的消息类别: 
    前 缀 消息类 
    ABM Application desktop toolbar 
    BM Button control 
    CB Combo box control 
    CDM Common dialog box 
    DBT Device 
    DL Drag list box 
    DM Default push button control 
    EM Edit control 
    HDM Header control 
    LB List box control 
    LVM List view control 
    PBM Progress bar 
    PSM Property sheet 
    SB Status bar window 
    SBM Scroll bar control 
    STM Static control 
    TB Toolbar 
    TBM Trackbar 
    TCM Tab control 
    TTM Tooltip control 
    TVM Tree-view control 
    UDM Up-down control 
    WM General window 
    通 用窗口消息覆盖了—个较大范围的信息和请求,包括鼠标和键盘输入消息、菜单和对话框输入消息、窗口创建和管理消息及动态数据交换消息(DDL)。 
    应用程序定义消息
    应用程 序可创建用在它自己的窗口中的消息,或是与其它进程中的窗口进行通信的消息。如果应用程序创建了它自己的消息,接收它们的窗口过程必须能够对消息进行翻 译,并提供相应的处理。 ’ 
    windows 系统保留用于系统定义的消息的标识值的范围从0x0000到0x03FF(等于WM_USER —1)和0x8000到 0xBFFF应用程序不能把这些值用于私有消息。 
    从0x0400(WM_USER 的值)到0x7FFF之间的值是可用于应用程序定义的用于它自己 的消息标识,而从0xC000到0xFFFF之间的值是应用程序为了与其它应用程序中的窗口进行通信所定义的消息标识。 
    应用程序用函数RegisterWindowMessage 注 册一条消息时,windows系统返回的消息标识在0xC000到0xFFFF之间,这个函数所返回的消息标识应保证在整个系统中是唯一的。如果应用程序 要创建与其它应用程序中的窗口进行通信的消息,则使用RegisterWindowMessage 来对它进行注册,这 个函数可防止由于其它的应用程序基于不同的目的使用了相同的消息标识所产生的冲突。 
    消息过滤
    应用程序可使用函数GetMessage 或PeekMessage 来 指定一个消息过滤器,从消息队列中检取指定的消息[忽略其它的消息),这是一个消息标识的范围(由第一个和最后一个标识指定)、一个窗口句柄或者两者都是GetMessage 和PeekMessage 利 用消息过滤器有选择地检取队列中的某条消息。如果某个应用程序必须检索消息队列中的排在后面的消息,消息过滤则是很有用的。 
    过滤消息的应用程序必须保证满足消息过滤器的消息是能被投 递的,例如,如果某个应用程序的过滤器用于一个并不接收键盘输入的窗口中的WM_CHAR 消息,函数GetMessage 就 不能返回,这样就会“挂起”这个应用程序。 
    要 过滤键盘、鼠标和DDE消息,应用程序可以便用下列常量WM_KEYFIRST 和 WM_KEYLAST, WM_MOUSEFIRST 和 WM_MOUSELAST messages, 和 WM_DDE_FIRST 和 WM_DDE_LAST 
    消息死锁
    调 用函数SendMessage 的线程向另一个线程发送一条消息,要等待接收消息的窗口过程返回,如果接收消息的线程在 处理消息时放弃了控制,发送消息的线程就不能继续执行下去,因为它正等待SendMessage 返回,这种情况就叫做 死锁。接收消息的线程无须直接地放弃控制,调用下列函数其个的一个就能让线程放弃控制。 
    DialogBox 
    DialogBoxIndirect 
    DialogBoxIndirectParam 
    DialogBoxParam 
    GetMessage 
    MessageBox 
    PeekMessage 
    窗口过程可以确定它所接收的 消息是不是另一个线程通过调用函数InSendMessage 发来的。在处理一条消息时调用前面所列出的任一个函数之 前,窗口过程应首先调用InSendMessage ,如果函数返回TRUE ,窗口 过程就必须在调用任何能使线程放弃控制的函数之前调用函数ReplyMessage 。 
    使用消息和消息队列
    这节描述如何完成下面的工作 
    创建消息环 
    检查消息队列 
    投递消息 
    发送消息 
    创建消息环
    windows 系统为每一个线程自动创建消息队列,如果线程创建了一个或多个窗口,就必须提供从线程消息队列中检取消息,并把它们发送至相应窗口过程的消息环。 
    因为windows系统指导向应用程 序中的某个窗口发送消息,线程就必须在启动它的消息环之前至少要创建—个窗口,绝大多数windows应用程序含有一个创建窗口的线程。一个典型的应用程 序是在函数WinMain 中注册它主窗口的窗口类。创建和显示主窗口.然后启动消息环。 
    函数GetMessage 和 DispatchMessage 用来创建消息环,如果应用程序必须从用户得到字符输入,那么在消息环中应包含函数TranslateMessage , TranslateMessage 把 虚键消转换成字符消息。下面的范例说明了一个简单的windows应用程序的WinMain 函数中的消息环 
    HINSTANCE hinst; 
    HWND hwndMain; 
    int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
    LPSTR lpszCmdLine, int nCmdShow) 

    MSG msg; 
    WNDCLASS wc; 
    UNREFERENCED_PARAMETER(lpszCmdLine); 
    // Register the window class for the main window. 
    if (!hPrevInstance) 

    wc.style = 0; 
    wc.lpfnWndProc = (WNDPROC) WndProc; 
    wc.cbClsExtra = 0; 
    wc.cbWndExtra = 0; 
    wc.hInstance = hInstance; 
    wc.hIcon = LoadIcon((HINSTANCE) NULL, IDI_APPLICATION); 
    wc.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW); 
    wc.hbrBackground = GetStockObject(WHITE_BRUSH); 
    wc.lpszMenuName = "MainMenu"; 
    wc.lpszClassName = "MainWndClass"; 
    if (!RegisterClass(&wc)) 
    return FALSE; 

    hinst = hInstance; // save instance handle 
    // Create the main window. 
    hwndMain = CreateWindow("MainWndClass", "Sample", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 
    CW_USEDEFAULT, CW_USEDEFAULT, (HWND) NULL, (HMENU) NULL, hinst, (LPVOID) NULL); 
    // If the main window cannot be created, terminate 
    // the application. 
    if (!hwndMain) 
    return FALSE; 
    // Show the window and paint its contents. 
    ShowWindow(hwndMain, nCmdShow); 
    UpdateWindow(hwndMain); 
    // Start the message loop. 
    while (GetMessage(&msg, (HWND) NULL, 0, 0)) 

    TranslateMessage(&msg); 
    DispatchMessage(&msg); 

    // Return the exit code to Windows. 
    return msg.wParam; 

    函数GetMessage,TranslateMessage 以 及DispatchMessage 把MSG 结构的指针当作一个参数。如果有消息,GetMessage 把 它复制到MSG 结构中,如果这个消息是一条虚键消息(如WM_KEYDOWN 或WM_SYSKEYDOWN ),TranslateMessage 产 生一个字符消息(WM_CHAR 或WM_SYSCHAR ),并把它放到消息队列中 去。DispatchMessage 也使用MSG 结构的成员用作窗口过程的参数. 但要等到窗口过程完成处理后才返回。 
    如 果某个线程支持加速键,那么它的消息环必须含有函数TranslateAccelerator 。这个函数检查与线程加 速键表中的一个入口相匹配的组合键,如果它找到一个匹配值.TranslateAccelerator 就把组合键翻译 成一条WM_COMMAND 消息,并把它发送到窗口过程。 
    如果某个线程使用模式对话框,消息环中必须含有函数IsDialogMessage 以 便于对话框能够接收键盘输入。 
    有 关对话框,参见“对话框”。 
    下 面的范例说明了一个使用加速键的线程的消息环,其中显示了一个模式对话框。 
    如果TranslateAccelerator 或IsDialogMessage 返 回TRUE (指示消息已被处理),就不再调用TranslateMessage 和 DispatchMessage 原因是TranslateAccelerator 或IsDialogMessage 完 成所有对消息的翻译和发送工作。 
    HWND hwndMain; 
    HWND hwndDlgModeless = NULL; 
    MSG msg; 
    HACCEL haccel; 
    // Perform initialization and create a main window. 
    while (GetMessage(&msg, (HWND) NULL, 0, 0)) 

    if (hwndDlgModeless == (HWND) NULL || 
    !IsDialogMessage(hwndDlgModeless, &msg) && 
    !TranslateAccelerator(hwndMain, haccel, 
    &msg)) 

    TranslateMessage(&msg); 
    DispatchMessage(&msg); 


    检消息队列
    有时,应用程序需要在线程 消息环的外面检查线程消息队列的内容,例如,如果某个应用程序的窗口过程进行一个较长的绘画 操作,就可能允许用户中断这个操作。除非应用程序在处理鼠标和键盘消息的操作过程中不停地检查消息队列,否则在操作结束之前就不再会响应用户的输入.原因 是线程消息环中的函数DispatchMessage在窗口过程处理完消息之前是不会返回的。 
    对于一个较长时间的操作,可使用函数PeekMessage来 检查消息队列,PeekMessage与函数GetMessage是很相似的,都 可用来检查消息队列中与过滤器标准相匹配的消息,再把这个消息复制到一个MSG结构中。它们之间主要的不同就是GetMessage要 等待队列中出现一条与过滤器标准相匹配的消息,而PeekMessage 会立即返回,不管队列中是否有某条消息。 
    下面的范例说明了如何使用PeekMessage在 一个长操作期间,检查消息队列中的一条单击鼠标或键盘输入消息。 
    HWND hwnd; 
    BOOL fDone; 
    MSG msg; 
    // Begin the operation and continue until it is complete 
    // or until the user clicks the mouse or presses a key. 
    fDone = FALSE; 
    while (!fDone) 

    fDone = DoLengthyOperation(); // application-defined function 
    // Remove any messages that may be in the queue. If the 
    // queue contains any mouse or keyboard 
    // messages, end the operation. 
    while (PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE)) 

    switch(msg.message) 

    case WM_LBUTTONDOWN: 
    case WM_RBUTTONDOWN: 
    case WM_KEYDOWN: 
    // Perform any required cleanup. 
    fDone = TRUE; 



    其它的函数如GetQueueStatus和GetInputState也 能用来检查线程消息队列中的内容,GetQueueStatus返回一组标志,用来指明队列中消息的类型,这是一个最 快的办法来确定队列中是否有消息,如果队列中台有鼠标或键盘消息,GetInputState就返回TRUE, 这两个函数都能用来确定队列中是否有需要处理的消息。 
    投递消息
    使用函数PostMessage把一条消息投递到消息队列中,PostMessage在 线程消息队列的最后放置消息并立即返回,它不等待线程处理这条消息。函数的参数包括窗口句柄、消息标识相两个消息参数,windows系统把这些参数复制 到一个MSG结构中,填充结构的time和pt成 员,再把这个结构放到消息队列中。 
    windows 系统用函数PostMessage所带的窗口句柄来决定哪一个线程消息队列接收消息.如果句柄是HWND_TOPMOST,windows 系统就把这条消息投递到所有顶层窗口的线程消息队列中。 
    函数PostThreadMessage可用来向一个指定的线程消息队列投递消息,PostThreadMessage与PostMessage也 很相似.只是它的第一个参数是线程标识而不是窗口句柄,可通过调用函数GetCurrentThreadId检取这个 线程标识。 
    函数PostQuitMessage用 来退出消息环,PostQuitMessage向当前正在执行的线程发送WM_QUIT消 息,如果线程消息环接收到WM_QUIT消息,就结束消息环并把控制返回给windows系统。应用程序通常调用PostQuitMessage响 应WM_DESTROY消息, 
    用法如下 
    case WM_DESTROY: 
    // Perform cleanup tasks. 
    PostQuitMessage(0); 
    break; 
    发送消息
    函数SendMessage是用来直接向 一个窗口过程发送消息,SendMessage调用一个窗口过程,并等待过程对消息的处理和返回结果。 一条消息可以被发往系统中的任何一个窗口,而仅要求有一个窗口句柄,windows系统用这个句柄决定哪一个窗口过程应该接收这条消息。 如果窗口过程在处理由另一个线程发来的消息时放弃控制,就会出现消息死锁(有关消息死锁,参见 “消息死锁”)。在处理一个可能是发自另一个线程的消息之前,窗口过程应首先调用函数InSendMessage,如 果这个函数返回TRUE,那么窗口过程就应在调用任何可以使线程放弃控制的函数之前调用ReplyMessage, 做法如下: 
    case WM_USER + 5: 
    if (InSendMessage()) 
    ReplyMessage(TRUE); 
    DialogBox(hInst, "MyDialogBox", hwndMain, (DLGPROC) MyDlgProc); 
    break; 
    有一些消息可以发给对话框中的控制框,这些控制框消息设置控制框的外观、特性和内容或是检取有关 控制框的信息。例如,CB_ADDSTRING消息可以向组合框添加字串,BM_SETCHECK消 息能够设置复选框或单选按钮的选择状态。 
    使 用函数SendDlgItemMessage向一个控制框发送一条消息,要指定控制框的标识,含有这个控制框的对话框 窗口的句柄。下面的范例用在对话框过程中的,把一个字串从组合框的编辑控制框拷到它的列表框,这个例子用SendDlgItemMessage向 组合框发送一条CB_ADDSTRING消息. 
    HWND hwndCombo; 
    int cTxtLen; 
    PSTR pszMem; 
    switch (uMsg) 

    case WM_COMMAND: 
    switch (LOWORD(wParam)) 

    case IDD_ADDCBITEM: 
    // Get the handle of the combo box and the 
    // length of the string in the edit control 
    // of the combo box. 
    hwndCombo = GetDlgItem(hwndDlg, IDD_COMBO); 
    cTxtLen = GetWindowTextLength(hwndCombo); 
    // Allocate memory for the string and copy 
    // the string into the memory. 
    pszMem=(PSTR)VirtualAlloc((LPVOID)NULL,(DWORD)(cTxtLen+1),MEM_COMMIT, PAGE_READWRITE); 
    GetWindowText(hwndCombo, pszMem, cTxtLen + 1); 
    // Add the string to the list box of the 
    // combo box and remove the string from the 
    // edit control of the combo box. 
    if (*pszMem != NULL) 

    SendDlgItemMessage(hwndDlg, IDD_COMBO, CB_ADDSTRING, 0, (DWORD) ((LPSTR) pszMem)); 
    SetWindowText(hwndCombo, (LPSTR) NULL); 

    // Free the memory and return. 
    VirtualFree(pszMem, 0, MEM_RELEASE); 
    return TRUE; 
    // Process other dialog box commands. 

    // Process other dialog box messages. 

    消息及消息队列参考
    下列函数函数用于消息和消息队列 
    BroadcastSystemMessage 
    DefWindowProc 
    DispatchMessage 
    GetInputState 
    GetMessage 
    GetMessageExtraInfo 
    GetMessagePos 
    GetMessageTime 
    GetQueueStatus 
    InSendMessage 
    PeekMessage 
    PostMessage 
    PostQuitMessage 
    PostThreadMessage 
    RegisterWindowMessage 
    ReplyMessage 
    SendAsyncProc 
    SendMessage 
    SendMessageCallback 
    SendMessageTimeout 
    SendNotifyMessage 
    SetMessageExtraInfo 
    TranslateMessage 
    WaitMessage 
    Obsolete Functions 
    PostAppMessage 
    SetMessageQueue 
    WM_USER
    展开全文
  • 主要介绍了Windows消息传递机制,有助于读者更好的理解windows编程的消息机制,需要的朋友可以参考下
  • windows消息传递机制详解

    千次阅读 多人点赞 2018-01-31 18:06:11
    Windows消息提供了应用程序之间、应用程序与Windows系统之间进行通信的手段。应用程序想要实现的功能由消息来触发,并且靠对消息的响应和处理来完成。必须注意的是,消息并非是抢占性的,无论事件的缓急,总是按照...
                
    林炳文Evankaka
    原创作品。转载请注明出处
    http://blog.csdn.net/evankaka 
    

         Windows是一个消息(Message)驱动系统。Windows的消息提供了应用程序之间、应用程序与Windows系统之间进行通信的手段。应用程序想要实现的功能由消息来触发,并且靠对消息的响应和处理来完成。必须注意的是,消息并非是抢占性的,无论事件的缓急,总是按照到达的先后派对,依次处理(一些系统消息除外),这样可能使一些实时外部事件得不到及时处理。

          Windows的应用程序一般包含窗口(Window),它主要为用户提供一种可视化的交互方式,窗口是总是在某个线程(Thread)内创建的。Windows系统通过消息机制来管理交互,消息(Message)被发送,保存,处理,一个线程会维护自己的一套消息队列(Message Queue),以保持线程间的独占性。队列的特点无非是先进先出,这种机制可以实现一种异步的需求响应过程。

    目录:

    1、消息

    2  、消息类型

    3 、消息队列(Message Queues)

    4 、队列消息(Queued Messages)和非队列消息(Non-Queued Messages)

    5 、PostMessage(PostThreadMessage), SendMessage

    6 、GetMessage, PeekMessage

    7 、TranslateMessage, TranslateAccelerator

    8、(消息死锁( Message Deadlocks)

    9、BroadcastSystemMessage

    10、消息的处理

    11、MFC的消息映射

    12、消息反射机制


    1、消息

        消息系统对于一个win32程序来说十分重要,它是一个程序运行的动力源泉。一个消息,是系统定义的一个32位的值,他唯一的定义了一个事件,向Windows发出一个通知,告诉应用程序某个事情发生了。例如,单击鼠标、改变窗口尺寸、按下键盘上的一个键

    都会使Windows发送一个消息给应用程序。

        消息本身是作为一个记录传递给应用程序的,这个记录中包含了消息的类型以及其他信息。例如,对于单击鼠标所产生的消息来

    说,这个记录中包含了单击鼠标时的坐标。这个记录类型叫做MSG,MSG含有来自windows应用程序消息队列的消息信息,它在

    Windows中声明如下: 
    typedef struct tagMsg 

    HWND hwnd;          // 接受该消息的窗口句柄 
    UINT message;         // 消息常量标识符,也就是我们通常所说的消息号 
    WPARAM wParam;     // 32位消息的特定附加信息,确切含义依赖于消息值 
    LPARAM lParam;       // 32位消息的特定附加信息,确切含义依赖于消息值 
    DWORD time;         // 消息创建时的时间 
    POINT pt;             // 消息创建时的鼠标/光标在屏幕坐标系中的位置 
    }MSG; 
        消息可以由系统或者应用程序产生。系统在发生输入事件时产生消息。举个例子, 当用户敲键, 移动鼠标或者单击控件。系统也
    产生消息以响应由应用程序带来的变化, 比如应用程序改变系统字体,改变窗体大小。应用程序可以产生消息使窗体执行任务,或者与其他应用程序中的窗口通讯。

    2、消息类型

    1) 系统定义消息(System-Defined Messages)
            在SDK中事先定义好的消息,非用户定义的,其范围在[0x0000, 0x03ff]之间, 可以分为以下三类: 
    1> 窗口消息(Windows Message)
           与窗口的内部运作有关,如创建窗口,绘制窗口,销毁窗口等。可以是一般的窗口,也可以是Dialog,控件等。 
    如:WM_CREATE, WM_PAINT, WM_MOUSEMOVE, WM_CTLCOLOR, WM_HSCROLL... 
    2> 命令消息(Command Message)
            与处理用户请求有关, 如单击菜单项或工具栏或控件时, 就会产生命令消息。 
    WM_COMMAND, LOWORD(wParam)表示菜单项,工具栏按钮或控件的ID。如果是控件, HIWORD(wParam)表示控件消息类型 
    3> 控件通知(Notify Message)
            控件通知消息, 这是最灵活的消息格式, 其Message, wParam, lParam分别为:WM_NOTIFY, 控件ID,指向NMHDR的指针。NMHDR包含控件通知的内容, 可以任意扩展。 
    2) 程序定义消息(Application-Defined Messages)
            用户自定义的消息, 对于其范围有如下规定: 
    WM_USER: 0x0400-0x7FFF      (ex. WM_USER+10) 
    WM_APP(winver> 4.0): 0x8000-0xBFFF (ex.WM_APP+4) 
    RegisterWindowMessage: 0xC000-0xFFFF

    3、消息队列(Message Queues)

     Windows中有两种类型的消息队列 
    1) 系统消息队列(System Message Queue)
            这是一个系统唯一的Queue,设备驱动(mouse, keyboard)会把操作输入转化成消息存在系统队列中,然后系统会把此消息放到目标窗口所在的线程的消息队列(thread-specific message queue)中等待处理 
    2) 线程消息队列(Thread-specific Message Queue)
            每一个GUI线程都会维护这样一个线程消息队列。(这个队列只有在线程调用GDI函数时才会创建,默认不创建)。然后线程消息队列中的消息会被送到相应的窗口过程(WndProc)处理. 
    注意: 线程消息队列中WM_PAINT,WM_TIMER只有在Queue中没有其他消息的时候才会被处理,WM_PAINT消息还会被合并以提高效率。其他所有消息以先进先出(FIFO)的方式被处理。

    4、队列消息(Queued Messages)和非队列消息(Non-Queued Messages)

    1)队列消息(Queued Messages)
            消息会先保存在消息队列中,消息循环会从此队列中取消息并分发到各窗口处理  、如鼠标,键盘消息。 
    2) 非队列消息(NonQueued Messages)
            消息会绕过系统消息队列和线程消息队列直接发送到窗口过程被处理  如: WM_ACTIVATE, WM_SETFOCUS, WM_SETCURSOR, WM_WINDOWPOSCHANGED 
    注意: postMessage发送的消息是队列消息,它会把消息Post到消息队列中; SendMessage发送的消息是非队列消息, 被直接送到窗口过程处理.

    队列消息和非队列消息的区别
            从消息的发送途径来看,消息可以分成2种:队列消息和非队列消息。消息队列由可以分成系统消息队列和线程消息队列。系统消息队列由Windows维护,线程消息队列则由每个GUI线程自己进行维护,为避免给non-GUI现成创建消息队列,所有线程产生时并没有消息队列,仅当线程第一次调用GDI函数时系统才给线程创建一个消息队列。队列消息送到系统消息队列,然后到线程消息队列;非队列消息直接送给目的窗口过程。
         对于队列消息,最常见的是鼠标和键盘触发的消息,例如WM_MOUSERMOVE,WM_CHAR等消息,还有一些其它的消息,例如:WM_PAINT、 WM_TIMER和WM_QUIT。当鼠标、键盘事件被触发后,相应的鼠标或键盘驱动程序就会把这些事件转换成相应的消息,然后输送到系统消息队列,由 Windows系统去进行处理。Windows系统则在适当的时机,从系统消息队列中取出一个消息,根据前面我们所说的MSG消息结构确定消息是要被送往那个窗口,然后把取出的消息送往创建窗口的线程的相应队列,下面的事情就该由线程消息队列操心了,Windows开始忙自己的事情去了。线程看到自己的消息队列中有消息,就从队列中取出来,通过操作系统发送到合适的窗口过程去处理。
         一般来讲,系统总是将消息Post在消息队列的末尾。这样保证窗口以先进先出的顺序接受消息。然而,WM_PAINT是一个例外,同一个窗口的多个 WM_PAINT被合并成一个 WM_PAINT 消息, 合并所有的无效区域到一个无效区域。合并WM_PAIN的目的是为了减少刷新窗口的次数。

          非队列消息将会绕过系统队列和消息队列,直接将消息发送到窗口过程,。系统发送非队列消息通知窗口,系统发送消息通知窗口。例如,当用户激活一个窗口系统发送WM_ACTIVATE, WM_SETFOCUS, and WM_SETCURSOR。这些消息通知窗口它被激活了。非队列消息也可以由当应用程序调用系统函数产生。例如,当程序调用SetWindowPos系统发送WM_WINDOWPOSCHANGED消息。一些函数也发送非队列消息,例如下面我们要谈到的函数。

    5 、PostMessage(PostThreadMessage), SendMessage
            PostMessage:把消息放到指定窗口所在的线程消息队列中后立即返回。 PostThreadMessage:把消息放到指定线程的消息队列中后立即返回。 
            SendMessage:直接把消息送到窗口过程处理, 处理完了才返回。

    PostMessage(异步)和SendMessage(同步)的区别

    a、 PostMessage 是异步的,SendMessage 是同步的。

             PostMessage 只把消息放到队列,不管消息是不是被处理就返回,消息可能不被处理;

            SendMessage等待消息被处理完了才返回,如果消息不被处理,发送消息的线程将一直处于阻塞状态,等待消息的返回。

    b、 同一个线程内:

              SendMessage 发送消息时,由USER32.DLL模块调用目标窗口的消息处理程序,并将结果返回,SendMessage 在同一个线程里面发送消息不进入线程消息队列;PostMessage 发送的消息要先放到消息队列,然后通过消息循环分派到目标窗口(DispatchMessage)。

    c、不同线程:

                 SendMessage 发送消息到目标窗口的消息队列,然后发送消息的线程在USER32。DLL模块内监视和等待消息的处理结果,直到目标窗口的才处理返回,SendMessage在返回之前还需要做许多工作,如响应别的线程向它发送的SendMessage().PostMessge() 到别的线程的时候最好使用PostThreadMessage   代替。PostMessage()的HWND 参数可以为NULL,相当于PostThreadMessage() + GetCrrentThreadId.

    d、系统处理消息。

           系统只处理(marshal)系统消息(0--WM_USER),发送用户消息(用户自己定义)时需要用户自己处理。

            使用PostMessage,SendNotifyMessage,SendMessageCallback等异步函数发送系统消息时,参数不可以使用指针,因为发送者不等待消息的处理就返回,接收者还没有处理,指针就有可能被释放了,或则内容变化了。

    e、在Windows 2000/XP,每个消息队列最多只能存放一定数量的消息,超过的将不会被处理就丢掉。系统默认是10000;:[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows] USERPostMessageLimit

    6 、GetMessage, PeekMessage
    PeekMessage会立即返回    可以保留消息 
    GetMessage在有消息时返回  会删除消息

    PeekMessage和GetMessage函数的主要区别有:
            a. GetMessage的主要功能是从消息队列中“取出”消息,消息被取出以后,就从消息队列中将其删除;而PeekMessage的主要功能是“窥视”消息,如果有消息,就返回true,否则返回false。也可以使用PeekMessage从消息队列中取出消息,这要用到它的一个参数(UINT wRemoveMsg),如果设置为PM_REMOVE,消息则被取出并从消息队列中删除;如果设置为PM_NOREMOVE,消息就不会从消息队列中取出。
            b. 如果GetMessage从消息队列中取不到消息,则线程就会被操作系统挂起,等到OS重新调度该线程时,两者的性质不同:使用GetMessage线程仍会被挂起,使用PeekMessage线程会得到CPU的控制权,运行一段时间。
            c、GetMessage每次都会等待消息,直到取到消息才返回;而PeekMessage只是查询消息队列,没有消息就立即返回,从返回值判断是否取到了消息。
    我们也可以说,PeekMessage是一个具有线程异步行为的函数,不管消息队列中是否有消息,函数都会立即返回。而GetMessage则是一个具有线程同步行为的函数,如果消息队列中没有消息的话,函数就会一直等待,直到消息队列中至少有一条消息时才返回。
    如果消息队列中没有消息,PeekMessage总是能返回,这就相当于在执行一个循环,如果消息队列一直为空, 它就进入了一个死循环。GetMessage则不可能因为消息队列为空而进入死循环。

    联系:

            在Windows的内部,GetMessage和PeekMessage执行着相同的代码,Peekmessage和Getmessage都是向系统的消息队列中取得消息,并将其放置在指定的结构。

    区别:

    PeekMessage:有消息时返回TRUE,没有消息返回FALSE 

    GetMessage:有消息时且消息不为WM_QUIT时返回TRUE,如果有消息且为WM_QUIT则返回FALSE,没有消息时不返回。

    GetMessage:取得消息后,删除除WM_PAINT消息以外的消息。

    PeekMessage:取得消息后,根据wRemoveMsg参数判断是否删除消息。PM_REMOVE则删除,PM_NOREMOVE不删除。

    The PeekMessage function normally does not remove WM_PAINT messages from the queue. WM_PAINT messages remain in the queue until they are processed. However, if a WM_PAINT message has a null update region, PeekMessage does remove it from the queue.

    不能用PeekMessage从消息队列中删除WM_PAINT消息,从队列中删除WM_PAINT消息可以令窗口显示区域的失效区域变得有效(刷新窗口),如果队列中包含WM_PAINT消息程序就会一直while循环了。

    7 、TranslateMessage, TranslateAccelerator
             TranslateMessage: 把一个virtual-key消息转化成字符消息(character message),并放到当前线程的消息队列中,消息循环下一次取出处理。 
            TranslateAccelerator: 将快捷键对应到相应的菜单命令。它会把WM_KEYDOWN 或 WM_SYSKEYDOWN转化成快捷键表中相应的WM_COMMAND 或WM_SYSCOMMAND消息, 然后把转化后的 WM_COMMAND或WM_SYSCOMMAND直接发送到窗口过程处理, 处理完后才会返回。

    8、(消息死锁( Message Deadlocks)
    假设有线程A和B, 现在有以下下步骤 
            1) 线程A SendMessage给线程B, A等待消息在线程B中处理后返回 
            2) 线程B收到了线程A发来的消息,并进行处理, 在处理过程中,B也向线程A SendMessgae,然后等待从A返回。  因为此时, 线程A正等待从线程B返回, 无法处理B发来的消息, 从而导致了线程A,B相互等待, 形成死锁。多个线程也可以形成环形死锁。 
    可以使用 SendNotifyMessage或SendMessageTimeout来避免出现死锁。

    9、BroadcastSystemMessage
            我们一般所接触到的消息都是发送给窗口的, 其实, 消息的接收者可以是多种多样的,它可以是应用程序(applications), 可安装驱动(installable drivers), 网络设备(network drivers), 系统级设备驱动(system-level device drivers)等, 
    BroadcastSystemMessage这个API可以对以上系统组件发送消息。

    10、消息的处理
            接下来我们谈一下消息的处理,首先我们来看一下VC中的消息泵:

    while(GetMessage(&msg, NULL, 0, 0))
    {
           if(!TranslateAccelerator(msg.hWnd, hAccelTable, &msg))

                TranslateMessage(&msg);
                DispatchMessage(&msg);
           }
    }

    TranslateMessage(转换消息):

            用来把虚拟键消息转换为字符消息。由于Windows对所有键盘编码都是采用虚拟键的定义,这样当按键按下时,并不得字符消息,需要键盘映射转换为字符的消息。

    TranslateMessage函数

            用于将虚拟键消息转换为字符消息。字符消息被投递到调用线程的消息队列中,当下一次调用GetMessage函数时被取出。当我们敲击键盘上的某个字符键时,系统将产生WM_KEYDOWN和WM_KEYUP消息。这两个消息的附加参数(wParam和lParam)包含的是虚拟键代码和扫描码等信息,而我们在程序中往往需要得到某个字符的ASCII码,TranslateMessage这个函数就可以将WM_KEYDOWN和WM_ KEYUP消息的组合转换为一条WM_CHAR消息(该消息的wParam附加参数包含了字符的ASCII码),并将转换后的新消息投递到调用线程的消息队列中。注意,TranslateMessage函数并不会修改原有的消息,它只是产生新的消息并投递到消息队列中。

    也就是说TranslateMessage会发现消息里是否有字符键的消息,如果有字符键的消息,就会产生WM_CHAR消息,如果没有就会产生什么消息。

    DispatchMessage(分派消息):

    把 TranslateMessage转换的消息发送到窗口的消息处理函数,此函数在窗口注册时已经指定。

            首先,GetMessage从进程的主线程的消息队列中获取一个消息并将它复制到MSG结构,如果队列中没有消息,则GetMessage函数将等待一个消息的到来以后才返回。如果你将一个窗口句柄作为第二个参数传入GetMessage,那么只有指定窗口的的消息可以从队列中获得。GetMessage也可以从消息队列中过滤消息只接受消息队列中落在范围内的消息。这时候就要利用GetMessage/PeekMessage指定一个消息过滤器。这个过滤器是一个消息标识符的范围或者是一个窗体句柄,或者两者同时指定。当应用程序要查找一个后入消息队列的消息是很有用。WM_KEYFIRST 和 WM_KEYLAST 常量用于接受所有的键盘消息。 WM_MOUSEFIRST 和 WM_MOUSELAST 常量用于接受所有的鼠标消息。
    然后TranslateAccelerator判断该消息是不是一个按键消息并且是一个加速键消息,如果是,则该函数将把几个按键消息转换成一个加速键消息传递给窗口的回调函数。处理了加速键之后,函数TranslateMessage将把两个按键消息WM_KEYDOWN和WM_KEYUP转换成一个 WM_CHAR,不过需要注意的是,消息WM_KEYDOWN,WM_KEYUP仍然将传递给窗口的回调函数。    
    处理完之后,DispatchMessage函数将把此消息发送给该消息指定的窗口中已设定的回调函数。如果消息是WM_QUIT,则 GetMessage返回0,从而退出循环体。应用程序可以使用PostQuitMessage来结束自己的消息循环。通常在主窗口的 WM_DESTROY消息中调用。

    11、MFC的消息映射
             使用MFC编程时,消息发送和处理的本质和Win32相同,但是,它对消息处理进行了封装,简化了程序员编程时消息处理的复杂性,它通过消息映射机制来处理消息,程序员不必去设计和实现自己的窗口过程。
    说白了,MFC中的消息映射机制实质是一张巨大的消息及其处理函数对应表。消息映射基本上分为两大部分:
    在头文件(.h)中有一个宏DECLARE_MESSAGE_MAP(),它放在类的末尾,是一个public属性的;与之对应的是在实现部分(.cpp)增加了一个消息映射表,内容如下:
    BEGIN_MASSAGE_MAP(当前类,当前类的基类)
    //{{AFX_MSG_MAP(CMainFrame)
    消息的入口项
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    但是仅是这两项还不足以完成一条消息,要是一个消息工作,必须还有以下3个部分去协作:
    1、在类的定义中加入相应的函数声明;
    2、在类的消息映射表中加入相应的消息映射入口项;
    3、在类的实现中加入相应的函数体;
    消息的添加
    (1)、利用Class Wizard实现自动添加
            在菜单中选择View -&gt; Class Wizard激活Class Wizard,选择Message Map标签,从Class name组合框中选取我们想要添加消息的类。在Object IDs列表框中,选取类的名称。此时,Messages列表框显示该类的可重载成员函数和窗口消息。可重载成员函数显示在列表的上部,以实际虚构成员函数的大小写字母来表示。其他为窗口消息,以大写字母出现。选中我们要添加的消息,单击Add Funtion按钮,Class Wizard自动将该消息添加进来。
    有时候,我们想要添加的消息在Message列表中找不到,我们可以利用Class Wizard上Class Info标签以扩展消息列表。在该页中,找到Message Filter组合框,通过它可以改变首页中Messages列表框中的选项。
    (2)、手动添加消息
     如果Messages列表框中确实没有我们想要的消息,就需要我们手工添加:
            1)在类的.h文件中添加处理函数的声明,紧接着在//}}AFX_MSG行之后加入声明,注意,一定要以afx_msg开头。
    通常,添加处理函数声明的最好的地方是源代码中Class Wizard维护的表的下面,在它标记其领域的{{ }}括弧外面。这些括弧中的任何东西都有可能会被Class Wizard销毁。
            2)接着,在用户类的.cpp文件中找到//}}AFX_MSG_MAP行,紧接在它之后加入消息入口项。同样,也放在{{ }}外面。
            3)最后,在该文件中添加消息处理函数的实体。
    对于能够使用Class Wizard添加的消息,尽量使用Class Wizard添加,以减少我们的工作量;对于不能使用Class Wizard添加的消息和自定义消息,需要手动添加。总体说来,MFC的消息编程对用户来说,相对比较简单,在此不再使用实例演示。
            12、消息反射机制
    什么叫消息反射?
             父窗口将控件发给它的通知消息,反射回控件进行处理(即让控件处理这个消息),这种通知消息让控件自己处理的机制叫做消息反射机制。
            通过前面的学习我们知道,一般情况下,控件向父窗口发送通知消息,由父窗口处理这些通知消息。这样,父窗口(通常是一个对话框)会对这些消息进行处理,换句话说,控件的这些消息处理必须在父窗口类体内,每当我们添加子控件的时候,就要在父窗口类中复制这些代码。很明显,这对代码的维护和移植带来了不便,而且,明显背离C++的对象编程原则。
            从4.0版开始,MFC提供了一种消息反射机制(Message Reflection),可以把控件通知消息反射回控件。具体地讲,对于反射消息,如果控件有该消息的处理函数,那么就由控件自己处理该消息,如果控件不处理该消息,则框架会把该消息继续送给父窗口,这样父窗口继续处理该消息。可见,新的消息反射机制并不破坏原来的通知消息处理机制。
    消息反射机制为控件提供了处理通知消息的机会,这是很有用的。如果按传统的方法,由父窗口来处理这个消息,则加重了控件对象对父窗口的依赖程度,这显然违背了面向对象的原则。若由控件自己处理消息,则使得控件对象具有更大的独立性,大大方便了代码的维护和移植。
            实例M8:简单地演示MFC的消息反射机制。(见附带源码 工程M8)
         开VC++ 6.0,新建一个基于对话框的工程M8。
    在该工程中,新建一个CMyEdit类,基类是CEdit。接着,在该类中添加三个变量,如下:
    private:
    CBrush m_brBkgnd;
    COLORREF m_clrBkgnd;
    COLORREF m_clrText;
    在CMyEdit::CMyEdit()中,给这三个变量赋初值:
    {
    m_clrBkgnd = RGB( 255, 255, 0 );
    m_clrText = RGB( 0, 0, 0 );
    m_brBkgnd.CreateSolidBrush(RGB( 150, 150, 150) );
    }
    打开ClassWizard,类名为CMyEdit,Messages处选中“=WM_CTLCOLOR”,您是否发现,WM_CTLCOLOR消息前面有一个等号,它表示该消息是反射消息,也就是说,前面有等号的消息是可以反射的消息。
    消息反射函数代码如下:
    HBRUSH CMyEdit::CtlColor(CDC* pDC, UINT nCtlColor)
    {
        // TODO: Change any attributes of the DC here
        pDC-&gt;SetTextColor( m_clrText );//设置文本颜色
        pDC-&gt;SetBkColor( m_clrBkgnd );//设置背景颜色
         //请注意,在我们改写该函数的内容前,函数返回NULL,即return NULL;
        //函数返回NULL将会执行父窗口的CtlColor函数,而不执行控件的CtlColor函数
        //所以,我们让函数返回背景刷,而不返回NULL,目的就是为了实现消息反射
        return m_brBkgnd; //返回背景刷
    }
    在IDD_M8_DIALOG对话框中添加一个Edit控件,使用ClassWizard给该Edit控件添加一个CMyEdit类型的变量m_edit1,把Edit控件和CMyEdit关联起来。

    林炳文Evankaka原创作品。转载请注明出处http://blog.csdn.net/evankaka

    展开全文
  • Windows消息机制简介

    2012-10-18 16:38:25
    windows消息机制简单介绍,对消息过程的简单介绍和解释
  • Windows消息机制

    千次阅读 2018-09-04 23:22:17
    消息队列在哪 消息队列 进程--&gt;消息队列 消息队列--&...Windows不是这样,Linux是这样。微软是把消息队列存到了0环。 怎么找到消息结构体,是KThread(任何一个线程都有个内核结构...
  • Windows的钩子机制详解

    2020-12-31 20:05:00
    了解windows程序设计的人都知道,Windows系统程序的运行是建立在消息传递机制的基础之上的,几乎所有的程序活动都由消息来驱动。钩子机制可以看作是一个消息的中转站,控制系统发出消息的处理和传递。利用钩子,我们...
  • 主要介绍了windows消息消息队列实例详解,详细讲述了Windows消息机制与原理,对于深入理解和学习Windows应用程序设计有不错的借鉴价值,需要的朋友可以参考下
  • windows消息循环机制

    2015-07-11 09:49:36
    Windows消息循环机制及API程序设计 包括了建立工程实现第一个小任务的详细步骤
  • windows消息机制概述(一)

    千次阅读 2017-07-08 17:52:02
    1. 引言 Windows 在操作系统平台占有绝对统治地位,基于...而很多Windows 程序开发人员也只是对消息运行机制一知半解,想要掌握Windows 编程的核心,必须深刻理解消息机制。事件驱动围绕着消息的产生与处理展开,
  • 本文以孙鑫老师VC++教程中的程序为基础,详细讲解了Windows程序内部运行机制,相信可以帮助大家更好的理解Windows程序运行原理及相应的VC++程序设计。具体内容如下: 创建一个Win32应用程序步骤: 1、编写WinMain...
  • QT消息机制Windows MFC 消息机制对接

    千次阅读 2019-09-20 20:48:09
    最近因为项目需要用到奥维地图(OvalMap)的三方接口,因为官网提供的三方接口程序是MFC写的,为了改写成QT版本,能够集成到项目中去,和MFC消息机制打上交道。 记录一下,看过的一些比较好的文章,后面需要复习这...
  • Windows service服务调用机制 详解.zip
  • 除了有《Windows消息大全使用详解》之外,还有《windows消息消息队列》,让你全面了解Windows消息机制
  • windows消息机制(MFC)

    千次阅读 2014-06-30 00:29:48
    Windows中,消息使用统一的结构体(MSG)来存放信息,其中message表明消息的具体的类型, 而wParam,lParam是其最灵活的两个变量,为不同的消息类型时,存放数据的含义也不一样。 time表示产生消息的时间,pt表示...
  • windows内部原理 1.今天明天 2. 体系结构-系统角度 3.体系结构-应用程序角度 4.操作系统概念 5.vista 新特性底层解密 6.开机引导过程 7.内部原理解密 8.sysinternals 工具使用
  • Windows窗口刷新机制详解

    千次阅读 2017-12-28 16:00:13
    1、Windows的窗口刷新管理 窗口句柄(HWND)都是由操作系统内核管理的,系统内部有一个z-order序列,记录着当前窗口从屏幕底部(假象的从屏幕到眼睛的方向),到屏幕最高层的一个窗口句柄的排序,这个排序不关注...
  • 以前经常听一些编程高手说windows是基于消息驱动的,但是一直没有时间研究windows消息机制。最近有点时间研究了一下windows消息机制。以前一直以为Windows消息机制只有在创建窗口的程序中才能使用,其实不然。...
  • 《VC++深入详解》主要从程序内部运行的机制和MFC程序的组织脉络入手,使读者在学习VC++编程知识时,既能够知其然,又能知其所以然,从而帮助读者从根本上理解和掌握Windows的程序设计。另外,《VC++深入详解》还贯穿...
  • 原创经典,威盛一线工程师倾力打造。深入驱动核心,剖析操作系统底层运行机制,通过实例引导,快速学
  • 在Win32下,可以使用两种编程方式实现串口通信,其一是使用ActiveX控件,这种方法程序简单,但欠...其二是调用Windows的API函数,这种方法可以清楚地掌握串口通信的机制,并且自由灵活。本文只介绍API串口通信部分。
  • MFC消息映射机制详解

    千次阅读 2015-10-21 13:57:09
    Windows程序和MFC程序是靠消息驱动的,他们...用多了mfc就想对它的消息映射机制有一个本质的了解,下面将对消息映射做详细的分析。当然,在分析MFC消息映射之前首先对Windows程序的消息处理过程进行一个简单的描述。
  • 众所周知,Linux 桌面系统与 MAC 或 Windows 相比有许多不如人意的地方,为了改善这种状况,开源社区提出用户态需要内核提供一些机制,以便用户态能够及时地得知内核或底层硬件设备发生了什么,从而能够更好地管理...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 45,808
精华内容 18,323
关键字:

windows消息机制详解