📄 g02.htm
字号:
───────────┴─────────────────────<br> 注意:还有其他的高级OS级标志,我们没有讨论。如果希望了解更多细节的话,可以通过编译器Win32 SDK的在线帮助来查阅。</p> <p> 可以同时使用表2.3中的值进行逻辑或运算,来创建一个信息框。一般情况下,只能从每一组中仅使用一个标志来进行或运算。<br> 当然,和所有Win2 API函数一样,MessageBox()函数返回一个值业通知编程者所发生的事件。但在这个例子中谁关心这个呢?通常情况下,如果信息框是yes/no提问之类的情况的话,就希望知道这个返回值。表2.4列出了可能的返回值。</p> <p> <b>表2.4 MessageBox()的返回值</b><br> ─────┬─────────────────────<br> 值 │ 按钮选择<br> ─────┼─────────────────────<br> IDABORT │Abort<br> IDCANCEL │Cancel<br> IDIGNORE │Ignore<br> IDNO │No<br> IDOK │OK<br> IDRETRY │Retry<br> IDYES │Yes<br> ─────┴─────────────────────</p> <p> 最后,这个表已经毫无遗漏地列出了所有的返回值,正在已经完成了对我们第一个Windows程序——单击的逐行分析。</p> <p> 技巧:现在希望你能轻松地对这个程序进行修改,并以不同的方式进行编译,使用不同的编译器选项,例如优化,然后尝试通过调试程序来运行该程序,看看你是否已经领会,做完后,请回到此处。 </p> <p> BOOL MessageBeep(UNIT utype);//运行声音<br> 可以从表2.5所示常数中得到不同的声音。</p> <p> 表2.5 MessageBeep()函数的声音标识符<br> ───────────┬───────────────<br> 值 │ 声音<br> ───────────┼───────────────<br> MB_ICONASTERISK │系统星号<br> MB_ICONEXCLAMATION │系统惊叹号<br> MB_ICONHAND │系统指针<br> MB_ICONQUESTION │系统问号<br> MB_OK │系统默认值<br> 0xFFFFFFFF │使用计算机扬声器的标准嘟嘟声<br> ───────────┴───────────────<br> 注意:如果已经安装了MS_Plus主题曲的话,你应能得到有意思的结果。<br> 看Win32 API多酷啊!可以有上百个函数使用。它们虽然不是世界是最快的函数,但是对于一般的内部管理I/O和GUN来讲,它们已经很棒了。<br> 让我们稍微花点时间总结一下我们目前所知的有关Windwos编程方面的知识。首先,Windows支持多任务/多线程,因此可以同时运行多个应用程序。我们不必费心就可以做到这一点,我们最关系的是Windows支持事件触发。这就意味着我们必须处理事件(在这一点上目前我们还不知如何做)并且做出反应。好,听上去不错。最后所有Windows程序都以函数WinMain()开始,WinMain()函数中的参数要比标准DOS Main()多得多,但这些参数都属于逻辑和推理的领域。<br> 掌握了上述的内容,就到了编写一个真正的Windows应用程序的时候了。 </p> <p></p> <p><b>真实的Windows应用程序</b></p> <p> 尽管本书的目标是编写在Windows环境下运行的3D游戏,但是你并不需要了解更多的Windows编程。实际上,你所需要的就是一个基本的Windows程序,可以打开一个窗口、处理信息、调用主游戏循环等等。了解了这些,本章中的目标是首先向你展示如何创建简单的Windows应用程序,同时为编写类似32位DOS环境的游戏外壳程序奠定基础。<br> 一个Windows程序的关键就是打开一个窗口。一个窗口就是一个显示文本和图形信息的工作区。要创建一个完全实用的Windows程序,只要进行下列工作:<br> 1.创建一个Windows类。<br> 2.创建一个事件句柄或WinProc。<br> 3.用Windows注册Windows类。<br> 4.用前面创建的Windows类创建一个窗口。<br> 5.创建一个能够从事件句柄获得或向事件句柄传递Windows信息的主事件循环。<br> 让我们详细了解一下每一步的工作。 </p> <p> <b>Windows类</b></p> <p> Windows实际上是一个面向对象的的操作系统,因此Windows中大量的概念和程序都出自C++。其中一个概念就是Windows类。Windows中的每一个窗口、控件、列表框、对话框和小部件等等实际上都是一个窗口。区别它们的就是定义它们的类。一个Windows类就是Windows能够操作的一个窗口类型的描述。<br> 有许多预定义的Windows类,如按钮、列表框、文件选择器等等。你也可以自己任意创建你的Windows类。实际上,你可以为自己编写的每一个应用程序创建至少一个Windows类。否则你的程序将非常麻烦。因此你应当在画一个窗口时,考虑一个Windows类来作为Windows的一个模板,以便于在其中处理信息。<br> 控制Windows类信息的数据结构有两个:WNDCLASS和WNDCLASSEX。WNDCLASS是比较古老的一个,可以不久将废弃,因此我们应当使用新的扩展版WNDLCASSEX。二都结构非常相似,如果有兴趣的话,可以在Win32帮助中查阅WNDCLASS。让我们看一下在Windows头文件中定义的WNDCLASSEX。<br> typedef struct _WNDCLASSEX<br> {<br> UINT cbSize;//size of this structure<br> UINT style;//style flags<br> WNDPROC lpfnWndProc;//function pointer to handler<br> int cbClsExtra;//extra class info<br> int cbWndExtra;//extra window info<br> HANDLE hInstance;//the instance of the application<br> HICON hIcon;//the main icon<br> HCURSOR hCursor;//the cursor for the window<br> HBRUSH hbrBackground;//the background brush to paint the window<br> LPCTSTR lpszMenuName;//the name of the menu to attach<br> LPCTSTR lpszClassName;//the name of the class itself<br> HICON hIconSm;//the handle of the small icon<br> } WNDCLASSEX <br> 因此你所要做的就是创建一个这样的结构,然后填写所有的字段:<br> WNDCLASSEX winclass;//a blank windows class<br> 第一个字段cbSize非常重要(但Petzold在《Programming Windows 95》忘记了这个内容),它是WNDCLASSEX结构本身的大小。你可能要问,为什么应当知道该结构的大小?这个问题问得好,原因是如果这个结构作为一个指针被传递的话,接收器首先构件第一个字段,以确定该数据导体最低限度有多大。这有点像提示和帮助信息,以便于其他函数在运行时不必计算该类的大小。因此,我们应当这样做:<br> winclass.cbSize = sizeof(WNDCLASSEX);<br> 第二个字段包含描述该窗口一般属性的结构信息标志。有许多这样的标志,因此我们不能全部列它们。只要能够使用它们创建任何类型的窗口就行了。表2.6列出了常用的标志。读者可以任意对这些值进行逻辑“或”运算,来派生所希望的窗口类型。</p> <p> <b>表2.6 Windows在的类型标志</b><br> ──────┬──────────────────────────<br> 标志 │ 说明<br> ──────┼──────────────────────────<br> <b>CS_HREDRAW</b> │若移动或改变了窗口宽度,则刷新整个窗口<br> <b>CS_VREDRAW</b> │若移动或改变了窗口高度,则刷新整个窗口<br> <b>CS_OWNDC</b> │为该类中每个窗口分配一个单值的设备描述表(在本章后<br> │面详细描述)<br> <b>CS_DBLCLKS</b> │当用户双击鼠标时向窗口程序发送一个双击的信息,同时,<br> │光标位于属于该类的窗口中<br> CS_PARENTDC│在母窗口中设定一个子窗口的剪切区,以便于子窗口能够<br> │画在母窗口中<br> CS_SAVEBITS│在一个窗口中保存用户图像,以便于在该窗口被遮住、移<br> │动时不必每次刷新屏幕。但是,这样会占用更多的内存,<br> │并且比人工同样操作要慢得多<br> CS_NOCLOSE │禁止系统菜单上的关闭命令<br> ──────┴──────────────────────────<br> 注意:用黑体显示的部分为最常用的标志 </p> <p> 表2.6包含了大量的标志,即使读者对此尚有疑问,也无关紧要。现在,设定类型标识符,描述如果窗口移动或改变尺寸就进行屏幕刷新,并可以获得一个静态的设备描述表以及处理双击事件的能力。<br> 我们将在第三章“高级Windows编程”中详细讨论设备描述表,但基本说来,它被用作窗口中图像着色的数据结构。因此如果你要处理一个图像,就应为感兴趣的特定窗口申请一个设备描述表。如果设定了一个Windows灰,它就通过CS_OMNDC得到了一个设备描述表,如果你不想每次处理图像时都申请设备描述表,可以将它保存一段时间。上面说的对你有帮助还是使你更糊涂?Windows就是这样——你知道得越多,问题就越多。旭了!下面说一下如何设定类型字段:<br> winclass.style = CS_VERDRAW | CS_HREDRAW | CS_OWNDC | CS_DBLCLICKS;<br> WNDCLASSEX结构的下一个字段lpfnWndProc是一个指向事件句柄的函数指针。基本上这里所设定的都是该类的回调函数。回调函数在Windows编程中经常使用,工作原理如下:当有事件发生时,Windows通过调用一个你已经提供的回调函数来通知你,这省去你盲目查询的麻烦。随后在回调函数中,再进行所需的操作。<br> 这个过程就是基本的Windows事件循环和事件句柄的操作过程。向Windows类申请一个回调函数(当然需要使用特定的原型)。当一个事件发生时,Windows按如图2.6所示的那样替你调用它。关于该项内容我们将在下面部分进行更详细的介绍。但是现在,读者只要将其设定到你将编写的事件函数中去:<br> winclass.lpfnWndProc = WinProc;//this is our function<br> -----------(图2.6 windows事件句柄回调函数的操作流程 略) </p> <p> <b>C++</b> 函数指针有点像C++中的虚函数。如果你对它们不熟悉的话,在这里讲一上,假设有两个函数用以操作两个数:<br> int Add(int op1,int op2) {return(op1+op2);}<br> int Sub(int op1,int op2) {return(op1-op2);}<br> 要想用同一调用来调用两个函数,可以用一个函数指针来实现,如下:<br> //define a function pointer that takes two int and returns an int<br> int (Math*)(int,int);<br> 然后可以如下配置函数指针:<br> Math = Add;<br> int result = Math(1,2);//this reslly calls Add(1,2)<br> //result will be 3<br> Math = Sub;<br> int result = Math(1,2);//this really calls Sub(1,2)<br> //result will be -2<br> 看,不错吧。</p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -