第3章,[标签 Win32] :窗口类03,窗口过程函数与消息机制
专栏导航
上一篇:第3章,[标签 Win32] :窗口类03,窗口过程函数字段
回到目录
下一篇:无
本节前言
对于本节所讲解的知识,有可能,你会需要时不时地参考本专栏之前的文章。真的遇到了需要参考之前的文章的知识点,请你自行查阅。
我呢,也会提到一部分的参考课节。但是呢,你不应该依赖于我的主动提及。最好呢,你自己能够多去了解和查看本专栏目录。
学习本节所讲的知识,需要你事先了解过本章的完整代码。完整的代码,请参考下述文章链接。
参考课节:第3章,[标签 Win32] :本章程序代码
在之前,我们有讲过窗口类的基本情况。
为了便于学习,我们还是再次贴出窗口类的各个成员变量,如下所示。
typedef struct {UINT style;WNDPROC lpfnWndProc;int cbClsExtra;int cbWndExtra;HINSTANCE hInstance;HICON hIcon;HCURSOR hCursor;HBRUSH hbrBackground;LPCTSTR lpszMenuName;LPCTSTR lpszClassName;
} WNDCLASS, * PWNDCLASS;
另外呢,本节内容与之前的章节内容,窗口过程函数字段,关系密切。所以,你务必需要先学习过关于窗口过程函数字段的课节。关于窗口过程函数字段的课节,文章链接如下。
参考课节:第3章,[标签 Win32] :窗口类03,窗口过程函数字段
本节,我们的内容,依然是讲解着窗口过程函数的相关内容。
我们进入本节的学习。
一. 常见的窗口消息与消息机制
窗口过程函数与消息机制有着密切的联系。
关于消息机制,本节不打算给出正式定义。可能本专栏也不会给出它的正式定义。想要了解消息机制,你可能需要自己去慢慢体会。
在这里,我首先给出常见的窗口消息。
在我学习 Windows API 程序的时候,常见的消息包括以下几种。
- 鼠标左键按下消息:WM_LBUTTONDOWN
- 鼠标左键松开消息:WM_LBUTTONUP
- 鼠标右键按下消息:WM_RBUTTONDOWN
- 鼠标右键松开消息:WM_RBUTTONUP
- 鼠标中键按下消息:WM_MBUTTONDOWN
- 鼠标中键松开消息:WM_MBUTTONUP
- 鼠标移动消息:WM_MOUSEMOVE
- 键盘按下消息:WM_KEYDOWN
- 键盘松开消息:WM_KEYUP
- 字符消息:WM_CHAR
在这些个消息标识符里面,都以 WM_ 作为前缀。WM,就是 Window Message 的意思,是窗口消息的意思。
WM_LBUTTONDOWN,里面的 L 是 Left 的意思,LBUTTONDOWN,就是 Left Button Down 的意思,就是鼠标左键按下的意思。
WM_RBUTTONDOWN,里面的 R 是 Right 的意思。所以呢,RBUTTONDOWN,就是 Right Button Down 的意思,是鼠标右键按下的意思。
同理,WM_MBUTTONDOWN 中的 M 是 Middle 的意思,跟鼠标中键有关。鼠标中键就是鼠标滚轮键。
而 WM_LBUTTONUP 中的 UP,就是抬起的意思。LBUTTONUP,就是 Left Button Up 的意思,是鼠标左键抬起的意思。鼠标的左键抬起来,就是说,原来的鼠标左键是按下的,现在呢,左键松开了,所以左键就抬起来了。
键盘按下消息,为 WM_KEYDOWN,就是 Key Down 的意思,是有键盘按下的意思。
WM_KEYUP,其中的 KEYUP 是 Key Up 的意思,就是有键盘抬起的意思。键盘松开了,就是键盘抬起来了。
WM_CHAR,这个消息,它是说,有字符输入了,所以叫做字符消息。
在我们打开了一个应用程序以后,我们会通过鼠标单击,双击,拖动,点击菜单项,键盘输入等等的操作,来与此应用程序进行着互动。
消息的种类有很多,多得难以一口气说出来。常见的消息见上面的列表。
当你单击了鼠标左键时,产生的消息是 WM_LBUTTONDOWN,表示鼠标左键被按下了,也就是执行了单击操作。
当你单击了鼠标右键,产生的消息是 WM_RBUTTONDOWN,表示鼠标右键被按下了,也就是执行了一次右击操作。
当你按下了键盘上的一个按键,会产生 WM_KEYDOWN 消息,表示有键盘被按下了。
当你松开了键盘按键,会产生 WM_KEYUP 消息,表示有键盘被松开了。
当你按下了一个键盘,这个键盘是字符键,数字键,标点符号键,那么,这些个按键,都是可以显示为某个字符的按键,则会产生 WM_CHAR 消息,表明输入了一个字符。
对于 Windows 程序,我们正是通过鼠标和键盘操作所产生的各种消息,来与应用程序进行交互的。所以说,Windows 程序是消息驱动的。
到了这里,对于常见的 Windows 窗口消息,相信你就有了一点了解了。
二. 消息队列,窗口与窗口过程函数
当 Windows 程序开始执行时,Windows 会首先为该程序创建一个消息队列。
消息队列,英文为 Message Queue 。
该消息队列中存放着应用程序可能创建的所有窗口的消息。
Windows 应用程序一般都会包含一小段称为消息循环(Message Loop)的代码。
消息循环代码,主要的功能是,从消息队列中检索消息,并将其分发给相应的窗口过程。
在 Windows 程序中,一般地,都会有一个应用程序主窗口。
是窗口,就会有它的窗口过程函数。
一个窗口,它是与它的窗口过程函数绑定在一起的。
应用程序主窗口会有它的对应的窗口过程函数。而这个窗口过程函数,正是我们自己所编写的。
本章程序代码的 60 行开始的位置,便是本章程序中的窗口过程函数,如下图所示。

在图1 里面,我只展示了部分的窗口过程函数代码。
这个窗口过程函数,其中的代码行为,执行逻辑,是我们自己编写的。它的执行逻辑,对应的是应用程序主窗口的执行逻辑。
所谓的应用程序主窗口,一般是指你打开应用程序的时候,所见到的那个窗口。它包含了程序的标题栏,菜单栏,工具栏等等元素,是程序的主要的,顶级的操作窗口。
一个应用程序,有时候,除了主窗口之外,还会有其他的窗口,比如说,点了某些个菜单项或工具栏按钮之后,会弹出来一个对话框。
这个对话框,也是一个窗口。是窗口,就会有它的窗口过程函数。
一个窗口,它是与它的窗口过程函数绑定在一起的。
有的对话框,它是 Windows 系统提供的,它的窗口过程函数,已经由 Windows 系统的开发者给写好了,我们直接用即可。
比如说,Windows 里面的打开文件对话框,字体对话框,颜色选择对话框,它们都是 Windows 系统预定义好了的。
有的对话框,它是我们程序员自己设计和开发的,这种自定义对话框,依然是要由我们程序员来写它的窗口过程函数代码。
而对话框里面呢,还会有许多的控件,比如说普通按钮,单选按钮,复选框,列表框,组合框啥的。这些个控件,它们也是一种窗口,叫做子窗口,控件窗口,或者叫做子窗口控件。既然是窗口,它们也有它们的窗口过程函数。
只是呢,子窗口控件的窗口过程函数,一般的呢,它们也是由 Windows 系统来提供的。因为,子窗口控件,本就是 Windows 系统已经封装好了的东西。由于子窗口控件是 Windows 系统已经封装好了的东西,所以呢,这种窗口的窗口过程函数,也是说,Windows 已经给写好了,我们直接用就可以了。
在学习 Win32 API 程序设计的时候,我们可以认为,子窗口控件的窗口过程函数,我们无法修改和干涉。但是呢,在后面,我们学习 MFC 的时候,我们还是可以对子窗口控件的执行逻辑,作出一定的调整和修改。但是呢,在本章,由于我们是在学习着 Windows API 编程,所以呢,我们还是假定,我们无法对子窗口控件的行为作出调整,只能够调用已有的 Windows 系统的对应的窗口过程。
这样一来呢,我们可以将一个应用程序中的所有窗口,大致地,分为两类。
一类呢,是自定义窗口,应用程序的主窗口,自定义对话框,它都是属于程序员自定义的窗口,这类窗口的窗口过程函数,由程序设计者自行编写。
另一类呢,是系统已经封装好了的窗口,比如系统预定义的对话框,比如普通按钮,单选按钮,复选框,列表框等等,这类窗口,它们的窗口过程函数,系统已经封装好了,程序设计者直接调用已有的代码就好。
无论是系统预定义的窗口,还是程序员自定义窗口,它们都有它们的窗口过程函数。无论此窗口过程函数是程序员自定义,还是系统预定义的。
既然有窗口和它所绑定的窗口过程函数,那么,该窗口的窗口过程函数就会接收和处理消息。
Windows 系统中的消息,有的呢,它会被放在消息队列里面。前面说过了,每一个 Windows 程序在被创建时,Windows 系统都会给这个程序创建一个消息队列。Windows 系统中的消息,如果会被放在消息队列里面,那么,它的存放位置,就是程序创建时,Windows 系统所创建的那个消息队列。
这种被存放在消息队列中的消息,叫做队列消息。
也有的消息,它不会被存放在消息队列里面,而是会直接发送给对应的窗口过程函数。这种不经过消息队列的消息,叫做非队列消息。
Windows 中的消息,无论是队列消息,还是非队列消息,它最终都是要发送给应用程序中的某个窗口的,并且要由此窗口的窗口过程函数来处理的。
在这里,对于消息的接收与处理,我的表述是,某一个窗口负责接收消息,此窗口所绑定的窗口过程函数负责处理该窗口接收到的消息。
一个应用程序,会有它的主窗口,主窗口也需要绑定一个窗口过程函数。
一个程序里面,我们可以编写很多的函数,包括说,我们可以编写许多的窗口过程函数。在这种情况下,究竟哪个函数,才是主窗口的窗口过程函数呢?
给应用程序的主窗口指定一个窗口过程函数,需要由程序员来做。
在本章程序代码里面,下图的红色框线所示的这一行,就是用来指定应用程序主窗口的窗口过程函数的。

图2 的红色框线所示的窗口过程函数 WndProc,我们在图1 中展示过部分代码。
也就是说,图2 中的红色框线所示的代码行,其作用,就是将应用程序主窗口和它的窗口过程函数绑定在一起。
当给主窗口绑定好了窗口过程函数以后,在程序运行时,主窗口会接收到许多的消息。无论是队列消息,还是非队列消息,主窗口都会接收到它们。接收到以后,由此主窗口的窗口过程函数,也就是我们在图2 的红色框线所示的,我们绑定的那个窗口过程函数,来处理接收到的消息。
鼠标单击也好,双击也好,键盘按下,输入字符也好,这些个消息,许多都会发送给应用程序的主窗口。而处理主窗口接收到的消息的,是这个主窗口所绑定的窗口过程函数,就是我们在图2 中的红色框线中,所绑定的窗口过程函数,WndProc 。
一个 Windows 程序,WinMain 函数一般不会占用太大的篇幅。占据的篇幅较大的,起到核心作用的,一般地,都是窗口过程函数,尤其是主窗口的窗口过程函数。
在本章,我们仅仅是一个入门章节,仅仅是让大家初步接触 Windows API 程序,所以,窗口过程函数的篇幅不会很大。
而在后面的章节的学习中,我们会看到,窗口过程函数,的确是可以很大。
结束语
本节所讲述的内容,不知道,你听得怎么样。
其实这是很抽象的一种东西,不太好理解。
建议你,多看看本节文章与本专栏相关课节。也可以参考佩措尔德的第五版 Windows 程序设计教材。
多看几遍,能够有一个大致的理解就好。
某些个太抽象的东西,第一次接触,是不容易理解的。
许多难点知识,我们初次学习时,都不要要求太高。像是本章所述的许多的概念,包括本节的窗口过程函数与消息机制,你就不太容易透彻理解。
对于这种东西,暂时地,先了解个大概就好了。
在后续的诸多的学习和使用过程中,逐渐地,来增加经验,来增加对它们的理解。
循序渐进,水滴石穿,铁杵磨针。
本节结束。
专栏导航
上一篇:第3章,[标签 Win32] :窗口类03,窗口过程函数字段
回到目录
下一篇:无