Windows消息队列学习笔记

1.windows消息和消息结构

一条消息是作为一个结构传递给应用程序的,这个结构中,包含了消息号,消息的类型,字参数和长字参数等信息。结构定义如下:

typedef struct tagMSG {
  HWND hwnd;
  UINT message;
  WPARAM wParam;
  LPARAM lParam;
  DWORD time;
  POINT pt;
 } MSG;
  • 第一个成员变量hwnd表示消息所属的窗口。在Windows程序中,用HWND类型的变量来标识窗口。
  • 第二个成员变量message指定了消息的标识符。在Windows中,消息是由一个数值来表示的,不同的消息对应不同的数值。但是由于数值不便于记忆,所以Windows将消息对应的数值定义为WM_XXX宏(WM是Window Message的缩写)的形式,XXX对应某种消息的英文拼写的大写形式。例如,鼠标左键按下消息是WM_LBUTTONDOWN,键盘按下消息是WM_KEYDOWN,字符消息是WM_CHAR,等等。在程序中我们通常都是以WM_XXX宏的形式来使用消息的。

    提示:如果想知道WM_XXX消息对应的具体数值,可以在Visual C++开发环境中选中WM_XXX,然后单击鼠标右键,在弹出菜单中选择goto definition,即可看到该宏的具体定义。跟踪或查看某个变量的定义,都可以使用这个方法。

  • 第三、第四个成员变量wParam和lParam,用于指定消息的附加信息。例如,当我们收到一个字符消息的时候,message成员变量的值就是WM_CHAR,但用户到底输入的是什么字符,那么就由wParam和lParam来说明。wParam、lParam表示的信息随消息的不同而不同。如果想知道这两个成员变量具体表示的信息,可以在MSDN中关于某个具体消息的说明文档查看到。读者可以在VC++的开发环境中通过goto definition查看一下WPARAM和LPARAM这两种类型的定义,可以发现这两种类型实际上就是unsigned int和long。
  • 最后两个变量分别表示消息投递到消息队列中的时间和鼠标的当前位置。

2.Windows消息类别

消息构成消息系统的主要框架,约有上百种常见的标准消息如下:

Windows用不同的前缀符号标致不同的消息种类,如BM表示按钮类消息,CB表示组合框消息,DM表示下压式按钮控制消息,EM表示编辑控制消息。

3.消息发送

Windows为了给运行程序一个强壮的运行环境,要求每个线程相对独立,系统会为线程分配一些资源,其中比较特殊的是分配一个THREADINFO结构,当线程有了与之相联系的THREADINFO结构时,线程就有了自己的消息队列集合,每个窗口维护自己的消息队列集合,并从中取出消息,再利用窗口函数处理。

一般调用PostMessage函数将消息发送到线程的等级消息队列中,函数原型如下:

BOOL  PostMessage(
HWND hWnd,  //窗口句柄
UINT Msg,    //要发送的消息
WPARAM wParam,   //第一个参数
LPARAM lParam     //第二个参数
);

当一个线程调用PostMessage函数时,系统首先要知道是哪一个线程建立了用hWnd参数标致的窗口,然后系统分配一块内存,将这个消息参数存储在这块内存中,并将这块内存增加到相应的线程的登记消息队列中。PostMessage函数在登记了消息之后立即返回,因此调用该函数的线程并不知道登记的消息能否被指定的窗口处理。

另外额可以调用PostThreadMessage函数将消息发送到线程的登记消息队列中。

BOOL PostThreadMessage(
DWORD idThread;    //线程标致。
UINT Msg;
WPARAM wParam;
LPARAM lParam
};

要终止消息循环,可以调用PostQuitMessage函数:

void PostQuitMessage(int nExitCode);

该函数实际上不会登记一个消息到任何THREADINFO结构队列中,只是在内部,PostQuitMessage函数设定QS_QUIT唤醒标致,并设置THREADINFO结构的nExitCode成员,因为这些操作永远不会失败,所以PostQuitMessage函数的原型被定义为返回void。

4.消息队列状态标志

可以调用GetQueueStatus函数来查询队列的状态:

DWORD GetQueueStatus(UINT flags);

参数flags是一个或一组or连接起来的标致,可用来测试特定位。

- QS_ALLEVENTS:输入,WM_TIMER, WM_PAINT,WM_HOTKEY或寄送的消息在队列里。

- QS_ALLINPUT:任何消息在队列里。

QS_ALLPOSTMESSAGE:寄送的消息(而不是其他所列消息)在队列里。

QS_HOTKEY:一条WM_HOTKEY消息在队列里。QS_INPUT:输入消息在队列里。

QS_KEY:一条WM_KEYUP WM_KEYDOWN,WM_SYSKEYUP或WM_SYSKEYDOWN消息在队列里。

QS_MOUSE:WM_MOUSEMOVE消息或鼠标键消息(WM_BUTTONUP WM_RBUTTONDOWN等)在消息队列里。

QS_MOUSEBUTTON:鼠标键消息(WM_LBUTTONUP,WM_RBUTTONDOWN等)在消息队列里。

QS_MOUSEMOVE:WM_MOUSEMOVE消息在消息队列里。

QS_FAINT:WM_PAINT消息在消息队列里。

QS_POSTMESSAGE:寄送的消息(而不是其他所列消息)在队列里。

QS_SENDMESSAGE:由其他线程或应用程序发送的消息在消息队列里。

QS_TIEMR:一条WM_TIEMR消息在消息队列里。

当调用此函数时,参数flags将要检查的消息类型告诉函数,返回时,当前消息类型在返回值得高字节中,而低字节指出已经添加到的队列中。

5.提取消息

可以通过GetMessage函数从消息队列中提取一个消息。GetMessage函数的原型如下:

GetMessage(
LPMSG lpMsg,
HWND hWnd,
UINT wMsgFilterMin,
UINT wMsgFilterMax
);

参数说明:

lpMsg:指向MSG结构的指针,该结构从线程的消息队列里接收消息信息。

hWnd:取得其消息的窗口的句柄。当其值取NULL时,GetMessage为任何属于调用线程的窗口检索消 息,线程消息通过PostThreadMessage寄送给调用线程。

wMsgFilterMin: 要获取消息的最小值,通产设为0。

wMsgFilterMax:要获取消息的最大值,若wMsgFilterMin、wMsgFilterMax均为0,则接受所有消息。

GetMessage 返回 TRUE 的条件是有消息且该消息不为WM_QUIT ;返回 FALSE 的条件是有消息且该消息 为 WM_QUIT 在没有消息的时候等待消息,cpu当然低阻塞。

关于消息的深入分析,可以看这个博客。这个也推荐看看



在提取消息时,系统必须检查队列状态,下图给出消息提取过程线:

(1)如果QS_SENDMESSAGE标志位被设置,系统向相应的窗口过程发送消息。GetMessage函数在窗口过程处理完消息后不返回,要等待其他要处理的消息。

(2)如果消息再消息登记队列中,GetMessage函数填充MSG结构,并返回,这时消息循环通常调用DispatchMessage函数,让窗口过程来处理消息。

(3)如果QS_QIUT标志被设置,GetMessage函数返回一个WM_QIUT消息,并复位QS_QIUT标致。

(4)如果消息再虚拟输入队列,GetMessage函数返回硬件输入消息。

(5)如果QS_TIMER标致被设置,GetMessage函数返回一个WM_TIMER消息。

(6)虽然称为消息队列,但队列中的消息并非总是先进先出。例如只要消息队列中存在WM_QIUT,就会先取出WM_QIUT,导致程序借宿。而只有在没有其它消息时WM_PAINT和WM_TIMER才会被取出。若有多个WM_PAINT或者WM_TIMER,则可能会被合并为一个。

最后用一个简单的图来总结一下流程:

由上图可知,基于消息驱动机制设计Windows应用程序时,程序的基本流程交由Windows去处理。Windows掌握着一定的主动权,全心全意为“接受到的消息找到对应的处理函数”提供服务,而用户只需要集中精力做自己的事情,如编写自己的窗口函数等。

时间: 2024-08-04 19:02:51

Windows消息队列学习笔记的相关文章

Windows录音API学习笔记--转

Windows录音API学习笔记 结构体和函数信息  结构体 WAVEINCAPS 该结构描述了一个波形音频输入设备的能力. typedef struct { WORD      wMid; 用于波形音频输入设备的设备驱动程序制造商标识符. WORD      wPid; 声音输入设备的产品识别码. MMVERSION vDriverVersion; 用于波形音频输入设备的设备驱动程序的版本号.高位字节是主版本号,低字节是次版本号. CHAR      szPname[MAXPNAMELEN];

Windows录音API学习笔记(转)

源:Windows录音API学习笔记 Windows录音API学习笔记 结构体和函数信息  结构体 WAVEINCAPS 该结构描述了一个波形音频输入设备的能力. typedef struct { WORD      wMid; 用于波形音频输入设备的设备驱动程序制造商标识符. WORD      wPid; 声音输入设备的产品识别码. MMVERSION vDriverVersion; 用于波形音频输入设备的设备驱动程序的版本号.高位字节是主版本号,低字节是次版本号. CHAR      sz

Windows phone 8 学习笔记(3) 通信(转)

Windows phone 8 可利用的数据通信方式比较广泛,在硬件支持的前提下,我们可以利用WiFi.蓝牙.临近感应等多种方式.数据交互一般通过套接字来完成,我们将在本文详细的分析. 快速导航:一.WP8套接字二.蓝牙三.NFC四.获取网络状态五.访问web的几种方式 一.WP8套接字 1)创建套接字客户端 Windows phone 8中的套接字并不支持发布服务端,我们只能利用它在手机上创建套接字客户端,我们在此例中要用套接字去访问web服务器.首先,我们定义一个SocketClient来表

Windows phone 8 学习笔记(5) 图块与通知(转)

基于metro风格的Windows phone 8 应用提到了图块的概念,它就是指启动菜单中的快速启动图标.一般一个应用必须有一个默认图块,还可以有若干个次要图块.另外,通知与图块的关系比较密切,我们可以通过在接受到消息时动态更新图块来达到适时的效果.我们本节把图块和通知放在一起讲. 快速导航:一.图块二.图块更新计划三.本地通知四.推送通知 一.图块 1)定义默认图块 默认图块只能在清单文件中定义它,并且选定的图块模板后就不能再改变,除非重新发布应用,但是我们可以更新同类型的模板.应用安装后默

Windows phone 8 学习笔记(6) 多任务(转)

Windows phone 8 是一个单任务操作系统,任何时候都只有一个应用处于活跃状态,这里的多任务是指对后台任务的支持.本节我们先讲讲应用程序的运行状态,然后看看支持的后台任务,包括:后台代理.后台音频.后台文件传输.后台辅助线程等. 快速导航:一.应用的状态二.后台代理三.后台音频四.后台文件传输五.后台辅助线程 一.应用的状态 1)应用的运行状态 我们通过图解来分析应用的运行状态,启动并置于前台界面的应用是唯一处于运行状态的,其他的操作,比如win键,后退导出应用,打开选择器和启动器时都

node.js在windows下的学习笔记(2)---简单熟悉一些命令

1.打开如下的安装 2.输入node -v,显示node的版本号 3.输入node --help.显示帮助命令 4.自己用一个文本编辑器编写一下代码,保存为text.js,然后在控制台输入node.exe  text.js的路径(直接把这个js文件拖到控制台自动显示路径),按下回车键 var http = require("http"); http.createServer(function(request, response) { response.writeHead(200, {&

Windows消息队列

一 Windows中有一个系统消息队列,对于每一个正在执行的Windows应用程序,系统为其建立一个"消息队列",即应用程序队列,用来存放该程序可能 创建的各种窗口的消息.应用程序中含有一段称作"消息循环"的代码,用来从消息队列中检索这些消息并把它们分发到相应的窗口函数中.  二 Windows为当前执行的每个Windows程序维护一个「消息队列」.在发生输入事件之后,Windows将事件转换为一个「消息」并将消息放入程序的消息队列中.程序通过执行一块称之为「消息循

node.js在windows下的学习笔记(1)---安装node.js

1.首先打开http://www.nodejs.org/ 2.选择DOWNLOADS,跳转到下面的画面,我的系统是windows7的32位.所以选择.msi的32bit版本. 3.下载后,得到一个5.43MB大小的安装包, 4.运行安装包 点击next 打个勾,点击next 选择安装目录 最后,安装成功啦 node.js在windows下的学习笔记(1)---安装node.js,布布扣,bubuko.com

细说UI线程和Windows消息队列

在 Windows应用程序中,窗体是由一种称为" UI线程( User Interface Thread)"的特殊类型的线程创建的. 首先, UI线程是一种"线程",所以它具有一个线程应该具有的所有特征,比如有一个线程函数和一个线程 ID. 其次," UI线程"又是"特殊"的,这是因为 UI线程的线程函数中会创建一种特殊的对象--窗体,同时,还一并负责创建窗体上的各种控件. 窗体和控件大家都很熟悉了,这些对象具有接收用户操作的