进行Windows程序设计时,其实就是在进行一种面向对象的编程。在面向对象中,对象是代码和数据的组合,一个窗口也是一个对象。
在用户眼中,窗口是屏幕上的对象,并可借助键盘或鼠标直接与之进行交互。
用户对窗口的输入以“消息”的形式传递给窗口,而窗口也借助消息来与其他窗口进行通信。
窗口创建看似容易,调用CreateWindow函数即可。
但是在创建窗口之前,需要注册一个窗口类。而窗口类又确定了处理窗口消息的窗口过程。
多个窗口可以同时基于某一窗口类来创建。注册窗口类必须调用RegisterClass函数。该函数只有一个参数,即一个指向WNDCLASS类型的结构的指针。下面我们看看这个结构:
首先是ASCII版本:
typedef struct tagWNDCLASSA{
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCSTR lpszMenuName;
LPCSTR lpszClassName;
} WNDCLASS, *PWNDCLASS;
其次是Unicode版本:
typedef struct tagWNDCLASSW{
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCWSTR lpszMenuName;
LPCWSTR lpszClassName;
} WNDCLASS, *PWNDCLASS;
可以看到只有最后两个字段不同,Unicode被定义为宽字符的常量字符串。
在WNDCLASS中最重要的两个字段是第二个lpfnWndProc和最后一个lpszClassName。
第二个字段是基于该窗口类的所有窗口的窗口过程的地址。
最后一个字段是窗口类的名称。
接下来该是创建了:
hwnd = CreateWindow(szAppName, //窗口类的名称
TEXT("The Hello Program"), //窗口标题
WS_OVERLAPPEDWINDOW, //窗口风格
CW_USEDEFAULT, //初始x坐标
CW_USEDEFAULT, //初始y坐标
CW_USEDEFAULT, //初始x方向尺寸
CW_USEDEFAULT, //初始y方向尺寸
NULL, //父窗口句柄
NULL, //窗口菜单句柄
hInstance, //程序实例句柄
NULL); //创建参数
创建之后,就该是窗口的显示了。即函数ShowWindow(hwnd, iCmdShow);
第一个参数就是CreateWindow所创建的窗口的句柄。
第二个参数就是WinMain函数所接受的iCmdShow值。
然后调用UpdateWindow(hwnd)进行窗口客户区重绘。
在UpdateWindow后,新建的窗口在屏幕中便完全可见了。
此时,该程序必须能够接收来自用户的键盘输入和鼠标输入。是如何做到的呢?
Windows为当前在其中运行的每一个Windows程序都维护了一个“消息队列”。当输入时间发生后,Windows会自动将这些事件转换为“消息”,并将其放置在应用程序的消息队列中。
应用程序通过如下代码循环:
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);//用于从消息队列中对消息进行检索
DispatchMessage(&msg);//将msg结构返还给Windows以进行某些键盘消息的转换
}
其中msg是一个结构变量,定义如下:
typedef struct tagMSG {
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG, *PMSG;
上诉结构中的POINT是另一种结构:
typedef struct tagPOINT {
LONG x;
LONG y;
} POINT, *PPOINT;
下面介绍真正有意思的事情–窗口过程
一个windows程序可以包含多个窗口过程,但一个窗口过程总是与一个通过调用RegisterClass注册的特定窗口类相关联。
窗口过程总是按照如下定义:
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
窗口过程函数的四个参数与MSG结构的4个字段一一对应。
第一个参数:表示接收消息的窗口的句柄
第二个参数:消息标识符
最后两个参数:32位的消息参数
最后就是消息处理了:
switch(message)
{
case WM_CREATE:
[处理WM_CREATE消息]
return 0;
case WM_PAINT:
[处理WM_PAINT消息]
return 0;
case WM_DESTROY:
[处理WM_DESTROY消息]
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);