http://www.5itjob.com
Win32编程-消息处理机制
【ITjob课程资料】
下面我们来了解一下:
windows消息处理机制
Windows编程是通过消息(事件)机制来完成的,一般消息的产生有三个来源: ? (1)用户操作产生的消息
比如,我们点击了窗口上的一个按钮,按下了键盘上的键等等,都会产生消息。
? (2)应用程序产生的消息
比如,一个窗口被最大化时,它就会产生重画最大化窗口的消息等等 ? (3)操作系统产生的消息 比如,我们在程序中有一个定时器,系统隔相应的时间就会产生WM_TIMER(计时器事件)。
在WinMain()函数中,创建了应用程序主窗口之后,就要启动消息循环,就像汽车等待被操控一样,其代码如下: MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
DispatchMessage(&msg); }
下面我们来解释这段程序:
GetMessage()函数是一个阻塞函数(就是遇到这个函数就进入等待状态),是用来从应用程序的消息队列中按照先进先出的原则将这些消息一个个的取出来。
GetMessage()函数的几个参数说明如下: (1)LPMSG lpMsg 是一个指向MSG结构体指针,每个消息对应一个MSG结构体
(2)HWND hWnd 指定哪个窗口的消息将被获取,如果不指定窗口则为NULL (3)UINT wMsgFilterMin 指定获取的主消息值的最小值,这里我们设置为0
(4)UINT wMsgFilterMax 指定获取的主消息值的最大值,这里我们设置为0
GetMessage()将获取的消息复制到一个MSG结构中。如果队列中没有任何消息,GetMessage()函数将一直空闲直到队列中又有消息时再返回。如果队列中已有消息,它将取出一个后返回。MSG结构包含了一条Windows消息的完整信息,其定义如下:
typedef struct tagMSG {
第一章:Win32编程 ITjob就业培训
HWND hwnd; //接收消息的窗口句柄 UINT message; //主消息值
WPARAM wParam; //副消息值,其具体含义依赖于主消息值 LPARAM lParam; //副消息值,其具体含义依赖于主消息值 DWORD time; //消息被投递的时间 POINT pt; //鼠标的位置 } MSG;
假如,我们在一个窗口中点击了一下鼠标左键,处理过程是这样的: 首先,系统会填充一个MSG消息结构,把当前的消息句柄放到MSG结构的hwnd成员中去,把消息类型WM_LBUTTONDOWN(鼠标左键按下)放到messge成员中,把鼠标的位置信息放到lParam中,然后把产生的消息放到系统消息队列的尾部,GetMessage函数从消息队列的头部一直不停的取消息,当取到刚才的消息后,会根据消息结构成员的第一个参数即窗口句柄,把消息分发给不同的窗口消息队列,窗口消息队列得到消息后,根据消息的类型,进行不同的处理。
问题是怎么让操作系统完成这个工作呢? 答案是通过回调函数来完成。
关于回调函数
Windows程序的原理是创建一个回调函数,然后在此函数中响应消息实现用户操作。它的实质是由系统调用,程序员负责代码实现,告诉系统如何响应消息。
回调函数的原型为:
LRESULT CALLBACK WinProc( HWND hwnd, // 窗口句柄 UINT uMsg, // 消息ID
WPARAM wParam, // 第1个消息参数 LPARAM lParam // 第2个消息参数
下面我们来实现回调函数,代码如下: LRESULT CALLBACK WinProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) {
switch (uMsg) {
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam); }
2
http://www.5itjob.com
return 0; }
当然这个函数要放置在WinMain的前面。 下面对这个函数的解释:
1、第一个参数HWND hwnd 是指接收消息窗口的句柄,这个函数因为是由WinMain自己调用,所以这个hwnd在系统自己调用的时候会自动赋值为刚刚创建的窗口句柄。
2、第二个参数UINT uMsg与MSG结构中的message值是一致的,代表了主消息值。程序中用switch语句来将不同类型的消息分配到不同的处理程序中去,这个系统也会自动捕捉并赋值
3、第三个参数WPARAM wParam 和第四个参数LPARAM lParam用于捕捉消息的附加参数,比如:具体键盘的字符或者鼠标的位置等。 4、函数的约定为CALLBACK,这是一个宏。 5、返回一个LRESULT数据类型。
6、通过DefWindowProc来完成创建窗口的过程。
值得注意的是,应用程序发送到窗口的消息远远不止以上这几条,除了WM_CREATE,象WM_SIZE、WM_MINIMIZE、WM_MOVE等这样频频使用的消息就有几十条。为了减轻编程的负担,Windows的API提供了DefWindowProc()函数来处理这些最常用的消息,调用了这个函数后,这些消息将按照系统默认的方式得到处理。
因此,在switch_case语句中,只须明确的处理那些有必要进行特别响应的消息,把其余的消息交给DefWindowProc()函数来处理,是一种明智的选择,也是你必须做的一件事。
程序运行,窗口出现,但是新的问题出现了,如何关闭窗口?当我们点击关闭按钮的时候窗口并没有关闭,我们要做如下处理: case WM_DESTROY:
PostQuitMessage(0); break;
因为当我们点击关闭按钮的时候,向程序发送了一个WM_DESTROY消息。在处理此消息时,调用了PostQuitMessage()函数,该函数会向窗口的消息队列中发送一条WM_QUIT的消息。在消息循环中,GetMessage()函数一旦检索到这条消息,就会返回FALSE,从而结束消息循环,随后,退出WinMain主函数,应用程序也就自然结束了。
注意:PostQuitMessage中的参数被用于消息WM_QUIT的wParam参数,但是实际上这个参数用处不大,因为无法捕获。
至此我们完成我们的第一个窗口的制作。
功能似乎有点太少,下面我们增加一些常用的功能。
这样我们的第一个windows程序就建立成功了,下面我们再来增加一个常用的键盘响应功能和鼠标响应功能: