很早之前就对windows程序设计的复杂性有所耳闻,总是听到同学这样描述windows编程——写一个很简单的窗口都要很长很长的代码。所以一直没有勇气去研究windows程序设计…
大二上,期末将至的时候,在图书馆里发现了《windows程序设计》这本书,而且还是全新的,挺厚的一本,我在书架前犹豫了一会后,终于下定决心把他借回去…
按照惯例,一本入门的编程书籍总是会介绍“hello world”。
这次让我兴奋的代码是这样的:
#include
和c语言相比,不过是头文件和入口函数不同罢了。
很简单的代码,不过当初我用VS2005写的时候,link的时候总是出错,后来才发现是入口函数没有调成WinMain,如果在VC6.0下,直接建立Win32 Application工程就行了。
看windows程序,常常会看到XX句柄,句柄无非就是一个数值,而且是可以标识某些东西的数值,就好比学号在学校里可以标识我们的身份。句柄参数名第一个字母都是”h”。
句柄的实际取值对我们来说并不重要,重要的是将句柄传递给我们所写的程序,让他们知道对哪个对象操作。而windows中有函数可以让我们很方便的获取句柄。
在windows.h中用define定义了大量的大写标识符,这些常量无需全部记住,不过记住他们的前缀我我们看懂windows程序设计十分重要。
CS 类风格选项
CW 创建窗口选项
DT 文本绘制选项
IDI 图标ID号
IDC 光标ID号
MB 消息框选项
SND 声音选项
WM 窗口消息
WS 窗口风格
变量的命名也很讲究,比如前缀i表示 int , 前缀sz表示 “以零结尾的字符串”…
在看windows程序时,会发现很多平常见不到的类型,有些类型不过是进行了同义转化,比如 UINT 实际上就是 unsigned int 类型,而有些类型不是,所以遇到陌生的类型,要查查帮助文档。
用C语言写一个窗口,代码真的很长很长,其实懂得了这些结构,看起来也不是那么的烦人。
创建一个窗口,首先要有窗口类,查查文档可以发现WNDCLASS有很多个字段,所以得一个一个的设置他们的属性。
接着是用RegisterClass注册窗口。注册失败返还0.
if (!RegisterClass (&wndclass)){
//错误处理代码
return 0;
}
注册完后用CreateWindow 创建窗口,该函数返回的是一个窗口句柄。这时窗口会在Windows内部被创建,即已经分配了一块内存来保存该窗口信息以及一些其他信息。
ShowWindow函数可以将该窗口显示出来。
UpdateWindow函数可以使传入句柄对应的窗口客户区重绘,而重绘是通过系统向窗口过程发送一条WM_PAINT信息完成的。
Windows为当前在其中运行的每一个Windows程序都维护了一个“消息队列”。当输入事件发生后,windows会自动将这些事件转换成“消息”,并将其放置在应用程序的消息队列中。
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
目前我看完本书的第五章,这段时间所接触到的windows程序中,以上的这些代码我都是copy的,真正让我写的就是窗口过程。
窗口过程的签名为:
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
这里需要注意的是,窗口过程的函数名不一定是WndProc,但一定要和wndclass.lpfnWndProc 字段的值相同。
窗口过程几乎总是由Windows自身调用的。
在窗口过程中,我们可以处理很多消息,函数可以根据传入消息message的值来判断类型。常常用switch实现。消息有很多种,比如WM_CREATE WM_PAINT WM_DESTROY…
窗口过程对消息处理后应返回0。
如果传入的类型不在我处理范围内呢?想想我们在编码时,switch还跟一个default字段经常在一起使用,而这里使用的是DefWinProc函数来处理我们不想处理的消息,这对程序的正常运行很重要。
WM_PAINT消息很常见。
用记事本举个例子,当我们调整记事本的大小时,记事本中的文字会根据我们所作的调整进行重新排版。窗口过程收到了WM_PAINT ,然后进行了重绘。
在设置窗口属性时,wndclass.style = CS_HREDRAW | CS_VREDRAW ; 意思为当窗口横向或纵向发生变化时就进行重绘。
WM_PAINT消息的处理过程总是有以下代码:
hdc = BeginPaint (hwnd, &ps) ; //hdc的类型是HDC
//重绘的代码…
EndPaint (hwnd, &ps) ;
上文提到的UpdateWindow就是指示窗口过程在窗口客户区进行绘制。
如果在case中有用到新的变量,应在switch外声明,我就有几次在case语句中声明变量然后出错都找不出来。
以下是书中的HELLOWIN.C,我常用他来做框架代码。
#include