|
学习提示:如果没有C语言基础可以通过下方链接学习:
0基础C语言学习与训练
0基础C++学习与训练
在我们学习Windows项目开发之前,需要先学习Windows应用程序的框架,而该框架是由C与C++语言构成,
所以,需要大家至少具备C语言的基础。
经过前面的学习,我们已经认识了(Windows应用程序的框架、WinMain入口函数、窗口类的信息与框架的联系、
窗口类的注册、窗口的创建、显示与更新),接下来,我们就继续学习Windows应用程序框架中的(消息处理机制)。
首先,我们回顾一下(Windows应用程序的框架)如下图:

1、当我们完成了上图中的(创建窗口)这一步以后,接下来,就进入到下一步的(主事件循环)中,而在这个
循环里面,它的工作是从(窗口的消息队列)中取出一个(消息),例如:窗口中发生的鼠标点击或键盘的按键消息等,
从上图中大家可以直观地看到,主事件循环有一个指向右方的箭头,是指向(窗口消息队列)。
2、当(主事件循环)取得一个(窗口消息)后,就会把消息发送给(回调函数)处理,就是上图中的(事件处理器),
通过上图大家可以直观地看到,主事件循环有一个指向下方的箭头,是指向(事件处理器)也就是一个回调函数,
而这个回调函数在往后的代码实现中,是需要我们自己编写的。
3、接下来,我们就需要知道,当取出一个消息后,如何通过代码去描述它,以及,它里面究竟包含哪些内容,
在Windows中,它提供了一个(结构体)去描述(消息),名字是tagMSG。
消息结构体的原型如下:
typedef struct tagMSG{
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
};
消息结构体的原型分析:
1、成员1:hwnd,用于说明一个(窗口句柄),即该消息是属于哪一个窗口产生的。
例如,你所开发的程序有多个窗口时,而当前的消息是在哪个窗口中产生的,通过该成员就可以知道了。
2、成员2:message,用于说明该消息的ID号,即消息编号,而每种消息的ID号都是不一样的,
那么,通过该成员就可以知道当前产生的是什么消息。
3、成员3:wParam,用于说明该消息的一个附加信息,可以进一步对当前消息进行判断。
4、成员4:lParam,用于说明该消息的一个附加信息,可以进一步对当前消息进行判断。
5、成员5:time,用于说明该消息产生的时间。
6、成员6:pt,用于说明该消息产生时,鼠标在屏幕中的位置。
通过对(消息结构体)tagMSG的分析以后,大家就可以了解到是如何通过代码去描述一个消息的,
接下来,我们就继续学习如何去获取一个消息,在(主事件循环)中,我们首先需要去(窗口的消息队列)中
获取一个(消息),而获取消息可以使用PeekMessage函数。
PeekMessage函数原型如下:
BooL PeekMessage(
LPMSG lpMsg,
HWND hWnd,
UINT wMsgFilterMin,
UINT wMsgFilterMax,
UINT wRemoveMsg);
获取消息函数的原型分析:
1、参数1:lpMsg, 接收一个描述(窗口消息)的结构体变量,即上面刚学习完的tagMSG消息结构体所定义的
结构体变量,那么,所获取到的消息就保存于该参数中。
2、参数2:hWnd,接收一个(窗口句柄),用于说明要获取哪一个窗口的(消息)。当你的程序中有多个窗口时,
当前要获取哪个窗口中的消息呢?就可以通过该参数说明。
3、参数3:wMsgFilterMin,用于说明获取消息范围的起始位置,因为,窗口消息队列中的消息是一个接着一个
排列的,而获取时,可以通过该参数说明,从第几个开始获取。
4、参数4:wMsgFilterMax,用于说明获取消息范围的结束位置,所以,通过参数3与参数4就可以指定一个获取消息的
范围,但一般情况下我们都是按顺序一个一个地获取,除非你所开发的程序有一些特别要求,那么,就可以通过参数3与
参数4指定范围。
5、参数5:wRemoveMsg,用于说明获取消息后的处理方式,而处理方式有两种。方式1:PM_NOREMOVE,消息在
被获取后,不会从队列中删除。方式2:PM_REMOVE,消息在被获取后,从队列中删除。
6、返回值,它是一个(布尔型)如果返回1,说明获取消息成功。如果返回0,说明获取消息失败。
通过对(PeekMessage)函数的原型分析以后,大家就可以了解到是如何通过代码去获取消息的,同时,
当PeekMessage获取窗口消息成功后,该消息是会保存于第一个参数所接收的tagMSG结构体变量中。
当我们成功获取到一个(窗口消息)后,就需要对该消息进行一个转换,然后,才可以把(转换后的消息)发送到
(事件处理器)即回调用函数中处理。所以,我们需要继续学习(消息转换与发送)的函数。
消息转换函数原型如下:
BOOL TranslateMessage( MSG *lpMsg );
分析:
1、参数1:lpMsg, 用于接收已经获取的窗口消息。即上面刚学习完的PeekMessage函数中的参数1,
就会传递到当前的参数中使用,同时,成功转换后的窗口消息仍然保存于该参数中。
2、返回值,它是一个(布尔型)如果返回1,说明转换消息成功。如果返回0,说明转换消息失败。
消息发送函数原型如下:
LRESULT DispatchMessage( MSG *lpMsg );
分析:
1、参数1:lpMsg, 用于接收已经成功转换的窗口消息,即TranslateMessage函数的参数1会传递到这里作为参数使用。
2、返回值,LRESULT,当DispatchMessage函数把(转换后的窗口消息)发送给(事件处理器)即回调用函数后,
就会有一个返回值,其含义取决于所(发送的消息),通常的情况下,我们可以忽略它。
现在,我们已经了解到如何通过代码描述(窗口消息),以及,如何从(窗口消息队列)中获取消息,
并转换与发送消息给(事件处理器)。
接下来,我们继续学习(事件处理器)即回调用函数。
回调函数的原型如下:
LRESULT CALLBACK Windowproc(
HWND hwnd,
UINT msg,
WPARAM wparam,
LPARAM lparam );
回调函数的原型分析:
1、参数1:hwnd,接收一个(窗口句柄),用于说明将要处理的(消息)是属于哪一个窗口的。
2、参数2:msg,用于说明当前要处理的消息ID号,即消息的编号,而通过这个(消息ID号),我们才可以知道,
当前传递进来的是什么消息。
而(消息ID号)是由Windows提供的,同时,每个ID号都有一个对应的(消息标识符),常用的(消息标识符),
大家可以通过下表查看到。
消息标识符 |
说明 |
WM_ACTIVATE |
当窗口激活或成为焦点时产生消息 |
WM_CREATE |
当窗口创建时产生的消息 |
WM_CLOSE |
当窗口关闭时产生的消息 |
WM_DESTROY |
当窗口销毁时产生的消息 |
WM_MOVE |
当窗口移时产生的消息 |
WM_MOUSEMOVE |
当窗口中的鼠标移动时产生的消息 |
WM_KEYUP |
当键盘的按键被松开时产生的消息 |
WM_KEYDOWN |
当键盘的按键被按下时产生的消息 |
WM_TIMER |
时钟产生的消息 |
WM_USER |
用户自定义的消息 |
WM_PAINT |
窗口需要重绘时产生的消息 |
WM_QUIT |
Windows应用程序结束时产生的消息 |
WM_SIZE |
窗口大小改变时产生的消息 |
3、参数3与参数4:wparam与lparam,用于匹配或分类(msg参数)中的信息。
4、返回类型,LRESULT,是一个长整型,返回1时,说明(回调用函数)执行成功,返回0时,说明执行失败。
5、CALLBACK标识符,用于说明该函数是一个(回调用函数),如果没有这个标识符的说明,就不是一个
(回调用函数)。
6、Windowproc是该(回调函数)的名字,但是,这个名字不是固定的,大家可以自己去定义。
当我们了解完(回调函数)的原型以后,我们还要了解它与(普通函数)的区别。
1、普通函数在定义后,如果要使用,是需要在程序中编写代码去调用才可以使用的,
同时,在调用时要进行参数的传递。
2、回调函数在定义后,不需要在程序中编写代码调用,也不需要通过程序传递参数。
它只需要在(窗口类)的第3个成员lpfnWndProc指定该(回调函数的名字)即可,
例子:lpfnWndProc=Windowproc,大家可以回顾(窗口类分析与联系)。
在我们学习(窗口类)分析时,当分析到它的第3个成员lpfnWndProc时,当时我们只是说明了它是要指向一个
(回调函数),而现在,大家终于可以明白到,什么是(回调函数),以及,如何指向(回调函数),其实,就是把
(回调函数的名字)赋值给(窗口类)中的第3个成员lpfnWndProc即可。
那么,当我们使用DispatchMessage发送窗口消息给(回调函数)时,Windows就会把消息发送给(窗口类)中
成员lpfnWndProc所设置的(回调用函数),同时,自动完成参数的传递。
另外,大家可以回顾一下(消息结构体tagMSG)的前4个成员,分别是:HWND hwnd,UINT message,
WPARAM wParam,LPARAM lParam,而这4个成员,刚好就是(回调函数)原型中所对应的4个参数。
接下来,我们继续学习在(回调函数)中,是如何对消息进行处理的。
例子:
LRESULT CALLBACK Windowproc(
HWND hwnd,
UINT msg,
WPARAM wparam,
LPARAM lparam )
{
switch( msg )
{
case WM_CREATE:
{
//添加消息处理的代码
//例如:游戏程序读取图片的代码。
}break;
case WM_CLOSE:
{
//添加消息处理的代码
//例如:显示询问是否关闭窗口的代码。
}break;
}
}
代码分析:
(1)在回调函数Windowproc中,我们通过(switch语句)判断(第2个参数msg)是否等于我们想要处理的
(消息标识符),如果判断成立,就可以执行对应的代码,也就是对该消息进行了处理。
(2)在例子中,我们判断了WM_CREATE窗口创建时产生的消息,一般我们会在该消息产生时,对程序进行
一些初始化的处理。另外,我们也判断了窗口关闭时的消息WM_CLOSE,那么,在这里,我们一般会对程序
占用的资源进行释放的处理,以及,关闭我们所创建出来的窗口。
当我们学习完(Windows应用程序框架的底层消息处理机制)以后,就可以进行代码的实践与训练,
大家可以通过下方的链接进行代码的下载。
>>>下载Windows应用程序开发代码 |