码迷,mamicode.com
首页 > Windows程序 > 详细

Windows消息队列学习笔记

时间:2016-04-29 16:29:31      阅读:267      评论:0      收藏:0      [点我收藏+]

标签:

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掌握着一定的主动权,全心全意为“接受到的消息找到对应的处理函数”提供服务,而用户只需要集中精力做自己的事情,如编写自己的窗口函数等。

Windows消息队列学习笔记

标签:

原文地址:http://blog.csdn.net/q__y__l/article/details/51259911

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!