📄 3.窗口和消息.txt
字号:
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
程序建立一个普通的应用程序窗口,如图3-1所示。在窗口显示区域的中央显示「Hello, Windows 98!」。如果安装了声卡,那么您还可以听到相应的朗读声音。
图3-1 HELLOWIN窗口
提醒您注意:如果您使用Microsoft Visual C++ 为此程序建立新项目,那么您得加上连结程序所需的链接库文件。从Project菜单选择 Setting选项,然后选取Link页面标签。从 Category清单方块中选择General,然后在 Object/Library Modules文字方块添加WINMM.LIB(Windows multimedia-Windows多媒体)。您这样做是因为HELLOWIN将使用多媒体功能呼叫,而内定的项目中又不包括多媒体链接库文件。不然连结程序报告了错误信息,表明PlaySound函数不可用。
HELLOWIN将存取文件HELLOWIN.WAV,该文件在本书所附光盘的HELLOWIN目录中。执行HELLOWIN.EXE时,内定的目录必须是HELLOWIN。在Visual C++中执行此程序时,虽然执行文件会产生在HELLOWIN的RELEASE或DEBUG子目录中,但执行程序的目录还是必须在HELLOWIN中。
通盘考量
实际上,每一个Windows程序代码中都包括HELLOWIN.C程序的大部分。没人能真正记住此程序的全部写法;通常,Windows程序写作者在开始写一个新程序时总是会复制一个现有的程序,然后再做相应的修改。您可以按此习惯自由使用本书附带光盘中的程序。
上面提到,HELLOWIN将在其窗口的中央显示字符串。这种说法不是完全正确的。文字实际显示在程序显示区域的中央,它在图3-1中是标题列和边界范围内的大片白色区域。这区别对我们来说很重要;显示区域就是程序自由绘图并且向使用者显示输出结果的窗口区域。
如果您认真思考一下,将会发现虽然只有80行程序代码,这个窗口却令人惊讶地具有许多功能。您可以用鼠标按住标题列,在屏幕上移动窗口;可以按住大小边框,改变窗口的大小。在窗口大小改变时,程序自动地将「Hello, Windows 98!」字符串重新定位在显示区域的中央。您可以按最大化按钮,放大HELLOWIN以充满整个屏幕;也可以按最小化按钮,将程序缩小成一个图示。您可以在系统菜单中执行所有选项(就是按下在标题列最左端的小图示);也可以从系统菜单中选择 Close选项,或者单击标题列最右端的关闭按钮,或者双击标题列最左端的图标,来关闭窗口以终止程序的执行。
我们将在本章的余下部分对此程序作一详细的检查。当然,我们首先要从整体上看一下。
与前两章中的范例程序一样,HELLOWIN.C也有一个WinMain函数,但它还有另外一个函数,名为WndProc。这就是窗口消息处理程序。注意,在HELLOWIN.C中没有呼叫WndProc的程序代码。当然,在WinMain中有对WndProc的参考,而这就是该函数要在程序开头附近声明的原因。
Windows函数呼叫
HELLOWIN至少呼叫了18个Windows函数。下面以它们在HELLOWIN中出现的次序列出这些函数以及各自的简明描述:
LoadIcon 加载图标供程序使用。
LoadCursor 加载鼠标光标供程序使用。
GetStockObject 取得一个图形对象(在这个例子中,是取得绘制窗口背景的画刷对象)。
RegisterClass 为程序窗口注册窗口类别。
MessageBox 显示消息框。
CreateWindow 根据窗口类别建立一个窗口。
ShowWindow 在屏幕上显示窗口。
UpdateWindow 指示窗口自我更新。
GetMessage 从消息队列中取得消息。
TranslateMessage 转译某些键盘消息。
DispatchMessage 将消息发送给窗口消息处理程序。
PlaySound 播放一个声音文件。
BeginPaint 开始绘制窗口。
GetClientRect 取得窗口显示区域的大小。
DrawText 显示字符串。
EndPaint 结束绘制窗口。
PostQuitMessage 在消息队列中插入一个「退出程序」消息。
DefWindowProc 执行内定的消息处理。
这些函数均在Platform SDK文件中说明,并在不同的表头文件中声明,其中绝大多数声明在WINUSER.H中。
大写字母标识符
读者可能注意到,HELLOWIN.C中有几个大写的标识符,这些标识符是在Windows表头文件中定义的。有些标识符含有两个字母或者三个字母的前缀,这些前缀后头接着一个底线:
这些是简单的数值常数。前缀指示该常数所属的类别,如表3-1所示。
表3-1
前缀
类别
CS
窗口类别样式
CW
建立窗口
DT
绘制文字
IDI
图示ID
IDC
游标ID
MB
消息框
SND
声音
WM
窗口消息
WS
窗口样式
奉劝程序写作者不要费力气去记忆Windows程序设计中的数值常数。实际上,Windows中使用的每个数值常数在表头文件中均有相应的标识符定义。
新的数据型态
HELLOWIN.C中的其它标识符是新的数据型态,也在Windows表头文件中使用typedef叙述或者#define叙述加以定义了。最初是为了便于将Windows程序从原来的16位系统上移植到未来的使用32位(或者其它)技术的操作系统上。这种作法并不如当时每个人想象的那样顺利,但是这种概念基本上是正确的。
有时这些新的数据型态只是为了方便缩写。例如,用于WndProc的第二个参数的UINT数据型态只是一个unsigned int (无正负号整数),在Windows 98中,这是一个32位的值。用于WinMain的第三个参数的PSTR数据型态是指向一个字符串的指针,即是一个char *。
其它数据型态的含义不太明显。例如,WndProc的第三和第四个参数分别被定义为WPARAM和LPARAM,这些名字的来源有点历史背景:当Windows还是16位系统时,WndProc的第三个参数被定义为一个WORD,这是一个16位的 无正负号短(unsigned short)整数,而第四个参数被定义为一个LONG,这是一个32位有正负号长整数,从而导致了文字「PARAM」前面加上了前置前缀「W」和「L」。当然,在32位的Windows中,WPARAM被定义为一个UINT,而LPARAM被定义为一个LONG(这就是C中的long整数型态),因此窗口消息处理程序的这两个参数都是32位的值。这也许有点奇怪,因为WORD数据型态在Windows98中仍然被定义为一种16位的 无正负号整数,因此「PARAM」前的「W」就有点误用了。
WndProc函数传回一个型态为LRESULT的值,该值简单地被定义为一个LONG。WinMain函数被指定了一个WINAPI型态(在表头文件中定义的所有Windows函数都被指定这种型态),而WndProc函数被指定一个CALLBACK型态。这两个标识符都被定义为_stdcall,表示在Windows本身和使用者的应用程序之间发生的函数呼叫的呼叫参数传递方式。
HELLOWIN还使用了Windows表头文件中定义的四种数据结构(我们将在本章稍后加以讨论)。这些数据结构如表3-2所示。
表3-2
结构
含义
MSG
消息结构
WNDCLASS
窗口类别结构
PAINTSTRUCT
绘图结构
RECT
矩形结构
前面两个数据结构在WinMain中使用,分别定义了两个名为msg和wndclass的结构,后面两个数据结构在WndProc中使用,分别定义了ps和rect结构。
句柄简介
最后,还有三个大写标识符(见表3-3),用于不同型态的「句柄」:
表3-3
标识符
含义
HINSTANCE
执行实体(程序自身)句柄
HWND
窗口句柄
HDC
设备内容句柄
句柄在Windows中使用非常频繁。在本章结束之前,我们将遇到HICON(图标句柄)、HCURSOR(鼠标光标句柄)和HBRUSH(画刷句柄)。
句柄是一个(通常为32位的)整数,它代表一个对象。Windows中的句柄类似传统C或者MS-DOS程序设计中使用的文件句柄。程序几乎总是通过呼叫Windows函数取得句柄。程序在其它Windows函数中使用这个句柄,以使用它代表的对象。代号的实际值对程序来说是无关紧要的。但是,向您的程序提供代号的Windows模块知道如何利用它来使用相对应的对象。
匈牙利表示法
读者可能注意到,HELLOWIN.C中有一些变量的名字显得很古怪。如szCmdLine,它是传递给WinMain的参数。
许多Windows程序写作者使用一种叫做「匈牙利表示法」的变量命名通则。这是为了纪念传奇性的Microsoft程序写作者Charles Simonyi。非常简单,变量名以一个或者多个小写字母开始,这些字母表示变量的数据型态。例如,szCmdLine中的sz代表「以0结尾的字符串」。在hInstance和hPrevInstance中的h前缀表示「句柄」;在iCmdShow中的i前缀表示「整数」。WndProc的后两个参数也使用匈牙利表示法。正如我在前面已经解释过的,尽管wParam应该更适当地被命名为uiParam(代表「无正负号整数」),但是因为这两个参数是使用数据型态WPARAM和LPARAM定义的,因此保留它们传统的名字。
在命名结构变量时,可以用结构名(或者结构名的一种缩写)的小写作为变量名的前缀,或者用作整个变量名。例如,在HELLOWIN. C的WinMain函数中,msg变量是MSG型态的结构;wndclass是WNDCLASSEX型态的一个结构。在WndPmc函数中,ps是一个PAINTSTRUCT结构,rect是一个RECT结构。
匈牙利表示法能够帮助程序写作者及早发现并避免程序中的错误。由于变量名既描述了变量的作用,又描述了其数据型态,就比较容易避免产生数据型态不合的错误。
表3-4列出了在本书中经常用到的变量前缀。
表3-4
前缀
数据型态
c
char或WCHAR或TCHAR
by
BYTE (无正负号字符)
n
short
i
int
x, y
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -