友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!阅读过程发现任何错误请告诉我们,谢谢!! 报告错误
喜书网 返回本书目录 我的书架 我的书签 TXT全本下载 进入书吧 加入书签

C语言实例教程(PDF格式)-第22章

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!




意的是,并不一定是所有属于某一个窗口的消息都发送给窗口的窗口 

过程,比如对于WM_TIMER消息,如果其lParam参数不为NULL的话,由 

该参数所指定的函数将被调用,而不是窗口过程。  



如果GetMessage从消息队列中得到一个WM_QUIT消息,则它将返回一 

个假值,从而退出消息循环,WM_QUIT消息的wParam参数指定了由 

PostQuitMessage函数给出的退出码,一般情况下,WinMain函数返回 

同一值。  



下面我们来看一下程序主窗口的窗口过程WndProc。窗口过程名是可 

以由用户自行定义,然后在注册窗口类时在WNDCLASS结构中指定。但 

是,一般来说,程序都把窗口过程命令为WndProc来类似的名称,如 

MainWndProc等,并不是一定要这样做,但是这样明显的有利于阅 

读,因此也是我们推荐的做法。窗口过程具有如下的原型:  



LRESULT WINAPI WndProc(HWND;UINT;WPARAM;LPARAM);  



或  



LRESULT CALLBACK WndProc(HWND;UINT;WPARAM;LPARAM);  



对于编译器而言,两种书写形式都是一样的,它们都等价于  


…………………………………………………………Page 135……………………………………………………………

long __stdcall WndProc(void *;unsigned int;unsigned int;long)  



窗口过程使用了四个参数,在它被调用时(再强调一点,一般情况 

下,窗口过程是由操作系统调用,而不是由应用程序调用的,这就是 

我们为什么将它们称为回调函数的道理),这四个参数对应于所发送 

消息结构的前四个成员。下面给出了一个窗口过程的例子:  



// WndProc 主窗口过程  



LRESULT WINAPI WndProc (HWND hWnd;  



UINT msg;  



WPARAM wParam;  



LPARAM lParam)  



{  



HDC hdc;  



RECT rc;  



HPEN hPen;hPenOld;  



HBRUSH hBrush;hBrushOld;  



switch (msg)  



{  



case WM_PAINT:  



hdc=GetDC(hWnd);  



GetClientRect(hWnd;&rc);  



hPen=CreatePen(PS_SOLID;0;RGB(0;0;0));  



hBrush=CreateHatchBrush(HS_DIAGCROSS;RGB(0;0;0));  



hPenOld=SelectObject(hdc;hPen);  



hBrushOld=SelectObject(hdc;hBrush);  



Ellipse(hdc;rc。left;rc。top;rc。right;rc。bottom);  



SelectObject(hdc;hPenOld);  



SelectObject(hdc;hBrushOld);  


…………………………………………………………Page 136……………………………………………………………

ReleaseDC(hWnd;hdc);  



break;  



case WM_DESTROY:  



PostQuitMessage(0);  



break;  



default:  



break;  



}  



return DefWindowProc(hWnd;msg;wParam;lParam);  



}  



在该窗口过程中,我们处理了最基本两条消息。  



第一条消息是WM_PAINT,当窗口客户区的全部或一部分需要重绘时, 

系统向该窗口发送该消息。在前面的过程中我们已经提到过,在使用 

ShowWindow函数显示窗口之后,通常随即调用函数UpdateWindow,该 

函数直接向窗口过程发送一个WM_PAINT消息,以通知窗口绘制其客户 

区。在该消息的处理函数中,我们先使用GetDC获得窗口的设备句 

柄,关于设备句柄本书后面将要专门涉及,这里我们只需知道它是用 

来调用各种绘图方法的。然后调用GetClientRect获得当前窗口的客 

户区矩形。接着调用CreatePen创建一个黑色画笔,调用 

CreateHatchBrush创建一个45度交叉线的填充画刷,并且 

SelectObject函数将它们选入设备描述表中,原有的画笔和画刷被保 

存到hPenOld和hBrushOld中,以便以后恢复。完成以上步骤之后,调 

用Ellipse函数以当前客户区大小绘制一个椭圆。最后,再一次调用 

SelectObject函数恢复原有的画笔和画刷,并调用ReleaseDC释放设 

备描述表句柄。在这个消息的处理代码中,我们涉及到了一些新的概 

念、数据类型和API函数,然而本章并不着意于讲述这些内容,读者 

也不必深究它们,这些代码只是为了完整该示例程序才使用的。对于 

窗口来说,除了客户区以外的其它内容将由系统进行重绘,这些内容 

包括窗口标题条、边框、菜单条、工具条以及其它控件,如果包含了 

它们的话。这种重绘往往发生在覆盖于窗口上方的其它窗口被移走, 

或者是窗口被移动或改变大小时。因此,对于大多数窗口过程来说, 

WM_PAINT消息是必须处理的。  



另一个对于绝大多数窗口过程都必须处理的消息是WM_DESTROY,当窗 


…………………………………………………………Page 137……………………………………………………………

口被撤消时(比如用户从窗口的系统菜单中选择了 “关闭”,或者单 

击了右边的小叉,对于这些事件,Windows的默认处理是调用 

DestroyWindow函数撤销相应的窗口),将会接收到该消息。由于本程 

序仅在一个窗口,因此在这种情况下应该终止应用程序的执行,因此 

我们调用了PostQuitMessage函数,该函数向线程的消息队列中放入 

