有了主函数,程序便可以运行了,程序首先找到WinMain入口,然后开始执行,但是注意,此时还没有任何的动作,所以此时的程序运行之后没有任何现象。
也许很多人预想的是,运行一个界面,上面显示一个Hello world。毕竟我们在控制台程序中也是这么过来的。那么我们接下来要做的就是“构造”一个窗口。
说到底我们的程序是一个系统调用,所以我们直接向操作系统请求构造窗口,并且要交给操作系统一些和窗口相关的参数,这样,操作系统就能按我们预想的那样构造窗口了。
自然地,这些我们逻辑上看起来的参数,实际上对操作系统而言就是一堆的数据,系统存储该数据并在需要的时候调用。我们把这些参数打包,够造成一个结构体,在C++中这个结构体就是WNDCLASSEX窗口类。
WNDCLASSEX的生命如下:
typedef struct WNDCLASSEX {
UINT cbSize;
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
HICON hIconSm;
} WNDCLASSEX, *PWNDCLASSEX;
每个窗口都是由以上十二个成员参数定义的,不同的组合产生了不同的窗口,这种定义方式是Win系统中最基础的定义,不像C#那样直接来一个继承就可以给你产生一个窗口,所以自然地他要麻烦一些,不过绝对很灵活。
不要被这十二个看不懂的成员吓到,分别解释,其实也不是很难。
第一个:UINT cbSize UINT是Win32中定义的一个宏,其实就是一个32位无符号整数。#define UINT nusigned int 这个变量存储了该结构体的大小赋值时,我们可以使用sizeof(WNDCLASSEX)
第二个:UINT style 这个变量可以定义窗口的风格,style 虽然是一个无符号整数,但是他的取值,是系统定义好的一组宏变量:
CS_HREDRAW 若移动或改变了窗口宽度,则刷新整个窗口
CS_VREDRAW 若移动或改变了窗口高度,则刷新整个窗口
CS_OWNDC 为该类中的每个窗口分配一个单值的设备描述表
CS_DBLCLKS 当用户双击鼠标时向窗口程序发送一个双击的信息,同时,光标位于属 于该类的窗口中
CS_PARENTDC 略
CS_NOCLOSE 禁止系统菜单上的关闭命令
CS_SAVEBITS 略
可以使用or 将不同的style连接起来。
第三个:WNDPROC lpfnWndProc 这个应该是该结构中最重要的一个成员,类型WNDPROC的实质是一个指向函数的长整类型的指针。 也就是说我们定义一个窗口,当鼠标在该窗口上操作,或键盘按键时,该窗口收到了这个消息。此时他的lpfnWndProc指向一个回调函数,(回调函数见下方讲解)该窗口将参数送到回调函数,由回调函数执行动作,之后则可以对动作作出相应。
第四个:int cbClsExtra 给类而外预留的空间默认设为0 当你需要的时候自然会明白它的用处。
第五个:int cbWndExtra 同上
第六个:HINSTANCE hInstance 该窗口的句柄
第七个:HICON hIcon 该窗口的图标的句柄
第八个:HCURSOR hCursor 该窗口光标形式的句柄
第九个:HBRUSH hbrBackground 该窗口画刷的句柄(一边以H开头的都是句柄)
第十个:LPCTSTR lpszMenuName
先介绍一下该变量 LPCTSTR 他比LPSTR 多了一个C一个T C代表这是一个const T代表支持_T宏命令。实际他就是一个指向String的const指针。这个变量指向其菜单的名字。
十一个:LPCTSTR lpszClassName该类的名字。即给该类起一个名字。
十二个:HICON hIconSm这个图标显示的是窗口在任务栏处显示的图标。
就这样十二个成员介绍完了,关于回调函数可以在下一次介绍。
到此,可能还有困惑,就是为什么要有个变量存储大小,为什么要有一个变量存储类名。其实很简单,我们以为的都是我们为类声明一个对象,然后不就可以直接使用此对象名引用该窗口类了?其实,这个名字只是存在我们的编译前,当我们定义了一个窗口进程会将窗口的各个成员值放入内存,也就是内存中存着的是各个成员的值,那么此时我们生命的对象名还有吗?当然不在了,所以我们要在内存中存一个名称,当然了这个名称不一定要是WNDCLASSEX我们可以任意起名。
我们有时候也会遇到一些名为WNDCLASS的类,其实他是WNDCLASSEX的老版本,他的存在只是为了兼容16位程序,当我们使用时优先使用带EX的,这也是一个命名规则。
定义完窗口类并不代表我们可以让程序显示一个窗口了,别忘了还要注册显示呢。