先来看看代码:看不懂不要慌!!!
#include<windows.h> #include<mmsystem.h> #pragma comment(lib,"WINMM.LIB") LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("HelloWin"); HWND hwnd; MSG msg; WNDCLASS 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; wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass)) { MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, TEXT("The Hello Program"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_U SEDEFAULT, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } system("pause"); return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, 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,Windows 98"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
让我们先从头向下看吧:
似乎第三行就有点懵了,是不是呢?那我来谈下把!
LRESULT是一个数据类型,指的是从窗口程序或者回调函数返回的32位值。
在WINNT.H中typedef long LONG;
在WINDEF.H中typedef LONG LRESULT;
所以LRESULT就是长整型。之所以取名类LRESULT,是因为L即long;result表示结果,说明这个函数的返回值是某个结果。
CALLBACK是由用户设计却由windows系统呼叫的函数,统称为callback函数。某些API函数要求以callback作为你参数之一。
实际上CALLBACK就是__stdcall(回调函数),这里也叫窗口函数,来执行窗口的消息循环,在建立窗口类的时候,可以指明窗口函数地址。
想到 WndProc是函数名了,后面跟着的是不是就是参数了呢?
其实并不是,它们都是标识符!!!
(HWND, UINT, WPARAM, LPARAM)各个标识符的意思:
前面谈到过:HWND 是窗口的句柄。hwnd用来接收当前消息的窗口句柄。
UINT 也谈过,就是unsigned int 无符号整型,两个字节。Messsage是被传过来的消息。
WPARAM WP是前缀名,表示宽字符指针。wParam 是用来附加在消息上的数据。和 MSG 结构体一样
LPARAM LP是前缀名,表示长指针。lParam 也是用来附加在消息上的数据。和 MSG 结构体一样。
从标识符的命名来说,英语好的话会对标识符有更好的理解和记忆。
谈完了函数的定义部分,接下来就谈一下函数的声明的部分啦:
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, 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,Windows 98"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
可以发现,Windows程序的定义和C语言的有些不同呢!
定义里括号里面的都是标识符,不用带参数的。不过声明到时一样的!
再向下看是不是又懵了,那些 HDC,PAINTSTRUCT, RECT 又是什么鬼?
下面再来介绍下:
HDC:设备上下文 句柄(可以理解为指向DC结构的指针),它指向一块描述设备的相关的内容的内存块。
DC: 设备上下文(设备描述表),是WINDOWS的一种数据类型。
这样说的话,又出现了新的问题,设备上下文 又是啥?
HDC设备上下文 是一种包含有关某个设备(如显示器或打印机)的绘制属性信息的 Windows 数据结构。所有绘制调用都通过设备上下文对象进行,这些对象封装了用于绘制线条、形状和文本的 Windows API。
简单的说:
HDC是指窗体、控件的句柄,是长整类型。这是windows编程里很重要的一个类型,它唯一标识了一个对象 ,比如窗口,按钮,视图等,也就是一个代号。
那 PAINTSTRUCT 是什么呢?
从名字上不难看出,应该是和绘图有关的结构体。 ps自然就是结构体变量。这里简单的了解下就行,后面会详细介绍的。
PAINTSTRUCT 包含了用于绘制窗口客户区的信息。例如要更新的客户区的矩形区域的大小等等。
程序处理 WM_PAINT 消息时将会用到它,该结构体的作用就是重绘客户区的。
每个窗口要有一个PAINTSTRUCT结构来记录一些绘制信息,PAINTSTRUCT结构保存了窗口绘制客户区的一些信息,例如,绘制客户区时是否要清除背景色,要更新的客户区的矩形区域的大小等等。
那RECT又是什么东西呢?
其实它也是一个结构体,用来显示窗口的位置的。可以看下它的结构体:
typedef struct _RECT { LONG left; LONG top; LONG right; LONG bottom; } RECT, *PRECT;
现在switch() 的语法大家都懂,但是里面的语句又很难受了!
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,Windows 98"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; }
看到这段代码,可以知道程序是想针对传入的消息进行处理。
消息的值可能是:WM_CREATE, WM_PAINT, WM_DESTROY 等。
你们肯定想到了,case 后面的都应该是整型常量表达式。其实消息的值都是这类型,只不过内部把这些数值
用宏定义#define处理了。
现在来看第一个 case 语句:WM_CREATE 是窗口消息中的 请求创建窗口时的消息
PlaySound函数的原型为:
BOOL PlaySound(LPCSTR pszSound, HMODULE hmod,DWORD fdwSound);
PlaySound参数:pszSound是指定了要播放声音的字符串,该参数可以是WAVE文件的名字,或是WAV资源的名字,或是内存中声音数据的指针,或是在系统注册表WIN.INI中定义的系统事件声音。如果该参数为NULL则停止正在播放的声音。
参数hmod是应用程序的实例句柄,除非pszSound的指向一个资源标识符(即fdwSound被定义为SND_RESOURCE),否则必须设置为NULL。
参数fdwSound是标志的组合。若成功则函数返回TRUE,否则返回FALSE。
一些fdwSound的标志请自己查找相关资料!!!
使用PlaySound函数时需要在 #include<windows.h> 后面加上 ( 不能在前面加 ).
#include <mmsystem.h>
#pragma comment(lib, "WINMM.LIB")
下面来看第二个case 语句:WM_PAINT 是窗口消息中的 客户区重绘消息
这个消息在Windows程序设计中是很重要的。当窗口显示区域的一部分显示内容或者全部变为“无效”,以致于必须“更新画面”时,将由这个消息通知程序。当需要绘制一部分应用窗口的时候,这个消息被Windows或者其他应用程序绘制调用。
对WM_PAINT的处理几乎总是从一个BeginPaint调用开始:hdc = BeginPaint (hwnd, &ps) ;
而以一个EndPaint调用结束:EndPaint (hwnd, &ps) ;
在这两个调用中,第一个参数都是程序的窗口句柄,第二个参数是指向型态为PAINTSTRUCT的结构指针。PAINTSTRUCT结构中包含一些窗口消息处理程序,可以用来更新显示区域的内容。
BeginPaint调用令整个显示区域有效,并传回一个“设备上下文句柄”。在窗口的显示区域显示文字和图形需要设备上下文句柄。但是从BeginPaint传回的设备上下文句柄不能在显示区域之外绘图。EndPaint释放设备上下文句柄,使之不再有效。
调用完BeginPaint之后,WndProc接着调用GetClientRect:
GetClientRect (hwnd, &rect) ;
第一个参数是程序窗口的句柄。第二个参数是一个指针,指向一个RECT型态的rectangle结构。该结构有四个LONG字段,分别为left、top、right和bottom。GetClientRect将这四个字段设定为窗口显示区域的尺寸。left和top字段通常设定为0,right和bottom字段设定为显示区域的宽度和高度(像素点数)。WndProc除了将该RECT结构指针作为DrawText的第四个参数传递外,不再对它做其它处理。
下面来看第三个 case 语句: WM_DESTROY 是窗口消息中的 窗口摧毁消息
PostQuitMessage,函数名。该函数向系统表明有个线程有终止请求。通常用来响应 WM_DESTROY 消息。
函数原型:
Void PostQuitMessage(
int
nExitCode)
参数:nExitCode:指定应用程序退出代码。此值被用作消息WM_QUIT的wParam参数。PostQuitMessage寄送一个WM_QUIT消息给线程的消息队列并立即返回;此函数向系统表明有个线程请求在随后的某一时间终止。当线程从消息队列里取得WM_QUIT消息时,应当退出消息循环并将控制返回给系统。返回给系统的退出值必须是消息WM_QUIT的wParam参数。
最 后 :return DefWindowProc(hwnd, message, wParam, lParam); 函数返回 DefWindowProc() 处理的结果。
关于DefWindowProc()函数
DefWindowProc()函数调用缺省的窗口过程来为应用程序没有处理的任何窗口消息提供缺省的处理。
该函数确保每一个消息得到处理。
DefWindowProc这个函数是默认的窗口处理函数,我们可以把不关心的消息都丢给它来处理。这个函数在处理关闭窗口消息WM_CLOSE时,是调用DestroyWindow函数关闭窗口并且发WM_DESTROY消息给应用程序;而它对WM_DESTROY这个消息是不处理的(考虑为什么?);我们在应用程序中对这个消息的处理是发出WM_QUIT消息。因此WM_CLOSE、WM_DESTROY、WM_QUIT这三个消息是先后产生的。
关于 WindowProc 的部分就介绍到这里了。这只是本节的一部分,下节内容将更详细的介绍。
抱歉,不太会用编辑器,导致多了一个代码段还删除不了。请读者多见谅!