一个WM_QUIT消息,传递给PostQuitMessage函数的参数将成为 

WM_QUIT消息的wParam参数,在上面的例子中,该值为0。  



对于其它情况,在上面的示例程序中我们没有必要进行处理, 

Windows专门为此提供了一个默认的窗口过程,称为DefWindowProc, 

我们只需要以WndProc的参数原封不动的调用默认窗口过程 

DefWindowProc,并将其返回值作为WndProc的返回值即可。  



将上面讲述的所有内容综合起来,我们就已经使用Win32   SDK完成了 

一个功能简单,但是结构完整的Win32应用程序了。对于使用Win32  

SDK编写的实用的Win32应用程序,它们的结构与此相比要复杂得多, 

在这些情况下,应用程序也许不仅仅包括一个窗口,而对应的窗口过 

程中的switch结构一般也会是一个异常膨胀的嵌套式switch结构。如 

此庞大的消息处理过程大大增加了程序调试和维护的难度,使用MFC 

则有可能在很多程度上减轻这种负担,这便是MFC为广大程序员所乐 

于接受,以至今天成为实际上的工业标准的原因。但是,不管它如何 

复杂,归根到底,一般情况下,它仍然具有和我们的这个功能简单的 

Win32应用程序一样或类似的结构。为了读者阅读和分析方便,我们 

把这个程序的完整代码给出如下:  



#include   



// 函数原型  



int WINAPI WinMain(HINSTANCE;HINSTANCE;LPSTR;int);  



LRESULT WINAPI WndProc(HWND;UINT;WPARAM;LPARAM);  



// WinMain 函数  



int WINAPI WinMain (HINSTANCE hInstance;  



HINSTANCE hPrevInstance;  



LPSTR lpCmdLine;  



int nCmdShow)  



{  


…………………………………………………………Page 138……………………………………………………………

HWND hWnd; // 主窗口句柄  



MSG msg; // 窗口消息  



WNDCLASS wc; // 窗口类  



if (!hPrevInstance)  



{  



// 填充窗口类信息  



wc。style=CS_HREDRAW|CS_VREDRAW;  



wc。lpfnWndProc=WndProc;  



wc。cbClsExtra=0;  



wc。cbWndExtra=0;  



wc。hInstance=hInstance;  



wc。hIcon=LoadIcon(NULL;IDI_APPLICATION);  



wc。hCursor=LoadCursor(NULL;IDC_ARROW);  



wc。hbrBackground=GetStockObject(WHITE_BRUSH);  



wc。lpszMenuName=NULL;  



wc。lpszClassName=〃SdkDemo1〃;  



// 注册窗口类  



RegisterClass(&wc);  



}  



// 创建应用程序主窗口  



hWnd=CreateWindow (〃SdkDemo1〃; // 窗口类名  



〃第一个Win32 SDK应用程序〃; // 窗口标题  



WS_OVERLAPPEDWINDOW; // 窗口样式  



CW_USEDEFAULT; // 初始化 x 坐标  



CW_USEDEFAULT; // 初始化 y 坐标  



CW_USEDEFAULT; // 初始化窗口宽度  


…………………………………………………………Page 139……………………………………………………………

CW_USEDEFAULT; // 初始化窗口高度  



NULL; // 父窗口句柄  



NULL; // 窗口菜单句柄  



hInstance; // 程序实例句柄  



NULL); // 创建参数  



// 显示窗口  



ShowWindow(hWnd;SW_SHOW);  



// 更新主窗口客户区  



UpdateWindow(hWnd);  



// 开始消息循环  



while (GetMessage(&msg;NULL;0;0))  



{  



TranslateMessage(&msg);  



DispatchMessage(&msg);  



}  



return msg。wParam;  



}  



// WndProc 主窗口过程  



LRESULT WINAPI WndProc (HWND hWnd;  



UINT msg;  



WPARAM wParam;  



LPARAM lParam)  



{  



HDC hdc;  



RECT rc;  



HPEN hPen;hPenOld;  


…………………………………………………………Page 140……………………………………………………………

HBRUSH hBrush;hBrushOld;  



switch (msg)  



{  



case WM_PAINT:  



hdc=GetDC(hWnd);  



GetClientRect(hWnd;&rc);  



hPen=CreatePen(PS_SOLID;0;RGB(0;0;0));  



hBrush=CreateHatchBrush(HS_DIAGCROSS;RGB(0;0;0));  



hPenOld=SelectObject(hdc;hPen);  



hBrushOld=SelectObject(hdc;hBrush);  



Ellipse(hdc;rc。left;rc。top;rc。right;rc。bottom);  



SelectObject(hdc;hPenOld);  



SelectObject(hdc;hBrushOld);  



ReleaseDC(hWnd;hdc);  



break;  



case WM_DESTROY:  



PostQuitMessage(0);  



break;  



default:  



break;  



}  



return DefWindowProc(hWnd;msg;wParam;lParam);  



}  



该示例代码中的所有内容都已在前面做了完整的讲解,这里我们简单 

的说一下如何在Microsoft Developer Studio中编译该示例程序。请 

按下面的步骤进行:  



1。  选择File菜单下的New命令,新建一个Win32  Application工程, 


…………………………………………………………Page 141……………………………………………………………

这里我们假设对该工程命名为SdkDemo1,而事实上这完全取决于你的 

意愿。这个过程已经在本书的第一章中作
返回目录 上一页 下一页 回到顶部 0 0
未阅读完?加入书签已便下次继续阅读!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!