当前位置:首页 > Windows程序 > 正文

收藏:Windows消息机制

2021-05-25 Windows程序

百度百科介绍的windows消息机制也不错: 

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


消息的是什么样子的?

消息由一个叫MSG的结构体定义,包括窗口句柄(HWND),消息ID(UINT),参数(WPARAM, LPARAM)等等:

struct MSG

{

HWND hwnd;

UINT message;

WPARAM wParam;

LPARAM lParam;

DWORD time;

POINT pt;

};


消息ID是消息的类型标识符,由系统或应用程序定义,消息ID为消息划分了类型。同时,也可以看出消息是对应于特定的窗口(窗口句柄)的。

消息是如何分类的?其前缀都代表什么含义?

消息ID只是一个整数,Windows系统预定义了很多消息ID,以不同的前缀来划分,比如WM_*,CB_*等等。
具体见下表:

PrefixMessage categoryABMApplication desktop toolbarBMButton controlCBCombo box controlCBEMExtended combo box controlCDMCommon dialog boxDBTDeviceDLDrag list boxDMDefault push button controlDTMDate and time picker controlEMEdit controlHDMHeader controlHKMHot key controlIPMIP address controlLBList box controlLVMList view controlMCMMonth calendar controlPBMProgress barPGMPager controlPSMProperty sheetRBRebar controlSBStatus bar windowSBMScroll bar controlSTMStatic controlTBToolbarTBMTrackbarTCMTab controlTTMTooltip controlTVMTree-view controlUDMUp-down controlWMGeneral window
应用程序可以定义自己的消息,其取值范围必须大于WM_USER。

如何通过消息传递任何参数?

Windows系统的消息机制都包含2个长整型的参数:WPARAM, LPARAM,可以存放指针,也就是说可以指向任何内容了。
传递的内容因消息各异,,消息处理函数会根据消息的类型进行特别的处理,它知道传递的参数是什么含义。

消息在线程内传递时,由于在同一个地址空间中,指针的值是有效的。但是夸线程的情况就不能直接使用指针了,所以Windows系统提供了 WM_SETTEXT, WM_GETTEXT, WM_COPYDATA等消息,用来特殊处理,指针的内容会被放到一个临时的内存映射文件(Memory-mapped File)里面,通过它实现线程间的共享数据。


消息队列和线程的关系是什么?消息队列的结构是什么样子的?

Windows系统本身会维护一个唯一的消息队列,以便于发送给各个线程,这是系统内部的实现方式。
而对于线程来说,每个线程可以拥有自己的消息队列,它和线程一一对应。在线程刚创建时,消息队列并不会被创建,而是当GDI的函数调用发生时,Windows系统才认为有必要为线程创建消息队列。
消息队列包含在一个叫THREADINFO的结构中,有四个队列:

Sent Message Queue
Posted Message Queue
Visualized Input Queue
Reply Message Queue

之所以维护多个队列,是因为不同消息的处理方式和处理顺序是不同的。

线程和窗口是一一对应的吗?如果想要有两个不同的窗口对消息作出不同反应,但是他们属于同一个线程,可能吗?

窗口由线程创建,一个线程可以创建多个窗口。窗口可由CreateWindow()函数创建,但前提是需要提供一个已注册的窗口类(Window Class),每一个窗口类在注册时需要指定一个窗口处理函数(Window Procedure),这个函数是一个回调函数,就是用来处理消息的。而由一个线程来创建对应于不同的窗口类的窗口是可以的。
由此可见,只要注册多个窗口类,每个窗口都可以拥有自己的消息处理函数,而同时,他们属于同一个线程。


如何发送消息?

消息的发送终归通过函数调用,比较常用的有PostMessage(),SendMessage(),另外还有一些Post*或Send*的函数。函数的调用者即发送消息的人。
这二者有什么不同呢?SendMessage()要求接收者立即处理消息,等处理完毕后才返回。而PostMessage()将消息发送到接收者队列中以后,立即返回,调用者不知道消息的处理情况。

他们的的原型如下:

LRESULT SendMessage(

HWND hwnd, 

UINT uMsg, 

WPARAM wParam, 

LPARAM lParam);

LRESULT PostMessage(

HWND hwnd, 

UINT uMsg, 

WPARAM wParam, 

LPARAM lParam);

温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/70759.html