要想熟练掌握 Windows 应用程序的开发, 首先需要理解 Windows 平台下程序运行的内部机制。如果想要更好的学习掌握 MFC,必须要先了解Windows 程序的内部运行机制,为我们扫清学习路途中的第一个障碍,为进一步学习 MFC 程序打下基础。
1.1 基本概念解释
我们在编写标准C程序的时候,经常会调用各种库函数来辅助完成某些功能:初学者使用得最多的C库函数就是printf了,这些库函数是由你所使用的编译器厂商提供的。在Windows平台下,也有类似的函数可供调用:不同的是,这些函数是由Windows操作系统本身提供的。
1.1.1 SDK和API
SDK: 软件开发工具包(Software Development Kit),一般都是一些被软件工程师用于为特定的软件包、软件框架、硬件平台、操作系统等建立应用软件的开发工具的集合。
API函数: Windows操作系统提供给应用程序编程的接口(Application Programming Interface)
Windows应用程序API函数是通过C语言实现的,所有主要的 Windows 函数都在 Windows.h 头文件中进行了声明。Windows 操作系统提供了 1000 多种 API 函数。
1.1.2 窗口和句柄
窗口是 Windows 应用程序中一个非常重要的元素,一个 Windows 应用程序至少要有一个窗口,称为主窗口。窗口是屏幕上的一块矩形区域,是 Windows 应用程序与用户进行交互的接口。利用窗口可以接收用户的输入、以及显示输出。一个应用程序窗口通常都包含标题栏、菜单栏、系统菜单、最小化框、最大化框、 可调边框,有的还有滚动条。如下图:
窗口可以分为客户区和非客户区, 如上图。 客户区是窗口的一部分, 应用程序通常在客户区中显示文字或者绘制图形。 标题栏、 菜单栏、 系统菜单、 最小化框和最大化框、 可调边框统称为窗口的非客户区, 它们由 Windows 系统来管理, 而应用程序则主要管理客户区的外观及操作。
窗口可以有一个父窗口, 有父窗口的窗口称为子窗口。除了上图所示类型的窗口外, 对话框和消息框也是一种窗口。 在对话框上通常还包含许多子窗口, 这些子窗口的形式有按钮、 单选按钮、 复选框、 组框、 文本编辑框等。
在 Windows 应用程序中, 窗口是通过窗口句柄( HWND) 来标识的。 我们要对某个窗口进行操作, 首先就要得到这个窗口的句柄。 句柄( HANDLE) 是 Windows 程序中一个重要的概念, 使用也非常频繁。 在 Windows 程序中, 有各种各样的资源( 窗口、 图标、光标,画刷等), 系统在创建这些资源时会为它们分配内存, 并返回标识这些资源的标识号, 即句柄。 在后面的内容中我们还会看到图标句柄( HICON)、 光标句柄( HCURSOR) 和画刷句柄( HBRUSH)。
1.1.3 消息与消息队列
Windows 程序设计是一种完全不同于传统的 DOS 方式的程序设计方法。它是一种事件驱动方式的程序设计模式,主要是基于消息的。例如,当用户在窗口中画图的时候,按下鼠标左键,此时,操作系统会感知到这一事件,于是将这个事件包装成一个消息,投递到应用程序的消息队列中,然后应用程序从消息队列中取出消息并进行响应。在这个处理过程中,操作系统也会给应用程序“ 发送消息”。所谓“ 发送消息”,实际上是操作系统调用程序中一个专门负责处理消息的函数,这个函数称为窗口过程。
消息
在 Windows 程序中,消息是由 MSG 结构体来表示的。MSG 结构体的定义如下:
该结构体中各成员变量的含义如下:
第一个成员变量 hwnd 表示消息所属的窗口。我们通常开发的程序都是窗口应用程序,一个消息一般都是与某个窗口相关联的。例如,在某个活动窗口中按下鼠标左键,产生的按键消息就是发给该窗口的。在 Windows 程序中,用 HWND类型的变量来标识窗口。
第二个成员变量 message 指定了消息的标识符。 在 Windows 中, 消息是由一个数值来表示的, 不同的消息对应不同的数值。 但是由于数值不便于记忆, 所以 Windows 将消息对应的数值定义为 WM_XXX 宏( WM 是 Window Message 的缩写) 的形式, XXX 对应某种消息的英文拼写的大写形式。 例如, 鼠标左键按下消息是 WM_LBUTTONDOWN, 键盘按下消息是 WM_KEYDOWN, 字符消息是 WM_CHAR , 等等。 在程序中我们通常都是以WM_XXX 宏的形式来使用消息的。
第三、 第四个成员变量 wParam 和 lParam,用于指定消息的附加信息。 例如, 当我们收到一个字符消息的时候,message 成员变量的值就是 WM_CHAR, 但用户到底输入的是什么字符,那么就由 wParam 和 lParam 来说明。wParam、lParam 表示的信息随消息的不同而不同。如果想知道这两个成员变量具体表示的信息,可以在 MSDN 中关于某个具体消息的说明文档查看到。WPARAM 和 LPARAM 这两种类型的定义,实际上就是 unsigned int和 long。
第五、第六个变量分别表示消息投递到消息队列中的时间和鼠标的当前位置。
|
typedef struct tagMSG { HWND hwnd; UINT message; WPARAM wParam; LPARAM lParam; DWORD time; POINT pt; } MSG; |
|
hwnd Handle to the window whose window procedure receives the message. message Specifies the message identifier.WM_XXX宏的形式 wParam Specifies additional information about the message. The exact meaning depends on the value of the message member. lParam Specifies additional information about the message. The exact meaning depends on the value of the message member. time Specifies the time at which the message was posted. pt Specifies the cursor position, in screen coordinates, when the message was posted.
|
消息队列
每一个 Windows 应用程序开始执行后, 系统都会为该程序创建一个消息队列, 这个消息队列用来存放该程序创建的窗口的消息。 例如, 当我们按下鼠标左键的时候, 将会产生WM_LBUTTONDOWN 消息, 系统会将这个消息放到窗口所属的应用程序的消息队列中,等待应用程序的处理。 Windows 将产生的消息依次放到消息队列中, 而应用程序则通过一个消息循环不断地从消息队列中取出消息, 并进行响应。 这种消息机制, 就是 Windows程序运行的机制。 关于消息队列和消息响应, 在后面我们还会详细讲述。
WinMain函数
当 Windows 操作系统启动一个程序时,它调用的就是该程序的 WinMain 函数( 实际是由插入到可执行文件中的启动代码调用的)。 WinMain 是 Windows程序的入口点函数,与 DOS 程序的入口点函数 main 的作用相同,当 WinMain 函数结束或返回时,Windows 应用程序结束。