您所在的位置:读书频道 > 设计开发 > 其它开发 > 2.1.3 晒一晒WinProc的秘密

2.1.3 晒一晒WinProc的秘密

2011-03-02 18:50 陈征/傅鑫 等译 机械工业出版社 字号:T | T
一键收藏,随时查看,分享好友!

《游戏编程入门(原书第3版)》第2章侦听Windows消息,本章将更详细地学习Windows消息机制和主循环,并编写一个完整的能够在屏幕上显示一些内容的窗口程序。将学习窗口句柄和设备环境如何一起在窗口上产生输出。本章继续探究实时游戏循环,尤其是获得WinMain之外的实时循环的方法。我们将在本章学到一些新的技巧,以便让实时循环运行,为下一章的DirectX做准备。本节为大家介绍WinProc的秘密。

AD:

2.1.3 晒一晒WinProc的秘密

WinProc是窗口回调过程,Windows通过它将事件传递给程序。回调函数是被调用回来的函数(可能你自己已经琢磨出了这句话的意思)。回忆一下MyRegisterClass设置的传递给RegisterClassEx的WNDCLASS结构。一旦注册了类,就可创建窗口并显示在屏幕上。该结构中的一个字段,lpfnWinProc,被设置为窗口回调过程的名称,通常为WinProc。这个函数处理所有发送给主程序窗口的消息。所以,通常WinProc是主程序源代码文件中最长的函数。图2-2显示了WinProc处理事件消息的方法。

1. WinProc函数调用

窗口回调函数如下所示:

 
图2-2 WinProc回调函数处理与该应用程序相关的事件
 

需要了解这个函数,因为它是通向初始化Direct3D的钥匙。它的参数既简单又直白,它们代表Windows程序的真实“引擎”。据前述,这一信息是早先在WinMain中由GetMessage函数获取的。不要将InitInstance和WinProc混淆在一起。InitInstance只运行一次,对选项进行设置。而后就由WinProc接管,接收并处理消息。

我们来看看WinProc的参数:

HWND hWnd。第一个参数是窗口句柄。在游戏中,通常要使用hWnd作为参数创建一个新的设备环境句柄,也就是一个hDC。在DirectX到来之前,必须要保留好窗口句柄,因为只要引用一个窗口或控件就必须使用到它。在DirectX程序中,窗口句柄仅在开始时用于创建窗口。

UINT message。第二个参数是发送给窗口回调过程的消息。消息可以是任何东西,甚至是无需使用的消息。由于这个原因,有一个将消息传递给默认消息处理器的方法(在下一节讨论)。

WPARAM wParam和LPARAM lParam。最后两个参数是与特定命令消息一起传递过来的参数值的高位和低位。下一节将讲解它们。

2. WinProc的大秘密

在随后的章节中开发的助手函数,其目标之一是为WinProc中的初始化和消息处理等事务提供帮助。我们的游戏库中的函数将在单独的源代码文件中处理窗口消息,以便将Windows核心代码与游戏代码分开(这样更易使用)。

以下是窗口回调过程的一个简单版本,随后是其解释:

 

 

由于我们已经熟悉了这些参数,就直接切入正题了。这个函数可以分为两个主要部分:声明部分和如同一个大的if语句嵌套的switch语句。在switch语句中也有两个主要部分:处理命令消息和正常消息的case语句。命令将使用WinProc的最后两个参数:wParam和lParam,而正常消息通常不需要这些参数。

PAINTSTRUCT变量ps用在WM_PAINT消息处理器中,用于启动及停止屏幕更新,这就如在进行更新时解锁和锁住设备环境(于是在这个过程中屏幕内容不会不完整)。hdc变量也在WM_PAINT消息处理器中使用,用于获取程序窗口的设备环境。其他变量用于在屏幕上显示消息(szHello)及在窗口中绘制像素点(x、y、n和c)。

在变量声明之后是switch(message)语句。它是处理多个消息更为容易的方法,要比使用嵌套if语句好得多。在处理大量条件测试时,switch的能力要强得多,所以将它用在WinProc中进行消息的检查。

首先要讲解的是WM_DESTROY。WM_DESTROY消息标识符告诉窗口该关闭了。程序应该从内存中移除对象,然后调用PostQuitMessage函数结束程序,从而优雅地关闭。下一步在编写Direct3D代码时,这将会是唯一需要关心的消息,因为WM_PAINT在Direct3D程序中不需要。

好了,回到第一个消息标识符—WM_PAINT。对于游戏编程而言这绝对是个最为有趣的消息,因为窗口更新在这里处理。再次看一下WM_PAINT的代码:

 

调用BeginPaint函数是为了锁住设备环境以便进行更新(使用窗口句柄和PAINTSTRUCT变量)。对GetClientRect的调用是为了获取程序窗口的矩形区域并保存到一个RECT变量中。DrawText使用它将消息绘制在窗口的中央。注意,BeginPaint返回程序窗口的设备环境。在每次刷新时这都是必需的,因为,尽管不常见,但在程序运行中不能保证设备环境是个常量(例如,内存不够用,程序被转移到虚拟内存的分页文件中,而后又重新取出。这样的事件几乎肯定会生成新的设备环境)。

真正在用户界面上做了一些事情的代码是第三行,它调用DrawText。这个函数在目标设备环境中显示消息。末尾的DT_CENTER参数告诉DrawText将消息对齐到所传递的矩形的顶部中央位置。当然,也正是这部分代码在屏幕上绘制像素点。那么,如果更改窗口尺寸所有的像素点都会被重新绘制吗?试一试吧!很酷,对不?这完美地演示了WM_PAINT:在窗口需要重绘时它会被调用。如果更改窗口尺寸,会发生对WM_PAINT的多次调用,每次的矩形(通过GetClientRect返回)都不一样。

绘制消息处理器的最后一行调用EndPaint以关闭本次消息处理器迭代所用的图形系统。

建议 系统不会连续不断地调用WM_PAINT,只有当窗口必须重绘时才会调用,这与实时循环不同。所以,WM_PAINT不是个适合为游戏插入屏幕刷新代码的位置。就如第3章要学的内容那样,我们必须修改WinMain中的循环,让代码在实时循环中运行。

【责任编辑:云霞 TEL:(010)68476606】

回书目   上一节   下一节

×
分享到:

  1. Linux服务器配置全程实录
  2. 揭秘--优秀PPT这样制作

热点职位

更多>>

热点专题

更多>>

读书

大师品软件——软件之痛与应对之道
这并不是一本传统的技术专著,因为它并没有包含一行代码,而更像是一部技术评论。作者通过幽默诙谐而又不失辛辣的语言,从程序员

51CTO旗下网站

领先的IT技术网站 51CTO 领先的中文存储媒体 WatchStor 中国首个CIO网站 CIOage 中国首家数字医疗网站 HC3i