以HELLOWIN为例剖析Windows的一般消息结构
// HELLOWIN.cpp
// 时间:2012-10-27
#include
解析:所有的基于windows程序,windows.h的头文件是必须的,是几乎所有用C语言编写的windows程序中都有的预处理器(precocessor)指令,在#include
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
解析:窗口过程函数的声明,窗口过程总是按照如上方式进行定义,参数1. 表示接收消息的窗口的句柄,是CreateWindow函数返回的句柄;参数2. 是MSG结构的message字段,是标识消息的数字,参数3,4,表示两个32位的“消息参数”,参数的含义和取值取决于具体的消息。
int WINAPI WinMain( HINSTANCE hInstance, // 程序当前实例句柄
HINSTANCEhPrevInstance,// 当前实例前一个句柄(在Win32下总为NULL)
PSTRszCmdLine, //以空终止的字符串
int iCmdShow // iCmdShow由程序的调用者(即操作系统)决定
)
解析:正像main是C程序的入口函数一样,Windows程序的入口函数是WinMain, 它总是如上形式出现,其中WINAPI标示符是一种函数调用约定,在#include
参数3,以空终止的字符串,用来运行程序的命令行,有些Windows程序启动是用它来将文件装入内存,如在D盘下有一个hello.txt得文件,当我们用鼠标双击这个文件时记事本启动程序notepad.ext将D:\hello.txt做为命令行参数传给notepad.exe的WinMain函数,notepad.ext程序得到这个文件全路径名后就在窗口显示该文件的内容。具体操作百度。
参数4.指定程序的窗口如何显示,如最大化,最小化,隐藏等,这个参数由程序调用者所指定,我们编写应用程序通常不予理会
{
// 设计一个窗口类
static TCHAR szAppName[] = TEXT("HEllOWin");
WNDCLASSwndclass; //定义一个WNDCLASS窗口类的结构
wndclass.style =CS_HREDRAW | CS_VREDRAW;// 类风格(水平和竖直尺寸被改变)
wndclass.lpfnWndProc = WndProc; // 指定窗口过程函数
wndclass.cbClsExtra = 0; // 类结构预留空间
wndclass.cbWndExtra = 0; // 窗口结构预留空间
wndclass.hInstance = hInstance; // 应用程序的实例
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);// 为窗口类的窗口设定一个图标
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);// 载入预定义的鼠标指针形状
wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); // 窗口客户区的背景色
wndclass.lpszMenuName = NULL; // 窗口类的菜单(不带菜单为NULL)
wndclass.lpszClassName = szAppName; // 窗口类的名字
解析:窗口类的设计就是定义一个窗口的基本属性(一般特征属性),多个窗口可以同时基于某一窗口类,而某一窗口的特有属性。可以在CreateWindow函数中予以指定。
参数6. wndclass.hIcon指定窗口类的图标句柄,如果为NULL,则系统将提供一个默认的图标,LoadIcon函数加载一个图标资源,返回系统分配给该资源的句柄,LoadIcon如果加载系统的标准图标,则第一个参数为NULL
常数7.wndclass.hCursor指定窗口类的光标句柄,如果为NULL.那么无论何时鼠标进入到应用程序窗口中,应用程序都必须明确的设置光标的形状。LoadIcon用法同参数6.
参数8.指定窗口类的背景画刷句柄,窗口重绘是系统使用此画刷插除窗口背景
// 注册窗口类
if (!RegisterClass(&wndclass))
{
MessageBox(NULL,TEXT("This Program require windows NT!"),
szAppName, MB_ICONERROR);
return 0;
}
解析:RegisterClass函数对窗口类进行注册,参数为窗口类对象的指针。注册成功后才能够创建窗口
// 创建窗口
HWND hwnd;
// CreateWindow函数返回指向所建窗口的句柄
hwnd = CreateWindow( szAppName, // 窗口类的名称(wndclass.lpszClassName)
TEXT("The Hello Program"), // 窗口标题(显示在窗口上)
WS_OVERLAPPEDWINDOW, // 窗口风格(多种窗口类型的组合)
CW_USEDEFAULT, // 初始X坐标
CW_USEDEFAULT, // 初始Y坐标
CW_USEDEFAULT, // 初始X方向尺寸
CW_USEDEFAULT, // 初始Y方向的尺寸
NULL, //父窗口句柄
NULL, //窗口菜单句柄(NULL表示无菜单)
hInstance, //程序实例句柄
NULL //创建参数
);
解析:CreateWindow的参数1,指定了窗口类的名称,以便于我们创建的窗口与窗口类相关联,参数2指定窗口的样式,这里我们窗口的样式是重叠的,有最大化,最小化,关闭按钮的形式,参数11(即最后一个),作为WM_CREATE消息的附加参数传入的数据指针,多数窗口为NULL。
// 显示及刷新窗口
ShowWindow(hwnd,iCmdShow); //将窗口显示在屏幕中
UpdateWindow(hwnd); // 刷新窗口(发送WM_PAINT消息)
解析:CreateWindow调用返回时,窗口已在Windows内部创建,Windows为其分配了一块内存保存CreateWindow调用指定的窗口信息及其他一些信息,那么ShowWindow就是将窗口显示出来。UpdateWindow函数调用重绘刷新窗口,至此,新建窗口完全显示出来,那么接下来就是新建窗口接收来自鼠标和键盘的消息(即下面的消息循环)。
// 定义消息结构体,开始消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) // 参数3为NULL表示接收调用线程的所有窗口消息
{
TranslateMessage(&msg); // 虚拟键消息转换为字符消息并将字符消息投递到消息队列
DispatchMessage(&msg); // 将消息回传给操作系统,由操作系统调用窗口过程函数
//对消息进行处理(响应)
}
return msg.wParam; // 收到WM_QUIT消息后,while返回0,退出循环,执行该语句
解析:当输入事件发生后,Windows会自动将这些事件转换为消息,并将其放置在消息队列中,上面消息循环不断的从消息队列中取出消息,并进行响应。GetMessage函数用于从消息队列中对消息进行检索,该调用将msg得消息结构体变量的指针传给Windows。第二,第三和第四个参数分别设为NULL或0,表示希望获取该程序创建的所有窗口的消息。GetMessage函数只有在接收到WM_QUIT消息时才返回0
returnmsg.wParam;返回语句中msg.wParam字段是传递给PoseQuitMessage函数的参数值(通常情况下位0),
该语句将从WinMain中退出并将程序结束。
}
// 窗口过程处理函数
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAMwParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
switch(message)
{
case WM_CREATE:
PlaySound(TEXT("Hellowin.wav"), NULL, SND_FILENAME |SND_ASYNC);
return 0;
case WM_PAINT:
hdc =BeginPaint(hwnd, &ps);
GetClientRect(hwnd,&rect);
DrawText(hdc,TEXT("Hello, window 7!"), -1,&rect,
DT_SINGLELINE| DT_CENTER | DT_VCENTER);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0); // 0为消息WM_QUIT的wParam参数
return0;
}
returnDefWindowProc(hwnd, message, wParam, lParam);
}
解析:当用户点击窗口上的关闭按钮时,系统会给应用程序发送一条WM_CLOSE消息,可以在这条消息中调用DestroyWindow函数销毁窗口(如果没有相应WM_CLOSE消息,则系统将把这条消息传给DefWindowProc函数,而DefWindowProc函数则调用DestroyWindows函数来销毁窗口)。DestroyWindows函数在销毁窗口之后会向窗口过程发送一条WM_DESTROY消息,我们在该消息的响应代码中调用PostQuitMessage函数,PostQuitMessge函数则向应用程序的消息队列中投递一条WM_QUIT消息并返回。此时GetMessage函数收到WM_QUIT消息后返回0,结束消息循环,程序正常退出。
注:传递给PostQuiteMessage函数的参数值通常是WM_QUIT消息的wParam参数,这个值通常用作WinMain函数的返回值,如return msg.wParam;
注:在处理CreateWindows函数的过程中,Windows对WndProc函数进行调用,响应WM_CREATE消息,这是整个窗口过程接到的第一条消息。
注:第一条WM_PAIT消息是在调用WinMain中的UpdatWindow时出现的,指示窗口过程在窗口客户区进行绘制。
//窗口过程处理函数的另一种写法
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAMwParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCTps;
RECT rect;
switch(message)
{
case WM_CREATE:
PlaySound(TEXT("Hellowin.wav"), NULL, SND_FILENAME |SND_ASYNC);
break;
case WM_PAINT:
hdc =BeginPaint(hwnd, &ps);
GetClientRect(hwnd,&rect);
DrawText(hdc,TEXT("Hello, window 7!"), -1,&rect,
DT_SINGLELINE| DT_CENTER | DT_VCENTER);
EndPaint(hwnd,&ps);
break;
case WM_DESTROY:
PostQuitMessage(0); // 0为消息WM_QUIT的wParam参数
break;
default:
returnDefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
注:改变的地方如红色标示的地方. break退出该层循环或switch ,而return退出函数